README

hrtime

GoDoc

Package hrtime implements high-resolution timing functions and benchmarking utilities.

hrtime relies on using the best timing mechanism on a particular system. At the moment, for Windows it is using Performance Counters and on other platforms standard time.Now (since it's good enough).

Package also supports using hardware time stamp counters (TSC). They offer better accuracy and on some platforms correspond to the processor cycles. However, they are not supported on all platforms.

For example measuring time.Sleep on Mac and Windows.

Example

package main

import (
    "fmt"
    "time"

    "github.com/loov/hrtime"
)

func main() {
    start := hrtime.Now()
    time.Sleep(1000 * time.Nanosecond)
    fmt.Println(hrtime.Since(start))

    const numberOfExperiments = 4096

    bench := hrtime.NewBenchmark(numberOfExperiments)
    for bench.Next() {
        time.Sleep(1000 * time.Nanosecond)
    }
    fmt.Println(bench.Histogram(10))
}

Output on Mac:

12µs
  avg 14.5µs;  min 2µs;  p50 12µs;  max 74µs;
  p90 22µs;  p99 44µs;  p999 69µs;  p9999 74µs;
        2µs [ 229] ██▌
       10µs [3239] ████████████████████████████████████████
       20µs [ 483] ██████
       30µs [  80] █
       40µs [  39] ▌
       50µs [  17] ▌
       60µs [   6]
       70µs [   3]
       80µs [   0]
       90µs [   0]

Output on Windows:

1.5155ms
  avg 1.49ms;  min 576µs;  p50 1.17ms;  max 2.47ms;
  p90 2.02ms;  p99 2.3ms;  p999 2.37ms;  p9999 2.47ms;
      577µs [   1]
      600µs [  57] █▌
      800µs [ 599] █████████████████
        1ms [1399] ████████████████████████████████████████
      1.2ms [  35] █
      1.4ms [   7]
      1.6ms [  91] ██▌
      1.8ms [ 995] ████████████████████████████
        2ms [ 778] ██████████████████████
      2.2ms [ 134] ███▌

A full explanation why it outputs this is out of the scope of this document. However, all sleep instructions have a specified granularity and time.Sleep actual sleeping time is requested time ± sleep granularity. There are also other explanations to that behavior.

Benchmarking

hrtime/hrtesting can be used to supplement existing benchmarks with more details:

package hrtesting_test

import (
	"fmt"
	"runtime"
	"testing"

	"github.com/loov/hrtime/hrtesting"
)

func BenchmarkReport(b *testing.B) {
	bench := hrtesting.NewBenchmark(b)
	defer bench.Report()

	for bench.Next() {
		r := fmt.Sprintf("hello, world %d", 123)
		runtime.KeepAlive(r)
	}
}

Documentation

Overview

Package hrtime implements High-Resolution Timing functions for benchmarking.

`hrtime` relies on using the best timing mechanism on a particular system. At the moment, for Windows it is using Performance Counters and on other platforms standard `time.Now` (since it's good enough).

Package also supports using hardware time stamp counters (TSC). They offer better accuracy and on some platforms correspond to the processor cycles. However, they are not supported on all platforms.

The basic usage of this package looks like:

package main

import (
    "fmt"
    "github.com/loov/hrtime"
)

func main() {
    const numberOfExperiments = 4096
    bench := hrtime.NewBenchmark(numberOfExperiments)
    for bench.Next() {
        time.Sleep(10)
    }
    fmt.Println(bench.Histogram(10))
}

To see more complex examples refer to the _example folder. (https://github.com/loov/hrtime/tree/master/_example)

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Now

func Now() time.Duration

Now returns current time.Duration with best possible precision.

Now returns time offset from a specific time. The values aren't comparable between computer restarts or between computers.

func NowPrecision

func NowPrecision() float64

NowPrecision returns maximum possible precision for Nanos in nanoseconds.

func Overhead

func Overhead() time.Duration

Overhead returns approximate overhead for a call to Now() or Since()

func RDTSC

func RDTSC() uint64

RDTSC returns Read Time-Stamp Counter value using RDTSC asm instruction.

If a platform doesn't support the instruction it returns 0. Use TSCSupported to check.

func RDTSCP

func RDTSCP() uint64

RDTSCP returns Read Time-Stamp Counter value using RDTSCP asm instruction.

If a platform doesn't support the instruction it returns 0. Use TSCSupported to check.

func Since

func Since(start time.Duration) time.Duration

Since returns time.Duration since start

func TSCSupported

func TSCSupported() bool

TSCSupported returns whether processor supports giving invariant time stamp counter values

Types

type Benchmark

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

Benchmark helps benchmarking using time.

Example
package main

import (
	"fmt"
	"time"

	"github.com/loov/hrtime"
)

func main() {
	const numberOfExperiments = 4096
	bench := hrtime.NewBenchmark(numberOfExperiments)
	for bench.Next() {
		time.Sleep(1000 * time.Nanosecond)
	}
	fmt.Println(bench.Histogram(10))
}
Output:

func NewBenchmark

func NewBenchmark(count int) *Benchmark

NewBenchmark creates a new benchmark using time. Count defines the number of samples to measure.

func (*Benchmark) Float64s

func (bench *Benchmark) Float64s() []float64

Float64s returns all measurements.

func (*Benchmark) Histogram

func (bench *Benchmark) Histogram(binCount int) *Histogram

Histogram creates an histogram of all the laps.

It creates binCount bins to distribute the data and uses the 99.9 percentile as the last bucket range. However, for a nicer output it might choose a larger value.

func (*Benchmark) HistogramClamp

func (bench *Benchmark) HistogramClamp(binCount int, min, max time.Duration) *Histogram

HistogramClamp creates an historgram of all the laps clamping minimum and maximum time.

It creates binCount bins to distribute the data and uses the maximum as the last bucket.

func (*Benchmark) Laps

func (bench *Benchmark) Laps() []time.Duration

Laps returns timing for each lap.

func (*Benchmark) Name

func (bench *Benchmark) Name() string

Name returns name of the benchmark.

func (*Benchmark) Next

func (bench *Benchmark) Next() bool

Next starts measuring the next lap. It will return false, when all measurements have been made.

func (*Benchmark) Unit

func (bench *Benchmark) Unit() string

Unit returns units it measures.

type BenchmarkTSC

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

BenchmarkTSC helps benchmarking using CPU counters.

Example
package main

import (
	"fmt"
	"time"

	"github.com/loov/hrtime"
)

func main() {
	const numberOfExperiments = 4096
	bench := hrtime.NewBenchmarkTSC(numberOfExperiments)
	for bench.Next() {
		time.Sleep(1000 * time.Nanosecond)
	}
	fmt.Println(bench.Histogram(10))
}
Output:

func NewBenchmarkTSC

func NewBenchmarkTSC(count int) *BenchmarkTSC

NewBenchmarkTSC creates a new benchmark using CPU counters. Count defines the number of samples to measure.

func (*BenchmarkTSC) Counts

func (bench *BenchmarkTSC) Counts() []Count

Counts returns counts for each lap.

func (*BenchmarkTSC) Float64s

func (bench *BenchmarkTSC) Float64s() []float64

Float64s returns all measurements as float64s

func (*BenchmarkTSC) Histogram

func (bench *BenchmarkTSC) Histogram(binCount int) *Histogram

Histogram creates an histogram of all the laps.

It creates binCount bins to distribute the data and uses the 99.9 percentile as the last bucket range. However, for a nicer output it might choose a larger value.

func (*BenchmarkTSC) HistogramClamp

func (bench *BenchmarkTSC) HistogramClamp(binCount int, min, max time.Duration) *Histogram

HistogramClamp creates an historgram of all the laps clamping minimum and maximum time.

It creates binCount bins to distribute the data and uses the maximum as the last bucket.

func (*BenchmarkTSC) Laps

func (bench *BenchmarkTSC) Laps() []time.Duration

Laps returns timing for each lap using the approximate conversion of Count.

func (*BenchmarkTSC) Name

func (bench *BenchmarkTSC) Name() string

Name returns name of the benchmark.

func (*BenchmarkTSC) Next

func (bench *BenchmarkTSC) Next() bool

Next starts measuring the next lap. It will return false, when all measurements have been made.

func (*BenchmarkTSC) Unit

func (bench *BenchmarkTSC) Unit() string

Unit returns units it measures.

type Count

type Count int64

Count represents represents Time Stamp Counter value, when available.

Count doesn't depend on power throttling making it useful for benchmarking. However it is not reliably convertible to a reasonable time-value.

func TSC

func TSC() Count

TSC reads the current Time Stamp Counter value.

Reminder: Time Stamp Count are processor specific and need to be converted to time.Duration with Count.ApproxDuration.

func TSCOverhead

func TSCOverhead() Count

TSCOverhead returns overhead of Count call

func TSCSince

func TSCSince(start Count) Count

TSCSince returns count since start.

Reminder: Count is processor specific and need to be converted to time.Duration with Count.ApproxDuration.

func (Count) ApproxDuration

func (count Count) ApproxDuration() time.Duration

ApproxDuration returns approximate conversion into a Duration.

First call to this function will do calibration and can take several milliseconds.

type Histogram

type Histogram struct {
	Minimum float64
	Average float64
	Maximum float64

	P50, P90, P99, P999, P9999 float64

	Bins []HistogramBin

	// for pretty printing
	Width int
}

Histogram is a binned historgram with different statistics.

func NewDurationHistogram

func NewDurationHistogram(durations []time.Duration, opts *HistogramOptions) *Histogram

NewDurationHistogram creates a histogram from time.Duration-s.

func NewHistogram

func NewHistogram(nanoseconds []float64, opts *HistogramOptions) *Histogram

NewHistogram creates a new histogram from the specified nanosecond values.

func (*Histogram) Divide

func (hist *Histogram) Divide(n int)

Divide divides histogram by number of repetitions for the tests.

func (*Histogram) String

func (hist *Histogram) String() string

String returns a string representation of the histogram.

func (*Histogram) StringStats

func (hist *Histogram) StringStats() string

StringStats returns a string representation of the histogram stats.

func (*Histogram) WriteStatsTo

func (hist *Histogram) WriteStatsTo(w io.Writer) (int64, error)

WriteStatsTo writes formatted statistics to w.

func (*Histogram) WriteTo

func (hist *Histogram) WriteTo(w io.Writer) (int64, error)

WriteTo writes formatted statistics and histogram to w.

type HistogramBin

type HistogramBin struct {
	Start float64
	Count int
	Width float64
	// contains filtered or unexported fields
}

HistogramBin is a single bin in histogram

type HistogramOptions

type HistogramOptions struct {
	BinCount int
	// NiceRange will try to round the bucket sizes to have a nicer output.
	NiceRange bool
	// Clamp values to either percentile or to a specific ns value.
	ClampMaximum    float64
	ClampPercentile float64
}

HistogramOptions is configuration.

type Span

type Span struct {
	Start  time.Duration
	Finish time.Duration
}

Span defines a time.Duration span

func (*Span) Duration

func (span *Span) Duration() time.Duration

Duration returns the duration of the time span.

type SpanTSC

type SpanTSC struct {
	Start  Count
	Finish Count
}

SpanTSC defines a Count span

func (*SpanTSC) ApproxDuration

func (span *SpanTSC) ApproxDuration() time.Duration

ApproxDuration returns the approximate duration of the span.

func (*SpanTSC) Count

func (span *SpanTSC) Count() Count

Count returns the duration in count of the count span.

type Stopwatch

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

Stopwatch allows concurrent benchmarking using Now

Example
package main

import (
	"fmt"
	"time"

	"github.com/loov/hrtime"
)

func main() {
	const numberOfExperiments = 4096
	bench := hrtime.NewStopwatch(numberOfExperiments)
	for i := 0; i < numberOfExperiments; i++ {
		go func() {
			lap := bench.Start()
			defer bench.Stop(lap)

			time.Sleep(1000 * time.Nanosecond)
		}()
	}
	bench.Wait()
	fmt.Println(bench.Histogram(10))
}
Output:

func NewStopwatch

func NewStopwatch(count int) *Stopwatch

NewStopwatch creates a new concurrent benchmark using Now

func (*Stopwatch) Durations

func (bench *Stopwatch) Durations() []time.Duration

Durations returns measured durations.

func (*Stopwatch) Float64s

func (bench *Stopwatch) Float64s() []float64

Float64s returns all measurements.

func (*Stopwatch) Histogram

func (bench *Stopwatch) Histogram(binCount int) *Histogram

Histogram creates an histogram of all the durations.

It creates binCount bins to distribute the data and uses the 99.9 percentile as the last bucket range. However, for a nicer output it might choose a larger value.

func (*Stopwatch) HistogramClamp

func (bench *Stopwatch) HistogramClamp(binCount int, min, max time.Duration) *Histogram

HistogramClamp creates an historgram of all the durations clamping minimum and maximum time.

It creates binCount bins to distribute the data and uses the maximum as the last bucket.

func (*Stopwatch) Name

func (bench *Stopwatch) Name() string

Name returns name of the benchmark.

func (*Stopwatch) Spans

func (bench *Stopwatch) Spans() []Span

Spans returns measured time-spans.

func (*Stopwatch) Start

func (bench *Stopwatch) Start() int32

Start starts measuring a new lap. It returns the lap number to pass in for Stop. It will return -1, when all measurements have been made.

Call to Stop with -1 is ignored.

func (*Stopwatch) Stop

func (bench *Stopwatch) Stop(lap int32)

Stop stops measuring the specified lap.

Call to Stop with -1 is ignored.

func (*Stopwatch) Unit

func (bench *Stopwatch) Unit() string

Unit returns units it measures.

func (*Stopwatch) Wait

func (bench *Stopwatch) Wait()

Wait waits for all measurements to be completed.

type StopwatchTSC

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

StopwatchTSC allows concurrent benchmarking using TSC

Example
package main

import (
	"fmt"
	"time"

	"github.com/loov/hrtime"
)

func main() {
	const numberOfExperiments = 4096
	bench := hrtime.NewStopwatchTSC(numberOfExperiments)
	for i := 0; i < numberOfExperiments; i++ {
		go func() {
			lap := bench.Start()
			defer bench.Stop(lap)

			time.Sleep(1000 * time.Nanosecond)
		}()
	}
	bench.Wait()
	fmt.Println(bench.Histogram(10))
}
Output:

func NewStopwatchTSC

func NewStopwatchTSC(count int) *StopwatchTSC

NewStopwatchTSC creates a new concurrent benchmark using TSC

func (*StopwatchTSC) ApproxDurations

func (bench *StopwatchTSC) ApproxDurations() []time.Duration

ApproxDurations returns measured durations.

func (*StopwatchTSC) Float64s

func (bench *StopwatchTSC) Float64s() []float64

Float64s returns all measurements.

func (*StopwatchTSC) Histogram

func (bench *StopwatchTSC) Histogram(binCount int) *Histogram

Histogram creates an histogram of all the durations.

It creates binCount bins to distribute the data and uses the 99.9 percentile as the last bucket range. However, for a nicer output it might choose a larger value.

func (*StopwatchTSC) HistogramClamp

func (bench *StopwatchTSC) HistogramClamp(binCount int, min, max time.Duration) *Histogram

HistogramClamp creates an historgram of all the durations clamping minimum and maximum time.

It creates binCount bins to distribute the data and uses the maximum as the last bucket.

func (*StopwatchTSC) Name

func (bench *StopwatchTSC) Name() string

Name returns name of the benchmark.

func (*StopwatchTSC) Spans

func (bench *StopwatchTSC) Spans() []SpanTSC

Spans returns measured time-spans.

func (*StopwatchTSC) Start

func (bench *StopwatchTSC) Start() int32

Start starts measuring a new lap. It returns the lap number to pass in for Stop. It will return -1, when all measurements have been made.

Call to Stop with -1 is ignored.

func (*StopwatchTSC) Stop

func (bench *StopwatchTSC) Stop(lap int32)

Stop stops measuring the specified lap.

Call to Stop with -1 is ignored.

func (*StopwatchTSC) Unit

func (bench *StopwatchTSC) Unit() string

Unit returns units it measures.

func (*StopwatchTSC) Wait

func (bench *StopwatchTSC) Wait()

Wait waits for all measurements to be completed.

Directories

Path Synopsis
_example
basic
This program demonstrates the basic usage of the package.
This program demonstrates the basic usage of the package.
benchtime
benchtime implements measuring and plotting of timing overheads.
benchtime implements measuring and plotting of timing overheads.
plotting
plotting demonstrates how to combine hrtime with plot package.
plotting demonstrates how to combine hrtime with plot package.
hrplot module
Package hrtesting implements wrappers for testing.B that allow to output more detailed information in standard go benchmarks.
Package hrtesting implements wrappers for testing.B that allow to output more detailed information in standard go benchmarks.