You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Loading FixedPointNumbers into a session that already has ModelingToolkit loaded invalidates 7,708 precompiled method instances and makes the first mtkcompile call take 23.59 s
instead of 0.04 s — a huge slowdown in a script that never uses a fixed-point number.
Most users meet this indirectly: ColorTypes/Colors depend on FixedPointNumbers, so any
Makie-based plotting next to ModelingToolkit pays this cost on the first model build.
MWE
# mwe.jlusing ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D
ifget(ENV, "LOAD_FPN", "0") =="1"@evalusing FixedPointNumbers # <-- the only differenceend@variablesx(t)=1.0y(t)=0.0@named sys =System([D(x) ~ y, D(y) ~-x], t)
t0 =time(); mtkcompile(sys); println("mtkcompile: ", round(time()-t0, digits=2), " s")
(test) pkg> st
Status `~/test/Project.toml`
[53c48c17] FixedPointNumbers v0.9.1
[961ee093] ModelingToolkit v11.41.0
$ julia --startup-file=no --project=. mwe.jl
mtkcompile: 0,04 s
$ LOAD_FPN=1 julia --startup-file=no --project=. mwe.jl
mtkcompile: 23.59 s
As a control, loading a package of comparable size that does not add methods to Base
generics (using LaTeXStrings) leaves the time unchanged at 0.04 s, so this is not the
general cost of loading a package.
Attribution
using SnoopCompileCore
using ModelingToolkit
invs =@snoop_invalidationsusing FixedPointNumbers;
using SnoopCompile
length(uinvalidated(invs)) # 7708, from 15 culprit methods
Ranked by countchildren:
children
method
14312
promote_rule(::Type{Fixed{T1,f1}}, ::Type{Fixed{T2,f2}}) where {T1,T2,f1,f2} — src/fixed.jl:199
3556
length(r::AbstractUnitRange{N}) where {T<:Unsigned, N<:Normed{T}} — src/normed.jl:304
3089
ceil(::Type{Ti}, x::Normed) where Ti<:Integer — src/normed.jl:277
1668
showarg(io::IO, a::Array{T}, toplevel) where T<:FixedPoint — src/FixedPointNumbers.jl:279
-(x::X) where X<:FixedPoint — src/FixedPointNumbers.jl:233
None of these are type piracy — every one is dispatching on a FixedPointNumbers type. The
cost seems to come from adding methods to widely-inferred Base generics (promote_rule, length, ceil, convert), which discards inference results in already-loaded packages
that call those generics on non-concrete argument types.
Question
Is there room to narrow any of these signatures, or is this something that has to be fixed
on the consuming side (or in Base)? I am mostly filing this for the record, since the
measured impact is large and I could not find an existing issue about it. Happy to run
further measurements if that helps.
Versions
Julia 1.12.7 (Linux, x86_64), FixedPointNumbers 0.8.6, ModelingToolkit 11.17.0,
SnoopCompile 3.2.9.
this adds methods to length(r::AbstractUnitRange{Union{}}), showarg(io::IO, a::Array{Union{}}, toplevel), and -(x::Union{}) which technically is piracy
I don't think length(r::StepRange{X,X}) where {X <: FixedPoint} is the essence of the problem, even though it is the trigger.
The invalidation triggered by length appears to be an issue of type instability or excessive precompilation related to SymbolicUtils.
PR #339 reduces the number of methods that are invalidated, but it does not appear to be a solution to the problem of mtkcompile taking a long time.
The promote_rule and showarg entries listed in FPN v0.8.6 triggers should have been fixed in FPN v0.9.0. (It looks like checked_mul has been added to the triggers.)
I think it will be necessary to use @snoop_inference or similar tools separately to perform analysis from the perspective of downstream packages.
I am not familiar with the MTK ecosystem.
julia>which(Base.Checked.checked_mul, Tuple{Integer, Any}) # without FPN
ERROR: Calling invoke(f, t, args...) would throw:
MethodError:checked_mul(::Integer, ::Any) is ambiguous.
Candidates:checked_mul(a::BigInt, b::BigInt)
@ Base.GMP gmp.jl:839checked_mul(x::T, y::T) where T<:Integer
@ Base.Checked checked.jl:295checked_mul(x::Integer, y::Integer)
@ Base.Checked checked.jl:30
To resolve the ambiguity, try making one of the methods more specific, or adding a new method more specific than any of the existing applicable methods.
Manifest.toml mwe.jl Project.toml
ufechner@framework:~/tmp$ julia --startup-file=no --project=. mwe.jl
mtkcompile: 0.05 s
ufechner@framework:~/tmp$ LOAD_FPN=1 julia --startup-file=no --project=. mwe.jl
mtkcompile: 3.4 s
And on Julia 1.12.7:
ufechner@framework:~/tmp$ julia --startup-file=no --project=. mwe.jl
mtkcompile: 0.05 s
ufechner@framework:~/tmp$ LOAD_FPN=1 julia --startup-file=no --project=. mwe.jl
mtkcompile: 4.22 s
This was on my laptop, the original test I did on my desktop, so a performance increase with Julia 1.13 by an estimated factor of 6.94*1.2 = 8.3 (could also be 10). Very good progress!
Status `~/tmp/Project.toml`
[53c48c17] FixedPointNumbers v0.9.2
[961ee093] ModelingToolkit v11.45.3
Unluckily, the invalidation penalty when loading GLMakie is still 27s. But that is no longer the mainly caused by FixedPointNumbers.
Activity
adienes commentedon Sep 6, 2026
this adds methods to
length(r::AbstractUnitRange{Union{}}),showarg(io::IO, a::Array{Union{}}, toplevel), and-(x::Union{})which technically is piracyadienes commentedon Sep 6, 2026
codex thinks the biggest offender is the
length(r::StepRange{X,X}) where {X <: FixedPoint}method, which invalidatesStepRange{<:Dates.TimeType}kimikage commentedon Sep 13, 2026
I don't think
length(r::StepRange{X,X}) where {X <: FixedPoint}is the essence of the problem, even though it is the trigger.The invalidation triggered by
lengthappears to be an issue of type instability or excessive precompilation related toSymbolicUtils.kimikage commentedon Sep 27, 2026
xref: https://discourse.julialang.org/t/invalidations-caused-by-fixedpointnumbers/139232
kimikage commentedon Sep 27, 2026
PR #339 reduces the number of methods that are invalidated, but it does not appear to be a solution to the problem of
mtkcompiletaking a long time.The
promote_ruleandshowargentries listed in FPN v0.8.6 triggers should have been fixed in FPN v0.9.0. (It looks likechecked_mulhas been added to the triggers.)I think it will be necessary to use
@snoop_inferenceor similar tools separately to perform analysis from the perspective of downstream packages.I am not familiar with the MTK ecosystem.
kimikage commentedon Sep 28, 2026
kimikage commentedon Sep 28, 2026
checked_mul(//(::Rational, ::Int64)) might be an issue that needs to be fixed in julia (if this can be easily precompiled).Edit: xref: JuliaLang/julia#63452, JuliaLang/julia#63455
kimikage commentedon Oct 10, 2026
xref: https://discourse.julialang.org/t/invalidations-caused-by-fixedpointnumbers/139232/6
kimikage commentedon Oct 10, 2026
Current Status:
Version Info.
ufechner7 commentedon Oct 11, 2026
Large progress, indeed. On Julia 1.13.1:
And on Julia 1.12.7:
This was on my laptop, the original test I did on my desktop, so a performance increase with Julia 1.13 by an estimated factor of 6.94*1.2 = 8.3 (could also be 10). Very good progress!
Unluckily, the invalidation penalty when loading GLMakie is still 27s. But that is no longer the mainly caused by FixedPointNumbers.