]> Cypherpunks.ru repositories - gostls13.git/blob - src/reflect/benchmark_test.go
reflect: optimize Value.IsZero for array types
[gostls13.git] / src / reflect / benchmark_test.go
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 BenchmarkMapsDeepEqual(b *testing.B) {
111         m1 := map[int]int{
112                 1: 1, 2: 2,
113         }
114         m2 := map[int]int{
115                 1: 1, 2: 2,
116         }
117         for i := 0; i < b.N; i++ {
118                 DeepEqual(m1, m2)
119         }
120 }
121
122 func BenchmarkIsZero(b *testing.B) {
123         type Int4 struct {
124                 a, b, c, d int
125         }
126         type Int1024 struct {
127                 a [1024]int
128         }
129         s := struct {
130                 ArrayComparable      [4]T
131                 ArrayIncomparable    [4]_Complex
132                 StructComparable     T
133                 StructIncomparable   _Complex
134                 ArrayInt_4           [4]int
135                 ArrayInt_1024        [1024]int
136                 ArrayInt_1024_NoZero [1024]int
137                 Struct4Int           Int4
138                 ArrayStruct4Int_1024 [256]Int4
139                 ArrayChanInt_1024    [1024]chan int
140         }{}
141         s.ArrayInt_1024_NoZero[512] = 1
142         source := ValueOf(s)
143
144         for i := 0; i < source.NumField(); i++ {
145                 name := source.Type().Field(i).Name
146                 value := source.Field(i)
147                 b.Run(name, func(b *testing.B) {
148                         for i := 0; i < b.N; i++ {
149                                 sink = value.IsZero()
150                         }
151                 })
152         }
153 }
154
155 func BenchmarkSetZero(b *testing.B) {
156         source := ValueOf(new(struct {
157                 Bool      bool
158                 Int       int64
159                 Uint      uint64
160                 Float     float64
161                 Complex   complex128
162                 Array     [4]Value
163                 Chan      chan Value
164                 Func      func() Value
165                 Interface interface{ String() string }
166                 Map       map[string]Value
167                 Pointer   *Value
168                 Slice     []Value
169                 String    string
170                 Struct    Value
171         })).Elem()
172
173         for i := 0; i < source.NumField(); i++ {
174                 name := source.Type().Field(i).Name
175                 value := source.Field(i)
176                 zero := Zero(value.Type())
177                 b.Run(name+"/Direct", func(b *testing.B) {
178                         for i := 0; i < b.N; i++ {
179                                 value.SetZero()
180                         }
181                 })
182                 b.Run(name+"/CachedZero", func(b *testing.B) {
183                         for i := 0; i < b.N; i++ {
184                                 value.Set(zero)
185                         }
186                 })
187                 b.Run(name+"/NewZero", func(b *testing.B) {
188                         for i := 0; i < b.N; i++ {
189                                 value.Set(Zero(value.Type()))
190                         }
191                 })
192         }
193 }
194
195 func BenchmarkSelect(b *testing.B) {
196         channel := make(chan int)
197         close(channel)
198         var cases []SelectCase
199         for i := 0; i < 8; i++ {
200                 cases = append(cases, SelectCase{
201                         Dir:  SelectRecv,
202                         Chan: ValueOf(channel),
203                 })
204         }
205         for _, numCases := range []int{1, 4, 8} {
206                 b.Run(strconv.Itoa(numCases), func(b *testing.B) {
207                         b.ReportAllocs()
208                         for i := 0; i < b.N; i++ {
209                                 _, _, _ = Select(cases[:numCases])
210                         }
211                 })
212         }
213 }
214
215 func BenchmarkCall(b *testing.B) {
216         fv := ValueOf(func(a, b string) {})
217         b.ReportAllocs()
218         b.RunParallel(func(pb *testing.PB) {
219                 args := []Value{ValueOf("a"), ValueOf("b")}
220                 for pb.Next() {
221                         fv.Call(args)
222                 }
223         })
224 }
225
226 type myint int64
227
228 func (i *myint) inc() {
229         *i = *i + 1
230 }
231
232 func BenchmarkCallMethod(b *testing.B) {
233         b.ReportAllocs()
234         z := new(myint)
235
236         v := ValueOf(z.inc)
237         for i := 0; i < b.N; i++ {
238                 v.Call(nil)
239         }
240 }
241
242 func BenchmarkCallArgCopy(b *testing.B) {
243         byteArray := func(n int) Value {
244                 return Zero(ArrayOf(n, TypeOf(byte(0))))
245         }
246         sizes := [...]struct {
247                 fv  Value
248                 arg Value
249         }{
250                 {ValueOf(func(a [128]byte) {}), byteArray(128)},
251                 {ValueOf(func(a [256]byte) {}), byteArray(256)},
252                 {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
253                 {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
254                 {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
255         }
256         for _, size := range sizes {
257                 bench := func(b *testing.B) {
258                         args := []Value{size.arg}
259                         b.SetBytes(int64(size.arg.Len()))
260                         b.ResetTimer()
261                         b.RunParallel(func(pb *testing.PB) {
262                                 for pb.Next() {
263                                         size.fv.Call(args)
264                                 }
265                         })
266                 }
267                 name := fmt.Sprintf("size=%v", size.arg.Len())
268                 b.Run(name, bench)
269         }
270 }
271
272 func BenchmarkPtrTo(b *testing.B) {
273         // Construct a type with a zero ptrToThis.
274         type T struct{ int }
275         t := SliceOf(TypeOf(T{}))
276         ptrToThis := ValueOf(t).Elem().FieldByName("PtrToThis")
277         if !ptrToThis.IsValid() {
278                 b.Skipf("%v has no ptrToThis field; was it removed from rtype?", t) // TODO fix this at top of refactoring
279                 // b.Fatalf("%v has no ptrToThis field; was it removed from rtype?", t)
280         }
281         if ptrToThis.Int() != 0 {
282                 b.Fatalf("%v.ptrToThis unexpectedly nonzero", t)
283         }
284         b.ResetTimer()
285
286         // Now benchmark calling PointerTo on it: we'll have to hit the ptrMap cache on
287         // every call.
288         b.RunParallel(func(pb *testing.PB) {
289                 for pb.Next() {
290                         PointerTo(t)
291                 }
292         })
293 }
294
295 type B1 struct {
296         X int
297         Y int
298         Z int
299 }
300
301 func BenchmarkFieldByName1(b *testing.B) {
302         t := TypeOf(B1{})
303         b.RunParallel(func(pb *testing.PB) {
304                 for pb.Next() {
305                         t.FieldByName("Z")
306                 }
307         })
308 }
309
310 func BenchmarkFieldByName2(b *testing.B) {
311         t := TypeOf(S3{})
312         b.RunParallel(func(pb *testing.PB) {
313                 for pb.Next() {
314                         t.FieldByName("B")
315                 }
316         })
317 }
318
319 func BenchmarkFieldByName3(b *testing.B) {
320         t := TypeOf(R0{})
321         b.RunParallel(func(pb *testing.PB) {
322                 for pb.Next() {
323                         t.FieldByName("X")
324                 }
325         })
326 }
327
328 type S struct {
329         i1 int64
330         i2 int64
331 }
332
333 func BenchmarkInterfaceBig(b *testing.B) {
334         v := ValueOf(S{})
335         b.RunParallel(func(pb *testing.PB) {
336                 for pb.Next() {
337                         v.Interface()
338                 }
339         })
340         b.StopTimer()
341 }
342
343 func BenchmarkInterfaceSmall(b *testing.B) {
344         v := ValueOf(int64(0))
345         b.RunParallel(func(pb *testing.PB) {
346                 for pb.Next() {
347                         v.Interface()
348                 }
349         })
350 }
351
352 func BenchmarkNew(b *testing.B) {
353         v := TypeOf(XM{})
354         b.RunParallel(func(pb *testing.PB) {
355                 for pb.Next() {
356                         New(v)
357                 }
358         })
359 }
360
361 func BenchmarkMap(b *testing.B) {
362         type V *int
363         type S string
364         value := ValueOf((V)(nil))
365         stringKeys := []string{}
366         mapOfStrings := map[string]V{}
367         uint64Keys := []uint64{}
368         mapOfUint64s := map[uint64]V{}
369         userStringKeys := []S{}
370         mapOfUserStrings := map[S]V{}
371         for i := 0; i < 100; i++ {
372                 stringKey := fmt.Sprintf("key%d", i)
373                 stringKeys = append(stringKeys, stringKey)
374                 mapOfStrings[stringKey] = nil
375
376                 uint64Key := uint64(i)
377                 uint64Keys = append(uint64Keys, uint64Key)
378                 mapOfUint64s[uint64Key] = nil
379
380                 userStringKey := S(fmt.Sprintf("key%d", i))
381                 userStringKeys = append(userStringKeys, userStringKey)
382                 mapOfUserStrings[userStringKey] = nil
383         }
384
385         tests := []struct {
386                 label          string
387                 m, keys, value Value
388         }{
389                 {"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value},
390                 {"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value},
391                 {"UserStringKeys", ValueOf(mapOfUserStrings), ValueOf(userStringKeys), value},
392         }
393
394         for _, tt := range tests {
395                 b.Run(tt.label, func(b *testing.B) {
396                         b.Run("MapIndex", func(b *testing.B) {
397                                 b.ReportAllocs()
398                                 for i := 0; i < b.N; i++ {
399                                         for j := tt.keys.Len() - 1; j >= 0; j-- {
400                                                 tt.m.MapIndex(tt.keys.Index(j))
401                                         }
402                                 }
403                         })
404                         b.Run("SetMapIndex", func(b *testing.B) {
405                                 b.ReportAllocs()
406                                 for i := 0; i < b.N; i++ {
407                                         for j := tt.keys.Len() - 1; j >= 0; j-- {
408                                                 tt.m.SetMapIndex(tt.keys.Index(j), tt.value)
409                                         }
410                                 }
411                         })
412                 })
413         }
414 }
415
416 func BenchmarkMapIterNext(b *testing.B) {
417         m := ValueOf(map[string]int{"a": 0, "b": 1, "c": 2, "d": 3})
418         it := m.MapRange()
419         for i := 0; i < b.N; i++ {
420                 for it.Next() {
421                 }
422                 it.Reset(m)
423         }
424 }