Skip to content

Commit 6cadfe2

Browse files
jsignmvdan
authored andcommitted
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: 9bbaa18 GitHub-Pull-Request: #43475 Reviewed-on: https://go-review.googlesource.com/c/go/+/281252 Reviewed-by: Daniel Martí <[email protected]> Reviewed-by: Keith Randall <[email protected]> Trust: Daniel Martí <[email protected]> Trust: Brad Fitzpatrick <[email protected]> Run-TryBot: Daniel Martí <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 43afb1a commit 6cadfe2

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

src/reflect/all_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -1942,6 +1942,22 @@ func BenchmarkCall(b *testing.B) {
19421942
})
19431943
}
19441944

1945+
type myint int64
1946+
1947+
func (i *myint) inc() {
1948+
*i = *i + 1
1949+
}
1950+
1951+
func BenchmarkCallMethod(b *testing.B) {
1952+
b.ReportAllocs()
1953+
z := new(myint)
1954+
1955+
v := ValueOf(z.inc)
1956+
for i := 0; i < b.N; i++ {
1957+
v.Call(nil)
1958+
}
1959+
}
1960+
19451961
func BenchmarkCallArgCopy(b *testing.B) {
19461962
byteArray := func(n int) Value {
19471963
return Zero(ArrayOf(n, TypeOf(byte(0))))

src/reflect/value.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,9 @@ func (v Value) call(op string, in []Value) []Value {
378378

379379
isSlice := op == "CallSlice"
380380
n := t.NumIn()
381+
isVariadic := t.IsVariadic()
381382
if isSlice {
382-
if !t.IsVariadic() {
383+
if !isVariadic {
383384
panic("reflect: CallSlice of non-variadic function")
384385
}
385386
if len(in) < n {
@@ -389,13 +390,13 @@ func (v Value) call(op string, in []Value) []Value {
389390
panic("reflect: CallSlice with too many input arguments")
390391
}
391392
} else {
392-
if t.IsVariadic() {
393+
if isVariadic {
393394
n--
394395
}
395396
if len(in) < n {
396397
panic("reflect: Call with too few input arguments")
397398
}
398-
if !t.IsVariadic() && len(in) > n {
399+
if !isVariadic && len(in) > n {
399400
panic("reflect: Call with too many input arguments")
400401
}
401402
}
@@ -409,7 +410,7 @@ func (v Value) call(op string, in []Value) []Value {
409410
panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
410411
}
411412
}
412-
if !isSlice && t.IsVariadic() {
413+
if !isSlice && isVariadic {
413414
// prepare slice for remaining values
414415
m := len(in) - n
415416
slice := MakeSlice(t.In(n), m, m)

0 commit comments

Comments
 (0)