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 i := 0; i < source.NumField(); i++ {
150 name := source.Type().Field(i).Name
151 value := source.Field(i)
152 b.Run(name, func(b *testing.B) {
153 for i := 0; i < b.N; i++ {
154 sink = value.IsZero()
155 }
156 })
157 }
158 }
159
160 func BenchmarkSetZero(b *testing.B) {
161 source := ValueOf(new(struct {
162 Bool bool
163 Int int64
164 Uint uint64
165 Float float64
166 Complex complex128
167 Array [4]Value
168 Chan chan Value
169 Func func() Value
170 Interface interface{ String() string }
171 Map map[string]Value
172 Pointer *Value
173 Slice []Value
174 String string
175 Struct Value
176 })).Elem()
177
178 for i := 0; i < source.NumField(); i++ {
179 name := source.Type().Field(i).Name
180 value := source.Field(i)
181 zero := Zero(value.Type())
182 b.Run(name+"/Direct", func(b *testing.B) {
183 for i := 0; i < b.N; i++ {
184 value.SetZero()
185 }
186 })
187 b.Run(name+"/CachedZero", func(b *testing.B) {
188 for i := 0; i < b.N; i++ {
189 value.Set(zero)
190 }
191 })
192 b.Run(name+"/NewZero", func(b *testing.B) {
193 for i := 0; i < b.N; i++ {
194 value.Set(Zero(value.Type()))
195 }
196 })
197 }
198 }
199
200
201
202
203 func BenchmarkZero(b *testing.B) {
204 type bm struct {
205 name string
206 zero Value
207 nonZero Value
208 size int
209 }
210 type Small struct {
211 A int64
212 B, C bool
213 }
214 type Big struct {
215 A int64
216 B, C bool
217 D [1008]byte
218 }
219 entry := func(name string, zero any, nonZero any) bm {
220 return bm{name, ValueOf(zero), ValueOf(nonZero).Elem(), int(TypeOf(zero).Size())}
221 }
222 nonZeroTime := func() *time.Time { t := time.Now(); return &t }
223
224 bms := []bm{
225 entry("ByteArray", [16]byte{}, &[16]byte{1}),
226 entry("ByteArray", [64]byte{}, &[64]byte{1}),
227 entry("ByteArray", [1024]byte{}, &[1024]byte{1}),
228 entry("BigStruct", Big{}, &Big{A: 1}),
229 entry("SmallStruct", Small{}, &Small{A: 1}),
230 entry("SmallStructArray", [4]Small{}, &[4]Small{0: {A: 1}}),
231 entry("SmallStructArray", [64]Small{}, &[64]Small{0: {A: 1}}),
232 entry("Time", time.Time{}, nonZeroTime()),
233 }
234
235 for _, bm := range bms {
236 b.Run(fmt.Sprintf("IsZero/%s/size=%d", bm.name, bm.size), func(b *testing.B) {
237 for i := 0; i < b.N; i++ {
238 bm.zero.IsZero()
239 }
240 })
241 }
242 for _, bm := range bms {
243 b.Run(fmt.Sprintf("SetZero/%s/size=%d", bm.name, bm.size), func(b *testing.B) {
244 for i := 0; i < b.N; i++ {
245 bm.nonZero.Set(bm.zero)
246 }
247 })
248 }
249 }
250
251 func BenchmarkSelect(b *testing.B) {
252 channel := make(chan int)
253 close(channel)
254 var cases []SelectCase
255 for i := 0; i < 8; i++ {
256 cases = append(cases, SelectCase{
257 Dir: SelectRecv,
258 Chan: ValueOf(channel),
259 })
260 }
261 for _, numCases := range []int{1, 4, 8} {
262 b.Run(strconv.Itoa(numCases), func(b *testing.B) {
263 b.ReportAllocs()
264 for i := 0; i < b.N; i++ {
265 _, _, _ = Select(cases[:numCases])
266 }
267 })
268 }
269 }
270
271 func BenchmarkCall(b *testing.B) {
272 fv := ValueOf(func(a, b string) {})
273 b.ReportAllocs()
274 b.RunParallel(func(pb *testing.PB) {
275 args := []Value{ValueOf("a"), ValueOf("b")}
276 for pb.Next() {
277 fv.Call(args)
278 }
279 })
280 }
281
282 type myint int64
283
284 func (i *myint) inc() {
285 *i = *i + 1
286 }
287
288 func BenchmarkCallMethod(b *testing.B) {
289 b.ReportAllocs()
290 z := new(myint)
291
292 v := ValueOf(z.inc)
293 for i := 0; i < b.N; i++ {
294 v.Call(nil)
295 }
296 }
297
298 func BenchmarkCallArgCopy(b *testing.B) {
299 byteArray := func(n int) Value {
300 return Zero(ArrayOf(n, TypeOf(byte(0))))
301 }
302 sizes := [...]struct {
303 fv Value
304 arg Value
305 }{
306 {ValueOf(func(a [128]byte) {}), byteArray(128)},
307 {ValueOf(func(a [256]byte) {}), byteArray(256)},
308 {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
309 {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
310 {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
311 }
312 for _, size := range sizes {
313 bench := func(b *testing.B) {
314 args := []Value{size.arg}
315 b.SetBytes(int64(size.arg.Len()))
316 b.ResetTimer()
317 b.RunParallel(func(pb *testing.PB) {
318 for pb.Next() {
319 size.fv.Call(args)
320 }
321 })
322 }
323 name := fmt.Sprintf("size=%v", size.arg.Len())
324 b.Run(name, bench)
325 }
326 }
327
328 func BenchmarkPtrTo(b *testing.B) {
329
330 type T struct{ int }
331 t := SliceOf(TypeOf(T{}))
332 ptrToThis := ValueOf(t).Elem().FieldByName("PtrToThis")
333 if !ptrToThis.IsValid() {
334 b.Skipf("%v has no ptrToThis field; was it removed from rtype?", t)
335
336 }
337 if ptrToThis.Int() != 0 {
338 b.Fatalf("%v.ptrToThis unexpectedly nonzero", t)
339 }
340 b.ResetTimer()
341
342
343
344 b.RunParallel(func(pb *testing.PB) {
345 for pb.Next() {
346 PointerTo(t)
347 }
348 })
349 }
350
351 type B1 struct {
352 X int
353 Y int
354 Z int
355 }
356
357 func BenchmarkFieldByName1(b *testing.B) {
358 t := TypeOf(B1{})
359 b.RunParallel(func(pb *testing.PB) {
360 for pb.Next() {
361 t.FieldByName("Z")
362 }
363 })
364 }
365
366 func BenchmarkFieldByName2(b *testing.B) {
367 t := TypeOf(S3{})
368 b.RunParallel(func(pb *testing.PB) {
369 for pb.Next() {
370 t.FieldByName("B")
371 }
372 })
373 }
374
375 func BenchmarkFieldByName3(b *testing.B) {
376 t := TypeOf(R0{})
377 b.RunParallel(func(pb *testing.PB) {
378 for pb.Next() {
379 t.FieldByName("X")
380 }
381 })
382 }
383
384 type S struct {
385 i1 int64
386 i2 int64
387 }
388
389 func BenchmarkInterfaceBig(b *testing.B) {
390 v := ValueOf(S{})
391 b.RunParallel(func(pb *testing.PB) {
392 for pb.Next() {
393 v.Interface()
394 }
395 })
396 b.StopTimer()
397 }
398
399 func BenchmarkInterfaceSmall(b *testing.B) {
400 v := ValueOf(int64(0))
401 b.RunParallel(func(pb *testing.PB) {
402 for pb.Next() {
403 v.Interface()
404 }
405 })
406 }
407
408 func BenchmarkNew(b *testing.B) {
409 v := TypeOf(XM{})
410 b.RunParallel(func(pb *testing.PB) {
411 for pb.Next() {
412 New(v)
413 }
414 })
415 }
416
417 func BenchmarkMap(b *testing.B) {
418 type V *int
419 type S string
420 value := ValueOf((V)(nil))
421 stringKeys := []string{}
422 mapOfStrings := map[string]V{}
423 uint64Keys := []uint64{}
424 mapOfUint64s := map[uint64]V{}
425 userStringKeys := []S{}
426 mapOfUserStrings := map[S]V{}
427 for i := 0; i < 100; i++ {
428 stringKey := fmt.Sprintf("key%d", i)
429 stringKeys = append(stringKeys, stringKey)
430 mapOfStrings[stringKey] = nil
431
432 uint64Key := uint64(i)
433 uint64Keys = append(uint64Keys, uint64Key)
434 mapOfUint64s[uint64Key] = nil
435
436 userStringKey := S(fmt.Sprintf("key%d", i))
437 userStringKeys = append(userStringKeys, userStringKey)
438 mapOfUserStrings[userStringKey] = nil
439 }
440
441 tests := []struct {
442 label string
443 m, keys, value Value
444 }{
445 {"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value},
446 {"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value},
447 {"UserStringKeys", ValueOf(mapOfUserStrings), ValueOf(userStringKeys), value},
448 }
449
450 for _, tt := range tests {
451 b.Run(tt.label, func(b *testing.B) {
452 b.Run("MapIndex", func(b *testing.B) {
453 b.ReportAllocs()
454 for i := 0; i < b.N; i++ {
455 for j := tt.keys.Len() - 1; j >= 0; j-- {
456 tt.m.MapIndex(tt.keys.Index(j))
457 }
458 }
459 })
460 b.Run("SetMapIndex", func(b *testing.B) {
461 b.ReportAllocs()
462 for i := 0; i < b.N; i++ {
463 for j := tt.keys.Len() - 1; j >= 0; j-- {
464 tt.m.SetMapIndex(tt.keys.Index(j), tt.value)
465 }
466 }
467 })
468 })
469 }
470 }
471
472 func BenchmarkMapIterNext(b *testing.B) {
473 m := ValueOf(map[string]int{"a": 0, "b": 1, "c": 2, "d": 3})
474 it := m.MapRange()
475 for i := 0; i < b.N; i++ {
476 for it.Next() {
477 }
478 it.Reset(m)
479 }
480 }
481
View as plain text