]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: cache IsVariadic calls in Call
authorIgnacio Hagopian <jsign.uy@gmail.com>
Tue, 30 Mar 2021 17:18:06 +0000 (17:18 +0000)
committerDaniel Martí <mvdan@mvdan.cc>
Tue, 30 Mar 2021 17:41:58 +0000 (17:41 +0000)
These calls are cacheable, so do that to avoid doing extra work.

This opportunity was discovered while taking a look at a CPU profile
while investigating #7818.

I added a BenchmarkCallMethod, which is similar to BechmarkCall but
for a method receiver.

Benchmark results, including the new BenchmarkCallMethod:

name                       old time/op    new time/op    delta
Call-16                      22.0ns ±19%    20.2ns ±17%  -8.08%  (p=0.000 n=40+40)
CallMethod-16                 100ns ± 3%      91ns ± 2%  -9.13%  (p=0.000 n=40+39)
CallArgCopy/size=128-16      15.7ns ± 1%    14.3ns ± 4%  -8.98%  (p=0.000 n=38+37)
CallArgCopy/size=256-16      15.9ns ± 3%    15.0ns ± 5%  -6.12%  (p=0.000 n=39+39)
CallArgCopy/size=1024-16     18.8ns ± 6%    17.1ns ± 6%  -9.03%  (p=0.000 n=38+38)
CallArgCopy/size=4096-16     26.6ns ± 3%    25.2ns ± 4%  -5.19%  (p=0.000 n=39+40)
CallArgCopy/size=65536-16     379ns ± 3%     371ns ± 5%  -2.11%  (p=0.000 n=39+40)

name                       old alloc/op   new alloc/op   delta
Call-16                       0.00B          0.00B         ~     (all equal)
CallMethod-16                 0.00B          0.00B         ~     (all equal)

name                       old allocs/op  new allocs/op  delta
Call-16                        0.00           0.00         ~     (all equal)
CallMethod-16                  0.00           0.00         ~     (all equal)

name                       old speed      new speed      delta
CallArgCopy/size=128-16    8.13GB/s ± 1%  8.92GB/s ± 4%  +9.77%  (p=0.000 n=38+38)
CallArgCopy/size=256-16    16.1GB/s ± 3%  17.1GB/s ± 5%  +6.56%  (p=0.000 n=39+39)
CallArgCopy/size=1024-16   54.6GB/s ± 6%  60.1GB/s ± 5%  +9.93%  (p=0.000 n=38+38)
CallArgCopy/size=4096-16    154GB/s ± 5%   163GB/s ± 4%  +5.63%  (p=0.000 n=40+40)
CallArgCopy/size=65536-16   173GB/s ± 3%   177GB/s ± 5%  +2.18%  (p=0.000 n=39+40)

Updates #7818.

Change-Id: I94f88811ea9faf3dc2543984a13b360b5db66a4b
GitHub-Last-Rev: 9bbaa1854aa32cade905eddb05737e6224c372a1
GitHub-Pull-Request: golang/go#43475
Reviewed-on: https://go-review.googlesource.com/c/go/+/281252
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Daniel Martí <mvdan@mvdan.cc>
Trust: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Go Bot <gobot@golang.org>

src/reflect/all_test.go
src/reflect/value.go

index accda7fa74bef4041e7811d2b9e80c8ce3619847..e4b74f72d9c0aa6a4619dcd580eefc930dd59509 100644 (file)
@@ -1942,6 +1942,22 @@ func BenchmarkCall(b *testing.B) {
        })
 }
 
+type myint int64
+
+func (i *myint) inc() {
+       *i = *i + 1
+}
+
+func BenchmarkCallMethod(b *testing.B) {
+       b.ReportAllocs()
+       z := new(myint)
+
+       v := ValueOf(z.inc)
+       for i := 0; i < b.N; i++ {
+               v.Call(nil)
+       }
+}
+
 func BenchmarkCallArgCopy(b *testing.B) {
        byteArray := func(n int) Value {
                return Zero(ArrayOf(n, TypeOf(byte(0))))
index eae1b9bf294b70589c5c22bbd9ddc1671b455c91..52639d5aadc523d35f517ce44a798b5adbc66855 100644 (file)
@@ -378,8 +378,9 @@ func (v Value) call(op string, in []Value) []Value {
 
        isSlice := op == "CallSlice"
        n := t.NumIn()
+       isVariadic := t.IsVariadic()
        if isSlice {
-               if !t.IsVariadic() {
+               if !isVariadic {
                        panic("reflect: CallSlice of non-variadic function")
                }
                if len(in) < n {
@@ -389,13 +390,13 @@ func (v Value) call(op string, in []Value) []Value {
                        panic("reflect: CallSlice with too many input arguments")
                }
        } else {
-               if t.IsVariadic() {
+               if isVariadic {
                        n--
                }
                if len(in) < n {
                        panic("reflect: Call with too few input arguments")
                }
-               if !t.IsVariadic() && len(in) > n {
+               if !isVariadic && len(in) > n {
                        panic("reflect: Call with too many input arguments")
                }
        }
@@ -409,7 +410,7 @@ func (v Value) call(op string, in []Value) []Value {
                        panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
                }
        }
-       if !isSlice && t.IsVariadic() {
+       if !isSlice && isVariadic {
                // prepare slice for remaining values
                m := len(in) - n
                slice := MakeSlice(t.In(n), m, m)