]> Cypherpunks repositories - gostls13.git/commitdiff
testing: print extra labels on benchmarks
authorQuentin Smith <quentin@golang.org>
Mon, 6 Feb 2017 16:59:01 +0000 (11:59 -0500)
committerQuentin Smith <quentin@golang.org>
Tue, 7 Feb 2017 00:08:39 +0000 (00:08 +0000)
When running benchmarks, print "goos", "goarch", and "pkg"
labels. This makes it easier to refer to benchmark logs and understand
how they were generated. "pkg" is printed only for benchmarks located
in GOPATH.

Change-Id: I397cbdd57b9fe8cbabbb354ec7bfba59f5625c42
Reviewed-on: https://go-review.googlesource.com/36356
Run-TryBot: Quentin Smith <quentin@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/go/go_test.go
src/cmd/go/internal/test/test.go
src/cmd/go/testdata/src/bench/x_test.go [new file with mode: 0644]
src/testing/benchmark.go
src/testing/internal/testdeps/deps.go
src/testing/testing.go

index ef5348bba40ff8844911e57dce951ad904086cf9..978b9302389787dee3d45d64e9d1c8cb1d42e398 100644 (file)
@@ -3690,6 +3690,28 @@ func TestMatchesOnlyBenchmarkIsOK(t *testing.T) {
        tg.grepBoth(okPattern, "go test did not say ok")
 }
 
+func TestBenchmarkLabels(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       // TODO: tg.parallel()
+       tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+       tg.run("test", "-run", "^$", "-bench", ".", "bench")
+       tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
+       tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
+       tg.grepStdout(`(?m)^pkg: bench`, "go test did not say pkg: bench")
+       tg.grepBothNot(`(?s)pkg:.*pkg:`, "go test said pkg multiple times")
+}
+
+func TestBenchmarkLabelsOutsideGOPATH(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       // TODO: tg.parallel()
+       tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
+       tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
+       tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
+       tg.grepBothNot(`(?m)^pkg:`, "go test did say pkg:")
+}
+
 func TestMatchesOnlyTestIsOK(t *testing.T) {
        tg := testgo(t)
        defer tg.cleanup()
index 366b19a7004672ef0aa18c0bf3fd41eee81463c9..feafaad2a8ba23ef5486b58f2732fd1b43d3e2d0 100644 (file)
@@ -1373,6 +1373,19 @@ func (t *testFuncs) CoverEnabled() bool {
        return testCover
 }
 
+// ImportPath returns the import path of the package being tested, if it is within GOPATH.
+// This is printed by the testing package when running benchmarks.
+func (t *testFuncs) ImportPath() string {
+       pkg := t.Package.ImportPath
+       if strings.HasPrefix(pkg, "_/") {
+               return ""
+       }
+       if pkg == "command-line-arguments" {
+               return ""
+       }
+       return pkg
+}
+
 // Covered returns a string describing which packages are being tested for coverage.
 // If the covered package is the same as the tested package, it returns the empty string.
 // Otherwise it is a comma-separated human-readable list of packages beginning with
@@ -1503,6 +1516,10 @@ var examples = []testing.InternalExample{
 {{end}}
 }
 
+func init() {
+       testdeps.ImportPath = {{.ImportPath | printf "%q"}}
+}
+
 {{if .CoverEnabled}}
 
 // Only updated by init functions, so no need for atomicity.
diff --git a/src/cmd/go/testdata/src/bench/x_test.go b/src/cmd/go/testdata/src/bench/x_test.go
new file mode 100644 (file)
index 0000000..32cabf8
--- /dev/null
@@ -0,0 +1,6 @@
+package bench
+
+import "testing"
+
+func Benchmark(b *testing.B) {
+}
index bcebb418c42572e1c26aa3427926667c596adf5b..8d3f63d232fd590ffb51bddac0cad7e8be0e89d8 100644 (file)
@@ -47,6 +47,7 @@ type InternalBenchmark struct {
 // affecting benchmark results.
 type B struct {
        common
+       importPath       string // import path of the package containing the benchmark
        context          *benchContext
        N                int
        previousN        int           // number of iterations in the previous run
@@ -233,9 +234,18 @@ func (b *B) run1() bool {
        return true
 }
 
+var labelsOnce sync.Once
+
 // run executes the benchmark in a separate goroutine, including all of its
 // subbenchmarks. b must not have subbenchmarks.
 func (b *B) run() BenchmarkResult {
+       labelsOnce.Do(func() {
+               fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS)
+               fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH)
+               if b.importPath != "" {
+                       fmt.Fprintf(b.w, "pkg: %s\n", b.importPath)
+               }
+       })
        if b.context != nil {
                // Running go test --test.bench
                b.context.processBench(b) // Must call doBench.
@@ -363,10 +373,10 @@ type benchContext struct {
 // An internal function but exported because it is cross-package; part of the implementation
 // of the "go test" command.
 func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
-       runBenchmarks(matchString, benchmarks)
+       runBenchmarks("", matchString, benchmarks)
 }
 
-func runBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool {
+func runBenchmarks(importPath string, matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool {
        // If no flag was specified, don't run benchmarks.
        if len(*matchBenchmarks) == 0 {
                return true
@@ -398,6 +408,7 @@ func runBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
                        w:      os.Stdout,
                        chatty: *chatty,
                },
+               importPath: importPath,
                benchFunc: func(b *B) {
                        for _, Benchmark := range bs {
                                b.Run(Benchmark.Name, Benchmark.F)
@@ -486,9 +497,10 @@ func (b *B) Run(name string, f func(b *B)) bool {
                        w:      b.w,
                        chatty: b.chatty,
                },
-               benchFunc: f,
-               benchTime: b.benchTime,
-               context:   b.context,
+               importPath: b.importPath,
+               benchFunc:  f,
+               benchTime:  b.benchTime,
+               context:    b.context,
        }
        if sub.run1() {
                sub.run()
index b08300b5d60a56157584e020b5ee8c8ab077d1f6..042f69614ee513bf7178b6dad2bcafaee33e6696 100644 (file)
@@ -49,3 +49,10 @@ func (TestDeps) WriteHeapProfile(w io.Writer) error {
 func (TestDeps) WriteProfileTo(name string, w io.Writer, debug int) error {
        return pprof.Lookup(name).WriteTo(w, debug)
 }
+
+// ImportPath is the import path of the testing binary, set by the generated main function.
+var ImportPath string
+
+func (TestDeps) ImportPath() string {
+       return ImportPath
+}
index 5efbc244fec961a006a94ccc1031d7d7713cba3d..97c703d8ba0e1bc8fca60ffba8c43b8e0b46b9bc 100644 (file)
@@ -766,6 +766,7 @@ func (f matchStringOnly) StartCPUProfile(w io.Writer) error           { return e
 func (f matchStringOnly) StopCPUProfile()                             {}
 func (f matchStringOnly) WriteHeapProfile(w io.Writer) error          { return errMain }
 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
+func (f matchStringOnly) ImportPath() string                          { return "" }
 
 // Main is an internal function, part of the implementation of the "go test" command.
 // It was exported because it is cross-package and predates "internal" packages.
@@ -795,6 +796,7 @@ type testDeps interface {
        StopCPUProfile()
        WriteHeapProfile(io.Writer) error
        WriteProfileTo(string, io.Writer, int) error
+       ImportPath() string
 }
 
 // MainStart is meant for use by tests generated by 'go test'.
@@ -827,7 +829,7 @@ func (m *M) Run() int {
        if !testRan && !exampleRan && *matchBenchmarks == "" {
                fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
        }
-       if !testOk || !exampleOk || !runBenchmarks(m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
+       if !testOk || !exampleOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
                fmt.Println("FAIL")
                m.after()
                return 1