1
2
3
4
5 package test
6
7 import (
8 "math/bits"
9 "testing"
10 )
11
12 func BenchmarkSwitch8Predictable(b *testing.B) {
13 benchmarkSwitch8(b, true)
14 }
15 func BenchmarkSwitch8Unpredictable(b *testing.B) {
16 benchmarkSwitch8(b, false)
17 }
18 func benchmarkSwitch8(b *testing.B, predictable bool) {
19 n := 0
20 rng := newRNG()
21 for i := 0; i < b.N; i++ {
22 rng = rng.next(predictable)
23 switch rng.value() & 7 {
24 case 0:
25 n += 1
26 case 1:
27 n += 2
28 case 2:
29 n += 3
30 case 3:
31 n += 4
32 case 4:
33 n += 5
34 case 5:
35 n += 6
36 case 6:
37 n += 7
38 case 7:
39 n += 8
40 }
41 }
42 sink = n
43 }
44
45 func BenchmarkSwitch32Predictable(b *testing.B) {
46 benchmarkSwitch32(b, true)
47 }
48 func BenchmarkSwitch32Unpredictable(b *testing.B) {
49 benchmarkSwitch32(b, false)
50 }
51 func benchmarkSwitch32(b *testing.B, predictable bool) {
52 n := 0
53 rng := newRNG()
54 for i := 0; i < b.N; i++ {
55 rng = rng.next(predictable)
56 switch rng.value() & 31 {
57 case 0, 1, 2:
58 n += 1
59 case 4, 5, 6:
60 n += 2
61 case 8, 9, 10:
62 n += 3
63 case 12, 13, 14:
64 n += 4
65 case 16, 17, 18:
66 n += 5
67 case 20, 21, 22:
68 n += 6
69 case 24, 25, 26:
70 n += 7
71 case 28, 29, 30:
72 n += 8
73 default:
74 n += 9
75 }
76 }
77 sink = n
78 }
79
80 func BenchmarkSwitchStringPredictable(b *testing.B) {
81 benchmarkSwitchString(b, true)
82 }
83 func BenchmarkSwitchStringUnpredictable(b *testing.B) {
84 benchmarkSwitchString(b, false)
85 }
86 func benchmarkSwitchString(b *testing.B, predictable bool) {
87 a := []string{
88 "foo",
89 "foo1",
90 "foo22",
91 "foo333",
92 "foo4444",
93 "foo55555",
94 "foo666666",
95 "foo7777777",
96 }
97 n := 0
98 rng := newRNG()
99 for i := 0; i < b.N; i++ {
100 rng = rng.next(predictable)
101 switch a[rng.value()&7] {
102 case "foo":
103 n += 1
104 case "foo1":
105 n += 2
106 case "foo22":
107 n += 3
108 case "foo333":
109 n += 4
110 case "foo4444":
111 n += 5
112 case "foo55555":
113 n += 6
114 case "foo666666":
115 n += 7
116 case "foo7777777":
117 n += 8
118 }
119 }
120 sink = n
121 }
122
123 func BenchmarkSwitchTypePredictable(b *testing.B) {
124 benchmarkSwitchType(b, true)
125 }
126 func BenchmarkSwitchTypeUnpredictable(b *testing.B) {
127 benchmarkSwitchType(b, false)
128 }
129 func benchmarkSwitchType(b *testing.B, predictable bool) {
130 a := []any{
131 int8(1),
132 int16(2),
133 int32(3),
134 int64(4),
135 uint8(5),
136 uint16(6),
137 uint32(7),
138 uint64(8),
139 }
140 n := 0
141 rng := newRNG()
142 for i := 0; i < b.N; i++ {
143 rng = rng.next(predictable)
144 switch a[rng.value()&7].(type) {
145 case int8:
146 n += 1
147 case int16:
148 n += 2
149 case int32:
150 n += 3
151 case int64:
152 n += 4
153 case uint8:
154 n += 5
155 case uint16:
156 n += 6
157 case uint32:
158 n += 7
159 case uint64:
160 n += 8
161 }
162 }
163 sink = n
164 }
165
166 func BenchmarkSwitchInterfaceTypePredictable(b *testing.B) {
167 benchmarkSwitchInterfaceType(b, true)
168 }
169 func BenchmarkSwitchInterfaceTypeUnpredictable(b *testing.B) {
170 benchmarkSwitchInterfaceType(b, false)
171 }
172
173 type SI0 interface {
174 si0()
175 }
176 type ST0 struct {
177 }
178
179 func (ST0) si0() {
180 }
181
182 type SI1 interface {
183 si1()
184 }
185 type ST1 struct {
186 }
187
188 func (ST1) si1() {
189 }
190
191 type SI2 interface {
192 si2()
193 }
194 type ST2 struct {
195 }
196
197 func (ST2) si2() {
198 }
199
200 type SI3 interface {
201 si3()
202 }
203 type ST3 struct {
204 }
205
206 func (ST3) si3() {
207 }
208
209 type SI4 interface {
210 si4()
211 }
212 type ST4 struct {
213 }
214
215 func (ST4) si4() {
216 }
217
218 type SI5 interface {
219 si5()
220 }
221 type ST5 struct {
222 }
223
224 func (ST5) si5() {
225 }
226
227 type SI6 interface {
228 si6()
229 }
230 type ST6 struct {
231 }
232
233 func (ST6) si6() {
234 }
235
236 type SI7 interface {
237 si7()
238 }
239 type ST7 struct {
240 }
241
242 func (ST7) si7() {
243 }
244
245 func benchmarkSwitchInterfaceType(b *testing.B, predictable bool) {
246 a := []any{
247 ST0{},
248 ST1{},
249 ST2{},
250 ST3{},
251 ST4{},
252 ST5{},
253 ST6{},
254 ST7{},
255 }
256 n := 0
257 rng := newRNG()
258 for i := 0; i < b.N; i++ {
259 rng = rng.next(predictable)
260 switch a[rng.value()&7].(type) {
261 case SI0:
262 n += 1
263 case SI1:
264 n += 2
265 case SI2:
266 n += 3
267 case SI3:
268 n += 4
269 case SI4:
270 n += 5
271 case SI5:
272 n += 6
273 case SI6:
274 n += 7
275 case SI7:
276 n += 8
277 }
278 }
279 sink = n
280 }
281
282
283 type rng uint64
284
285 func newRNG() rng {
286 return 1
287 }
288 func (r rng) next(predictable bool) rng {
289 if predictable {
290 return r + 1
291 }
292 return rng(bits.RotateLeft64(uint64(r), 13) * 0x3c374d)
293 }
294 func (r rng) value() uint64 {
295 return uint64(r)
296 }
297
298
299
300
301
302
303 func switchLookup8(x int) int {
304 switch x {
305 case 0:
306 return 1
307 case 1:
308 return 2
309 case 2:
310 return 3
311 case 3:
312 return 5
313 case 4:
314 return 8
315 case 5:
316 return 13
317 case 6:
318 return 21
319 case 7:
320 return 34
321 default:
322 return 0
323 }
324 }
325
326
327 func switchLookup32(x int) int {
328 switch x {
329 case 0:
330 return 10
331 case 1:
332 return 20
333 case 2:
334 return 30
335 case 3:
336 return 40
337 case 4:
338 return 50
339 case 5:
340 return 60
341 case 6:
342 return 70
343 case 7:
344 return 80
345 case 8:
346 return 90
347 case 9:
348 return 100
349 case 10:
350 return 110
351 case 11:
352 return 120
353 case 12:
354 return 130
355 case 13:
356 return 140
357 case 14:
358 return 150
359 case 15:
360 return 160
361 case 16:
362 return 170
363 case 17:
364 return 180
365 case 18:
366 return 190
367 case 19:
368 return 200
369 case 20:
370 return 210
371 case 21:
372 return 220
373 case 22:
374 return 230
375 case 23:
376 return 240
377 case 24:
378 return 250
379 case 25:
380 return 260
381 case 26:
382 return 270
383 case 27:
384 return 280
385 case 28:
386 return 290
387 case 29:
388 return 300
389 case 30:
390 return 310
391 case 31:
392 return 320
393 default:
394 return 0
395 }
396 }
397
398 func BenchmarkSwitchLookup8Predictable(b *testing.B) {
399 benchmarkSwitchLookup8(b, true)
400 }
401 func BenchmarkSwitchLookup8Unpredictable(b *testing.B) {
402 benchmarkSwitchLookup8(b, false)
403 }
404 func benchmarkSwitchLookup8(b *testing.B, predictable bool) {
405 n := 0
406 rng := newRNG()
407 for i := 0; i < b.N; i++ {
408 rng = rng.next(predictable)
409 n += switchLookup8(int(rng.value() & 7))
410 }
411 sink = n
412 }
413
414 func BenchmarkSwitchLookup32Predictable(b *testing.B) {
415 benchmarkSwitchLookup32(b, true)
416 }
417 func BenchmarkSwitchLookup32Unpredictable(b *testing.B) {
418 benchmarkSwitchLookup32(b, false)
419 }
420 func benchmarkSwitchLookup32(b *testing.B, predictable bool) {
421 n := 0
422 rng := newRNG()
423 for i := 0; i < b.N; i++ {
424 rng = rng.next(predictable)
425 n += switchLookup32(int(rng.value() & 31))
426 }
427 sink = n
428 }
429
View as plain text