github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/reflect/benchmark_test.go (about)

     1  // Copyright 2022 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 reflect_test
     6  
     7  import (
     8  	"fmt"
     9  	. "reflect"
    10  	"strconv"
    11  	"testing"
    12  )
    13  
    14  var sourceAll = struct {
    15  	Bool         Value
    16  	String       Value
    17  	Bytes        Value
    18  	NamedBytes   Value
    19  	BytesArray   Value
    20  	SliceAny     Value
    21  	MapStringAny Value
    22  }{
    23  	Bool:         ValueOf(new(bool)).Elem(),
    24  	String:       ValueOf(new(string)).Elem(),
    25  	Bytes:        ValueOf(new([]byte)).Elem(),
    26  	NamedBytes:   ValueOf(new(namedBytes)).Elem(),
    27  	BytesArray:   ValueOf(new([32]byte)).Elem(),
    28  	SliceAny:     ValueOf(new([]any)).Elem(),
    29  	MapStringAny: ValueOf(new(map[string]any)).Elem(),
    30  }
    31  
    32  var sinkAll struct {
    33  	RawBool   bool
    34  	RawString string
    35  	RawBytes  []byte
    36  	RawInt    int
    37  }
    38  
    39  func BenchmarkBool(b *testing.B) {
    40  	for i := 0; i < b.N; i++ {
    41  		sinkAll.RawBool = sourceAll.Bool.Bool()
    42  	}
    43  }
    44  
    45  func BenchmarkString(b *testing.B) {
    46  	for i := 0; i < b.N; i++ {
    47  		sinkAll.RawString = sourceAll.String.String()
    48  	}
    49  }
    50  
    51  func BenchmarkBytes(b *testing.B) {
    52  	for i := 0; i < b.N; i++ {
    53  		sinkAll.RawBytes = sourceAll.Bytes.Bytes()
    54  	}
    55  }
    56  
    57  func BenchmarkNamedBytes(b *testing.B) {
    58  	for i := 0; i < b.N; i++ {
    59  		sinkAll.RawBytes = sourceAll.NamedBytes.Bytes()
    60  	}
    61  }
    62  
    63  func BenchmarkBytesArray(b *testing.B) {
    64  	for i := 0; i < b.N; i++ {
    65  		sinkAll.RawBytes = sourceAll.BytesArray.Bytes()
    66  	}
    67  }
    68  
    69  func BenchmarkSliceLen(b *testing.B) {
    70  	for i := 0; i < b.N; i++ {
    71  		sinkAll.RawInt = sourceAll.SliceAny.Len()
    72  	}
    73  }
    74  
    75  func BenchmarkMapLen(b *testing.B) {
    76  	for i := 0; i < b.N; i++ {
    77  		sinkAll.RawInt = sourceAll.MapStringAny.Len()
    78  	}
    79  }
    80  
    81  func BenchmarkStringLen(b *testing.B) {
    82  	for i := 0; i < b.N; i++ {
    83  		sinkAll.RawInt = sourceAll.String.Len()
    84  	}
    85  }
    86  
    87  func BenchmarkArrayLen(b *testing.B) {
    88  	for i := 0; i < b.N; i++ {
    89  		sinkAll.RawInt = sourceAll.BytesArray.Len()
    90  	}
    91  }
    92  
    93  func BenchmarkSliceCap(b *testing.B) {
    94  	for i := 0; i < b.N; i++ {
    95  		sinkAll.RawInt = sourceAll.SliceAny.Cap()
    96  	}
    97  }
    98  
    99  func BenchmarkDeepEqual(b *testing.B) {
   100  	for _, bb := range deepEqualPerfTests {
   101  		b.Run(ValueOf(bb.x).Type().String(), func(b *testing.B) {
   102  			b.ReportAllocs()
   103  			for i := 0; i < b.N; i++ {
   104  				sink = DeepEqual(bb.x, bb.y)
   105  			}
   106  		})
   107  	}
   108  }
   109  
   110  func BenchmarkIsZero(b *testing.B) {
   111  	source := ValueOf(struct {
   112  		ArrayComparable    [4]T
   113  		ArrayIncomparable  [4]_Complex
   114  		StructComparable   T
   115  		StructIncomparable _Complex
   116  	}{})
   117  
   118  	for i := 0; i < source.NumField(); i++ {
   119  		name := source.Type().Field(i).Name
   120  		value := source.Field(i)
   121  		b.Run(name, func(b *testing.B) {
   122  			for i := 0; i < b.N; i++ {
   123  				sink = value.IsZero()
   124  			}
   125  		})
   126  	}
   127  }
   128  
   129  func BenchmarkSetZero(b *testing.B) {
   130  	source := ValueOf(new(struct {
   131  		Bool      bool
   132  		Int       int64
   133  		Uint      uint64
   134  		Float     float64
   135  		Complex   complex128
   136  		Array     [4]Value
   137  		Chan      chan Value
   138  		Func      func() Value
   139  		Interface interface{ String() string }
   140  		Map       map[string]Value
   141  		Pointer   *Value
   142  		Slice     []Value
   143  		String    string
   144  		Struct    Value
   145  	})).Elem()
   146  
   147  	for i := 0; i < source.NumField(); i++ {
   148  		name := source.Type().Field(i).Name
   149  		value := source.Field(i)
   150  		zero := Zero(value.Type())
   151  		b.Run(name+"/Direct", func(b *testing.B) {
   152  			for i := 0; i < b.N; i++ {
   153  				value.SetZero()
   154  			}
   155  		})
   156  		b.Run(name+"/CachedZero", func(b *testing.B) {
   157  			for i := 0; i < b.N; i++ {
   158  				value.Set(zero)
   159  			}
   160  		})
   161  		b.Run(name+"/NewZero", func(b *testing.B) {
   162  			for i := 0; i < b.N; i++ {
   163  				value.Set(Zero(value.Type()))
   164  			}
   165  		})
   166  	}
   167  }
   168  
   169  func BenchmarkSelect(b *testing.B) {
   170  	channel := make(chan int)
   171  	close(channel)
   172  	var cases []SelectCase
   173  	for i := 0; i < 8; i++ {
   174  		cases = append(cases, SelectCase{
   175  			Dir:  SelectRecv,
   176  			Chan: ValueOf(channel),
   177  		})
   178  	}
   179  	for _, numCases := range []int{1, 4, 8} {
   180  		b.Run(strconv.Itoa(numCases), func(b *testing.B) {
   181  			b.ReportAllocs()
   182  			for i := 0; i < b.N; i++ {
   183  				_, _, _ = Select(cases[:numCases])
   184  			}
   185  		})
   186  	}
   187  }
   188  
   189  func BenchmarkCall(b *testing.B) {
   190  	fv := ValueOf(func(a, b string) {})
   191  	b.ReportAllocs()
   192  	b.RunParallel(func(pb *testing.PB) {
   193  		args := []Value{ValueOf("a"), ValueOf("b")}
   194  		for pb.Next() {
   195  			fv.Call(args)
   196  		}
   197  	})
   198  }
   199  
   200  type myint int64
   201  
   202  func (i *myint) inc() {
   203  	*i = *i + 1
   204  }
   205  
   206  func BenchmarkCallMethod(b *testing.B) {
   207  	b.ReportAllocs()
   208  	z := new(myint)
   209  
   210  	v := ValueOf(z.inc)
   211  	for i := 0; i < b.N; i++ {
   212  		v.Call(nil)
   213  	}
   214  }
   215  
   216  func BenchmarkCallArgCopy(b *testing.B) {
   217  	byteArray := func(n int) Value {
   218  		return Zero(ArrayOf(n, TypeOf(byte(0))))
   219  	}
   220  	sizes := [...]struct {
   221  		fv  Value
   222  		arg Value
   223  	}{
   224  		{ValueOf(func(a [128]byte) {}), byteArray(128)},
   225  		{ValueOf(func(a [256]byte) {}), byteArray(256)},
   226  		{ValueOf(func(a [1024]byte) {}), byteArray(1024)},
   227  		{ValueOf(func(a [4096]byte) {}), byteArray(4096)},
   228  		{ValueOf(func(a [65536]byte) {}), byteArray(65536)},
   229  	}
   230  	for _, size := range sizes {
   231  		bench := func(b *testing.B) {
   232  			args := []Value{size.arg}
   233  			b.SetBytes(int64(size.arg.Len()))
   234  			b.ResetTimer()
   235  			b.RunParallel(func(pb *testing.PB) {
   236  				for pb.Next() {
   237  					size.fv.Call(args)
   238  				}
   239  			})
   240  		}
   241  		name := fmt.Sprintf("size=%v", size.arg.Len())
   242  		b.Run(name, bench)
   243  	}
   244  }
   245  
   246  func BenchmarkPtrTo(b *testing.B) {
   247  	// Construct a type with a zero ptrToThis.
   248  	type T struct{ int }
   249  	t := SliceOf(TypeOf(T{}))
   250  	ptrToThis := ValueOf(t).Elem().FieldByName("ptrToThis")
   251  	if !ptrToThis.IsValid() {
   252  		b.Fatalf("%v has no ptrToThis field; was it removed from rtype?", t)
   253  	}
   254  	if ptrToThis.Int() != 0 {
   255  		b.Fatalf("%v.ptrToThis unexpectedly nonzero", t)
   256  	}
   257  	b.ResetTimer()
   258  
   259  	// Now benchmark calling PointerTo on it: we'll have to hit the ptrMap cache on
   260  	// every call.
   261  	b.RunParallel(func(pb *testing.PB) {
   262  		for pb.Next() {
   263  			PointerTo(t)
   264  		}
   265  	})
   266  }
   267  
   268  type B1 struct {
   269  	X int
   270  	Y int
   271  	Z int
   272  }
   273  
   274  func BenchmarkFieldByName1(b *testing.B) {
   275  	t := TypeOf(B1{})
   276  	b.RunParallel(func(pb *testing.PB) {
   277  		for pb.Next() {
   278  			t.FieldByName("Z")
   279  		}
   280  	})
   281  }
   282  
   283  func BenchmarkFieldByName2(b *testing.B) {
   284  	t := TypeOf(S3{})
   285  	b.RunParallel(func(pb *testing.PB) {
   286  		for pb.Next() {
   287  			t.FieldByName("B")
   288  		}
   289  	})
   290  }
   291  
   292  func BenchmarkFieldByName3(b *testing.B) {
   293  	t := TypeOf(R0{})
   294  	b.RunParallel(func(pb *testing.PB) {
   295  		for pb.Next() {
   296  			t.FieldByName("X")
   297  		}
   298  	})
   299  }
   300  
   301  type S struct {
   302  	i1 int64
   303  	i2 int64
   304  }
   305  
   306  func BenchmarkInterfaceBig(b *testing.B) {
   307  	v := ValueOf(S{})
   308  	b.RunParallel(func(pb *testing.PB) {
   309  		for pb.Next() {
   310  			v.Interface()
   311  		}
   312  	})
   313  	b.StopTimer()
   314  }
   315  
   316  func BenchmarkInterfaceSmall(b *testing.B) {
   317  	v := ValueOf(int64(0))
   318  	b.RunParallel(func(pb *testing.PB) {
   319  		for pb.Next() {
   320  			v.Interface()
   321  		}
   322  	})
   323  }
   324  
   325  func BenchmarkNew(b *testing.B) {
   326  	v := TypeOf(XM{})
   327  	b.RunParallel(func(pb *testing.PB) {
   328  		for pb.Next() {
   329  			New(v)
   330  		}
   331  	})
   332  }
   333  
   334  func BenchmarkMap(b *testing.B) {
   335  	type V *int
   336  	type S string
   337  	value := ValueOf((V)(nil))
   338  	stringKeys := []string{}
   339  	mapOfStrings := map[string]V{}
   340  	uint64Keys := []uint64{}
   341  	mapOfUint64s := map[uint64]V{}
   342  	userStringKeys := []S{}
   343  	mapOfUserStrings := map[S]V{}
   344  	for i := 0; i < 100; i++ {
   345  		stringKey := fmt.Sprintf("key%d", i)
   346  		stringKeys = append(stringKeys, stringKey)
   347  		mapOfStrings[stringKey] = nil
   348  
   349  		uint64Key := uint64(i)
   350  		uint64Keys = append(uint64Keys, uint64Key)
   351  		mapOfUint64s[uint64Key] = nil
   352  
   353  		userStringKey := S(fmt.Sprintf("key%d", i))
   354  		userStringKeys = append(userStringKeys, userStringKey)
   355  		mapOfUserStrings[userStringKey] = nil
   356  	}
   357  
   358  	tests := []struct {
   359  		label          string
   360  		m, keys, value Value
   361  	}{
   362  		{"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value},
   363  		{"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value},
   364  		{"UserStringKeys", ValueOf(mapOfUserStrings), ValueOf(userStringKeys), value},
   365  	}
   366  
   367  	for _, tt := range tests {
   368  		b.Run(tt.label, func(b *testing.B) {
   369  			b.Run("MapIndex", func(b *testing.B) {
   370  				b.ReportAllocs()
   371  				for i := 0; i < b.N; i++ {
   372  					for j := tt.keys.Len() - 1; j >= 0; j-- {
   373  						tt.m.MapIndex(tt.keys.Index(j))
   374  					}
   375  				}
   376  			})
   377  			b.Run("SetMapIndex", func(b *testing.B) {
   378  				b.ReportAllocs()
   379  				for i := 0; i < b.N; i++ {
   380  					for j := tt.keys.Len() - 1; j >= 0; j-- {
   381  						tt.m.SetMapIndex(tt.keys.Index(j), tt.value)
   382  					}
   383  				}
   384  			})
   385  		})
   386  	}
   387  }
   388  
   389  func BenchmarkMapIterNext(b *testing.B) {
   390  	m := ValueOf(map[string]int{"a": 0, "b": 1, "c": 2, "d": 3})
   391  	it := m.MapRange()
   392  	for i := 0; i < b.N; i++ {
   393  		for it.Next() {
   394  		}
   395  		it.Reset(m)
   396  	}
   397  }