1// Copyright 2021 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package test
6
7import (
8	"math/bits"
9	"testing"
10)
11
12func BenchmarkSwitch8Predictable(b *testing.B) {
13	benchmarkSwitch8(b, true)
14}
15func BenchmarkSwitch8Unpredictable(b *testing.B) {
16	benchmarkSwitch8(b, false)
17}
18func 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
45func BenchmarkSwitch32Predictable(b *testing.B) {
46	benchmarkSwitch32(b, true)
47}
48func BenchmarkSwitch32Unpredictable(b *testing.B) {
49	benchmarkSwitch32(b, false)
50}
51func 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
80func BenchmarkSwitchStringPredictable(b *testing.B) {
81	benchmarkSwitchString(b, true)
82}
83func BenchmarkSwitchStringUnpredictable(b *testing.B) {
84	benchmarkSwitchString(b, false)
85}
86func 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
123func BenchmarkSwitchTypePredictable(b *testing.B) {
124	benchmarkSwitchType(b, true)
125}
126func BenchmarkSwitchTypeUnpredictable(b *testing.B) {
127	benchmarkSwitchType(b, false)
128}
129func 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
166func BenchmarkSwitchInterfaceTypePredictable(b *testing.B) {
167	benchmarkSwitchInterfaceType(b, true)
168}
169func BenchmarkSwitchInterfaceTypeUnpredictable(b *testing.B) {
170	benchmarkSwitchInterfaceType(b, false)
171}
172
173type SI0 interface {
174	si0()
175}
176type ST0 struct {
177}
178
179func (ST0) si0() {
180}
181
182type SI1 interface {
183	si1()
184}
185type ST1 struct {
186}
187
188func (ST1) si1() {
189}
190
191type SI2 interface {
192	si2()
193}
194type ST2 struct {
195}
196
197func (ST2) si2() {
198}
199
200type SI3 interface {
201	si3()
202}
203type ST3 struct {
204}
205
206func (ST3) si3() {
207}
208
209type SI4 interface {
210	si4()
211}
212type ST4 struct {
213}
214
215func (ST4) si4() {
216}
217
218type SI5 interface {
219	si5()
220}
221type ST5 struct {
222}
223
224func (ST5) si5() {
225}
226
227type SI6 interface {
228	si6()
229}
230type ST6 struct {
231}
232
233func (ST6) si6() {
234}
235
236type SI7 interface {
237	si7()
238}
239type ST7 struct {
240}
241
242func (ST7) si7() {
243}
244
245func 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// A simple random number generator used to make switches conditionally predictable.
283type rng uint64
284
285func newRNG() rng {
286	return 1
287}
288func (r rng) next(predictable bool) rng {
289	if predictable {
290		return r + 1
291	}
292	return rng(bits.RotateLeft64(uint64(r), 13) * 0x3c374d)
293}
294func (r rng) value() uint64 {
295	return uint64(r)
296}
297