Skip to content

Instantly share code, notes, and snippets.

@KristofferC
Last active May 19, 2025 13:31
Show Gist options
  • Save KristofferC/7cd3a4d0f157c73fe49c73f882886ec8 to your computer and use it in GitHub Desktop.
Save KristofferC/7cd3a4d0f157c73fe49c73f882886ec8 to your computer and use it in GitHub Desktop.

Plots.jl precompile issue

  • Create LocalPreferences.toml with
    [PrecompileTools]
    precompile_workloads = false
  • Install Plots + HTTP.
  • Run julia +1.10 --project --trace-compile=plots_compile.jl
  • Run the following:
julia> @time using Plots
  0.740981 seconds (768.54 k allocations: 57.182 MiB, 0.84% gc time, 6.02% compilation time)

julia> @time @eval (p = Plots.plot(rand(10), rand(10)); display(p));
  3.452190 seconds (20.40 M allocations: 1.374 GiB, 7.79% gc time, 92.98% compilation time: <1% of which was recompilation)

Make sure the TTFP is slow so to ensure that the precompile workload disabling was effective (cf JuliaLang/PrecompileTools.jl#62). This should generate a plots_compile.jl with ~ 504 statements.


Import precompile file:
  • Start julia: julia +1.10 --project --trace-compile=plots_compile_after_include.jl
  • Run the following:
julia> using Plots, HTTP

julia> for mod in Base.loaded_modules_order
           if !(nameof(mod) in (:Main, :Core, :Base))
               Core.eval(@__MODULE__, :(const $(Symbol(mod)) = $mod))
           end
       end

julia> @time include("plots_compile.jl")
  3.429380 seconds (20.86 M allocations: 1.405 GiB, 8.20% gc time, 97.42% compilation time)
true

julia> g() = rand()

julia> g()

julia> @time @eval (p = Plots.plot(rand(10), rand(10)); display(p));
  0.292021 seconds (141.86 k allocations: 9.912 MiB, 22.93% compilation time)
  • Open up the plots_compile_after_include.jl and find the precompile(Tuple{typeof(Base.rand), Int64}) call and delete everything above it, resulting file will have ~18 signatures.

Now run: julia +1.10 --project

julia> using Plots, HTTP

julia> for mod in Base.loaded_modules_order
           if !(nameof(mod) in (:Main, :Core, :Base))
               Core.eval(@__MODULE__, :(const $(Symbol(mod)) = $mod))
           end
       end

julia> @time include("plots_compile.jl")
  3.767446 seconds (20.67 M allocations: 1.392 GiB, 8.30% gc time, 97.37% compilation time)
true

julia> @time include("plots_compile_after_include.jl")
  0.053578 seconds (128.33 k allocations: 8.950 MiB, 91.61% compilation time)
true

julia> @time @eval (p = Plots.plot(rand(10), rand(10)); display(p));
  0.237858 seconds (16.35 k allocations: 1.159 MiB, 2.42% compilation time)

Note the low compilation time on the plot call compared to earlier. Also, note how including the full plots_compile.jl twice does not work:

julia> using Plots, HTTP

julia> for mod in Base.loaded_modules_order
           if !(nameof(mod) in (:Main, :Core, :Base))
               Core.eval(@__MODULE__, :(const $(Symbol(mod)) = $mod))
           end
       end

julia> @time include("plots_compile.jl")
  3.697584 seconds (20.67 M allocations: 1.392 GiB, 8.27% gc time, 97.31% compilation time)
true

julia> @time include("plots_compile.jl")
  0.093587 seconds (78.69 k allocations: 4.360 MiB)
true

julia> @time @eval (p = Plots.plot(rand(10), rand(10)); display(p));
  0.298213 seconds (142.06 k allocations: 9.929 MiB, 21.79% compilation time)

Open questions:

  • Why does replaying the precompile file not remove virtually all compilation time?
  • Why is it required to only execute a part of the precompile statements twice to remove the compilation time? What is it about the earlier ones that causes the latter ones to not be effective?
  • Is there something special about the signatures of the functions that fail to cache?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment