-
Notifications
You must be signed in to change notification settings - Fork 11
/
tsc.go
86 lines (68 loc) · 2.06 KB
/
tsc.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
package hrtime
import (
"sync"
"time"
)
// 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.
type Count int64
var calibrateOnce sync.Once
// ApproxDuration returns approximate conversion into a Duration.
//
// First call to this function will do calibration and can take several milliseconds.
func (count Count) ApproxDuration() time.Duration {
calibrateOnce.Do(calculateTSCConversion)
return time.Duration(count) * ratioNano / time.Duration(ratioCount)
}
// 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 TSC() Count { return Count(RDTSC()) }
// TSCSince returns count since start.
//
// Reminder: Count is processor specific and need to be converted to
// time.Duration with Count.ApproxDuration.
func TSCSince(start Count) Count { return TSC() - start }
// TSCSupported returns whether processor supports giving invariant time stamp counter values
func TSCSupported() bool { return rdtscpInvariant }
// TSCOverhead returns overhead of Count call
func TSCOverhead() Count { return readTSCOverhead }
var (
rdtscpInvariant = false
readTSCOverhead Count
cpuid func(op1, op2 uint32) (eax, ebx, ecx, edx uint32)
ratioNano time.Duration
ratioCount Count
)
func calculateTSCOverhead() {
if !rdtscpInvariant {
return
}
start := TSC()
for i := 0; i < calibrationCalls; i++ {
TSC()
}
stop := TSC()
readTSCOverhead = (stop - start) / (calibrationCalls + 1)
}
func calculateTSCConversion() {
// warmup
for i := 0; i < 64*calibrationCalls; i++ {
empty()
}
nanostart := Now()
countstart := TSC()
for i := 0; i < 64*calibrationCalls; i++ {
empty()
}
nanoend := Now()
countstop := TSC()
// TODO: figure out a better way to calculate this
ratioNano = nanoend - nanostart - Overhead()
ratioCount = countstop - countstart - TSCOverhead()
}
//go:noinline
func empty() {}