blob: 14da3e1f0e8ca8670b706ce2e29150de5ac02c4b [file] [log] [blame]
// 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"
"strings"
"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() {
r := removeAllIncludingReadonly(tmpDir)
if err == nil && r != nil {
err = fmt.Errorf("error removing temporary directory: %w", r)
} else if err != nil && r != nil {
log.Printf("failed to clean up sweet temporary directory: %v", r)
}
}()
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", filepath.Join(sweetRoot, "assets.hash"),
)
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", filepath.Join(sweetRoot, "benchmarks"),
"-cache", assetsCacheDir,
"-work-dir", workDir,
"-results", resultsDir,
confFile,
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// Don't fail immediately. Let's try to dump whatever results we have first.
sweetErr := cmd.Run()
defer func() {
// Any sweet errors take precendence over errors encountered in printing
// results.
if sweetErr != nil {
if err != nil {
log.Printf("error dumping results: %v", err)
}
err = fmt.Errorf("error running sweet run: %w", sweetErr)
}
}()
// 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 {
// Print pkg and shortname tags because Sweet won't do it.
benchName := filepath.Base(filepath.Dir(match))
fmt.Printf("pkg: golang.org/x/benchmarks/sweet/benchmarks/%s\n", benchName)
fmt.Printf("shortname: sweet_%s\n", strings.ReplaceAll(benchName, "-", "_"))
// Dump results file.
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
}