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 }