From 344cdd5e7b961147cc8f4951409289f2ea7b96ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Sun, 24 Sep 2023 15:32:36 +0100 Subject: [PATCH] make `go test -race` fast again on Go 1.21 On my laptop, `go test -short -race` on Go 1.20 used to take about 62s. Jumping to Go 1.21, I was surprised to see an increase to 152s, more than double - which was weird given how often the CPU was idle. This manifested when updating our CI to start testing on Go 1.21. Where Go 1.20 on Linux took about 10m to run `go test -race`, Go 1.21 hit the 20m timeout every single time. After a bit of googling, I was reminded of https://go.dev/issues/20364 as well as https://go.dev/doc/articles/race_detector#Options: atexit_sleep_ms (default 1000): Amount of milliseconds to sleep in the main goroutine before exiting. This default is a bit aggressive for Go, but usually harmless, having each test binary sleep for 1s after the package has been tested. However, this 1s sleep after main runs is horrendous for garble's tests; the testscripts run `garble build` many times, running the test binary. It then runs `go build -toolexec=garble`, which runs the test binary many more times: for every compiler, linker, etc invocation. This means that our testscripts would include dozens of 1s sleeps, in many cases blocking the continuation of the entire test. This seemed to not be happening on earlier Go versions due to a bug; Go 1.21's race mode started obeying this default properly. The added change sets atexit_sleep_ms to something more reasonable if GORACE isn't set at all; 10ms doesn't disable this check entirely, but its overhead is orders of magnitude less noticeable than 1000ms. `go test -short -race` on Go 1.21 drops back down to 68s for me. --- main_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main_test.go b/main_test.go index f1c034e..a26f179 100644 --- a/main_test.go +++ b/main_test.go @@ -31,6 +31,15 @@ import ( var proxyURL string func TestMain(m *testing.M) { + // If GORACE is unset, lower the default of atexit_sleep_ms=1000, + // since otherwise every execution of garble through the test binary + // would sleep for one second before exiting. + // Given how many times garble runs via toolexec, that is very slow! + // If GORACE is set, we assume that the caller knows what they are doing, + // and we don't try to replace or modify their flags. + if os.Getenv("GORACE") == "" { + os.Setenv("GORACE", "atexit_sleep_ms=10") + } if os.Getenv("RUN_GARBLE_MAIN") == "true" { os.Exit(main1()) }