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 BenchmarkCall(b *testing.B) {
269 fv := ValueOf(func(a, b string) {})
270 b.ReportAllocs()
271 b.RunParallel(func(pb *testing.PB) {
272 args := []Value{ValueOf("a"), ValueOf("b")}
273 for pb.Next() {
274 fv.Call(args)
275 }
276 })
277 }
278
279 type myint int64
280
281 func (i *myint) inc() {
282 *i = *i + 1
283 }
284
285 func BenchmarkCallMethod(b *testing.B) {
286 b.ReportAllocs()
287 z := new(myint)
288
289 v := ValueOf(z.inc)
290 for i := 0; i < b.N; i++ {
291 v.Call(nil)
292 }
293 }
294
295 func BenchmarkCallArgCopy(b *testing.B) {
296 byteArray := func(n int) Value {
297 return Zero(ArrayOf(n, TypeOf(byte(0))))
298 }
299 sizes := [...]struct {
300 fv Value
301 arg Value
302 }{
303 {ValueOf(func(a [128]byte) {}), byteArray(128)},
304 {ValueOf(func(a [256]byte) {}), byteArray(256)},
305 {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
306 {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
307 {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
308 }
309 for _, size := range sizes {
310 bench := func(b *testing.B) {
311 args := []Value{size.arg}
312 b.SetBytes(int64(size.arg.Len()))
313 b.ResetTimer()
314 b.RunParallel(func(pb *testing.PB) {
315 for pb.Next() {
316 size.fv.Call(args)
317 }
318 })
319 }
320 name := fmt.Sprintf("size=%v", size.arg.Len())
321 b.Run(name, bench)
322 }
323 }
324
325 func BenchmarkPtrTo(b *testing.B) {
326
327 type T struct{ int }
328 t := SliceOf(TypeOf(T{}))
329 ptrToThis := ValueOf(t).Elem().FieldByName("PtrToThis")
330 if !ptrToThis.IsValid() {
331 b.Skipf("%v has no ptrToThis field; was it removed from rtype?", t)
332
333 }
334 if ptrToThis.Int() != 0 {
335 b.Fatalf("%v.ptrToThis unexpectedly nonzero", t)
336 }
337 b.ResetTimer()
338
339
340
341 b.RunParallel(func(pb *testing.PB) {
342 for pb.Next() {
343 PointerTo(t)
344 }
345 })
346 }
347
348 type B1 struct {
349 X int
350 Y int
351 Z int
352 }
353
354 func BenchmarkFieldByName1(b *testing.B) {
355 t := TypeOf(B1{})
356 b.RunParallel(func(pb *testing.PB) {
357 for pb.Next() {
358 t.FieldByName("Z")
359 }
360 })
361 }
362
363 func BenchmarkFieldByName2(b *testing.B) {
364 t := TypeOf(S3{})
365 b.RunParallel(func(pb *testing.PB) {
366 for pb.Next() {
367 t.FieldByName("B")
368 }
369 })
370 }
371
372 func BenchmarkFieldByName3(b *testing.B) {
373 t := TypeOf(R0{})
374 b.RunParallel(func(pb *testing.PB) {
375 for pb.Next() {
376 t.FieldByName("X")
377 }
378 })
379 }
380
381 type S struct {
382 i1 int64
383 i2 int64
384 }
385
386 func BenchmarkInterfaceBig(b *testing.B) {
387 v := ValueOf(S{})
388 b.RunParallel(func(pb *testing.PB) {
389 for pb.Next() {
390 v.Interface()
391 }
392 })
393 b.StopTimer()
394 }
395
396 func BenchmarkInterfaceSmall(b *testing.B) {
397 v := ValueOf(int64(0))
398 b.RunParallel(func(pb *testing.PB) {
399 for pb.Next() {
400 v.Interface()
401 }
402 })
403 }
404
405 func BenchmarkNew(b *testing.B) {
406 v := TypeOf(XM{})
407 b.RunParallel(func(pb *testing.PB) {
408 for pb.Next() {
409 New(v)
410 }
411 })
412 }
413
414 func BenchmarkMap(b *testing.B) {
415 type V *int
416 type S string
417 value := ValueOf((V)(nil))
418 stringKeys := []string{}
419 mapOfStrings := map[string]V{}
420 uint64Keys := []uint64{}
421 mapOfUint64s := map[uint64]V{}
422 userStringKeys := []S{}
423 mapOfUserStrings := map[S]V{}
424 for i := 0; i < 100; i++ {
425 stringKey := fmt.Sprintf("key%d", i)
426 stringKeys = append(stringKeys, stringKey)
427 mapOfStrings[stringKey] = nil
428
429 uint64Key := uint64(i)
430 uint64Keys = append(uint64Keys, uint64Key)
431 mapOfUint64s[uint64Key] = nil
432
433 userStringKey := S(fmt.Sprintf("key%d", i))
434 userStringKeys = append(userStringKeys, userStringKey)
435 mapOfUserStrings[userStringKey] = nil
436 }
437
438 tests := []struct {
439 label string
440 m, keys, value Value
441 }{
442 {"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value},
443 {"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value},
444 {"UserStringKeys", ValueOf(mapOfUserStrings), ValueOf(userStringKeys), value},
445 }
446
447 for _, tt := range tests {
448 b.Run(tt.label, func(b *testing.B) {
449 b.Run("MapIndex", func(b *testing.B) {
450 b.ReportAllocs()
451 for i := 0; i < b.N; i++ {
452 for j := tt.keys.Len() - 1; j >= 0; j-- {
453 tt.m.MapIndex(tt.keys.Index(j))
454 }
455 }
456 })
457 b.Run("SetMapIndex", func(b *testing.B) {
458 b.ReportAllocs()
459 for i := 0; i < b.N; i++ {
460 for j := tt.keys.Len() - 1; j >= 0; j-- {
461 tt.m.SetMapIndex(tt.keys.Index(j), tt.value)
462 }
463 }
464 })
465 })
466 }
467 }
468
469 func BenchmarkMapIterNext(b *testing.B) {
470 m := ValueOf(map[string]int{"a": 0, "b": 1, "c": 2, "d": 3})
471 it := m.MapRange()
472 for i := 0; i < b.N; i++ {
473 for it.Next() {
474 }
475 it.Reset(m)
476 }
477 }
478
View as plain text