Skip to content

Loading FixedPointNumbers invalidates ~7,700 precompiled method instances (7x slower first mtkcompile) #331

Description

@ufechner7

Summary

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.jl
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D
if get(ENV, "LOAD_FPN", "0") == "1"
    @eval using FixedPointNumbers      # <-- the only difference
end
@variables x(t)=1.0 y(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_invalidations using 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
403 reduce_first(::typeof(Base.add_sum), x::FixedPoint) — src/FixedPointNumbers.jl:296
109 -(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.

Activity

  1. adienes commented on Sep 6, 2026

    @adienes

    this adds methods to length(r::AbstractUnitRange{Union{}}), showarg(io::IO, a::Array{Union{}}, toplevel), and -(x::Union{}) which technically is piracy

  2. adienes commented on Sep 6, 2026

    @adienes

    codex thinks the biggest offender is the length(r::StepRange{X,X}) where {X <: FixedPoint} method, which invalidates StepRange{<:Dates.TimeType}

  3. kimikage commented on Sep 13, 2026

    @kimikage
    Collaborator

    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.

  4. kimikage commented on Sep 27, 2026

    @kimikage
    Collaborator

    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.

  5. kimikage commented on Sep 28, 2026

    @kimikage
  6. kimikage commented on Sep 28, 2026

    @kimikage
    Collaborator

    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

    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:839
      checked_mul(x::T, y::T) where T<:Integer
        @ Base.Checked checked.jl:295
      checked_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.
  7. kimikage commented on Oct 10, 2026

    @kimikage
    Collaborator

    Current Status:

    julia> length(uinvalidated(invs))
    966
    
    julia> trees = invalidation_trees(invs)
    8-element Vector{SnoopCompile.MethodInvalidations}:
     inserting reinterpret(::Type{X}, x::T) where {T<:Integer, X<:(FixedPoint{T})} @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/FixedPointNumbers.jl:48 invalidated:
       backedges: 1: superseding reinterpret(::Type{Out}, x) where Out @ Base essentials.jl:785 with MethodInstance for reinterpret(::Type, ::UInt16) (1 children)
    
     inserting promote_rule(::Type{X1}, ::Type{X2}) where {T1, f1, X1<:FixedPoint{T1, f1}, T2, f2, X2<:FixedPoint{T2, f2}} @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/FixedPointNumbers.jl:536 invalidated:
       backedges: 1: superseding promote_rule(::Type, ::Type) @ Base promotion.jl:334 with MethodInstance for promote_rule(::Type, ::Type) (4 children)
    
     inserting Float64(x::Normed{UInt128, f}) where f @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/normed.jl:235 invalidated:
       mt_backedges: 1: signature Tuple{Type{Float64}, Number} triggered MethodInstance for Base.Broadcast.combine_eltypes(::Type{Float64}, ::Tuple{Vector{Number}}) (2 children)
                     2: signature Tuple{Type{Float64}, Any} triggered MethodInstance for Base.Broadcast.combine_eltypes(::Type{Float64}, ::Tuple{Vector{Any}}) (2 children)
                     3: signature Tuple{Type{Float64}, Any} triggered MethodInstance for Base.Broadcast.combine_eltypes(::Type{Float64}, ::Tuple{Matrix{Any}}) (2 children)
    
     inserting (::Type{Ti})(x::FixedPoint) where Ti<:Integer @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/FixedPointNumbers.jl:86 invalidated:
       mt_backedges: 1: signature Tuple{Type{Int64}, Number} triggered MethodInstance for Base.Broadcast.combine_eltypes(::Type{Int64}, ::Tuple{Vector{Number}}) (10 children)
    
     inserting reduce_first(::typeof(Base.mul_prod), x::FixedPoint) @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/FixedPointNumbers.jl:563 invalidated:
       backedges: 1: superseding reduce_first(::typeof(Base.mul_prod), x) @ Base reduce.jl:408 with MethodInstance for Base.reduce_first(::typeof(Base.mul_prod), ::Any) (16 children)
    
     inserting checked_mul(x::Real, ::Type{X}) where X<:FixedPoint @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/FixedPointNumbers.jl:62 invalidated:
       mt_backedges: 1: signature Tuple{typeof(Base.Checked.checked_mul), Any, Any} triggered MethodInstance for checked_mul(::Int64, ::Integer) (0 children)
                     2: signature Tuple{typeof(Base.Checked.checked_mul), Int64, Any} triggered MethodInstance for (::Base.BottomRF{typeof(Base.Checked.checked_mul)})(::Int64, ::Any) (0 children)
                     3: signature Tuple{typeof(Base.Checked.checked_mul), Int64, Any} triggered MethodInstance for (::Base.BottomRF{typeof(Base.Checked.checked_mul)})(::Int64, ::Any) (0 children)
                     4: signature Tuple{typeof(Base.Checked.checked_mul), Any, Any} triggered MethodInstance for checked_mul(::Int64, ::Integer) (3 children)
                     5: signature Tuple{typeof(Base.Checked.checked_mul), Any, Any} triggered MethodInstance for (::Base.BottomRF{typeof(Base.Checked.checked_mul)})(::Any, ::Any) (43 children)
    
     inserting reduce_first(::typeof(Base.add_sum), x::FixedPoint) @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/FixedPointNumbers.jl:560 invalidated:
       backedges: 1: superseding reduce_first(::typeof(Base.add_sum), x) @ Base reduce.jl:405 with MethodInstance for Base.reduce_first(::typeof(Base.add_sum), ::Any) (313 children)
    
     inserting -(x::X) where X<:FixedPoint @ FixedPointNumbers ~/.julia/packages/FixedPointNumbers/l6dW1/src/FixedPointNumbers.jl:332 invalidated:
       mt_backedges: 1: signature Tuple{typeof(-), Number} triggered MethodInstance for Base.Broadcast.combine_eltypes(::typeof(-), ::Tuple{Vector{Number}}) (20 children)
                     2: signature Tuple{typeof(-), Number} triggered MethodInstance for Base.Broadcast.combine_eltypes(::typeof(-), ::Tuple{Vector{Number}}) (1099 children)
    Version Info. ```julia pkg> st -m Status `/tmp/jl_suOBhy/Manifest.toml` [47edcb42] ADTypes v1.24.0 [14f7f29c] AMD v0.5.4 [6e696c72] AbstractPlutoDingetjes v1.4.1 [1520ce14] AbstractTrees v0.4.5 [7d9f7c33] Accessors v0.1.45 [79e6a3ab] Adapt v4.7.4 [ec485272] ArnoldiMethod v0.4.0 [4fba245c] ArrayInterface v7.30.2 [4c555306] ArrayLayouts v1.14.0 [aae01518] BandedMatrices v1.13.1 [e2ed5e7c] Bijections v0.2.2 [b2a6c25c] BinaryHeaps v1.1.0 [caf10ac8] BipartiteGraphs v0.1.14 [8e7c35d0] BlockArrays v1.10.1 [70df07ce] BracketingNonlinearSolve v1.12.8 ⌅ [861a8166] Combinatorics v1.0.2 [38540f10] CommonSolve v0.2.14 [bbf7d656] CommonSubexpressions v0.3.1 [f70d9fcc] CommonWorldInvalidations v1.2.2 [34da2185] Compat v4.18.1 [b152e2b5] CompositeTypes v0.1.4 [a33af91c] CompositionsBase v0.1.2 [2569d6c7] ConcreteStructs v0.2.8 [187b0558] ConstructionBase v1.6.0 [a8cc5b0e] Crayons v4.2.0 [9a962f9c] DataAPI v1.16.0 [864edb3b] DataStructures v0.19.6 [e2d170a0] DataValueInterfaces v1.0.0 [8bb1440f] DelimitedFiles v1.9.1 [2b5f629d] DiffEqBase v7.21.3 [459566f4] DiffEqCallbacks v4.19.4 [163ba53b] DiffResults v1.1.0 [b552c78f] DiffRules v1.16.0 [a0c0ee7d] DifferentiationInterface v0.7.21 [ffbed154] DocStringExtensions v0.9.5 [5b8099bc] DomainSets v0.8.3 [7c1d4256] DynamicPolynomials v0.6.8 [4e289a0a] EnumX v1.0.7 [f151be2c] EnzymeCore v0.8.22 [e2ba6199] ExprTools v0.1.11 [55351af7] ExproniconLite v0.10.14 [7034ab61] FastBroadcast v1.4.0 [9aa1b823] FastClosures v0.3.2 [a4df4552] FastPower v1.5.0 [1a297f60] FillArrays v1.17.1 [64ca27bc] FindFirstFunctions v3.4.0 [6a86dc24] FiniteDiff v2.33.0 [53c48c17] FixedPointNumbers v0.9.2 [f6369f11] ForwardDiff v1.4.6 [a85aefff] FunctionMaps v0.1.2 [069b7b12] FunctionWrappers v1.1.3 [77dc65aa] FunctionWrappersWrappers v1.13.0 [46192b85] GPUArraysCore v0.2.1 [86223c79] Graphs v1.15.0 [3263718b] ImplicitDiscreteSolve v2.3.0 [d25df0c9] Inflate v0.1.5 [18e54dd8] IntegerMathUtils v0.1.4 [8197267c] IntervalSets v0.7.15 [3587e190] InverseFunctions v0.1.17 [92d709cd] IrrationalConstants v0.2.6 [82899510] IteratorInterfaceExtensions v1.0.0 [692b3bcd] JLLWrappers v1.8.0 [ae98c720] Jieko v0.2.1 [ccbc3e58] JumpProcesses v9.33.1 [ba0b0d4f] Krylov v0.10.10 [2faa5264] LHLFactorization v2.2.2 [b964fa9f] LaTeXStrings v1.4.1 [87fe0de2] LineSearch v0.1.19 [7ed4a6bd] LinearSolve v5.18.2 [2ab3a3ac] LogExpFunctions v1.0.2 [e6f89c97] LoggingExtras v1.2.0 [1914dd2f] MacroTools v0.5.16 [bb5d69b7] MaybeInplace v0.1.8 [961ee093] ModelingToolkit v11.45.3 [7771a370] ModelingToolkitBase v1.77.3 [6bb917b9] ModelingToolkitTearing v1.20.7 [2e0e35c7] Moshi v0.3.13 [46d2c3a1] MuladdMacro v0.2.7 [102ac46a] MultivariatePolynomials v0.5.20 [d8a4904e] MutableArithmetics v1.8.1 [77ba4419] NaNMath v1.1.4 [be0214bd] NonlinearSolveBase v2.54.1 [5959db7a] NonlinearSolveFirstOrder v2.10.0 [6fe1bfb0] OffsetArrays v1.17.0 [bac558e1] OrderedCollections v2.0.2 [bbf590c4] OrdinaryDiffEqCore v4.18.1 [e409e4f3] PoissonRandom v0.4.13 [d236fae5] PreallocationTools v1.7.1 [aea7be01] PrecompileTools v1.3.4 [21216c6a] Preferences v1.6.0 [08abe8d2] PrettyTables v3.5.0 [27ebfcd6] Primes v0.5.7 [0c0d3e7f] PureKLU v1.6.0 [988b38a3] ReadOnlyArrays v0.2.0 [795d4caa] ReadOnlyDicts v1.0.1 [3cdcf5f2] RecipesBase v1.4.0 [731186ca] RecursiveArrayTools v4.5.3 [189a3867] Reexport v1.2.2 [9fe22ead] RespecializeParams v1.3.0 [7e49a35a] RuntimeGeneratedFunctions v0.5.27 [9dfe8606] SCCNonlinearSolve v1.15.4 [0bca4576] SciMLBase v3.57.0 [19f34311] SciMLJacobianOperators v0.1.19 [a6db7da4] SciMLLogging v2.1.0 [c0aeaf25] SciMLOperators v1.30.2 [431bcebd] SciMLPublic v1.3.0 [53ae85a6] SciMLStructures v1.10.5 [efcf1570] Setfield v1.1.2 [727e6d20] SimpleNonlinearSolve v2.14.6 [699a6c99] SimpleTraits v0.9.6 [ed01d8cd] Sobol v1.5.0 [a57abbd0] SparseColumnPivotedQR v2.1.8 [276daf66] SpecialFunctions v2.9.0 [0c0c59c1] StarAlgebras v0.3.0 [64909d44] StateSelection v1.11.1 [90137ffa] StaticArrays v1.9.23 [1e83bf80] StaticArraysCore v1.4.4 [10745b16] Statistics v1.11.5 [892a3eda] StringManipulation v0.6.1 [2efcf032] SymbolicIndexingInterface v0.3.55 [19f23fe9] SymbolicLimits v1.2.1 [d1185830] SymbolicUtils v4.50.0 [0c5d862f] Symbolics v7.45.0 [3783bdb8] TableTraits v1.0.1 [bd369af6] Tables v1.14.0 [ed4db957] TaskLocalValues v0.1.3 [8ea1fca8] TermInterface v2.0.0 [a759f4b9] TimerOutputs v1.2.2 [781d530d] TruncatedStacktraces v1.4.0 [3a884ed6] UnPack v1.0.2 [d30d5f5c] WeakCacheSets v0.1.0 [1d5cc7b8] IntelOpenMP_jll v2025.2.0+0 [856f044c] MKL_jll v2025.2.0+0 [efe28fd5] OpenSpecFun_jll v0.5.6+0 [1317d2d5] oneTBB_jll v2022.3.0+0 [0dad84c5] ArgTools v1.1.2 [56f22d72] Artifacts v1.11.0 [2a0f44e3] Base64 v1.11.0 [ade2ca70] Dates v1.11.0 [8ba89e20] Distributed v1.11.0 [f43a241f] Downloads v1.7.0 [7b1f6079] FileWatching v1.11.0 [9fa8497b] Future v1.11.0 [b77e0a4c] InteractiveUtils v1.11.0 [ac6e5ff7] JuliaSyntaxHighlighting v1.12.0 [4af54fe1] LazyArtifacts v1.11.0 [b27032c2] LibCURL v1.0.0 [76f85450] LibGit2 v1.11.0 [8f399da3] Libdl v1.11.0 [37e2e46d] LinearAlgebra v1.13.0 [56ddb016] Logging v1.11.0 [d6f4376e] Markdown v1.11.0 [a63ad114] Mmap v1.11.0 [ca575930] NetworkOptions v1.3.0 [44cfe95a] Pkg v1.13.0 [de0858da] Printf v1.11.0 [3fa0cd96] REPL v1.11.0 [9a3f8284] Random v1.11.0 [ea8e919c] SHA v1.0.0 [9e88b42a] Serialization v1.11.0 [6462fe0b] Sockets v1.11.0 [2f01184e] SparseArrays v1.13.0 [f489334b] StyledStrings v1.11.0 [fa267f1f] TOML v1.0.3 [a4e569a6] Tar v1.10.0 [8dfed614] Test v1.11.0 [cf7118a7] UUIDs v1.11.0 [4ec0a83e] Unicode v1.11.0 [e66e0078] CompilerSupportLibraries_jll v1.5.5+2 [deac9b47] LibCURL_jll v8.18.0+1 [e37daf67] LibGit2_jll v1.9.1+0 [29816b5a] LibSSH2_jll v1.11.104+0 [14a3606d] MozillaCACerts_jll v2026.8.13 [4536629a] OpenBLAS_jll v0.3.30+0 [05823500] OpenLibm_jll v0.8.7+0 [458c3c95] OpenSSL_jll v3.5.6+0 [efcefdf7] PCRE2_jll v10.46.0+0 [bea87d4a] SuiteSparse_jll v7.10.1+0 [83775a58] Zlib_jll v1.3.1+2 [3161d3a3] Zstd_jll v1.5.7+1 [8e850b90] libblastrampoline_jll v5.15.0+0 [8e850ede] nghttp2_jll v1.67.1+0 [3f19e933] p7zip_jll v17.8.2+0 Info Packages marked with ⌅ have new versions available but compatibility constraints restrict them from upgrading. To see why use `status --outdated -m`

    julia> versioninfo()
    Julia Version 1.13.1
    Commit 96ca370cf0e (2026-09-25 19:34 UTC)
    Build Info:
    Official https://julialang.org release
    Platform Info:
    OS: Linux (x86_64-linux-gnu)
    CPU: 8 × 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
    WORD_SIZE: 64
    LLVM: libLLVM-20.1.8 (ORCJIT, tigerlake)
    GC: Built with stock GC
    Threads: 1 default, 1 interactive, 1 GC (on 8 virtual cores)

    </details>
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions