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

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