1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package parse provides support for parsing benchmark results as
6 // generated by 'go test -bench'.
7 package parse // import "golang.org/x/tools/benchmark/parse"
18 // Flags used by Benchmark.Measured to indicate
19 // which measurements a Benchmark contains.
27 // Benchmark is one run of a single benchmark.
28 type Benchmark struct {
29 Name string // benchmark name
30 N int // number of iterations
31 NsPerOp float64 // nanoseconds per iteration
32 AllocedBytesPerOp uint64 // bytes allocated per iteration
33 AllocsPerOp uint64 // allocs per iteration
34 MBPerS float64 // MB processed per second
35 Measured int // which measurements were recorded
36 Ord int // ordinal position within a benchmark run
39 // ParseLine extracts a Benchmark from a single line of testing.B
41 func ParseLine(line string) (*Benchmark, error) {
42 fields := strings.Fields(line)
44 // Two required, positional fields: Name and iterations.
46 return nil, fmt.Errorf("two fields required, have %d", len(fields))
48 if !strings.HasPrefix(fields[0], "Benchmark") {
49 return nil, fmt.Errorf(`first field does not start with "Benchmark"`)
51 n, err := strconv.Atoi(fields[1])
55 b := &Benchmark{Name: fields[0], N: n}
57 // Parse any remaining pairs of fields; we've parsed one pair already.
58 for i := 1; i < len(fields)/2; i++ {
59 b.parseMeasurement(fields[i*2], fields[i*2+1])
64 func (b *Benchmark) parseMeasurement(quant string, unit string) {
67 if f, err := strconv.ParseFloat(quant, 64); err == nil {
72 if f, err := strconv.ParseFloat(quant, 64); err == nil {
77 if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
78 b.AllocedBytesPerOp = i
79 b.Measured |= AllocedBytesPerOp
82 if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
84 b.Measured |= AllocsPerOp
89 func (b *Benchmark) String() string {
90 buf := new(bytes.Buffer)
91 fmt.Fprintf(buf, "%s %d", b.Name, b.N)
92 if (b.Measured & NsPerOp) != 0 {
93 fmt.Fprintf(buf, " %.2f ns/op", b.NsPerOp)
95 if (b.Measured & MBPerS) != 0 {
96 fmt.Fprintf(buf, " %.2f MB/s", b.MBPerS)
98 if (b.Measured & AllocedBytesPerOp) != 0 {
99 fmt.Fprintf(buf, " %d B/op", b.AllocedBytesPerOp)
101 if (b.Measured & AllocsPerOp) != 0 {
102 fmt.Fprintf(buf, " %d allocs/op", b.AllocsPerOp)
107 // Set is a collection of benchmarks from one
108 // testing.B run, keyed by name to facilitate comparison.
109 type Set map[string][]*Benchmark
111 // ParseSet extracts a Set from testing.B output.
112 // ParseSet preserves the order of benchmarks that have identical
114 func ParseSet(r io.Reader) (Set, error) {
116 scan := bufio.NewScanner(r)
119 if b, err := ParseLine(scan.Text()); err == nil {
122 bb[b.Name] = append(bb[b.Name], b)
126 if err := scan.Err(); err != nil {