github.com/loov/hrtime@v1.0.3/benchmark.go (about)

     1  package hrtime
     2  
     3  import (
     4  	"time"
     5  )
     6  
     7  // Benchmark helps benchmarking using time.
     8  type Benchmark struct {
     9  	step  int
    10  	laps  []time.Duration
    11  	start time.Duration
    12  	stop  time.Duration
    13  }
    14  
    15  // NewBenchmark creates a new benchmark using time.
    16  // Count defines the number of samples to measure.
    17  func NewBenchmark(count int) *Benchmark {
    18  	if count <= 0 {
    19  		panic("must have count at least 1")
    20  	}
    21  
    22  	return &Benchmark{
    23  		step:  0,
    24  		laps:  make([]time.Duration, count),
    25  		start: 0,
    26  		stop:  0,
    27  	}
    28  }
    29  
    30  // mustBeCompleted checks whether measurement has been completed.
    31  func (bench *Benchmark) mustBeCompleted() {
    32  	if bench.stop == 0 {
    33  		panic("benchmarking incomplete")
    34  	}
    35  }
    36  
    37  // finalize calculates diffs for each lap.
    38  func (bench *Benchmark) finalize(last time.Duration) {
    39  	if bench.stop != 0 {
    40  		return
    41  	}
    42  
    43  	bench.start = bench.laps[0]
    44  	bench.stop = last
    45  	for i := range bench.laps[:len(bench.laps)-1] {
    46  		bench.laps[i] = bench.laps[i+1] - bench.laps[i]
    47  	}
    48  	bench.laps[len(bench.laps)-1] = bench.stop - bench.laps[len(bench.laps)-1]
    49  }
    50  
    51  // Next starts measuring the next lap.
    52  // It will return false, when all measurements have been made.
    53  func (bench *Benchmark) Next() bool {
    54  	now := Now()
    55  	if bench.step >= len(bench.laps) {
    56  		bench.finalize(now)
    57  		return false
    58  	}
    59  	bench.laps[bench.step] = Now()
    60  	bench.step++
    61  	return true
    62  }
    63  
    64  // Laps returns timing for each lap.
    65  func (bench *Benchmark) Laps() []time.Duration {
    66  	bench.mustBeCompleted()
    67  	return append(bench.laps[:0:0], bench.laps...)
    68  }
    69  
    70  // Name returns name of the benchmark.
    71  func (bench *Benchmark) Name() string { return "" }
    72  
    73  // Unit returns units it measures.
    74  func (bench *Benchmark) Unit() string { return "ns" }
    75  
    76  // Float64s returns all measurements.
    77  func (bench *Benchmark) Float64s() []float64 {
    78  	measurements := make([]float64, len(bench.laps))
    79  	for i := range measurements {
    80  		measurements[i] = float64(bench.laps[i].Nanoseconds())
    81  	}
    82  	return measurements
    83  }
    84  
    85  // Histogram creates an histogram of all the laps.
    86  //
    87  // It creates binCount bins to distribute the data and uses the
    88  // 99.9 percentile as the last bucket range. However, for a nicer output
    89  // it might choose a larger value.
    90  func (bench *Benchmark) Histogram(binCount int) *Histogram {
    91  	bench.mustBeCompleted()
    92  
    93  	opts := defaultOptions
    94  	opts.BinCount = binCount
    95  
    96  	return NewDurationHistogram(bench.laps, &opts)
    97  }
    98  
    99  // HistogramClamp creates an historgram of all the laps clamping minimum and maximum time.
   100  //
   101  // It creates binCount bins to distribute the data and uses the
   102  // maximum as the last bucket.
   103  func (bench *Benchmark) HistogramClamp(binCount int, min, max time.Duration) *Histogram {
   104  	bench.mustBeCompleted()
   105  
   106  	laps := make([]time.Duration, 0, len(bench.laps))
   107  	for _, lap := range bench.laps {
   108  		if lap < min {
   109  			laps = append(laps, min)
   110  		} else {
   111  			laps = append(laps, lap)
   112  		}
   113  	}
   114  
   115  	opts := defaultOptions
   116  	opts.BinCount = binCount
   117  	opts.ClampMaximum = float64(max.Nanoseconds())
   118  	opts.ClampPercentile = 0
   119  
   120  	return NewDurationHistogram(laps, &opts)
   121  }