From a68f9113a2d4043ef28d2e4395485ee187e5532d Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 15 Nov 2022 10:47:00 -0500 Subject: [PATCH] cmd/pprof: use the test binary as 'pprof' instead of rebuilding it This not only reduces the latency of the test, but also respects build flags like '-race' and '-cover' passed to the 'go test' command. Change-Id: Icdf256420c4dce2da7a187513b7dd08393b76146 Reviewed-on: https://go-review.googlesource.com/c/go/+/450708 Reviewed-by: Ian Lance Taylor TryBot-Result: Gopher Robot Auto-Submit: Bryan Mills Run-TryBot: Bryan Mills --- src/cmd/pprof/pprof_test.go | 59 ++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/src/cmd/pprof/pprof_test.go b/src/cmd/pprof/pprof_test.go index 753d2b149f..ed6a9386d5 100644 --- a/src/cmd/pprof/pprof_test.go +++ b/src/cmd/pprof/pprof_test.go @@ -5,55 +5,48 @@ package main import ( - "fmt" "internal/testenv" "os" "os/exec" "path/filepath" "runtime" "strings" + "sync" "testing" ) -var tmp, pprofExe string // populated by buildPprof - +// TestMain executes the test binary as the pprof command if +// GO_PPROFTEST_IS_PPROF is set, and runs the tests otherwise. func TestMain(m *testing.M) { - if !testenv.HasGoBuild() { - return + if os.Getenv("GO_PPROFTEST_IS_PPROF") != "" { + main() + os.Exit(0) } - var exitcode int - if err := buildPprof(); err == nil { - exitcode = m.Run() - } else { - fmt.Println(err) - exitcode = 1 - } - os.RemoveAll(tmp) - os.Exit(exitcode) + os.Setenv("GO_PPROFTEST_IS_PPROF", "1") // Set for subprocesses to inherit. + os.Exit(m.Run()) } -func buildPprof() error { - var err error - tmp, err = os.MkdirTemp("", "TestPprof") - if err != nil { - return fmt.Errorf("TempDir failed: %v", err) - } +// pprofPath returns the path to the "pprof" binary to run. +func pprofPath(t testing.TB) string { + t.Helper() + testenv.MustHaveExec(t) - pprofExe = filepath.Join(tmp, "testpprof.exe") - gotool, err := testenv.GoTool() - if err != nil { - return err + pprofPathOnce.Do(func() { + pprofExePath, pprofPathErr = os.Executable() + }) + if pprofPathErr != nil { + t.Fatal(pprofPathErr) } - out, err := exec.Command(gotool, "build", "-o", pprofExe, "cmd/pprof").CombinedOutput() - if err != nil { - os.RemoveAll(tmp) - return fmt.Errorf("go build -o %v cmd/pprof: %v\n%s", pprofExe, err, string(out)) - } - - return nil + return pprofExePath } +var ( + pprofPathOnce sync.Once + pprofExePath string + pprofPathErr error +) + // See also runtime/pprof.cpuProfilingBroken. func mustHaveCPUProfiling(t *testing.T) { switch runtime.GOOS { @@ -112,13 +105,13 @@ func TestDisasm(t *testing.T) { t.Fatalf("cpu failed: %v\n%s", err, out) } - cmd = exec.Command(pprofExe, "-disasm", "main.main", cpuExe, profile) + cmd = exec.Command(pprofPath(t), "-disasm", "main.main", cpuExe, profile) out, err = cmd.CombinedOutput() if err != nil { t.Errorf("pprof -disasm failed: %v\n%s", err, out) // Try to print out profile content for debugging. - cmd = exec.Command(pprofExe, "-raw", cpuExe, profile) + cmd = exec.Command(pprofPath(t), "-raw", cpuExe, profile) out, err = cmd.CombinedOutput() if err != nil { t.Logf("pprof -raw failed: %v\n%s", err, out) -- 2.50.0