/
main.go
141 lines (111 loc) · 2.83 KB
/
main.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
135
136
137
138
139
140
141
package main
import (
"fmt"
"math"
"time"
"github.com/sirupsen/logrus"
)
// Test program for the busy sleeper that tests the looper
type BusySleeper struct {
// v = beta * time + alpha
alpha float64
beta float64
r2 float64
maxSleepTimeUs float64
foundPrime int64 // Hopefully this means the computePrime function won't be optimized out
}
func NewBusySleeper(maxSleepTimeUs float64) *BusySleeper {
s := &BusySleeper{
maxSleepTimeUs: maxSleepTimeUs,
}
s.calibrate()
return s
}
func (s *BusySleeper) Sleep(timeUs float64) {
sleepTimeRemaining := timeUs
for sleepTimeRemaining > 0 {
timeToSleep := sleepTimeRemaining
if timeToSleep > s.maxSleepTimeUs {
timeToSleep = s.maxSleepTimeUs
}
v := math.Round(s.beta*timeToSleep + s.alpha)
s.computePrime(int64(v))
sleepTimeRemaining -= timeToSleep
}
}
// Very inefficient prime computation to burn time
func (s *BusySleeper) computePrime(v int64) {
var isPrime bool = true
for i := int64(1); i < v; i++ {
if v%i == 0 {
isPrime = false
}
}
if isPrime {
s.foundPrime += 1
}
}
func (s *BusySleeper) calibrate() {
var currentV int64 = 0
var currentTimingUs int64 = 0
diff := int64(200000)
timings := [][2]int64{}
for currentTimingUs < int64(s.maxSleepTimeUs) {
currentV += diff
start := time.Now()
s.computePrime(currentV)
currentTimingUs = time.Since(start).Microseconds()
row := [2]int64{currentTimingUs, currentV}
timings = append(timings, row)
// fmt.Printf("%d, %d\n", row[0], row[1])
}
s.alpha, s.beta, s.r2 = simpleLinearRegression(timings)
logrus.Debugf("v = %.3E * t + %.3f (r^2 = %.6f, n = %d)", s.beta, s.alpha, s.r2, len(timings))
logrus.Debugf("Ignore me: %d", s.foundPrime) // Hopefully means that computePrime won't be optimized out.
}
// y = alpha + beta * x
func simpleLinearRegression(data [][2]int64) (float64, float64, float64) {
xbar := 0.0
ybar := 0.0
xybar := 0.0
x2bar := 0.0
y2bar := 0.0
for _, row := range data {
xbar += float64(row[0])
ybar += float64(row[1])
xybar += float64(row[0] * row[1])
x2bar += float64(row[0] * row[0])
y2bar += float64(row[1] * row[1])
}
n := float64(len(data))
xbar /= n
ybar /= n
xybar /= n
x2bar /= n
y2bar /= n
top := 0.0
bottom := 0.0
for _, row := range data {
x := float64(row[0])
y := float64(row[1])
top += (x - xbar) * (y - ybar)
bottom += (x - xbar) * (x - xbar)
}
beta := top / bottom
alpha := ybar - (beta * xbar)
r := (xybar - xbar*ybar) / math.Sqrt((x2bar-xbar*xbar)*(y2bar-ybar*ybar))
return alpha, beta, r * r
}
func main() {
logrus.SetLevel(logrus.DebugLevel)
s := NewBusySleeper(25000)
start := time.Now()
s.Sleep(200)
fmt.Println(time.Since(start).Microseconds())
start = time.Now()
s.Sleep(50000)
fmt.Println(time.Since(start).Microseconds())
start = time.Now()
s.Sleep(220000)
fmt.Println(time.Since(start).Microseconds())
}