cmd/bench: integrate the Sweet benchmarks
For golang/go#49207.
Change-Id: Ib18c5f574e30333a7d9d80019e26d6a565f4db1e
Reviewed-on: https://go-review.googlesource.com/c/benchmarks/+/378274
Reviewed-by: Michael Pratt <mpratt@google.com>
Trust: Michael Knyszek <mknyszek@google.com>
diff --git a/cmd/bench/main.go b/cmd/bench/main.go
index e3bb6f2..12fe37b 100644
--- a/cmd/bench/main.go
+++ b/cmd/bench/main.go
@@ -68,6 +68,10 @@
pass = false
log.Printf("Error running bent: %v", err)
}
+ if err := sweet(tcs); err != nil {
+ pass = false
+ log.Printf("Error running sweet: %v", err)
+ }
if !pass {
return fmt.Errorf("benchmarks failed")
}
diff --git a/cmd/bench/sweet.go b/cmd/bench/sweet.go
new file mode 100644
index 0000000..54cbffd
--- /dev/null
+++ b/cmd/bench/sweet.go
@@ -0,0 +1,139 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+
+ "golang.org/x/benchmarks/sweet/common"
+)
+
+func writeSweetConfiguration(filename string, tcs []*toolchain) error {
+ var cfg common.ConfigFile
+ for _, tc := range tcs {
+ cfg.Configs = append(cfg.Configs, &common.Config{
+ Name: tc.Name,
+ GoRoot: tc.GOROOT(),
+ })
+ }
+ f, err := os.Create(filename)
+ if err != nil {
+ return fmt.Errorf("error creating configuration file for Sweet: %w", err)
+ }
+ defer f.Close()
+ b, err := common.ConfigFileMarshalTOML(&cfg)
+ if err != nil {
+ return fmt.Errorf("error marshaling configuration file for Sweet: %w", err)
+ }
+ if _, err := f.Write(b); err != nil {
+ return fmt.Errorf("error writing configuration file for Sweet: %w", err)
+ }
+ return nil
+}
+
+func sweet(tcs []*toolchain) (err error) {
+ tmpDir, err := os.MkdirTemp("", "go-sweet")
+ if err != nil {
+ return fmt.Errorf("error creating temporary directory: %w", err)
+ }
+ defer func() {
+ err = removeAllIncludingReadonly(tmpDir)
+ if err != nil {
+ err = fmt.Errorf("error removing temporary directory: %w", err)
+ }
+ }()
+ log.Printf("Sweet temporary directory: %s", tmpDir)
+
+ dirBytes, err := tcs[0].List("-f", "{{.Dir}}", "golang.org/x/benchmarks/sweet/cmd/sweet")
+ if err != nil {
+ return fmt.Errorf("finding sweet root: %w", err)
+ }
+ sweetRoot := filepath.Dir(filepath.Dir(string(dirBytes)))
+ sweetBin := filepath.Join(tmpDir, "sweet")
+
+ log.Printf("Building Sweet...")
+
+ // Build Sweet itself. N.B. we don't need to do this with the goroot
+ // under test since we aren't testing sweet itself, but we are sure that
+ // this toolchain exists.
+ if err := tcs[0].BuildPackage("golang.org/x/benchmarks/sweet/cmd/sweet", sweetBin); err != nil {
+ return fmt.Errorf("building sweet: %v", err)
+ }
+
+ log.Printf("Initializing Sweet...")
+
+ var assetsCacheDir string
+ if os.Getenv("GO_BUILDER_NAME") != "" {
+ // Be explicit that we want /tmp, because the builder is
+ // going to try and give us /workdir/tmp which will not
+ // have enough space for us.
+ assetsCacheDir = filepath.Join("/", "tmp", "go-sweet-assets")
+ } else {
+ assetsCacheDir = filepath.Join(tmpDir, "assets")
+ }
+ cmd := exec.Command(
+ sweetBin, "get",
+ "-cache", assetsCacheDir,
+ "-auth", "none",
+ "-assets-hash-file", fmt.Sprintf("%s/assets.hash", sweetRoot),
+ )
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("error running sweet get: %w", err)
+ }
+
+ confFile := filepath.Join(tmpDir, "config.toml")
+ if err := writeSweetConfiguration(confFile, tcs); err != nil {
+ return fmt.Errorf("error writing configuration: %w", err)
+ }
+
+ log.Printf("Running Sweet...")
+
+ // Finally we can actually run the benchmarks.
+ resultsDir := filepath.Join(tmpDir, "results")
+ workDir := filepath.Join(tmpDir, "work")
+ cmd = exec.Command(
+ sweetBin, "run",
+ "-run", "all",
+ "-count", "10",
+ "-bench-dir", fmt.Sprintf("%s/benchmarks", sweetRoot),
+ "-cache", assetsCacheDir,
+ "-work-dir", workDir,
+ "-results", resultsDir,
+ confFile,
+ )
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("error running sweet run: %w", err)
+ }
+
+ // Dump results to stdout.
+ for _, tc := range tcs {
+ matches, err := filepath.Glob(filepath.Join(resultsDir, "*", fmt.Sprintf("%s.results", tc.Name)))
+ if err != nil {
+ return fmt.Errorf("searching for results for %s in %s: %v", tc.Name, resultsDir, err)
+ }
+ fmt.Printf("toolchain: %s\n", tc.Name)
+ for _, match := range matches {
+ f, err := os.Open(match)
+ if err != nil {
+ return fmt.Errorf("opening result %s: %v", match, err)
+ }
+ if _, err := io.Copy(os.Stdout, f); err != nil {
+ f.Close()
+ return fmt.Errorf("reading result %s: %v", match, err)
+ }
+ f.Close()
+ }
+ }
+ return nil
+}
diff --git a/sweet/common/gotool.go b/sweet/common/gotool.go
index 633092f..a718950 100644
--- a/sweet/common/gotool.go
+++ b/sweet/common/gotool.go
@@ -41,6 +41,13 @@
return cmd.Run()
}
+func (g *Go) List(args ...string) ([]byte, error) {
+ cmd := exec.Command(g.Tool, append([]string{"list"}, args...)...)
+ cmd.Env = g.Env.Collapse()
+ log.TraceCommand(cmd, false)
+ return cmd.CombinedOutput()
+}
+
func (g *Go) GOROOT() string {
return filepath.Dir(filepath.Dir(g.Tool))
}