| // 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 |
| } |
| |
| func BenchmarkSwitchTypePredictable(b *testing.B) { |
| benchmarkSwitchType(b, true) |
| } |
| func BenchmarkSwitchTypeUnpredictable(b *testing.B) { |
| benchmarkSwitchType(b, false) |
| } |
| func benchmarkSwitchType(b *testing.B, predictable bool) { |
| a := []any{ |
| int8(1), |
| int16(2), |
| int32(3), |
| int64(4), |
| uint8(5), |
| uint16(6), |
| uint32(7), |
| uint64(8), |
| } |
| n := 0 |
| rng := newRNG() |
| for i := 0; i < b.N; i++ { |
| rng = rng.next(predictable) |
| switch a[rng.value()&7].(type) { |
| case int8: |
| n += 1 |
| case int16: |
| n += 2 |
| case int32: |
| n += 3 |
| case int64: |
| n += 4 |
| case uint8: |
| n += 5 |
| case uint16: |
| n += 6 |
| case uint32: |
| n += 7 |
| case uint64: |
| n += 8 |
| } |
| } |
| sink = n |
| } |
| |
| func BenchmarkSwitchInterfaceTypePredictable(b *testing.B) { |
| benchmarkSwitchInterfaceType(b, true) |
| } |
| func BenchmarkSwitchInterfaceTypeUnpredictable(b *testing.B) { |
| benchmarkSwitchInterfaceType(b, false) |
| } |
| |
| type SI0 interface { |
| si0() |
| } |
| type ST0 struct { |
| } |
| |
| func (ST0) si0() { |
| } |
| |
| type SI1 interface { |
| si1() |
| } |
| type ST1 struct { |
| } |
| |
| func (ST1) si1() { |
| } |
| |
| type SI2 interface { |
| si2() |
| } |
| type ST2 struct { |
| } |
| |
| func (ST2) si2() { |
| } |
| |
| type SI3 interface { |
| si3() |
| } |
| type ST3 struct { |
| } |
| |
| func (ST3) si3() { |
| } |
| |
| type SI4 interface { |
| si4() |
| } |
| type ST4 struct { |
| } |
| |
| func (ST4) si4() { |
| } |
| |
| type SI5 interface { |
| si5() |
| } |
| type ST5 struct { |
| } |
| |
| func (ST5) si5() { |
| } |
| |
| type SI6 interface { |
| si6() |
| } |
| type ST6 struct { |
| } |
| |
| func (ST6) si6() { |
| } |
| |
| type SI7 interface { |
| si7() |
| } |
| type ST7 struct { |
| } |
| |
| func (ST7) si7() { |
| } |
| |
| func benchmarkSwitchInterfaceType(b *testing.B, predictable bool) { |
| a := []any{ |
| ST0{}, |
| ST1{}, |
| ST2{}, |
| ST3{}, |
| ST4{}, |
| ST5{}, |
| ST6{}, |
| ST7{}, |
| } |
| n := 0 |
| rng := newRNG() |
| for i := 0; i < b.N; i++ { |
| rng = rng.next(predictable) |
| switch a[rng.value()&7].(type) { |
| case SI0: |
| n += 1 |
| case SI1: |
| n += 2 |
| case SI2: |
| n += 3 |
| case SI3: |
| n += 4 |
| case SI4: |
| n += 5 |
| case SI5: |
| n += 6 |
| case SI6: |
| n += 7 |
| case SI7: |
| 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) |
| } |