cmd/bent: remove required dependencies
Make rsync optional with fallback to cp.
Remove use of /usr/bin/time and replace with measuring time directly
from Go.
For golang/go#49207
Change-Id: Ief5a7a90f9460ddec1d5a51c99d4a534e38a5d9c
Reviewed-on: https://go-review.googlesource.com/c/benchmarks/+/361734
Trust: Michael Pratt <mpratt@google.com>
Run-TryBot: Michael Pratt <mpratt@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
diff --git a/cmd/bent/README.md b/cmd/bent/README.md
index 2d55f62..213e5db 100644
--- a/cmd/bent/README.md
+++ b/cmd/bent/README.md
@@ -6,13 +6,14 @@
Installation:
```go get github.com/dr2chase/bent```
-Requires commands `rsync` and `/usr/bin/time`.
-Also depends on burntsushi/toml, and expects that Docker is installed and available on the command line.
+Depends on burntsushi/toml, and expects that Docker is installed and available on the command line.
You can avoid the need for Docker with the `-U` command line flag, if you're okay with running benchmarks outside containers.
Alternately, if you wish to only run those benchmarks that can be compiled into a container (this is platform-dependent)
use the -S flag.
+Install `rsync` for slightly improved copy performance.
+
Initial usage :
```
diff --git a/cmd/bent/bent.go b/cmd/bent/bent.go
index 4081800..01e6ec1 100644
--- a/cmd/bent/bent.go
+++ b/cmd/bent/bent.go
@@ -30,7 +30,7 @@
type BenchStat struct {
Name string
- RealTime, UserTime, SysTime int64 // nanoseconds, -1 if missing.
+ RealTime, UserTime, SysTime time.Duration
}
type Benchmark struct {
@@ -81,6 +81,7 @@
var wikiTable = false // emit the tests in a form usable in a wiki table
var explicitAll counterFlag // Include "-a" on "go test -c" test build ; repeating flag causes multiple rebuilds, useful for build benchmarking.
var shuffle = 2 // Dimensionality of (build) shuffling; 0 = none, 1 = per-benchmark, configuration ordering, 2 = bench, config pairs, 3 = across repetitions.
+var haveRsync = true
//go:embed scripts/*
var scripts embed.FS
@@ -187,20 +188,10 @@
flag.Parse()
- // Fail early if either of these commands is missing.
- _, errTime := exec.LookPath("/usr/bin/time")
_, errRsync := exec.LookPath("rsync")
- if errTime != nil && errRsync != nil {
- fmt.Println("This program needs /usr/bin/time and rsync commands to run")
- os.Exit(1)
- }
if errRsync != nil {
- fmt.Println("This program needs the rsync command to run")
- os.Exit(1)
- }
- if errTime != nil {
- fmt.Println("This program needs the /usr/bin/time command to run")
- os.Exit(1)
+ haveRsync = false
+ fmt.Println("Warning: using cp instead of rsync")
}
if requireSandbox {
@@ -567,7 +558,12 @@
config.Disabled = true
}
- cp := exec.Command("rsync", "-a", from+"/", to)
+ var cp *exec.Cmd
+ if haveRsync {
+ cp = exec.Command("rsync", "-a", from+"/", to)
+ } else {
+ cp = exec.Command("cp", "-a", from+"/.", to)
+ }
s, _ = config.runBinary("", cp, false)
if s != "" {
fmt.Println("Error copying directory tree, ", from, to)
diff --git a/cmd/bent/configuration.go b/cmd/bent/configuration.go
index 89f1f25..301c5ec 100644
--- a/cmd/bent/configuration.go
+++ b/cmd/bent/configuration.go
@@ -16,9 +16,9 @@
"os/exec"
"path"
"runtime"
- "strconv"
"strings"
"sync"
+ "time"
)
// Configuration is a structure that holds all the variables necessary to
@@ -172,8 +172,7 @@
}
}
- // Prefix with time for build benchmarking:
- cmd := exec.Command("/usr/bin/time", "-p", gocmd, "test", "-vet=off", "-c")
+ cmd := exec.Command(gocmd, "test", "-vet=off", "-c")
compileTo := path.Join(dirs.wd, dirs.testBinDir, config.benchName(bench))
cmd.Args = append(cmd.Args, "-o", compileTo)
cmd.Args = append(cmd.Args, bench.BuildFlags...)
@@ -206,7 +205,9 @@
defer cleanup(gopath)
+ start := time.Now()
output, err := cmd.CombinedOutput()
+ realTime := time.Since(start)
if err != nil {
s := ""
switch e := err.(type) {
@@ -220,12 +221,13 @@
return s + "(" + bench.Name + ")\n"
}
soutput := string(output)
- // Capture times from the end of the output.
- rbt := extractTime(soutput, "real")
- ubt := extractTime(soutput, "user")
- sbt := extractTime(soutput, "sys")
- config.buildStats = append(config.buildStats,
- BenchStat{Name: bench.Name, RealTime: rbt, UserTime: ubt, SysTime: sbt})
+ bs := BenchStat{
+ Name: bench.Name,
+ RealTime: realTime,
+ UserTime: cmd.ProcessState.UserTime(),
+ SysTime: cmd.ProcessState.SystemTime(),
+ }
+ config.buildStats = append(config.buildStats, bs)
// Report and record build stats to testbin
@@ -239,7 +241,7 @@
buf.WriteString(s)
}
s := fmt.Sprintf("Benchmark%s 1 %d build-real-ns/op %d build-user-ns/op %d build-sys-ns/op\n",
- strings.Title(bench.Name), rbt, ubt, sbt)
+ strings.Title(bench.Name), bs.RealTime.Nanoseconds(), bs.UserTime.Nanoseconds(), bs.SysTime.Nanoseconds())
if verbose > 0 {
fmt.Print(s)
}
@@ -365,30 +367,3 @@
}
return "", rc
}
-
-// extractTime extracts a time (from /usr/bin/time -p) based on the tag
-// and returns the time converted to nanoseconds. Missing times and bad
-// data result in NaN.
-func extractTime(output, label string) int64 {
- // find tag in first column
- li := strings.LastIndex(output, label)
- if li < 0 {
- return -1
- }
- output = output[li+len(label):]
- // lose intervening white space
- li = strings.IndexAny(output, "0123456789-.eEdD")
- if li < 0 {
- return -1
- }
- output = output[li:]
- li = strings.IndexAny(output, "\n\r\t ")
- if li >= 0 { // failing to find EOL is a special case of done.
- output = output[:li]
- }
- x, err := strconv.ParseFloat(output, 64)
- if err != nil {
- return -1
- }
- return int64(x * 1000 * 1000 * 1000)
-}