]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/dist: run shards of test dir in parallel
authorRuss Cox <rsc@golang.org>
Tue, 22 Dec 2015 01:42:40 +0000 (20:42 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 29 Dec 2015 17:18:04 +0000 (17:18 +0000)
Saves 15 seconds from all.bash on my laptop (3:20 -> 3:05).

Change-Id: Ic5dc3c7804e78b584789dd856a3dada94000a8e2
Reviewed-on: https://go-review.googlesource.com/18199
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/cmd/dist/test.go

index 77c736501a2e15e0a72c4cb366365c4070260067..cb99b0e3584e3d5b43fffa5ef34f24cd9ac69046 100644 (file)
@@ -17,6 +17,7 @@ import (
        "regexp"
        "strconv"
        "strings"
+       "sync"
        "time"
 )
 
@@ -195,6 +196,7 @@ func (t *tester) run() {
                }
                dt := dt // dt used in background after this iteration
                if err := dt.fn(&dt); err != nil {
+                       t.runPending(dt) // in case that hasn't been done yet
                        t.failed = true
                        if t.keepGoing {
                                log.Printf("Failed: %v", err)
@@ -788,8 +790,11 @@ func (t *tester) cgoTest(dt *distTest) error {
 }
 
 // run pending test commands, in parallel, emitting headers as appropriate.
-// When finished, emit header for dt, which is going to run after the
+// When finished, emit header for nextTest, which is going to run after the
 // pending commands are done (and runPending returns).
+// A test should call runPending if it wants to make sure that it is not
+// running in parallel with earlier tests, or if it has some other reason
+// for needing the earlier tests to be done.
 func (t *tester) runPending(nextTest *distTest) {
        worklist := t.worklist
        t.worklist = nil
@@ -961,20 +966,35 @@ func (t *tester) raceTest(dt *distTest) error {
        return nil
 }
 
+var runtest struct {
+       sync.Once
+       exe string
+       err error
+}
+
 func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
-       t.runPending(dt)
-       const runExe = "runtest.exe" // named exe for Windows, but harmless elsewhere
-       cmd := t.dirCmd("test", "go", "build", "-o", runExe, "run.go")
-       cmd.Env = mergeEnvLists([]string{"GOOS=" + t.gohostos, "GOARCH=" + t.gohostarch, "GOMAXPROCS="}, os.Environ())
-       if err := cmd.Run(); err != nil {
-               return err
+       runtest.Do(func() {
+               const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere
+               cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go")
+               cmd.Env = mergeEnvLists([]string{"GOOS=" + t.gohostos, "GOARCH=" + t.gohostarch, "GOMAXPROCS="}, os.Environ())
+               runtest.exe = filepath.Join(cmd.Dir, exe)
+               if err := cmd.Run(); err != nil {
+                       runtest.err = err
+                       return
+               }
+               xatexit(func() {
+                       os.Remove(runtest.exe)
+               })
+       })
+       if runtest.err != nil {
+               return runtest.err
        }
-       absExe := filepath.Join(cmd.Dir, runExe)
-       defer os.Remove(absExe)
-       return t.dirCmd("test", absExe,
+
+       t.addCmd(dt, "test", runtest.exe,
                fmt.Sprintf("--shard=%d", shard),
                fmt.Sprintf("--shards=%d", shards),
-       ).Run()
+       )
+       return nil
 }
 
 func (t *tester) shootoutTests() []string {