mirror of https://github.com/golang/go.git
297 lines
4.2 KiB
Go
297 lines
4.2 KiB
Go
// 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)
|
|
}
|