tachymeter

package module
v2.0.0+incompatible Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2019 License: MIT Imports: 12 Imported by: 37

README

GoDoc

tachymeter

Tachymeter captures event timings and returns latency and rate statistics: "In a loop with 1,000 database calls, what was the 95%ile and lowest observed latency? What was the per-second rate?"

Tachymeter stores data in a lossless sliding window. This means it's accurate but take o(n) space in relation to the desired sample size.

Examples

Code examples. Tachymeter is also suitable for general purpose use, such as load testing tools.

Usage

After initializing a tachymeter, event durations in the form of time.Duration are added using the AddTime(t time.Duration) call. Once all desired timing have been collected, the data is summarized by calling the Calc(), returning a *Metrics). *Metrics fields can be accessed directly or via other output methods.

import "github.com/jamiealquiza/tachymeter"

func main() {
    // Initialize a tachymeter with a sample window
    // size of 50 events.
    t := tachymeter.New(&tachymeter.Config{Size: 50})

    for i := 0; i < 100; i++ {
        start := time.Now()
        doSomeWork()
        // We add the time that
        // each doSomeWork() call took.
        t.AddTime(time.Since(start))
    }

    // The timing summaries are calculated
    // and printed to console.
    fmt.Println(t.Calc())
}
50 samples of 100 events
Cumulative:	671.871ms
HMean:		125.38µs
Avg.:		13.43742ms
p50: 		13.165ms
p75:		20.058ms
p95:		27.536ms
p99:		30.043ms
p999:		30.043ms
Long 5%:	29.749ms
Short 5%:	399.666µs
Max:		30.043ms
Min:		4µs
Range:		30.039ms
StdDev:		8.385117ms
Rate/sec.:	74.42
Output Descriptions
  • Cumulative: Aggregate of all sample durations.
  • HMean: Event duration harmonic mean.
  • Avg.: Average event duration per sample.
  • p<N>: Nth %ile.
  • Long 5%: Average event duration of the longest 5%.
  • Short 5%: Average event duration of the shortest 5%.
  • Max: Max observed event duration.
  • Min: Min observed event duration.
  • Range: The delta between the max and min sample time
  • StdDev: The population standard deviation
  • Rate/sec.: Per-second rate based on cumulative time and sample count.

Output Methods

Tachymeter output is stored in two primary forms:

  • A *Metrics, which holds the calculated percentiles, rates and other information detailed in the Output Descriptions section
  • A *Histogram of all measured event durations, nested in the Metrics.Histogram field

t represents a tachymeter instance. Calling t.Calc() returns a *Metrics. Metrics and the nested Histogram types can be access in several ways:

Metrics: raw struct
metrics := t.Calc()
fmt.Printf("Median latency: %s\n", metrics.Time.P50)

Output:

Median latency: 13.165ms
Metrics: JSON string
fmt.Printf("%s\n\", metrics.JSON())

Output:

{"Time":{"Cumulative":"671.871ms","HMean":"125.38µs","Avg":"13.43742ms","P50":"13.165ms","P75":"20.058ms","P95":"27.536ms","P99":"30.043ms","P999":"30.043ms","Long5p":"29.749ms","Short5p":"399.666µs","Max":"30.043ms","Min":"4µs","Range":"30.039ms","StdDev":"8.385117ms"},"Rate":{"Second":74.41904770409796},"Samples":50,"Count":100,"Histogram":[{"4µs - 3.007ms":5},{"3.007ms - 6.011ms":4},{"6.011ms - 9.015ms":10},{"9.015ms - 12.019ms":6},{"12.019ms - 15.023ms":7},{"15.023ms - 18.027ms":3},{"18.027ms - 21.031ms":4},{"21.031ms - 24.035ms":3},{"24.035ms - 27.039ms":3},{"27.039ms - 30.043ms":5}]}
Metrics: pre-formatted, multi-line string
fmt.Println(metrics)

Output:

50 samples of 100 events
Cumulative:	671.871ms
HMean:		125.38µs
Avg.:		13.43742ms
p50: 		13.165ms
p75:		20.058ms
p95:		27.536ms
p99:		30.043ms
p999:		30.043ms
Long 5%:	29.749ms
Short 5%:	399.666µs
Max:		30.043ms
Min:		4µs
Range:		30.039ms
StdDev:		8.385117ms
Rate/sec.:	74.42
Histogram: text

The Histogram.String(int) method generates a text version of the histogram. Histogram bar scaling is specified with width int.

fmt.Println(metrics.Histogram.String(25))

Output:

       4µs - 3.007ms -----
   3.007ms - 6.011ms ---
   6.011ms - 9.015ms ---------------
  9.015ms - 12.019ms -------
 12.019ms - 15.023ms ---------
 15.023ms - 18.027ms -
 18.027ms - 21.031ms ---
 21.031ms - 24.035ms -
 24.035ms - 27.039ms -
 27.039ms - 30.043ms -----
Histogram: HTML

A Histogram can be written as HTML histograms. The Metrics.WriteHTML(p string) method is called where p is an output path where the HTML file should be written.

err := metrics.WriteHTML(".")

Output: ss

Tachymeter also provides a Timeline type that's used to gather a series of *Metrics (each *Metrics object holding data summarizing a series of measured events). *Metrics are added to a *Timeline using the AddEvent(m *Metrics) method. Once the desired number of *Metrics has been collected, WriteHTML can be called on the *Timeline, resulting in an single HTML page with a histogram for each captured *Metrics. An example use case may be a benchmark where tachymeter is used to summarize the timing results of a loop, but several iterations of the loop are to be called in series. See the tachymeter-graphing example for further details.

Configuration

Tachymeter is initialized with a Size parameter that specifies the maximum sample count that can be held. This is done to set bounds on tachymeter memory usage (since it's a lossless storage structure). The AddTime method is o(1) and typically sub-microsecond modern hardware. If the actual event count is smaller than or equal to the configured tachymeter size, all of the measured events will be included in the calculated results. If the event count exceeds the tachymeter size, the oldest data will be overwritten. In this scenario, the last window of Size events will be used for output calculations.

Accurate Rates With Parallelism

By default, tachymeter calculates rate based on the number of events possible per-second according to average event duration. This model doesn't work in asynchronous or parallelized scenarios since events may be overlapping in time. For example, with many Goroutines writing durations to a shared tachymeter in parallel, the global rate must be determined by using the total event count over the total wall time elapsed.

Tachymeter exposes a SetWallTime method for these scenarios.

Example:

<...>

func main() {
    // Initialize tachymeter.
    c := tachymeter.New(&tachymeter.Config{Size: 50})

    // Start wall time for all Goroutines.
    wallTimeStart := time.Now()
    var wg sync.WaitGroup

    // Run tasks.
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go someTask(t, wg)
    }

    wg.Wait()

    // When finished, set elapsed wall time.
    t.SetWallTime(time.Since(wallTimeStart))

    // Rate outputs will be accurate.
    fmt.Println(t.Calc().String())
}

func someTask(t *tachymeter.Tachymeter, wg *sync.WaitGroup) {
    defer wg.Done()
    start := time.Now()

    // doSomeSlowDbCall()

    // Task we're timing added here.
    t.AddTime(time.Since(start))
}

<...>

Documentation

Overview

Package tachymeter yields summarized data describing a series of timed events.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Size  int
	Safe  bool // Deprecated. Flag held on to as to not break existing users.
	HBins int  // Histogram bins.
}

Config holds tachymeter initialization parameters. Size defines the sample capacity. Tachymeter is thread safe.

type Histogram

type Histogram []map[string]uint64

Histogram is a map["low-high duration"]count of events that fall within the low-high time duration range.

func (*Histogram) String

func (h *Histogram) String(s int) string

String returns a formatted Metrics string scaled to a width of s.

type Metrics

type Metrics struct {
	Time struct {
		Cumulative time.Duration // Cumulative time of all sampled events.
		HMean      time.Duration // Event duration harmonic mean.
		Avg        time.Duration // Event duration average.
		P50        time.Duration // Event duration nth percentiles ..
		P75        time.Duration
		P95        time.Duration
		P99        time.Duration
		P999       time.Duration
		Long5p     time.Duration // Average of the longest 5% event durations.
		Short5p    time.Duration // Average of the shortest 5% event durations.
		Max        time.Duration // Highest event duration.
		Min        time.Duration // Lowest event duration.
		StdDev     time.Duration // Standard deviation.
		Range      time.Duration // Event duration range (Max-Min).
	}
	Rate struct {
		// Per-second rate based on event duration avg. via Metrics.Cumulative / Metrics.Samples.
		// If SetWallTime was called, event duration avg = wall time / Metrics.Count
		Second float64
	}
	Histogram        *Histogram    // Frequency distribution of event durations in len(Histogram) bins of HistogramBinSize.
	HistogramBinSize time.Duration // The width of a histogram bin in time.
	Samples          int           // Number of events included in the sample set.
	Count            int           // Total number of events observed.
}

Metrics holds the calculated outputs produced from a Tachymeter sample set.

func (*Metrics) JSON

func (m *Metrics) JSON() string

JSON returns a *Metrics as a JSON string.

func (*Metrics) MarshalJSON

func (m *Metrics) MarshalJSON() ([]byte, error)

MarshalJSON defines the output formatting for the JSON() method. This is exported as a requirement but not intended for end users.

func (*Metrics) String

func (m *Metrics) String() string

String satisfies the String interface.

func (*Metrics) WriteHTML

func (m *Metrics) WriteHTML(p string) error

WriteHTML writes a histograph html file to the cwd.

type Tachymeter

type Tachymeter struct {
	sync.Mutex
	Size     uint64
	Times    timeSlice
	Count    uint64
	WallTime time.Duration
	HBins    int
}

Tachymeter holds event durations and counts.

func New

func New(c *Config) *Tachymeter

New initializes a new Tachymeter.

func (*Tachymeter) AddTime

func (m *Tachymeter) AddTime(t time.Duration)

AddTime adds a time.Duration to Tachymeter.

func (*Tachymeter) Calc

func (m *Tachymeter) Calc() *Metrics

Calc summarizes Tachymeter sample data and returns it in the form of a *Metrics.

func (*Tachymeter) Reset

func (m *Tachymeter) Reset()

Reset resets a Tachymeter instance for reuse.

func (*Tachymeter) SetWallTime

func (m *Tachymeter) SetWallTime(t time.Duration)

SetWallTime optionally sets an elapsed wall time duration. This affects rate output by using total events counted over time. This is useful for concurrent/parallelized events that overlap in wall time and are writing to a shared Tachymeter instance.

type Timeline

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

Timeline holds a []*timelineEvents, which nest *Metrics for analyzing multiple collections of measured events.

func (*Timeline) AddEvent

func (t *Timeline) AddEvent(m *Metrics)

AddEvent adds a *Metrics to the *Timeline.

func (*Timeline) WriteHTML

func (t *Timeline) WriteHTML(p string) error

WriteHTML takes an absolute path p and writes an html file to 'p/tachymeter-<timestamp>.html' of all histograms held by the *Timeline, in series.

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

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