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 }