(Compiler) Performance of Dict

10 posts were split to a new topic: Code isolation side discussion

Perhaps code isolation should be it’s own thread.

5 Likes

Done.

Yes. Julia performs an optimization in the case that there’s only one (or a couple, I think) methods to possibly call in the face of a type-instability, it’ll avoid doing the dynamic dispatch. Example:

julia> f(x) = 1
f (generic function with 1 method)

julia> g(x) = f(x[])*2
g (generic function with 1 method)

julia> @time g(Ref{Any}(1))
  0.007295 seconds (3.41 k allocations: 216.416 KiB)
2

julia> @time g(Ref{Any}(1))
  0.000015 seconds (5 allocations: 176 bytes)
2

The outer function g doesn’t know what it’ll get out of a Ref{Any}, so that’s a type instability, but it knows that there’s only one possible method for f, so it can avoid the expensive consequence of a type instability — the dynamic dispatch. Even better, it’s “fixed” our type instability because it knows that f will only ever return the number 1!

julia> @code_typed g(Ref{Any}(1))
CodeInfo(
1 ─     Base.getfield(x, :x)::Any
└──     return 2
) => Int64

So this is now compiled and happily marching along. Then some package adds another method — note that the argument could be a type it defines itself; definitely not piracy. It’s a method that never gets called, and yet it forces the recompilation of g… and of course causes our previous example to become somewhat type-unstable again. Add enough other methods and eventually Julia will give up on the small unions and just return Any:

julia> struct TT end

julia> f(::TT) = 3//2
f (generic function with 2 methods)

julia> @time g(Ref{Any}(1))
  0.048927 seconds (137.27 k allocations: 7.199 MiB)
2

julia> @time g(Ref{Any}(1))
  0.000025 seconds (5 allocations: 176 bytes)
2

julia> @code_typed g(Ref{Any}(1))
CodeInfo(
1 ── %1  = Base.getfield(x, :x)::Any
... # so much code ...
18 ┄ %38 = φ (#5 => %15, #16 => %33)::Union{Rational{Int64}, Int64}
└───       return %38
) => Union{Rational{Int64}, Int64}
10 Likes

That’s really informative @mbauman, many thanks. Also, it’s really important to learn this type of compiler details to develop a sense of where performance opportunities lie. For me the compiler is still a magic black box… A box of black magic, actually :-D.