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.
pull/789/head
Daniel Martí 8 months ago
parent 66bdc8b124
commit 344cdd5e7b

@ -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())
}

Loading…
Cancel
Save