benchfmt

package
v0.0.0-...-f3e401e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2024 License: BSD-3-Clause Imports: 12 Imported by: 8

Documentation

Overview

Package benchfmt provides a high-performance reader and writer for the Go benchmark format.

This implements the format documented at https://golang.org/design/14313-benchmark-format.

The reader and writer are structured as streaming operations to allow incremental processing and avoid dictating a data model. This allows consumers of these APIs to provide their own data model best suited to its needs. The reader also performs in-place updates to reduce allocation, enabling it to parse millions of benchmark results per second on a typical laptop.

This package is designed to be used with the higher-level packages benchunit, benchmath, and benchproc.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Key   string
	Value []byte
	File  bool // Set if this is a file configuration key, otherwise internal
}

A Config is a single key/value configuration pair. This can be a file configuration, which was read directly from a benchmark results file; or an "internal" configuration that was supplied by tooling.

type Files

type Files struct {
	// Paths is the list of file names to read in.
	//
	// If AllowLabels is set, these strings may be of the form
	// label=path, and the label part will be used for the
	// ".file" key in the results.
	Paths []string

	// AllowStdin indicates that the path "-" should be treated as
	// stdin and if the file list is empty, it should be treated
	// as consisting of stdin.
	//
	// This is generally the desired behavior when the file list
	// comes from command-line flags.
	AllowStdin bool

	// AllowLabels indicates that custom labels are allowed in
	// Paths.
	//
	// This is generally the desired behavior when the file list
	// comes from command-line flags, as it allows users to
	// override .file.
	AllowLabels bool
	// contains filtered or unexported fields
}

A Files reads benchmark results from a sequence of input files.

This reader adds a ".file" configuration key to the output Results corresponding to each path read in. By default, this will be the file name directly from Paths, except that duplicate strings will be disambiguated by appending "#N". If AllowLabels is true, then entries in Path may be of the form label=path, and the label part will be used for .file (without any disambiguation).

func (*Files) Err

func (f *Files) Err() error

Err returns the I/O error that stopped Scan, if any. If Scan stopped because it read each file to completion, or if Scan has not yet returned false, Err returns nil.

func (*Files) Result

func (f *Files) Result() Record

Result returns the record that was just read by Scan. See Reader.Result.

func (*Files) Scan

func (f *Files) Scan() bool

Scan advances the reader to the next result in the sequence of files and reports whether a result was read. The caller should use the Result method to get the result. If Scan reaches the end of the file sequence, or if an I/O error occurs, it returns false. In this case, the caller should use the Err method to check for errors.

func (*Files) Units

func (f *Files) Units() map[UnitMetadataKey]*UnitMetadata

Units returns the accumulated unit metadata. See Reader.Units.

type Name

type Name []byte

A Name is a full benchmark name, including all sub-benchmark configuration.

func (Name) Base

func (n Name) Base() []byte

Base returns the base part of a full benchmark name, without any configuration keys or GOMAXPROCS.

func (Name) Full

func (n Name) Full() []byte

Full returns the full benchmark name as a []byte. This is simply the value of n, but helps with code readability.

func (Name) Parts

func (n Name) Parts() (baseName []byte, parts [][]byte)

Parts splits a benchmark name into the base name and sub-benchmark configuration parts. Each sub-benchmark configuration part is one of three forms:

1. "/<key>=<value>" indicates a key/value configuration pair.

2. "/<string>" indicates a positional configuration pair.

3. "-<gomaxprocs>" indicates the GOMAXPROCS of this benchmark. This part can only appear last.

Concatenating the base name and the configuration parts reconstructs the full name.

func (Name) String

func (n Name) String() string

String returns the full benchmark name as a string.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

A Reader reads the Go benchmark format.

Its API is modeled on bufio.Scanner. To minimize allocation, a Reader retains ownership of everything it creates; a caller should copy anything it needs to retain.

To construct a new Reader, either call NewReader, or call Reset on a zeroed Reader.

func NewReader

func NewReader(r io.Reader, fileName string) *Reader

NewReader constructs a reader to parse the Go benchmark format from r. fileName is used in error messages; it is purely diagnostic.

func (*Reader) Err

func (r *Reader) Err() error

Err returns the first non-EOF I/O error that was encountered by the Reader.

func (*Reader) Reset

func (r *Reader) Reset(ior io.Reader, fileName string, initConfig ...string)

Reset resets the reader to begin reading from a new input. It also resets all accumulated configuration values. It does NOT reset unit metadata because it carries across files.

initConfig is an alternating sequence of keys and values. Reset will install these as the initial internal configuration before any results are read from the input file.

func (*Reader) Result

func (r *Reader) Result() Record

Result returns the record that was just read by Scan. This is either a *Result, a *UnitMetadata, or a *SyntaxError indicating a parse error. It may return more types in the future.

Parse errors are non-fatal, so the caller can continue to call Scan.

If this returns a *Result, the caller should not retain the Result, as it will be overwritten by the next call to Scan.

func (*Reader) Scan

func (r *Reader) Scan() bool

Scan advances the reader to the next result and reports whether a result was read. The caller should use the Result method to get the result. If Scan reaches EOF or an I/O error occurs, it returns false, in which case the caller should use the Err method to check for errors.

func (*Reader) Units

func (r *Reader) Units() UnitMetadataMap

Units returns the accumulated unit metadata.

Callers that want to consume the entire stream of benchmark results and then process units can use this instead of monitoring *UnitMetadata Records.

type Record

type Record interface {
	// Pos returns the position of this record as a file name and a
	// 1-based line number within that file. If this record was not read
	// from a file, it returns "", 0.
	Pos() (fileName string, line int)
}

A Record is a single record read from a benchmark file. It may be a *Result or a *SyntaxError.

type Result

type Result struct {
	// Config is the set of key/value configuration pairs for this result,
	// including file and internal configuration. This does not include
	// sub-name configuration.
	//
	// This slice is mutable, as are the values in the slice.
	// Result internally maintains an index of the keys of this slice,
	// so callers must use SetConfig to add or delete keys,
	// but may modify values in place. There is one exception to this:
	// for convenience, new Results can be initialized directly,
	// e.g., using a struct literal.
	//
	// SetConfig appends new keys to this slice and updates existing ones
	// in place. To delete a key, it swaps the deleted key with
	// the final slice element. This way, the order of these keys is
	// deterministic.
	Config []Config

	// Name is the full name of this benchmark, including all
	// sub-benchmark configuration.
	Name Name

	// Iters is the number of iterations this benchmark's results
	// were averaged over.
	Iters int

	// Values is this benchmark's measurements and their units.
	Values []Value
	// contains filtered or unexported fields
}

A Result is a single benchmark result and all of its measurements.

Results are designed to be mutated in place and reused to reduce allocation.

func (*Result) Clone

func (r *Result) Clone() *Result

Clone makes a copy of Result that shares no state with r.

func (*Result) ConfigIndex

func (r *Result) ConfigIndex(key string) (pos int, ok bool)

ConfigIndex returns the index in r.Config of key.

func (*Result) GetConfig

func (r *Result) GetConfig(key string) string

GetConfig returns the value of a configuration key, or "" if not present.

func (*Result) Pos

func (r *Result) Pos() (fileName string, line int)

Pos returns the file name and line number of a Result that was read by a Reader. For Results that were not read from a file, it returns "", 0.

func (*Result) SetConfig

func (r *Result) SetConfig(key, value string)

SetConfig sets configuration key to value, overriding or adding the configuration as necessary, and marks it internal. If value is "", SetConfig deletes key.

func (*Result) Value

func (r *Result) Value(unit string) (float64, bool)

Value returns the measurement for the given unit.

type SyntaxError

type SyntaxError struct {
	FileName string
	Line     int
	Msg      string
}

A SyntaxError represents a syntax error on a particular line of a benchmark results file.

func (*SyntaxError) Error

func (s *SyntaxError) Error() string

func (*SyntaxError) Pos

func (e *SyntaxError) Pos() (fileName string, line int)

type UnitMetadata

type UnitMetadata struct {
	UnitMetadataKey

	// OrigUnit is the original, untidied unit as written in the input.
	OrigUnit string

	Value string
	// contains filtered or unexported fields
}

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`.

func (*UnitMetadata) Pos

func (u *UnitMetadata) Pos() (fileName string, line int)

type UnitMetadataKey

type UnitMetadataKey struct {
	Unit string
	Key  string // Metadata key (e.g., "better" or "assume")
}

UnitMetadataKey identifies a single piece of unit metadata by unit and metadata name.

type UnitMetadataMap

type UnitMetadataMap map[UnitMetadataKey]*UnitMetadata

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.

func (UnitMetadataMap) Get

func (m UnitMetadataMap) Get(unit, key string) *UnitMetadata

Get returns the unit metadata for the specified unit and metadata key. It tidies unit if necessary.

func (UnitMetadataMap) GetAssumption

func (m UnitMetadataMap) GetAssumption(unit string) benchmath.Assumption

GetAssumption returns the appropriate statistical Assumption to make about distributions of values in the given unit.

func (UnitMetadataMap) GetBetter

func (m UnitMetadataMap) GetBetter(unit string) int

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.

type Value

type Value struct {
	Value float64
	Unit  string

	// OrigValue and OrigUnit, if non-zero, give the original,
	// untidied value and unit, typically as read from the
	// original input. OrigUnit may be "", indicating that the
	// value wasn't transformed.
	OrigValue float64
	OrigUnit  string
}

A Value is a single value/unit measurement from a benchmark result.

Values should be tidied to use base units like "sec" and "B" when constructed. Reader ensures this.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

A Writer writes the Go benchmark format.

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter returns a writer that writes Go benchmark results to w.

func (*Writer) Write

func (w *Writer) Write(rec Record) error

Write writes Record rec to w. If rec is a *Result and rec's file configuration differs from the current file configuration in w, it first emits the appropriate file configuration lines. For Result.Values that have a non-zero OrigUnit, this uses OrigValue and OrigUnit in order to better reproduce the original input.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL