| // Copyright 2022 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package benchfmt | |
| import ( | |
| "golang.org/x/perf/benchmath" | |
| "golang.org/x/perf/benchunit" | |
| ) | |
| // Unit metadata is a single piece of unit metadata. | |
| // | |
| // Unit metadata gives information that's useful to interpreting | |
| // values in a given unit. The following metadata keys are predefined: | |
| // | |
| // better={higher,lower} indicates whether higher or lower values of | |
| // this unit are better (indicate an improvement). | |
| // | |
| // assume={nothing,exact} indicates what statistical assumption to | |
| // make when considering distributions of values. | |
| // `nothing` means to make no statistical assumptions (e.g., use | |
| // non-parametric methods) and `exact` means to assume measurements are | |
| // exact (repeated measurement does not increase confidence). | |
| // The default is `nothing`. | |
| type UnitMetadata struct { | |
| UnitMetadataKey | |
| // OrigUnit is the original, untidied unit as written in the input. | |
| OrigUnit string | |
| Value string | |
| fileName string | |
| line int | |
| } | |
| func (u *UnitMetadata) Pos() (fileName string, line int) { | |
| return u.fileName, u.line | |
| } | |
| // UnitMetadataKey identifies a single piece of unit metadata by unit | |
| // and metadata name. | |
| type UnitMetadataKey struct { | |
| Unit string | |
| Key string // Metadata key (e.g., "better" or "assume") | |
| } | |
| // UnitMetadataMap stores the accumulated metadata for several units. | |
| // This is indexed by tidied units, while the values store the original | |
| // units from the benchmark file. | |
| type UnitMetadataMap map[UnitMetadataKey]*UnitMetadata | |
| // Get returns the unit metadata for the specified unit and metadata key. | |
| // It tidies unit if necessary. | |
| func (m UnitMetadataMap) Get(unit, key string) *UnitMetadata { | |
| _, tidyUnit := benchunit.Tidy(1, unit) | |
| return m[UnitMetadataKey{tidyUnit, key}] | |
| } | |
| // GetAssumption returns the appropriate statistical Assumption to make | |
| // about distributions of values in the given unit. | |
| func (m UnitMetadataMap) GetAssumption(unit string) benchmath.Assumption { | |
| dist := m.Get(unit, "assume") | |
| if dist != nil && dist.Value == "exact" { | |
| return benchmath.AssumeExact | |
| } | |
| // The default is to assume nothing. | |
| return benchmath.AssumeNothing | |
| } | |
| // GetBetter returns whether higher or lower values of the given unit | |
| // indicate an improvement. It returns +1 if higher values are better, | |
| // -1 if lower values are better, or 0 if unknown. | |
| func (m UnitMetadataMap) GetBetter(unit string) int { | |
| better := m.Get(unit, "better") | |
| if better != nil { | |
| switch better.Value { | |
| case "higher": | |
| return 1 | |
| case "lower": | |
| return -1 | |
| } | |
| return 0 | |
| } | |
| // Fall back to some built-in defaults. | |
| switch unit { | |
| case "ns/op", "sec/op": | |
| // This measures "duration", so lower is better. | |
| return -1 | |
| case "MB/s", "B/s": | |
| // This measures "speed", so higher is better. | |
| return 1 | |
| case "B/op", "allocs/op": | |
| // These measure amount of allocation, so lower is better. | |
| return -1 | |
| } | |
| return 0 | |
| } |