A playful competition: who can define a method that invalidates the most code?

I believe this is related to the push towards fixing invalidations: Finding and fixing invalidations: now, everyone can help reduce time-to-first-plot

1 Like

Thanks for the reference, but how invalidations are fixed? Is this by changing something in the language or by changing code in Base so it will not be invalidated?

Analyzing sources of compiler latency in Julia: method invalidations is a good read.

In short, an invalidation occurs when a new method is added that breaks an assumption inference made to compute some earlier result and compiled code based on that result. Code in Base can be tweaked in such a way that it relies less on assumptions that packages tend to invalidate. This can be done by adding type assertions and conversions in strategical places, or use Base.invokelatest to “shield” certain parts of the code from inference.

It should be noted that there is nothing wrong with invalidations and they are very useful in the sense that it can give you nice optimizations and recompiling a small set of methods is often fast. It is just when they get excessive it creates noticeable compiler latency so it is good to get rid of the most egregious ones. But I think we are pretty good on that front now after all of Tim’s work. There are a few patterns that are still pretty bad (like convert(::Type{T}, ...) where {T}). but that is not too common to define in packages.

10 Likes

I agree with everything that @kristoffer.carlsson said, but one more point worth noting is that invalidations can also block effective precompilation. Even a small method that is quick to re-infer can block a big method that is really expensive to infer. Consequently, fixing invalidations can make more (still not all, but more) methods precompilable, and that’s another contribution to reducing latency. I agree 100% that we shouldn’t (and can’t) be dogmatic about getting rid of them all, but any “frivolous” invalidations may ultimately be worth someone’s time and attention.

When pre-release versions of 1.6 become available, I hope package authors take a new look at adding more precompile directives to reduce package latency. Once those precompile statements are in place, we’ll also start learning more about the ways that packages invalidate each other (you can only detect invalidations in methods that have been inferred). If the story of Julia itself is any guide, tracking those down and eliminating them will be another big step in reducing latency in interactive settings where people do some stuff, then load more packages, do more stuff, etc.

14 Likes

Not as bad as the winning convert methods, but it’s also easy to rack up a lot of invalidations with constructors

julia> using SnoopCompileCore

julia> struct X <: Integer; i::Int; end

julia> invalidations = @snoopr (::Type{T})(x::X) where {T} = T(x.i);

julia> using SnoopCompile; length(uinvalidated(invalidations))
733
2 Likes