| // Copyright 2021 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package test | |
| import ( | |
| "math/bits" | |
| "testing" | |
| ) | |
| func BenchmarkSwitch8Predictable(b *testing.B) { | |
| benchmarkSwitch8(b, true) | |
| } | |
| func BenchmarkSwitch8Unpredictable(b *testing.B) { | |
| benchmarkSwitch8(b, false) | |
| } | |
| func benchmarkSwitch8(b *testing.B, predictable bool) { | |
| n := 0 | |
| rng := newRNG() | |
| for i := 0; i < b.N; i++ { | |
| rng = rng.next(predictable) | |
| switch rng.value() & 7 { | |
| case 0: | |
| n += 1 | |
| case 1: | |
| n += 2 | |
| case 2: | |
| n += 3 | |
| case 3: | |
| n += 4 | |
| case 4: | |
| n += 5 | |
| case 5: | |
| n += 6 | |
| case 6: | |
| n += 7 | |
| case 7: | |
| n += 8 | |
| } | |
| } | |
| sink = n | |
| } | |
| func BenchmarkSwitch32Predictable(b *testing.B) { | |
| benchmarkSwitch32(b, true) | |
| } | |
| func BenchmarkSwitch32Unpredictable(b *testing.B) { | |
| benchmarkSwitch32(b, false) | |
| } | |
| func benchmarkSwitch32(b *testing.B, predictable bool) { | |
| n := 0 | |
| rng := newRNG() | |
| for i := 0; i < b.N; i++ { | |
| rng = rng.next(predictable) | |
| switch rng.value() & 31 { | |
| case 0, 1, 2: | |
| n += 1 | |
| case 4, 5, 6: | |
| n += 2 | |
| case 8, 9, 10: | |
| n += 3 | |
| case 12, 13, 14: | |
| n += 4 | |
| case 16, 17, 18: | |
| n += 5 | |
| case 20, 21, 22: | |
| n += 6 | |
| case 24, 25, 26: | |
| n += 7 | |
| case 28, 29, 30: | |
| n += 8 | |
| default: | |
| n += 9 | |
| } | |
| } | |
| sink = n | |
| } | |
| func BenchmarkSwitchStringPredictable(b *testing.B) { | |
| benchmarkSwitchString(b, true) | |
| } | |
| func BenchmarkSwitchStringUnpredictable(b *testing.B) { | |
| benchmarkSwitchString(b, false) | |
| } | |
| func benchmarkSwitchString(b *testing.B, predictable bool) { | |
| a := []string{ | |
| "foo", | |
| "foo1", | |
| "foo22", | |
| "foo333", | |
| "foo4444", | |
| "foo55555", | |
| "foo666666", | |
| "foo7777777", | |
| } | |
| n := 0 | |
| rng := newRNG() | |
| for i := 0; i < b.N; i++ { | |
| rng = rng.next(predictable) | |
| switch a[rng.value()&7] { | |
| case "foo": | |
| n += 1 | |
| case "foo1": | |
| n += 2 | |
| case "foo22": | |
| n += 3 | |
| case "foo333": | |
| n += 4 | |
| case "foo4444": | |
| n += 5 | |
| case "foo55555": | |
| n += 6 | |
| case "foo666666": | |
| n += 7 | |
| case "foo7777777": | |
| n += 8 | |
| } | |
| } | |
| sink = n | |
| } | |
| // A simple random number generator used to make switches conditionally predictable. | |
| type rng uint64 | |
| func newRNG() rng { | |
| return 1 | |
| } | |
| func (r rng) next(predictable bool) rng { | |
| if predictable { | |
| return r + 1 | |
| } | |
| return rng(bits.RotateLeft64(uint64(r), 13) * 0x3c374d) | |
| } | |
| func (r rng) value() uint64 { | |
| return uint64(r) | |
| } |