diff options
author | Ignacio Hagopian <jsign.uy@gmail.com> | 2021-03-30 17:18:06 +0000 |
---|---|---|
committer | Daniel Martí <mvdan@mvdan.cc> | 2021-03-30 17:41:58 +0000 |
commit | 6cadfe2fee9b063651f163aaa4734979944e7a9f (patch) | |
tree | b1b3a3510d948cc3ebd5cf786b35575a475ed999 /src/reflect | |
parent | 43afb1a22016ec537915ed8ade0039ad8c6559ce (diff) | |
download | go-6cadfe2fee9b063651f163aaa4734979944e7a9f.tar.gz go-6cadfe2fee9b063651f163aaa4734979944e7a9f.zip |
reflect: cache IsVariadic calls in Call
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>
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/all_test.go | 16 | ||||
-rw-r--r-- | src/reflect/value.go | 9 |
2 files changed, 21 insertions, 4 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index accda7fa74..e4b74f72d9 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -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)))) diff --git a/src/reflect/value.go b/src/reflect/value.go index eae1b9bf29..52639d5aad 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -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) |