Source file
src/math/big/calibrate_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package big
21
22 import (
23 "flag"
24 "fmt"
25 "testing"
26 "time"
27 )
28
29 var calibrate = flag.Bool("calibrate", false, "run calibration test")
30
31 const (
32 sqrModeMul = "mul(x, x)"
33 sqrModeBasic = "basicSqr(x)"
34 sqrModeKaratsuba = "karatsubaSqr(x)"
35 )
36
37 func TestCalibrate(t *testing.T) {
38 if !*calibrate {
39 return
40 }
41
42 computeKaratsubaThresholds()
43
44
45 minSqr := computeSqrThreshold(10, 30, 1, 3, sqrModeMul, sqrModeBasic)
46
47 maxSqr := computeSqrThreshold(200, 500, 10, 3, sqrModeBasic, sqrModeKaratsuba)
48 if minSqr != 0 {
49 fmt.Printf("found basicSqrThreshold = %d\n", minSqr)
50 } else {
51 fmt.Println("no basicSqrThreshold found")
52 }
53 if maxSqr != 0 {
54 fmt.Printf("found karatsubaSqrThreshold = %d\n", maxSqr)
55 } else {
56 fmt.Println("no karatsubaSqrThreshold found")
57 }
58 }
59
60 func karatsubaLoad(b *testing.B) {
61 BenchmarkMul(b)
62 }
63
64
65
66 func measureKaratsuba(th int) time.Duration {
67 th, karatsubaThreshold = karatsubaThreshold, th
68 res := testing.Benchmark(karatsubaLoad)
69 karatsubaThreshold = th
70 return time.Duration(res.NsPerOp())
71 }
72
73 func computeKaratsubaThresholds() {
74 fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
75 fmt.Printf("(run repeatedly for good results)\n")
76
77
78 Tb := measureKaratsuba(1e9)
79 fmt.Printf("Tb = %10s\n", Tb)
80
81
82 th := 4
83 th1 := -1
84 th2 := -1
85
86 var deltaOld time.Duration
87 for count := -1; count != 0 && th < 128; count-- {
88
89 Tk := measureKaratsuba(th)
90
91
92 delta := (Tb - Tk) * 100 / Tb
93
94 fmt.Printf("th = %3d Tk = %10s %4d%%", th, Tk, delta)
95
96
97 if Tk < Tb && th1 < 0 {
98 th1 = th
99 fmt.Print(" break-even point")
100 }
101
102
103 if 0 < delta && delta < deltaOld && th2 < 0 {
104 th2 = th
105 fmt.Print(" diminishing return")
106 }
107 deltaOld = delta
108
109 fmt.Println()
110
111
112 if th1 >= 0 && th2 >= 0 && count < 0 {
113 count = 10
114 }
115
116 th++
117 }
118 }
119
120 func measureSqr(words, nruns int, mode string) time.Duration {
121
122 initBasicSqr, initKaratsubaSqr := basicSqrThreshold, karatsubaSqrThreshold
123
124 switch mode {
125 case sqrModeMul:
126 basicSqrThreshold = words + 1
127 case sqrModeBasic:
128 basicSqrThreshold, karatsubaSqrThreshold = words-1, words+1
129 case sqrModeKaratsuba:
130 karatsubaSqrThreshold = words - 1
131 }
132
133 var testval int64
134 for i := 0; i < nruns; i++ {
135 res := testing.Benchmark(func(b *testing.B) { benchmarkNatSqr(b, words) })
136 testval += res.NsPerOp()
137 }
138 testval /= int64(nruns)
139
140 basicSqrThreshold, karatsubaSqrThreshold = initBasicSqr, initKaratsubaSqr
141
142 return time.Duration(testval)
143 }
144
145 func computeSqrThreshold(from, to, step, nruns int, lower, upper string) int {
146 fmt.Printf("Calibrating threshold between %s and %s\n", lower, upper)
147 fmt.Printf("Looking for a timing difference for x between %d - %d words by %d step\n", from, to, step)
148 var initPos bool
149 var threshold int
150 for i := from; i <= to; i += step {
151 baseline := measureSqr(i, nruns, lower)
152 testval := measureSqr(i, nruns, upper)
153 pos := baseline > testval
154 delta := baseline - testval
155 percent := delta * 100 / baseline
156 fmt.Printf("words = %3d deltaT = %10s (%4d%%) is %s better: %v", i, delta, percent, upper, pos)
157 if i == from {
158 initPos = pos
159 }
160 if threshold == 0 && pos != initPos {
161 threshold = i
162 fmt.Printf(" threshold found")
163 }
164 fmt.Println()
165
166 }
167 if threshold != 0 {
168 fmt.Printf("Found threshold = %d between %d - %d\n", threshold, from, to)
169 } else {
170 fmt.Printf("Found NO threshold between %d - %d\n", from, to)
171 }
172 return threshold
173 }
174
View as plain text