Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: reflect: add allocation-free variant of Value.Call #43732

Closed
dsnet opened this issue Jan 15, 2021 · 4 comments
Closed

proposal: reflect: add allocation-free variant of Value.Call #43732

dsnet opened this issue Jan 15, 2021 · 4 comments

Comments

@dsnet
Copy link
Member

dsnet commented Jan 15, 2021

At present, Value.Call for any function with any return arguments is slow because it needs to:

  1. allocate a stack frame for the underlying return values
  2. allocate a []Value for the return Values themselves

This is unfortunate since calling a function that returns any arguments is likely the common case. The aforementioned allocations cannot be eliminated because the current API Value.Call pretty much requires that the implementation be responsible for allocating the return arguments.

I propose a new CallWith (or any other suggested name) method with the modified signature:

func (v Value) CallWith(out, in []reflect.Value)

where:

  • the in argument is identical to that for Call
  • the out argument must be a slice where len(out) == v.NumOut().
    • If out[n] is a valid, settable value where v.Out(n).AssignableTo(out[n].Type()), then CallWith uses the existing value to store the output (with Value.Set).
    • Otherwise, CallWith allocates new underlying storage for a new reflect.Value and stores that into out[n].

With this API, I believe it is theoretically possible to have an allocation-free version of Value.Call.

The description above only proposes CallWith as an optimized version of Call. You can imagine a CallSliceWith as an optimized version of CallSlice.

\cc @mvdan @rogpeppe

@gopherbot gopherbot added this to the Proposal milestone Jan 15, 2021
@ianlancetaylor ianlancetaylor added this to Incoming in Proposals (old) Jan 15, 2021
@ianlancetaylor
Copy link
Contributor

I don't mind the idea but I'm not fond of the name. Can we do better than CallWith? That doesn't really convey anything to me.

@dsnet dsnet changed the title proposal: reflect: add Value.CallWith proposal: reflect: add allocation-free variant of Value.Call Jan 15, 2021
@gopherbot
Copy link

Change https://golang.org/cl/284222 mentions this issue: reflect: add Value.CallWith and Value.CallSliceWith

@dsnet
Copy link
Member Author

dsnet commented Jan 17, 2021

Using this benchmark and CL/284222, we achieve a runtime reduction of 1.5x:

name    old time/op    new time/op    delta
Call-8     454ns ± 8%     302ns ± 1%   -33.49%    (p=0.000 n=9+9)

name    old alloc/op   new alloc/op   delta
Call-8      280B ± 0%       0B ±NaN%  -100.00%  (p=0.000 n=10+10)

name    old allocs/op  new allocs/op  delta
Call-8      2.00 ± 0%     0.00 ±NaN%  -100.00%  (p=0.000 n=10+10)

@rsc
Copy link
Contributor

rsc commented Dec 1, 2021

Closing as duplicate of #49340 (yes, it was filed second, but we ended up with it in the active column first).

@rsc rsc closed this as completed Dec 1, 2021
@rsc rsc moved this from Incoming to Declined in Proposals (old) Dec 1, 2021
@golang golang locked and limited conversation to collaborators Dec 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Development

No branches or pull requests

4 participants