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