On upgrading to Julia from 1.8.5. to 1.9.0 I noticed code in one of my packages slow down significantly. It has taken me a long time to get down to the simplest code which replicates the problem, but I have it now. After upgrading, the following code has become type unstable, and 1000x slower as a result:
using StaticArrays, BenchmarkTools
@inline function countvars(bitflags, var)
return bitflags >> 0
end
function myfunc(::Val{bitflags}, var) where bitflags
N = countvars(bitflags, var)
return zeros(SVector{N, Float64})
end
struct A
data::Float64
end
a = A(0.)
@btime myfunc(Val(1), $a);
@code_warntype myfunc(Val(1), a);
Moreover, this effect is very unstable - seemingly insignificant changes to the code result in the type stability disappearing. For example:
Removing data from struct A
Moving the code from countvars directly into myfunc
Removing the redundant var from the inputs to countvars
Changing the >> in line 4 to something like & or +
I have raised an issue about this in GitHub, but wanted to see if anyone else had seen anything similar. Is this expected, or unexpected?
Yeah, that’s really weird. I can confirm the regression exists on master as well. One minor simplification is to change myfunc to
function myfunc(::Val{bitflags}, var) where bitflags
N = countvars(bitflags, var)
return Array{Float64, N}
end
which removes the dependency on StaticArrays. The part of this that makes no sense to me is that the compiler knows that countvars is constant foldable, but for some reason isn’t constant folding it.
This is not a valid Base.@constprop annotation. Base.@constprop can only be applied on a method definition, not on callsites. And the @inline annotation is enough to encourage constant propagation.
Really? I think it only exists on 1.9 only. And it looks like something about semi-concrete abstract interpretation. Since we add many refinements on it after branching on 1.9, I guess the inference regression has been resolved on 1.10 but still there for 1.9.
I have found another performance regression moving from Julia v1.8.5 to v1.9.0. Some code now allocates memory, when none was allocated using v1.8.5. This makes the code 5x slower. There doesn’t appear to be any type instability. I have created an issue here.
Is there any information on what has changed? I guess it some under-the-hood compiler inference algorithms.