From: Brad Fitzpatrick Date: Tue, 21 May 2019 19:02:00 +0000 (+0000) Subject: cmd/dist: support using cross-compiled std test binaries for slow builders X-Git-Tag: go1.13beta1~221 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7a567a631f48f19817a4c9a221e9951ffebfa8cb;p=gostls13.git cmd/dist: support using cross-compiled std test binaries for slow builders We want the builders to be able to cross-compile test binaries for a few of the super slow builders that require either slow hardware or slow full CPU emulation. Updates golang/go#31217 Change-Id: I8d33b18efaf788f6f131354b2917ac9738ca975e Reviewed-on: https://go-review.googlesource.com/c/go/+/178399 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 833baf8f91..f63c94697c 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -12,6 +12,7 @@ import ( "log" "os" "os/exec" + "path" "path/filepath" "reflect" "regexp" @@ -277,8 +278,17 @@ func (t *tester) tags() string { return "-tags=" } +// timeoutDuration converts the provided number of seconds into a +// time.Duration, scaled by the t.timeoutScale factor. +func (t *tester) timeoutDuration(sec int) time.Duration { + return time.Duration(sec) * time.Second * time.Duration(t.timeoutScale) +} + +// timeout returns the "-timeout=" string argument to "go test" given +// the number of seconds of timeout. It scales it by the +// t.timeoutScale factor. func (t *tester) timeout(sec int) string { - return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale)) + return "-timeout=" + t.timeoutDuration(sec).String() } // ranGoTest and stdMatches are state closed over by the stdlib @@ -319,6 +329,11 @@ func (t *tester) registerStdTest(pkg string) { break } } + // Special case for our slow cross-compiled + // qemu builders: + if t.shouldUsePrecompiledStdTest() { + return t.runPrecompiledStdTest(t.timeoutDuration(timeoutSec)) + } args := []string{ "test", short(), @@ -1416,6 +1431,60 @@ func (t *tester) makeGOROOTUnwritable() { } } +// shouldUsePrecompiledStdTest reports whether "dist test" should use +// a pre-compiled go test binary on disk rather than running "go test" +// and compiling it again. This is used by our slow qemu-based builder +// that do full processor emulation where we cross-compile the +// make.bash step as well as pre-compile each std test binary. +// +// This only reports true if dist is run with an single go_test:foo +// argument (as the build coordinator does with our slow qemu-based +// builders), we're in a builder environment ("GO_BUILDER_NAME" is set), +// and the pre-built test binary exists. +func (t *tester) shouldUsePrecompiledStdTest() bool { + bin := t.prebuiltGoPackageTestBinary() + if bin == "" { + return false + } + _, err := os.Stat(bin) + return err == nil +} + +// prebuiltGoPackageTestBinary returns the path where we'd expect +// the pre-built go test binary to be on disk when dist test is run with +// a single argument. +// It returns an empty string if a pre-built binary should not be used. +func (t *tester) prebuiltGoPackageTestBinary() string { + if len(stdMatches) != 1 || t.race || t.compileOnly || os.Getenv("GO_BUILDER_NAME") == "" { + return "" + } + pkg := stdMatches[0] + return filepath.Join(os.Getenv("GOROOT"), "src", pkg, path.Base(pkg)+".test") +} + +// runPrecompiledStdTest runs the pre-compiled standard library package test binary. +// See shouldUsePrecompiledStdTest above; it must return true for this to be called. +func (t *tester) runPrecompiledStdTest(timeout time.Duration) error { + bin := t.prebuiltGoPackageTestBinary() + fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin) + cmd := exec.Command(bin, "-test.short", "-test.timeout="+timeout.String()) + cmd.Dir = filepath.Dir(bin) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Start(); err != nil { + return err + } + // And start a timer to kill the process if it doesn't kill + // itself in the prescribed timeout. + const backupKillFactor = 1.05 // add 5% + timer := time.AfterFunc(time.Duration(float64(timeout)*backupKillFactor), func() { + fmt.Fprintf(os.Stderr, "# %s: timeout running %s; killing...\n", stdMatches[0], bin) + cmd.Process.Kill() + }) + defer timer.Stop() + return cmd.Wait() +} + // raceDetectorSupported is a copy of the function // cmd/internal/sys.RaceDetectorSupported, which can't be used here // because cmd/dist has to be buildable by Go 1.4.