github.com/jgbaldwinbrown/perf@v0.1.1/benchfmt/units.go (about)

     1  // Copyright 2022 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.
     4  
     5  package benchfmt
     6  
     7  import (
     8  	"golang.org/x/perf/benchmath"
     9  	"golang.org/x/perf/benchunit"
    10  )
    11  
    12  // Unit metadata is a single piece of unit metadata.
    13  //
    14  // Unit metadata gives information that's useful to interpreting
    15  // values in a given unit. The following metadata keys are predefined:
    16  //
    17  // better={higher,lower} indicates whether higher or lower values of
    18  // this unit are better (indicate an improvement).
    19  //
    20  // assume={nothing,exact} indicates what statistical assumption to
    21  // make when considering distributions of values.
    22  // `nothing` means to make no statistical assumptions (e.g., use
    23  // non-parametric methods) and `exact` means to assume measurements are
    24  // exact (repeated measurement does not increase confidence).
    25  // The default is `nothing`.
    26  type UnitMetadata struct {
    27  	UnitMetadataKey
    28  
    29  	// OrigUnit is the original, untidied unit as written in the input.
    30  	OrigUnit string
    31  
    32  	Value string
    33  
    34  	fileName string
    35  	line     int
    36  }
    37  
    38  func (u *UnitMetadata) Pos() (fileName string, line int) {
    39  	return u.fileName, u.line
    40  }
    41  
    42  // UnitMetadataKey identifies a single piece of unit metadata by unit
    43  // and metadata name.
    44  type UnitMetadataKey struct {
    45  	Unit string
    46  	Key  string // Metadata key (e.g., "better" or "assume")
    47  }
    48  
    49  // UnitMetadataMap stores the accumulated metadata for several units.
    50  // This is indexed by tidied units, while the values store the original
    51  // units from the benchmark file.
    52  type UnitMetadataMap map[UnitMetadataKey]*UnitMetadata
    53  
    54  // Get returns the unit metadata for the specified unit and metadata key.
    55  // It tidies unit if necessary.
    56  func (m UnitMetadataMap) Get(unit, key string) *UnitMetadata {
    57  	_, tidyUnit := benchunit.Tidy(1, unit)
    58  	return m[UnitMetadataKey{tidyUnit, key}]
    59  }
    60  
    61  // GetAssumption returns the appropriate statistical Assumption to make
    62  // about distributions of values in the given unit.
    63  func (m UnitMetadataMap) GetAssumption(unit string) benchmath.Assumption {
    64  	dist := m.Get(unit, "assume")
    65  	if dist != nil && dist.Value == "exact" {
    66  		return benchmath.AssumeExact
    67  	}
    68  	// The default is to assume nothing.
    69  	return benchmath.AssumeNothing
    70  }
    71  
    72  // GetBetter returns whether higher or lower values of the given unit
    73  // indicate an improvement. It returns +1 if higher values are better,
    74  // -1 if lower values are better, or 0 if unknown.
    75  func (m UnitMetadataMap) GetBetter(unit string) int {
    76  	better := m.Get(unit, "better")
    77  	if better != nil {
    78  		switch better.Value {
    79  		case "higher":
    80  			return 1
    81  		case "lower":
    82  			return -1
    83  		}
    84  		return 0
    85  	}
    86  	// Fall back to some built-in defaults.
    87  	switch unit {
    88  	case "ns/op", "sec/op":
    89  		// This measures "duration", so lower is better.
    90  		return -1
    91  	case "MB/s", "B/s":
    92  		// This measures "speed", so higher is better.
    93  		return 1
    94  	case "B/op", "allocs/op":
    95  		// These measure amount of allocation, so lower is better.
    96  		return -1
    97  	}
    98  	return 0
    99  }