From 669e4cc96a88ee5df5c95b8ea5f4485d8f721ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Sun, 10 May 2020 20:44:50 +0100 Subject: [PATCH] cmd/gogio: speed up the wine e2e test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First, use wineboot instead of winecfg to set up the WINEPREFIX. It's the right tool for it. Second, when initialising WINEPREFIX, use output pipes instead of CombinedOutput. The latter will wait for *all* output to be copied to a buffer, including the output from grandchildren processes. Since wine starts wineserver automatically, and wineserver lingers for three seconds by default, this is bad. We would waste three seconds waiting for wineserver doing nothing, and then the next wine call (to start the app) would need to start wineserver all over. Instead, with pipes we can get cmd.Run to only wait for the parent process to finish. wineserver stays running but we don't care. And, when we start the gio app, we very likely reuse the same wineserver process. Third, disable wine-gecko and wine-mono. This ensures we don't get stuck if they're not installed, and speeds up wineboot by avoiding work we don't need. The time to set up WINEPREFIX goes down form ~6s to ~1s, and the overall subtest run-time goes down from ~10s to ~3s. Finally, copiously document all of the precious data I've gathered above after hours of debugging. Signed-off-by: Daniel Martí --- cmd/gogio/windows_test.go | 48 +++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/cmd/gogio/windows_test.go b/cmd/gogio/windows_test.go index 6c26ed50..86fa48e1 100644 --- a/cmd/gogio/windows_test.go +++ b/cmd/gogio/windows_test.go @@ -5,6 +5,7 @@ package main_test import ( "context" "image" + "io" "os" "os/exec" "path/filepath" @@ -69,29 +70,46 @@ func (d *WineTestDriver) Start(path string) { // to reuse a previously set up wineprefix. wineprefix := filepath.Join(cacheDir, "gio-e2e-wine") - // First, run a headless winecfg to make sure the wineprefix is - // set up. If Wine encounters any issue setting up, we can also - // report it early. This can easily take 5s the first time. The - // "/?" parameter is just to not try to open the winecfg GUI. - // TODO(mvdan): Why does this take ~2s when run with a terminal - // (pty), but it takes ~6s when run here? + // First, ensure that wineprefix is up to date with wineboot. + // Wait for this separately from the first frame, as setting up + // a new prefix might take 5s on its own. + env := []string{ + "DISPLAY=" + d.display, + "WINEDEBUG=fixme-all", // hide "fixme" noise + "WINEPREFIX=" + wineprefix, + + // Disable wine-gecko (Explorer) and wine-mono (.NET). + // Otherwise, if not installed, wineboot will get stuck + // with a prompt to install them on the virtual X + // display. Moreover, Gio doesn't need either, and wine + // is faster without them. + "WINEDLLOVERRIDES=mscoree,mshtml=", + } { start := time.Now() - cmd := exec.Command("wine", "winecfg", "/?") - cmd.Env = []string{"WINEPREFIX=" + wineprefix} - if out, err := cmd.CombinedOutput(); err != nil { - d.Fatalf("%v: %s", err, out) + cmd := exec.Command("wine", "wineboot", "-i") + cmd.Env = env + // Use a combined output pipe instead of CombinedOutput, + // so that we only wait for the child process to exit, + // and we don't need to wait for all of wine's + // grandchildren to exit and stop writing. This is + // relevant as wine leaves "wineserver" lingering for + // three seconds by default, to be reused later. + stdout, err := cmd.StdoutPipe() + if err != nil { + d.Fatal(err) + } + cmd.Stderr = cmd.Stdout + if err := cmd.Run(); err != nil { + io.Copy(os.Stderr, stdout) + d.Fatal(err) } d.Logf("set up WINEPREFIX in %s", time.Since(start)) } ctx, cancel := context.WithCancel(context.Background()) cmd := exec.CommandContext(ctx, "wine", bin) - cmd.Env = []string{ - "DISPLAY=" + d.display, - "WINEDEBUG=-all", // hide warnings and other noise - "WINEPREFIX=" + wineprefix, - } + cmd.Env = env output, err := cmd.StdoutPipe() if err != nil { d.Fatal(err)