Commit 961f6a46 authored by Russ Cox's avatar Russ Cox

benchstat: rename Benchstat→Metrics, BenchKey→Key

These will work better in the eventual package benchstat API.

Change-Id: I95c63f2fe7c1a0f6db09afbe9776539f264a577c
Reviewed-on: https://go-review.googlesource.com/35933Reviewed-by: default avatarQuentin Smith <quentin@golang.org>
parent a7cba317
...@@ -119,7 +119,7 @@ var ( ...@@ -119,7 +119,7 @@ var (
flagHTML = flag.Bool("html", false, "print results as an HTML table") flagHTML = flag.Bool("html", false, "print results as an HTML table")
) )
var deltaTestNames = map[string]func(old, new *Benchstat) (float64, error){ var deltaTestNames = map[string]func(old, new *Metrics) (float64, error){
"none": notest, "none": notest,
"u": utest, "u": utest,
"u-test": utest, "u-test": utest,
...@@ -159,23 +159,23 @@ func main() { ...@@ -159,23 +159,23 @@ func main() {
// Read in benchmark data. // Read in benchmark data.
c := readFiles(flag.Args()) c := readFiles(flag.Args())
for _, stat := range c.Stats { for _, m := range c.Metrics {
stat.ComputeStats() m.ComputeStats()
} }
var tables [][]*row var tables [][]*row
switch len(c.Configs) { switch len(c.Configs) {
case 2: case 2:
before, after := c.Configs[0], c.Configs[1] before, after := c.Configs[0], c.Configs[1]
key := BenchKey{} key := Key{}
for _, key.Unit = range c.Units { for _, key.Unit = range c.Units {
var table []*row var table []*row
metric := metricOf(key.Unit) metric := metricOf(key.Unit)
for _, key.Benchmark = range c.Benchmarks { for _, key.Benchmark = range c.Benchmarks {
key.Config = before key.Config = before
old := c.Stats[key] old := c.Metrics[key]
key.Config = after key.Config = after
new := c.Stats[key] new := c.Metrics[key]
if old == nil || new == nil { if old == nil || new == nil {
continue continue
} }
...@@ -210,7 +210,7 @@ func main() { ...@@ -210,7 +210,7 @@ func main() {
} }
default: default:
key := BenchKey{} key := Key{}
for _, key.Unit = range c.Units { for _, key.Unit = range c.Units {
var table []*row var table []*row
metric := metricOf(key.Unit) metric := metricOf(key.Unit)
...@@ -229,15 +229,15 @@ func main() { ...@@ -229,15 +229,15 @@ func main() {
row := newRow(key.Benchmark) row := newRow(key.Benchmark)
var scaler func(float64) string var scaler func(float64) string
for _, key.Config = range c.Configs { for _, key.Config = range c.Configs {
stat := c.Stats[key] m := c.Metrics[key]
if stat == nil { if m == nil {
row.add("") row.add("")
continue continue
} }
if scaler == nil { if scaler == nil {
scaler = newScaler(stat.Mean, stat.Unit) scaler = newScaler(m.Mean, m.Unit)
} }
row.add(stat.Format(scaler)) row.add(m.Format(scaler))
} }
row.trim() row.trim()
if len(row.cols) > 1 { if len(row.cols) > 1 {
...@@ -335,14 +335,14 @@ func addGeomean(table []*row, c *Collection, unit string, delta bool) []*row { ...@@ -335,14 +335,14 @@ func addGeomean(table []*row, c *Collection, unit string, delta bool) []*row {
} }
row := newRow("[Geo mean]") row := newRow("[Geo mean]")
key := BenchKey{Unit: unit} key := Key{Unit: unit}
geomeans := []float64{} geomeans := []float64{}
for _, key.Config = range c.Configs { for _, key.Config = range c.Configs {
var means []float64 var means []float64
for _, key.Benchmark = range c.Benchmarks { for _, key.Benchmark = range c.Benchmarks {
stat := c.Stats[key] m := c.Metrics[key]
if stat != nil { if m != nil {
means = append(means, stat.Mean) means = append(means, m.Mean)
} }
} }
if len(means) == 0 { if len(means) == 0 {
...@@ -454,13 +454,13 @@ func newScaler(val float64, unit string) func(float64) string { ...@@ -454,13 +454,13 @@ func newScaler(val float64, unit string) func(float64) string {
} }
} }
func (b *Benchstat) Format(scaler func(float64) string) string { func (m *Metrics) Format(scaler func(float64) string) string {
diff := 1 - b.Min/b.Mean diff := 1 - m.Min/m.Mean
if d := b.Max/b.Mean - 1; d > diff { if d := m.Max/m.Mean - 1; d > diff {
diff = d diff = d
} }
s := scaler(b.Mean) s := scaler(m.Mean)
if b.Mean == 0 { if m.Mean == 0 {
s += " " s += " "
} else { } else {
s = fmt.Sprintf("%s ±%3s", s, fmt.Sprintf("%.0f%%", diff*100.0)) s = fmt.Sprintf("%s ±%3s", s, fmt.Sprintf("%.0f%%", diff*100.0))
...@@ -470,51 +470,52 @@ func (b *Benchstat) Format(scaler func(float64) string) string { ...@@ -470,51 +470,52 @@ func (b *Benchstat) Format(scaler func(float64) string) string {
// ComputeStats updates the derived statistics in s from the raw // ComputeStats updates the derived statistics in s from the raw
// samples in s.Values. // samples in s.Values.
func (stat *Benchstat) ComputeStats() { func (m *Metrics) ComputeStats() {
// Discard outliers. // Discard outliers.
values := stats.Sample{Xs: stat.Values} values := stats.Sample{Xs: m.Values}
q1, q3 := values.Percentile(0.25), values.Percentile(0.75) q1, q3 := values.Percentile(0.25), values.Percentile(0.75)
lo, hi := q1-1.5*(q3-q1), q3+1.5*(q3-q1) lo, hi := q1-1.5*(q3-q1), q3+1.5*(q3-q1)
for _, value := range stat.Values { for _, value := range m.Values {
if lo <= value && value <= hi { if lo <= value && value <= hi {
stat.RValues = append(stat.RValues, value) m.RValues = append(m.RValues, value)
} }
} }
// Compute statistics of remaining data. // Compute statistics of remaining data.
stat.Min, stat.Max = stats.Bounds(stat.RValues) m.Min, m.Max = stats.Bounds(m.RValues)
stat.Mean = stats.Mean(stat.RValues) m.Mean = stats.Mean(m.RValues)
} }
// A Benchstat is the metrics along one axis (e.g., ns/op or MB/s) // A Metrics holds the measurements of a single metric (for example, ns/op or MB/s)
// for all runs of a specific benchmark. // for all runs of a particular benchmark.
type Benchstat struct { type Metrics struct {
Unit string Unit string // unit being measured
Values []float64 // metrics Values []float64 // measured values
RValues []float64 // metrics with outliers removed RValues []float64 // Values with outliers removed
Min float64 // min of RValues Min float64 // min of RValues
Mean float64 // mean of RValues Mean float64 // mean of RValues
Max float64 // max of RValues Max float64 // max of RValues
} }
// A BenchKey identifies one metric (e.g., "ns/op", "B/op") from one // A Key identifies one metric (e.g., "ns/op", "B/op") from one
// benchmark (function name sans "Benchmark" prefix) in one // benchmark (function name sans "Benchmark" prefix) in one
// configuration (input file name). // configuration (input file name).
type BenchKey struct { type Key struct {
Config, Benchmark, Unit string Config, Benchmark, Unit string
} }
type Collection struct { type Collection struct {
Stats map[BenchKey]*Benchstat
// Configs, Benchmarks, and Units give the set of configs, // Configs, Benchmarks, and Units give the set of configs,
// benchmarks, and units from the keys in Stats in an order // benchmarks, and units from the keys in Stats in an order
// meant to match the order the benchmarks were read in. // meant to match the order the benchmarks were read in.
Configs, Benchmarks, Units []string Configs, Benchmarks, Units []string
// Metrics holds the accumulated metrics for each key.
Metrics map[Key]*Metrics
} }
func (c *Collection) AddStat(key BenchKey) *Benchstat { func (c *Collection) AddStat(key Key) *Metrics {
if stat, ok := c.Stats[key]; ok { if stat, ok := c.Metrics[key]; ok {
return stat return stat
} }
...@@ -529,14 +530,14 @@ func (c *Collection) AddStat(key BenchKey) *Benchstat { ...@@ -529,14 +530,14 @@ func (c *Collection) AddStat(key BenchKey) *Benchstat {
addString(&c.Configs, key.Config) addString(&c.Configs, key.Config)
addString(&c.Benchmarks, key.Benchmark) addString(&c.Benchmarks, key.Benchmark)
addString(&c.Units, key.Unit) addString(&c.Units, key.Unit)
stat := &Benchstat{Unit: key.Unit} m := &Metrics{Unit: key.Unit}
c.Stats[key] = stat c.Metrics[key] = m
return stat return m
} }
// readFiles reads a set of benchmark files. // readFiles reads a set of benchmark files.
func readFiles(files []string) *Collection { func readFiles(files []string) *Collection {
c := Collection{Stats: make(map[BenchKey]*Benchstat)} c := Collection{Metrics: make(map[Key]*Metrics)}
for _, file := range files { for _, file := range files {
readFile(file, &c) readFile(file, &c)
} }
...@@ -546,7 +547,7 @@ func readFiles(files []string) *Collection { ...@@ -546,7 +547,7 @@ func readFiles(files []string) *Collection {
// readFile reads a set of benchmarks from a file in to a Collection. // readFile reads a set of benchmarks from a file in to a Collection.
func readFile(file string, c *Collection) { func readFile(file string, c *Collection) {
c.Configs = append(c.Configs, file) c.Configs = append(c.Configs, file)
key := BenchKey{Config: file} key := Key{Config: file}
text, err := ioutil.ReadFile(file) text, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
...@@ -595,11 +596,11 @@ func metricOf(unit string) string { ...@@ -595,11 +596,11 @@ func metricOf(unit string) string {
// Significance tests. // Significance tests.
func notest(old, new *Benchstat) (pval float64, err error) { func notest(old, new *Metrics) (pval float64, err error) {
return -1, nil return -1, nil
} }
func ttest(old, new *Benchstat) (pval float64, err error) { func ttest(old, new *Metrics) (pval float64, err error) {
t, err := stats.TwoSampleWelchTTest(stats.Sample{Xs: old.RValues}, stats.Sample{Xs: new.RValues}, stats.LocationDiffers) t, err := stats.TwoSampleWelchTTest(stats.Sample{Xs: old.RValues}, stats.Sample{Xs: new.RValues}, stats.LocationDiffers)
if err != nil { if err != nil {
return -1, err return -1, err
...@@ -607,7 +608,7 @@ func ttest(old, new *Benchstat) (pval float64, err error) { ...@@ -607,7 +608,7 @@ func ttest(old, new *Benchstat) (pval float64, err error) {
return t.P, nil return t.P, nil
} }
func utest(old, new *Benchstat) (pval float64, err error) { func utest(old, new *Metrics) (pval float64, err error) {
u, err := stats.MannWhitneyUTest(old.RValues, new.RValues, stats.LocationDiffers) u, err := stats.MannWhitneyUTest(old.RValues, new.RValues, stats.LocationDiffers)
if err != nil { if err != nil {
return -1, err return -1, err
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment