github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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.Skipf("%v has no ptrToThis field; was it removed from rtype?", t) // TODO fix this at top of refactoring 253 // b.Fatalf("%v has no ptrToThis field; was it removed from rtype?", t) 254 } 255 if ptrToThis.Int() != 0 { 256 b.Fatalf("%v.ptrToThis unexpectedly nonzero", t) 257 } 258 b.ResetTimer() 259 260 // Now benchmark calling PointerTo on it: we'll have to hit the ptrMap cache on 261 // every call. 262 b.RunParallel(func(pb *testing.PB) { 263 for pb.Next() { 264 PointerTo(t) 265 } 266 }) 267 } 268 269 type B1 struct { 270 X int 271 Y int 272 Z int 273 } 274 275 func BenchmarkFieldByName1(b *testing.B) { 276 t := TypeOf(B1{}) 277 b.RunParallel(func(pb *testing.PB) { 278 for pb.Next() { 279 t.FieldByName("Z") 280 } 281 }) 282 } 283 284 func BenchmarkFieldByName2(b *testing.B) { 285 t := TypeOf(S3{}) 286 b.RunParallel(func(pb *testing.PB) { 287 for pb.Next() { 288 t.FieldByName("B") 289 } 290 }) 291 } 292 293 func BenchmarkFieldByName3(b *testing.B) { 294 t := TypeOf(R0{}) 295 b.RunParallel(func(pb *testing.PB) { 296 for pb.Next() { 297 t.FieldByName("X") 298 } 299 }) 300 } 301 302 type S struct { 303 i1 int64 304 i2 int64 305 } 306 307 func BenchmarkInterfaceBig(b *testing.B) { 308 v := ValueOf(S{}) 309 b.RunParallel(func(pb *testing.PB) { 310 for pb.Next() { 311 v.Interface() 312 } 313 }) 314 b.StopTimer() 315 } 316 317 func BenchmarkInterfaceSmall(b *testing.B) { 318 v := ValueOf(int64(0)) 319 b.RunParallel(func(pb *testing.PB) { 320 for pb.Next() { 321 v.Interface() 322 } 323 }) 324 } 325 326 func BenchmarkNew(b *testing.B) { 327 v := TypeOf(XM{}) 328 b.RunParallel(func(pb *testing.PB) { 329 for pb.Next() { 330 New(v) 331 } 332 }) 333 } 334 335 func BenchmarkMap(b *testing.B) { 336 type V *int 337 type S string 338 value := ValueOf((V)(nil)) 339 stringKeys := []string{} 340 mapOfStrings := map[string]V{} 341 uint64Keys := []uint64{} 342 mapOfUint64s := map[uint64]V{} 343 userStringKeys := []S{} 344 mapOfUserStrings := map[S]V{} 345 for i := 0; i < 100; i++ { 346 stringKey := fmt.Sprintf("key%d", i) 347 stringKeys = append(stringKeys, stringKey) 348 mapOfStrings[stringKey] = nil 349 350 uint64Key := uint64(i) 351 uint64Keys = append(uint64Keys, uint64Key) 352 mapOfUint64s[uint64Key] = nil 353 354 userStringKey := S(fmt.Sprintf("key%d", i)) 355 userStringKeys = append(userStringKeys, userStringKey) 356 mapOfUserStrings[userStringKey] = nil 357 } 358 359 tests := []struct { 360 label string 361 m, keys, value Value 362 }{ 363 {"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value}, 364 {"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value}, 365 {"UserStringKeys", ValueOf(mapOfUserStrings), ValueOf(userStringKeys), value}, 366 } 367 368 for _, tt := range tests { 369 b.Run(tt.label, func(b *testing.B) { 370 b.Run("MapIndex", func(b *testing.B) { 371 b.ReportAllocs() 372 for i := 0; i < b.N; i++ { 373 for j := tt.keys.Len() - 1; j >= 0; j-- { 374 tt.m.MapIndex(tt.keys.Index(j)) 375 } 376 } 377 }) 378 b.Run("SetMapIndex", func(b *testing.B) { 379 b.ReportAllocs() 380 for i := 0; i < b.N; i++ { 381 for j := tt.keys.Len() - 1; j >= 0; j-- { 382 tt.m.SetMapIndex(tt.keys.Index(j), tt.value) 383 } 384 } 385 }) 386 }) 387 } 388 } 389 390 func BenchmarkMapIterNext(b *testing.B) { 391 m := ValueOf(map[string]int{"a": 0, "b": 1, "c": 2, "d": 3}) 392 it := m.MapRange() 393 for i := 0; i < b.N; i++ { 394 for it.Next() { 395 } 396 it.Reset(m) 397 } 398 }