Source file
src/reflect/benchmark_test.go
1
2
3
4
5 package reflect_test
6
7 import (
8 "fmt"
9 . "reflect"
10 "strconv"
11 "testing"
12 "time"
13 )
14
15 var sourceAll = struct {
16 Bool Value
17 String Value
18 Bytes Value
19 NamedBytes Value
20 BytesArray Value
21 SliceAny Value
22 MapStringAny Value
23 }{
24 Bool: ValueOf(new(bool)).Elem(),
25 String: ValueOf(new(string)).Elem(),
26 Bytes: ValueOf(new([]byte)).Elem(),
27 NamedBytes: ValueOf(new(namedBytes)).Elem(),
28 BytesArray: ValueOf(new([32]byte)).Elem(),
29 SliceAny: ValueOf(new([]any)).Elem(),
30 MapStringAny: ValueOf(new(map[string]any)).Elem(),
31 }
32
33 var sinkAll struct {
34 RawBool bool
35 RawString string
36 RawBytes []byte
37 RawInt int
38 }
39
40 func BenchmarkBool(b *testing.B) {
41 for i := 0; i < b.N; i++ {
42 sinkAll.RawBool = sourceAll.Bool.Bool()
43 }
44 }
45
46 func BenchmarkString(b *testing.B) {
47 for i := 0; i < b.N; i++ {
48 sinkAll.RawString = sourceAll.String.String()
49 }
50 }
51
52 func BenchmarkBytes(b *testing.B) {
53 for i := 0; i < b.N; i++ {
54 sinkAll.RawBytes = sourceAll.Bytes.Bytes()
55 }
56 }
57
58 func BenchmarkNamedBytes(b *testing.B) {
59 for i := 0; i < b.N; i++ {
60 sinkAll.RawBytes = sourceAll.NamedBytes.Bytes()
61 }
62 }
63
64 func BenchmarkBytesArray(b *testing.B) {
65 for i := 0; i < b.N; i++ {
66 sinkAll.RawBytes = sourceAll.BytesArray.Bytes()
67 }
68 }
69
70 func BenchmarkSliceLen(b *testing.B) {
71 for i := 0; i < b.N; i++ {
72 sinkAll.RawInt = sourceAll.SliceAny.Len()
73 }
74 }
75
76 func BenchmarkMapLen(b *testing.B) {
77 for i := 0; i < b.N; i++ {
78 sinkAll.RawInt = sourceAll.MapStringAny.Len()
79 }
80 }
81
82 func BenchmarkStringLen(b *testing.B) {
83 for i := 0; i < b.N; i++ {
84 sinkAll.RawInt = sourceAll.String.Len()
85 }
86 }
87
88 func BenchmarkArrayLen(b *testing.B) {
89 for i := 0; i < b.N; i++ {
90 sinkAll.RawInt = sourceAll.BytesArray.Len()
91 }
92 }
93
94 func BenchmarkSliceCap(b *testing.B) {
95 for i := 0; i < b.N; i++ {
96 sinkAll.RawInt = sourceAll.SliceAny.Cap()
97 }
98 }
99
100 func BenchmarkDeepEqual(b *testing.B) {
101 for _, bb := range deepEqualPerfTests {
102 b.Run(ValueOf(bb.x).Type().String(), func(b *testing.B) {
103 b.ReportAllocs()
104 for i := 0; i < b.N; i++ {
105 sink = DeepEqual(bb.x, bb.y)
106 }
107 })
108 }
109 }
110
111 func BenchmarkMapsDeepEqual(b *testing.B) {
112 m1 := map[int]int{
113 1: 1, 2: 2,
114 }
115 m2 := map[int]int{
116 1: 1, 2: 2,
117 }
118 for i := 0; i < b.N; i++ {
119 DeepEqual(m1, m2)
120 }
121 }
122
123 func BenchmarkIsZero(b *testing.B) {
124 type Int4 struct {
125 a, b, c, d int
126 }
127 type Int1024 struct {
128 a [1024]int
129 }
130 type Int512 struct {
131 a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 [16]S
132 }
133 s := struct {
134 ArrayComparable [4]T
135 ArrayIncomparable [4]_Complex
136 StructComparable T
137 StructIncomparable _Complex
138 ArrayInt_4 [4]int
139 ArrayInt_1024 [1024]int
140 ArrayInt_1024_NoZero [1024]int
141 Struct4Int Int4
142 ArrayStruct4Int_1024 [256]Int4
143 ArrayChanInt_1024 [1024]chan int
144 StructInt_512 Int512
145 }{}
146 s.ArrayInt_1024_NoZero[512] = 1
147 source := ValueOf(s)
148
149 for field, value := range source.Fields() {
150 b.Run(field.Name, func(b *testing.B) {
151 for i := 0; i < b.N; i++ {
152 sink = value.IsZero()
153 }
154 })
155 }
156 }
157
158 func BenchmarkSetZero(b *testing.B) {
159 source := ValueOf(new(struct {
160 Bool bool
161 Int int64
162 Uint uint64
163 Float float64
164 Complex complex128
165 Array [4]Value
166 Chan chan Value
167 Func func() Value
168 Interface interface{ String() string }
169 Map map[string]Value
170 Pointer *Value
171 Slice []Value
172 String string
173 Struct Value
174 })).Elem()
175
176 for field, value := range source.Fields() {
177 name := field.Name
178 zero := Zero(value.Type())
179 b.Run(name+"/Direct", func(b *testing.B) {
180 for i := 0; i < b.N; i++ {
181 value.SetZero()
182 }
183 })
184 b.Run(name+"/CachedZero", func(b *testing.B) {
185 for i := 0; i < b.N; i++ {
186 value.Set(zero)
187 }
188 })
189 b.Run(name+"/NewZero", func(b *testing.B) {
190 for i := 0; i < b.N; i++ {
191 value.Set(Zero(value.Type()))
192 }
193 })
194 }
195 }
196
197
198
199
200 func BenchmarkZero(b *testing.B) {
201 type bm struct {
202 name string
203 zero Value
204 nonZero Value
205 size int
206 }
207 type Small struct {
208 A int64
209 B, C bool
210 }
211 type Big struct {
212 A int64
213 B, C bool
214 D [1008]byte
215 }
216 entry := func(name string, zero any, nonZero any) bm {
217 return bm{name, ValueOf(zero), ValueOf(nonZero).Elem(), int(TypeOf(zero).Size())}
218 }
219 nonZeroTime := func() *time.Time { t := time.Now(); return &t }
220
221 bms := []bm{
222 entry("ByteArray", [16]byte{}, &[16]byte{1}),
223 entry("ByteArray", [64]byte{}, &[64]byte{1}),
224 entry("ByteArray", [1024]byte{}, &[1024]byte{1}),
225 entry("BigStruct", Big{}, &Big{A: 1}),
226 entry("SmallStruct", Small{}, &Small{A: 1}),
227 entry("SmallStructArray", [4]Small{}, &[4]Small{0: {A: 1}}),
228 entry("SmallStructArray", [64]Small{}, &[64]Small{0: {A: 1}}),
229 entry("Time", time.Time{}, nonZeroTime()),
230 }
231
232 for _, bm := range bms {
233 b.Run(fmt.Sprintf("IsZero/%s/size=%d", bm.name, bm.size), func(b *testing.B) {
234 for i := 0; i < b.N; i++ {
235 bm.zero.IsZero()
236 }
237 })
238 }
239 for _, bm := range bms {
240 b.Run(fmt.Sprintf("SetZero/%s/size=%d", bm.name, bm.size), func(b *testing.B) {
241 for i := 0; i < b.N; i++ {
242 bm.nonZero.Set(bm.zero)
243 }
244 })
245 }
246 }
247
248 func BenchmarkSelect(b *testing.B) {
249 channel := make(chan int)
250 close(channel)
251 var cases []SelectCase
252 for i := 0; i < 8; i++ {
253 cases = append(cases, SelectCase{
254 Dir: SelectRecv,
255 Chan: ValueOf(channel),
256 })
257 }
258 for _, numCases := range []int{1, 4, 8} {
259 b.Run(strconv.Itoa(numCases), func(b *testing.B) {
260 b.ReportAllocs()
261 for i := 0; i < b.N; i++ {
262 _, _, _ = Select(cases[:numCases])
263 }
264 })
265 }
266 }
267
268 func BenchmarkSelectStaticLit(b *testing.B) {
269 channel := make(chan int)
270 close(channel)
271
272 sc := SelectCase{Dir: SelectRecv, Chan: ValueOf(channel)}
273 b.Run("[4]SelectCase", func(b *testing.B) {
274 for range b.N {
275 _, _, _ = Select([]SelectCase{sc, sc, sc, sc})
276 }
277 })
278
279 b.Run("[8]SelectCase", func(b *testing.B) {
280 for range b.N {
281 _, _, _ = Select([]SelectCase{sc, sc, sc, sc, sc, sc, sc, sc})
282 }
283 })
284 }
285
286 func BenchmarkCall(b *testing.B) {
287 fv := ValueOf(func(a, b string) {})
288 b.ReportAllocs()
289 b.RunParallel(func(pb *testing.PB) {
290 args := []Value{ValueOf("a"), ValueOf("b")}
291 for pb.Next() {
292 fv.Call(args)
293 }
294 })
295 }
296
297 type myint int64
298
299 func (i *myint) inc() {
300 *i = *i + 1
301 }
302
303 func BenchmarkCallMethod(b *testing.B) {
304 b.ReportAllocs()
305 z := new(myint)
306
307 v := ValueOf(z.inc)
308 for i := 0; i < b.N; i++ {
309 v.Call(nil)
310 }
311 }
312
313 func BenchmarkCallArgCopy(b *testing.B) {
314 byteArray := func(n int) Value {
315 return Zero(ArrayOf(n, TypeOf(byte(0))))
316 }
317 sizes := [...]struct {
318 fv Value
319 arg Value
320 }{
321 {ValueOf(func(a [128]byte) {}), byteArray(128)},
322 {ValueOf(func(a [256]byte) {}), byteArray(256)},
323 {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
324 {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
325 {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
326 }
327 for _, size := range sizes {
328 bench := func(b *testing.B) {
329 args := []Value{size.arg}
330 b.SetBytes(int64(size.arg.Len()))
331 b.ResetTimer()
332 b.RunParallel(func(pb *testing.PB) {
333 for pb.Next() {
334 size.fv.Call(args)
335 }
336 })
337 }
338 name := fmt.Sprintf("size=%v", size.arg.Len())
339 b.Run(name, bench)
340 }
341 }
342
343 func BenchmarkPtrTo(b *testing.B) {
344
345 type T struct{ int }
346 t := SliceOf(TypeOf(T{}))
347 ptrToThis := ValueOf(t).Elem().FieldByName("PtrToThis")
348 if !ptrToThis.IsValid() {
349 b.Skipf("%v has no ptrToThis field; was it removed from rtype?", t)
350
351 }
352 if ptrToThis.Int() != 0 {
353 b.Fatalf("%v.ptrToThis unexpectedly nonzero", t)
354 }
355 b.ResetTimer()
356
357
358
359 b.RunParallel(func(pb *testing.PB) {
360 for pb.Next() {
361 PointerTo(t)
362 }
363 })
364 }
365
366 type B1 struct {
367 X int
368 Y int
369 Z int
370 }
371
372 func BenchmarkFieldByName1(b *testing.B) {
373 t := TypeOf(B1{})
374 b.RunParallel(func(pb *testing.PB) {
375 for pb.Next() {
376 t.FieldByName("Z")
377 }
378 })
379 }
380
381 func BenchmarkFieldByName2(b *testing.B) {
382 t := TypeOf(S3{})
383 b.RunParallel(func(pb *testing.PB) {
384 for pb.Next() {
385 t.FieldByName("B")
386 }
387 })
388 }
389
390 func BenchmarkFieldByName3(b *testing.B) {
391 t := TypeOf(R0{})
392 b.RunParallel(func(pb *testing.PB) {
393 for pb.Next() {
394 t.FieldByName("X")
395 }
396 })
397 }
398
399 type S struct {
400 i1 int64
401 i2 int64
402 }
403
404 func BenchmarkInterfaceBig(b *testing.B) {
405 v := ValueOf(S{})
406 b.RunParallel(func(pb *testing.PB) {
407 for pb.Next() {
408 v.Interface()
409 }
410 })
411 b.StopTimer()
412 }
413
414 func BenchmarkInterfaceSmall(b *testing.B) {
415 v := ValueOf(int64(0))
416 b.RunParallel(func(pb *testing.PB) {
417 for pb.Next() {
418 v.Interface()
419 }
420 })
421 }
422
423 func BenchmarkNew(b *testing.B) {
424 v := TypeOf(XM{})
425 b.RunParallel(func(pb *testing.PB) {
426 for pb.Next() {
427 New(v)
428 }
429 })
430 }
431
432 func BenchmarkMap(b *testing.B) {
433 type V *int
434 type S string
435 value := ValueOf((V)(nil))
436 stringKeys := []string{}
437 mapOfStrings := map[string]V{}
438 uint64Keys := []uint64{}
439 mapOfUint64s := map[uint64]V{}
440 userStringKeys := []S{}
441 mapOfUserStrings := map[S]V{}
442 for i := 0; i < 100; i++ {
443 stringKey := fmt.Sprintf("key%d", i)
444 stringKeys = append(stringKeys, stringKey)
445 mapOfStrings[stringKey] = nil
446
447 uint64Key := uint64(i)
448 uint64Keys = append(uint64Keys, uint64Key)
449 mapOfUint64s[uint64Key] = nil
450
451 userStringKey := S(fmt.Sprintf("key%d", i))
452 userStringKeys = append(userStringKeys, userStringKey)
453 mapOfUserStrings[userStringKey] = nil
454 }
455
456 tests := []struct {
457 label string
458 m, keys, value Value
459 }{
460 {"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value},
461 {"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value},
462 {"UserStringKeys", ValueOf(mapOfUserStrings), ValueOf(userStringKeys), value},
463 }
464
465 for _, tt := range tests {
466 b.Run(tt.label, func(b *testing.B) {
467 b.Run("MapIndex", func(b *testing.B) {
468 b.ReportAllocs()
469 for i := 0; i < b.N; i++ {
470 for j := tt.keys.Len() - 1; j >= 0; j-- {
471 tt.m.MapIndex(tt.keys.Index(j))
472 }
473 }
474 })
475 b.Run("SetMapIndex", func(b *testing.B) {
476 b.ReportAllocs()
477 for i := 0; i < b.N; i++ {
478 for j := tt.keys.Len() - 1; j >= 0; j-- {
479 tt.m.SetMapIndex(tt.keys.Index(j), tt.value)
480 }
481 }
482 })
483 })
484 }
485 }
486
487 func BenchmarkMapIterNext(b *testing.B) {
488 m := ValueOf(map[string]int{"a": 0, "b": 1, "c": 2, "d": 3})
489 it := m.MapRange()
490 for i := 0; i < b.N; i++ {
491 for it.Next() {
492 }
493 it.Reset(m)
494 }
495 }
496
View as plain text