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