...
1
2
3
4
5
6
7 package parse
8
9 import (
10 "bufio"
11 "bytes"
12 "fmt"
13 "io"
14 "strconv"
15 "strings"
16 )
17
18
19
20 const (
21 NsPerOp = 1 << iota
22 MBPerS
23 AllocedBytesPerOp
24 AllocsPerOp
25 )
26
27
28 type Benchmark struct {
29 Name string
30 N int
31 NsPerOp float64
32 AllocedBytesPerOp uint64
33 AllocsPerOp uint64
34 MBPerS float64
35 Measured int
36 Ord int
37 }
38
39
40
41 func ParseLine(line string) (*Benchmark, error) {
42 fields := strings.Fields(line)
43
44
45 if len(fields) < 2 {
46 return nil, fmt.Errorf("two fields required, have %d", len(fields))
47 }
48 if !strings.HasPrefix(fields[0], "Benchmark") {
49 return nil, fmt.Errorf(`first field does not start with "Benchmark"`)
50 }
51 n, err := strconv.Atoi(fields[1])
52 if err != nil {
53 return nil, err
54 }
55 b := &Benchmark{Name: fields[0], N: n}
56
57
58 for i := 1; i < len(fields)/2; i++ {
59 b.parseMeasurement(fields[i*2], fields[i*2+1])
60 }
61 return b, nil
62 }
63
64 func (b *Benchmark) parseMeasurement(quant string, unit string) {
65 switch unit {
66 case "ns/op":
67 if f, err := strconv.ParseFloat(quant, 64); err == nil {
68 b.NsPerOp = f
69 b.Measured |= NsPerOp
70 }
71 case "MB/s":
72 if f, err := strconv.ParseFloat(quant, 64); err == nil {
73 b.MBPerS = f
74 b.Measured |= MBPerS
75 }
76 case "B/op":
77 if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
78 b.AllocedBytesPerOp = i
79 b.Measured |= AllocedBytesPerOp
80 }
81 case "allocs/op":
82 if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
83 b.AllocsPerOp = i
84 b.Measured |= AllocsPerOp
85 }
86 }
87 }
88
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)
94 }
95 if (b.Measured & MBPerS) != 0 {
96 fmt.Fprintf(buf, " %.2f MB/s", b.MBPerS)
97 }
98 if (b.Measured & AllocedBytesPerOp) != 0 {
99 fmt.Fprintf(buf, " %d B/op", b.AllocedBytesPerOp)
100 }
101 if (b.Measured & AllocsPerOp) != 0 {
102 fmt.Fprintf(buf, " %d allocs/op", b.AllocsPerOp)
103 }
104 return buf.String()
105 }
106
107
108
109 type Set map[string][]*Benchmark
110
111
112
113
114 func ParseSet(r io.Reader) (Set, error) {
115 bb := make(Set)
116 scan := bufio.NewScanner(r)
117 ord := 0
118 for scan.Scan() {
119 if b, err := ParseLine(scan.Text()); err == nil {
120 b.Ord = ord
121 ord++
122 bb[b.Name] = append(bb[b.Name], b)
123 }
124 }
125
126 if err := scan.Err(); err != nil {
127 return nil, err
128 }
129
130 return bb, nil
131 }
132
View as plain text