Can't figure out why dynamic dispatch is occuring

I’m trying to figure out why the profiler and @code_warntype are picking up dynamic dispatch in the following MWE. The basic function applies matrix multiplications to each column of a matrix array and accumulates the result to another matrix array.

u = rand(4,100)
v = rand(4,100)
A = rand(4,4)
U = (u,v)

function init(A)
    mxm_accum!(X,x,j) = X[:,j] += 2 * (A*x)
    return mxm_accum!
end
mxm_accum! = init(A)

function foo(A,U)
    out = (x->A*x).(U)
    for j = 1:size(U[1],2)
        Uj = getindex.(U,:,j)
        mxm_accum!.(out,Uj,j)
    end
    return out
end

However, when I run profiler on it, it shows that the broadcasted function mxm_accum! is being dynamically dispatched.

@code_warntype shows that the broadcast in this step seems to be type unstable, but I can’t figure out why this would be the case.

mxm_accum! is a global non constant.

Passing it in and specializing fixes things, but now I’m confused about my “draft” MWEs. I moved the function definition outside b/c I didn’t understand what was going on.

If I define mxm_accum! inside the function, it’s no longer a global non-constant, but I sometimes get dynamic dispatch. The profiler shows that this MWE experiences dynamic dispatch

u = rand(4,100)
v = rand(4,100)
A = rand(4,4)
U = (u,v)

function foo(A,U)
    out = (x->A*x).(U)
    for j = 1:size(U[1],2)
        Uj = getindex.(U,:,j)
        mxm_accum!(X,x,j) = X[:,j] += 2 * (A*x)
        mxm_accum!.(out,Uj,j)
    end
    return out
end

while this MWE does not

u = rand(4,100)
v = rand(4,100)
A = rand(4,4)
U = (u,v)

function foo(A,U)
    mxm_accum!(X,x,j) = X[:,j] += 2 * (A*x)
    out = (x->A*x).(U)
    for j = 1:size(U[1],2)
        Uj = getindex.(U,:,j)
        mxm_accum!.(out,Uj,j)
    end
    return out
end

The difference is where I define mxm_accum! (inside/outside the loop), but I don’t know why dynamic dispatch happens in one and not the other.

It’s the global part that’s important. In the first case, mxm_accum! is a non-constant global variable (which is bad). In the second case, it’s a local variable (which is fine). Edit: nope, misread the question. Sorry!

Oh, sorry, I misread the question. Edited…

After correctly reading the question (sorry), I can’t reproduce the result. I don’t see any type-instability in either of your MWE with mxm_accum! as local variables in Julia 1.4.0. What Julia version are you using?

1 Like

Odd - I restarted Atom and now @profiler doesn’t show dynamic dispatch either.

These Heisenbugs will be the death of me. Sorry for the red herring.

1 Like