In Cassette.overdub passes, one often finds that varargs incurs a performance penalty.
For instance,
using Cassette
Cassette.@context TraceCtx
mutable struct Trace
current::Vector{Any}
stack::Vector{Any}
Trace() = new(Any[], Any[])
end
function enter!(t::Trace, args...)
pair = args => Any[]
push!(t.current, pair)
push!(t.stack, t.current)
t.current = pair.second
return nothing
end
function exit!(t::Trace)
t.current = pop!(t.stack)
return nothing
end
Cassette.prehook(ctx::TraceCtx, args...) = enter!(ctx.metadata, args...)
Cassette.posthook(ctx::TraceCtx, args...) = exit!(ctx.metadata)
trace = Trace()
x, y, z = rand(3)
f(x, y, z) = x*y + y*z
julia> @btime Cassette.overdub(TraceCtx(metadata = trace), () -> f(x, y, z))
3.315 μs (41 allocations: 1.48 KiB)
0.2360528466104866
Here, the vararg splatting in enter!(t::Trace, args...) accounts for a large fraction of the above allocations and runtime. Switching to args::Vararg{Any, N} where N doesn't seem to help:
julia> function enter!(t::Trace, args::Vararg{Any, N}) where {N}
pair = args => Any[]
push!(t.current, pair)
push!(t.stack, t.current)
t.current = pair.second
return nothing
end
enter! (generic function with 1 method)
julia> @btime Cassette.overdub(TraceCtx(metadata = trace), () -> f(x, y, z))
3.883 μs (61 allocations: 1.81 KiB)
0.1532882013156685
(note that enter!(t::Trace, args::Vararg{<:T, N}) where {T, N} won't work because it forces all the varargs to be the same subtype of T.)
In
Cassette.overdub
passes, one often finds that varargs incurs a performance penalty.For instance,
Here, the vararg splatting in
enter!(t::Trace, args...)
accounts for a large fraction of the above allocations and runtime. Switching toargs::Vararg{Any, N} where N
doesn't seem to help:(note that
enter!(t::Trace, args::Vararg{<:T, N}) where {T, N}
won't work because it forces all the varargs to be the same subtype ofT
.)but a macro I made for getting around this does:
What the above macro did was to make 5 copies of the method:
This is a bit clunky and ideally wouldn't be necessary if
args::Vararg{Any, N}
or something similar was more strict.