Source file 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  }
   297  

View as plain text