Unsolvable dynamic dispatch in a `for` loop

Hello,

I posted about this problem last week. I think now I have the most simple example to illustrate it:

function my2outputs(a::Float64, g::Function)
    myRange = LinRange(-10.0,10.0,100)
    myMax, myLoc = findmax(map(x -> a^x / g(x), myRange))

    return myMax, myRange[myLoc]
end

function my3outputs(g::Function)
    auxRange = LinRange(1.0,3.0,100)

    Vs = Vector{Float64}(undef, 100)
    Xs = Vector{Float64}(undef, 100)
    for (ind, a) in enumerate(auxRange)
        Vs[ind], Xs[ind] = my2outputs(a, g)
    end

    auxMax, auxLoc = findmax(Vs)

    return auxMax, auxRange[auxLoc], Xs[auxLoc]
end

Juno’s compiler flags the following line as incurring in dynamic dispatch:

Vs[ind], Xs[ind] = my2outputs(a, g)

I can’t figure out why and how to fix it. Does anybody have a clue?

Thank you!

You want g<:Function this is important because all functions have their own type for performance reasons.

2 Likes
julia> using BenchmarkTools

julia> function my2outputs(a::Float64, g::F) where {F<:Function}
           myRange = LinRange(-10.0,10.0,100)
           myMax = -Inf; myx = zero(eltype(myRange));
           loga = log(a)
           for i ∈ eachindex(myRange)
               x = myRange[i]
               y = exp(x*loga) / g(x)
               newMax = y > myMax
               myMax = newMax ? y : myMax
               myx = newMax ? x : myx
           end

           return myMax, myx
       end
my2outputs (generic function with 1 method)

julia> function my3outputs(g::F) where {F<:Function}
           auxRange = LinRange(1.0,3.0,100)

           Vs = Vector{Float64}(undef, 100)
           Xs = Vector{Float64}(undef, 100)
           for (ind, a) in enumerate(auxRange)
               Vs[ind], Xs[ind] = my2outputs(a, g)
           end

           auxMax, auxLoc = findmax(Vs)

           return auxMax, auxRange[auxLoc], Xs[auxLoc]
       end
my3outputs (generic function with 1 method)

julia> @btime my3outputs(abs2)
  110.051 μs (2 allocations: 1.75 KiB)
(590.4900000000008, 3.0, 10.0)

Versus the original:

julia> @btime my3outputs(abs2)
  190.881 μs (503 allocations: 97.09 KiB)
(590.49, 3.0, 10.0)

For some reason, Julia master is around 40% slower than 1.5 when running the above. If I add @inline to my2outputs, it is about 40% faster than Julia 1.5 (which remains the same fast).

2 Likes

I think it has to do with this.

2 Likes