Addressing code review comments.

Mainly:
* Moving the averaging/merging of benchmarks from the parser to the formatter package
* Tightening up the regex so it only captures the numeric values (no more of trimming spaces and the ns/op)
* Deleting the writing up in xml file the benchmark memory sections of B/op and Allocs/op

Also added a test case for parseNanoseconds().
This commit is contained in:
Brittany Walentin
2018-05-25 10:59:00 -07:00
parent b2f467b67c
commit 260b47cabe
9 changed files with 185 additions and 128 deletions

View File

@ -55,9 +55,6 @@ type Benchmark struct {
Bytes int
// number of allocs/op
Allocs int
// number of times this benchmark has been seen (for averaging).
Count int
Output []string
}
var (
@ -65,7 +62,7 @@ var (
regexCoverage = regexp.MustCompile(`^coverage:\s+(\d+\.\d+)%\s+of\s+statements(?:\sin\s.+)?$`)
regexResult = regexp.MustCompile(`^(ok|FAIL)\s+([^ ]+)\s+(?:(\d+\.\d+)s|\(cached\)|(\[\w+ failed]))(?:\s+coverage:\s+(\d+\.\d+)%\sof\sstatements(?:\sin\s.+)?)?$`)
// regexBenchmark captures 3-5 groups: benchmark name, number of times ran, ns/op (with or without decimal), B/op (optional), and allocs/op (optional).
regexBenchmark = regexp.MustCompile(`^(Benchmark\w+)-\d\s+(\d+)\s+((\d+|\d+\.\d+)\sns/op)(\s+\d+\sB/op)?(\s+\d+\sallocs/op)?`)
regexBenchmark = regexp.MustCompile(`^(Benchmark[^ ]+)-\d\s+(\d+)\s+(\d+|\d+\.\d+)\sns/op(?:\s+(\d+)\sB/op)?(?:\s+(\d+)\sallocs/op)?`)
regexOutput = regexp.MustCompile(`( )*\t(.*)`)
regexSummary = regexp.MustCompile(`^(PASS|FAIL|SKIP)$`)
)
@ -128,60 +125,16 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
// clear the current build package, so output lines won't be added to that build
capturedPackage = ""
seenSummary = false
} else if strings.HasPrefix(line, "Benchmark") {
// parse benchmarking info
matches := regexBenchmark.FindStringSubmatch(line)
if len(matches) < 1 {
continue
}
var name string
var duration time.Duration
var bytes int
var allocs int
for _, field := range matches[1:] {
field = strings.TrimSpace(field)
if strings.HasPrefix(field, "Benchmark") {
name = field
}
if strings.HasSuffix(field, " ns/op") {
durString := strings.TrimSuffix(field, " ns/op")
duration = parseNanoseconds(durString)
}
if strings.HasSuffix(field, " B/op") {
b, _ := strconv.Atoi(strings.TrimSuffix(field, " B/op"))
bytes = b
}
if strings.HasSuffix(field, " allocs/op") {
a, _ := strconv.Atoi(strings.TrimSuffix(field, " allocs/op"))
allocs = a
}
}
var duplicate bool
// check if duplicate benchmark
for _, bench := range benchmarks {
if bench.Name == name {
duplicate = true
bench.Count++
bench.Duration += duration
bench.Bytes += bytes
bench.Allocs += allocs
}
}
if len(benchmarks) < 1 || duplicate == false {
// the first time this benchmark has been seen
benchmarks = append(benchmarks, &Benchmark{
Name: name,
Duration: duration,
Bytes: bytes,
Allocs: allocs,
Count: 1,
},
)
}
} else if matches := regexBenchmark.FindStringSubmatch(line); len(matches) == 6 {
bytes, _ := strconv.Atoi(matches[4])
allocs, _ := strconv.Atoi(matches[5])
benchmarks = append(benchmarks, &Benchmark{
Name: matches[1],
Duration: parseNanoseconds(matches[3]),
Bytes: bytes,
Allocs: allocs,
})
} else if strings.HasPrefix(line, "=== PAUSE ") {
continue
} else if strings.HasPrefix(line, "=== CONT ") {
@ -212,15 +165,6 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
// all tests in this package are finished
for _, bench := range benchmarks {
if bench.Count > 1 {
bench.Allocs = bench.Allocs / bench.Count
bench.Bytes = bench.Bytes / bench.Count
newDuration := bench.Duration / time.Duration(bench.Count)
bench.Duration = newDuration
}
}
report.Packages = append(report.Packages, Package{
Name: matches[2],
Duration: parseSeconds(matches[3]),

View File

@ -24,3 +24,24 @@ func TestParseSeconds(t *testing.T) {
}
}
}
func TestParseNanoseconds(t *testing.T) {
tests := []struct {
in string
d time.Duration
}{
{"", 0},
{"0.1", 0 * time.Nanosecond},
{"0.9", 0 * time.Nanosecond},
{"4", 4 * time.Nanosecond},
{"5000", 5 * time.Microsecond},
{"2000003", 2*time.Millisecond + 3*time.Nanosecond},
}
for _, test := range tests {
d := parseNanoseconds(test.in)
if d != test.d {
t.Errorf("parseSeconds(%q) == %v, want %v\n", test.in, d, test.d)
}
}
}