benchstat: avoid reading whole inputs
For very large benchmark inputs it makes sense to avoid
reading the entire file into memory.
Change-Id: Ib7f1b13c1b7b4659323a912aee1c4a5a3d6a49a5
Reviewed-on: https://go-review.googlesource.com/c/159057
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Ian Rogers <irogers@google.com>
diff --git a/benchstat/data.go b/benchstat/data.go
index 3c3a08b..6332950 100644
--- a/benchstat/data.go
+++ b/benchstat/data.go
@@ -7,6 +7,7 @@
import (
"bytes"
"fmt"
+ "io"
"strconv"
"strings"
@@ -159,19 +160,29 @@
// AddConfig adds the benchmark results in the formatted data
// to the named configuration.
+// If the input is large, AddFile should be preferred,
+// since it avoids the need to read a copy of the entire raw input
+// into memory.
func (c *Collection) AddConfig(config string, data []byte) {
- c.Configs = append(c.Configs, config)
- key := Key{Config: config}
- br := benchfmt.NewReader(bytes.NewReader(data))
- for br.Next() {
- c.addResult(key, br.Result())
- }
- if err := br.Err(); err != nil {
+ err := c.AddFile(config, bytes.NewReader(data))
+ if err != nil {
// bytes.Reader never returns errors
panic(err)
}
}
+// AddFile adds the benchmark results in the formatted data
+// (read from the reader r) to the named configuration.
+func (c *Collection) AddFile(config string, r io.Reader) error {
+ c.Configs = append(c.Configs, config)
+ key := Key{Config: config}
+ br := benchfmt.NewReader(r)
+ for br.Next() {
+ c.addResult(key, br.Result())
+ }
+ return br.Err()
+}
+
// AddResults adds the benchmark results to the named configuration.
func (c *Collection) AddResults(config string, results []*benchfmt.Result) {
c.Configs = append(c.Configs, config)
diff --git a/cmd/benchstat/main.go b/cmd/benchstat/main.go
index 7d87625..4b27d7f 100644
--- a/cmd/benchstat/main.go
+++ b/cmd/benchstat/main.go
@@ -98,7 +98,6 @@
"bytes"
"flag"
"fmt"
- "io/ioutil"
"log"
"os"
"strings"
@@ -172,11 +171,14 @@
c.Order = order
}
for _, file := range flag.Args() {
- data, err := ioutil.ReadFile(file)
+ f, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
- c.AddConfig(file, data)
+ if err := c.AddFile(file, f); err != nil {
+ log.Fatal(err)
+ }
+ f.Close()
}
tables := c.Tables()