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