]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/test/switch_test.go
cmd/compile: improve interface type switches
[gostls13.git] / src / cmd / compile / internal / test / switch_test.go
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
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 // A simple random number generator used to make switches conditionally predictable.
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 }