Optimizing a package: how to get started

More helpful tips:

  1. Don’t pay attention to the length of invalidations directly. Use length(uinvalidated(invalidations)), where you have to load the full SnoopCompile package to get uinvalidated.
  2. Use precompilation. Below is a demo.

(Note juliamns is my alias for julia-master --startup-file=no since I don’t want any other packages to cloud this analysis. You should be able to do everything except this invalidation analysis above on 1.5, however.)

tim@diva:~/.julia/dev/Gaston$ juliamns -q
julia> @time (using Gaston; display(plot(1:10)))
  2.142460 seconds (6.28 M allocations: 399.821 MiB, 4.51% gc time)

julia> 
tim@diva:~/.julia/dev/Gaston$ juliamns -q
julia> using SnoopCompileCore

julia> @snoopi tmin=0.01 begin
           using Gaston
           display(plot(1:10))
       end
2-element Vector{Tuple{Float64, Core.MethodInstance}}:
 (0.08780097961425781, MethodInstance for display(::Gaston.Figure))
 (0.4707939624786377, MethodInstance for plot(::UnitRange{Int64}))

First column is inference time, second is the MethodInstance it was inferring. This implies you spend nearly 0.5s on inferring plot(::UnitRange{Int}). So add this:

diff --git a/src/Gaston.jl b/src/Gaston.jl
index 2731d24..c7ccb7b 100644
--- a/src/Gaston.jl
+++ b/src/Gaston.jl
@@ -91,4 +91,7 @@ function __init__()
     return nothing
 end
 
+@assert precompile(plot, (UnitRange{Int},))
+@assert precompile(display, (Figure,))
+
 end

and then try again:

tim@diva:~/.julia/dev/Gaston$ juliamns -q
julia> @time (using Gaston; display(plot(1:10)))
  1.651489 seconds (3.32 M allocations: 230.272 MiB, 2.84% gc time)

julia>

If it doesn’t work, double-check whether it actually “took”:

tim@diva:~/.julia/dev/Gaston$ juliamns -q
julia> using SnoopCompileCore

julia> @snoopi tmin=0.01 begin
           using Gaston
           display(plot(1:10))
       end
4-element Vector{Tuple{Float64, Core.MethodInstance}}:
 (0.01037907600402832, MethodInstance for #plot#17(::Nothing, ::Int64, ::Nothing, ::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, ::typeof(plot), ::UnitRange{Int64}, ::UnitRange{Int64}, ::Nothing, ::Axes))
 (0.010785102844238281, MethodInstance for Vector{Gaston.Curve}(::Vector{Gaston.Curve{UnitRange{Int64}, UnitRange{Int64}, Nothing, Nothing}}))
 (0.016611099243164062, MethodInstance for write_data(::Gaston.Curve{UnitRange{Int64}, UnitRange{Int64}, Nothing, Nothing}, ::Int64, ::String))
 (0.044039011001586914, MethodInstance for Vector{Union{Nothing, Gaston.Plot}}(::Vector{Gaston.Plot}))

All this is documented in SnoopCompile. Note that you might want to precompile for more than just UnitRange{Int}, of course.

EDIT: ooh, the plot thickens! See https://github.com/JuliaLang/julia/issues/37509. Thanks for asking this question, I had never traced this issue down though I’ve definitely noticed some weird things about precompilation. EDIT2: nvm, though it’s a funny read!

4 Likes