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

Extra allocations from passing keyword arguments #28158

Closed
quinnj opened this issue Jul 18, 2018 · 3 comments
Closed

Extra allocations from passing keyword arguments #28158

quinnj opened this issue Jul 18, 2018 · 3 comments

Comments

@quinnj
Copy link
Member

quinnj commented Jul 18, 2018

Take this example:

julia> struct Foo
           b::Tuple{Int, String, Float64}
       end

julia> function foo(f::Foo)
           bar(foo=f.b)
       end
foo (generic function with 1 method)

julia> @noinline function bar(; kwargs...)
           # println(kwargs)
           s = 0
           for (k, v) in pairs(kwargs)
               v isa Int && (s = v)
           end
           return s
       end
bar (generic function with 1 method)

julia> @btime foo(Foo((1, "hey", 3.14)))
  28.989 ns (3 allocations: 80 bytes)
0

julia> @code_warntype foo(Foo((1, "hey", 3.14)))
Body::Int64
2 1%1 = Base.getfield(%%f, :b)::Tuple{Int64,String,Float64}                                                │╻   getproperty
  │   %2 = new(NamedTuple{(:foo,),Tuple{Tuple{Int64,String,Float64}}}, %1)::NamedTuple{(:foo,),Tuple{Tuple{Int64,String,Float64}}}%3 = :(Main.bar)::Core.Compiler.Const(bar, false)                                                       │
  │   %4 = new(Base.Iterators.Pairs{Symbol,Tuple{Int64,String,Float64},Tuple{Symbol},NamedTuple{(:foo,),Tuple{Tuple{Int64,String,Float64}}}}, %2, (:foo,))::Base.Iterators.Pairs{Symbol,Tuple{Int64,String,Float64},Tuple{Symbol},NamedTuple{(:foo,),Tuple{Tuple{Int64,String,Float64}}}}
  │   %5 = invoke Main.:(#bar#13)(%4::Base.Iterators.Pairs{Symbol,Tuple{Int64,String,Float64},Tuple{Symbol},NamedTuple{(:foo,),Tuple{Tuple{Int64,String,Float64}}}}, %3::Function)::Int64
  └──      return %5

Note in the final @code_warntype how we're both creating new(NamedTuple... as well as new(Base.Iterators.Pairs, while %2 doesn't even end up being used (or eliminated in the @code_llvm).

@quinnj
Copy link
Member Author

quinnj commented Jul 18, 2018

Oh, I actually see now that the Base.Iterators.Pairs is being constructed from the NamedTuple object. Is there anything better we can do here to avoid the extra allocations?

@JeffBezanson JeffBezanson changed the title Extra allocations from passing keyword arguments to inner functions Extra allocations from passing keyword arguments Jul 18, 2018
@JeffBezanson
Copy link
Member

This is expected; it's very difficult to optimize away rest keywords (kwargs... in bar). In fact I don't think we can ever eliminate the allocation of any object passed to a @noinline function.

@quinnj
Copy link
Member Author

quinnj commented Jul 25, 2018

It turns out most of my problem was actually #28147; after commenting out all my @debug statements, I avoid almost all extra allocations of rest keyword args. It was insightful to learn about the "codegen" peculiarities of explicit keyword args vs. rest; i.e. explicit, named keyword arguments that get passed down to another function are better to be explicitly named and passed rather than bundled w/ a generic kwargs... catchall.

@quinnj quinnj closed this as completed Jul 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants