Why does Pkg.activate(".") require compilation? Time to first project activation

Pkg.activate(".") seems to to take about 200 milliseconds, mostly due to compilation. It still takes 40 milliseconds even after activating the same environment again.

$ julia -e 'using Pkg; for i in 1:5; @time Pkg.activate("."); end'
  Activating project at `~/.julia/dev/ScriptUtils`
  0.220025 seconds (232.01 k allocations: 16.980 MiB, 98.52% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.042125 seconds (81.89 k allocations: 5.737 MiB, 95.17% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.001953 seconds (3.73 k allocations: 414.523 KiB)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.001633 seconds (3.73 k allocations: 414.180 KiB)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.001591 seconds (3.73 k allocations: 414.086 KiB)

I thought perhaps the second round of compilation had to due with the environment changing. Even if I initialize Julia with the correct environment these compilation times persist.

$ julia --project=. -e 'using Pkg; for i in 1:5; @time Pkg.activate("."); end'
  Activating project at `~/.julia/dev/ScriptUtils`
  0.219066 seconds (231.95 k allocations: 16.975 MiB, 98.48% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.051085 seconds (81.89 k allocations: 5.737 MiB, 95.46% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.001949 seconds (3.73 k allocations: 414.492 KiB)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.001591 seconds (3.73 k allocations: 414.148 KiB)
  Activating project at `~/.julia/dev/ScriptUtils`
  0.001618 seconds (3.73 k allocations: 414.055 KiB)

If I want to simplify usage of Julia code from the command line via an executable script, a Pkg.activate call is usually one of the first tasks.

Are we not precompiling Pkg.activate(::String) into the system image?

It appears we are indeed not precompiling Pkg.activate at all.

Edit: There is actually one precompilation of Pkg.activate, but it is for an empty Project.toml.

Activating an empty Project.toml is fast, but perhaps this is not a useful case.

$ julia -e 'using Pkg; touch("Project.toml"); @time Pkg.activate(".")'
  Activating project at `~/src/Pkg.jl/test/blah`
  0.000665 seconds (525 allocations: 51.023 KiB)
2 Likes

I submitted a pull request.

Edit: Doing this with a local build seems to have helped with the default environment, but there is still some compilation needed to activate one of my test enviornments.

$ ./julia -e 'using Pkg; for i in 1:5; @time Pkg.activate(); end' --trace-compile=stderr;
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.11`
  0.000518 seconds (543 allocations: 41.523 KiB)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.11`
  0.000251 seconds (538 allocations: 41.133 KiB)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.11`
  0.000215 seconds (538 allocations: 41.133 KiB)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.11`
  0.000213 seconds (538 allocations: 41.133 KiB)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.11`
  0.000205 seconds (539 allocations: 41.430 KiB)

$ ./julia -e 'using Pkg; for i in 1:5; @time Pkg.activate("/home/mkitti/.julia/dev/ScriptUtils/examples/Echo.jl"); end' --trace-compile=stderr;
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
precompile(Tuple{Type{Base.Generator{I, F} where F where I}, Pkg.Types.var"#52#55"{String, String}, Array{Any, 1}})
precompile(Tuple{typeof(Base.collect_similar), Array{Any, 1}, Base.Generator{Array{Any, 1}, Pkg.Types.var"#52#55"{String, String}}})
precompile(Tuple{Pkg.Types.var"#52#55"{String, String}, Base.Dict{String, Any}})
precompile(Tuple{Type{Array{Dates.DateTime, 1}}, UndefInitializer, Tuple{Int64}})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Dates.DateTime, 1}, Dates.DateTime, Base.Generator{Array{Any, 1}, Pkg.Types.var"#52#55"{String, String}}, Int64})
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt64, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{UInt64}, Base.IdDict{Any, Any}})
precompile(Tuple{typeof(Base.Ryu.writefixed), Float64, Int64})
  0.110661 seconds (134.34 k allocations: 10.412 MiB, 96.54% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})
  0.009558 seconds (9.16 k allocations: 830.914 KiB, 77.94% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.001870 seconds (3.44 k allocations: 406.727 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.001649 seconds (3.44 k allocations: 406.727 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.001662 seconds (3.44 k allocations: 407.023 KiB)
5 Likes