Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precompile Pkg.activate() #3540

Merged
merged 10 commits into from Nov 1, 2023
Merged

Conversation

mkitti
Copy link
Contributor

@mkitti mkitti commented Jul 5, 2023

Pkg.activate is a necessary first step for running executable Julia scripts.
For a novice Julia user, it is often easier to provide them with a script to run simply via julia script.jl.

script.jl may contain the following contents.

#!/bin/env julia
using Pkg
Pkg.activate("/path/to/the/right/environment")
using PackageInEnvironment
...

While trying to build such scripts, I found that Pkg.activate is contributing some latency.

Activating the environment at https://github.com/mkitti/ScriptUtils.jl/tree/main/examples/Echo.jl
can take 100 to 200 milliseconds on my computer, with most of the time being compilation. Even a
second activation requires an additional 40 mlliseconds of compilation time.

$ julia --project=. -e 'using Pkg; for i in 1:5; @time Pkg.activate("."); end'
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.106829 seconds (159.75 k allocations: 11.833 MiB, 97.05% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.042188 seconds (81.92 k allocations: 5.750 MiB, 95.15% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.001958 seconds (3.76 k allocations: 419.430 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.001606 seconds (3.76 k allocations: 419.180 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.001637 seconds (3.76 k allocations: 419.133 KiB)

Alternating between the default environment and the current directory, also seems to involve compilation
up to four activations.

$ julia --project=. -e 'using Pkg; for i in 1:5; @time Pkg.activate("."); @time Pkg.activate(); end'
  Activating project at `~/src/Pkg.jl`
  0.115365 seconds (73.03 k allocations: 5.318 MiB, 99.10% compilation time)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.9`
  0.124273 seconds (166.67 k allocations: 12.133 MiB, 97.72% compilation time)
  Activating project at `~/src/Pkg.jl`
  0.004956 seconds (742 allocations: 76.609 KiB, 88.74% compilation time)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.9`
  0.038794 seconds (81.91 k allocations: 5.739 MiB, 94.59% compilation time)
  Activating project at `~/src/Pkg.jl`
  0.000546 seconds (727 allocations: 75.516 KiB)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.9`
  0.001853 seconds (3.77 k allocations: 417.180 KiB)
  Activating project at `~/src/Pkg.jl`
  0.000377 seconds (728 allocations: 75.812 KiB)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.9`
  0.001656 seconds (3.77 k allocations: 417.273 KiB)
  Activating project at `~/src/Pkg.jl`
  0.000365 seconds (727 allocations: 75.516 KiB)
  Activating project at `/tmp/tmp.298dOvl2Nq/environments/v1.9`
  0.001650 seconds (3.77 k allocations: 417.180 KiB)

As such I propose adding four Pkg.activate calls to the Pkg.jl precompilation script, alternating
between the default environment and TestPkg.jl.

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

I enhanced this now activate all the pakcages in test/test_packages, twice.

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

With these changes with Julia master, I get the following results.

$ ./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{typeof(Base.Ryu.writefixed), Float64, Int64})
  0.003658 seconds (5.78 k allocations: 546.281 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.002774 seconds (5.09 k allocations: 497.031 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.002456 seconds (5.10 k allocations: 497.078 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.002447 seconds (5.09 k allocations: 497.031 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.002454 seconds (5.10 k allocations: 497.328 KiB)

$ ./julia -e 'using Pkg; for i in 1:5; @time Pkg.activate("/home/mkitti/src/Pkg.jl"); end' --trace-compile=stderr;
  Activating project at `~/src/Pkg.jl`
  0.000935 seconds (859 allocations: 84.102 KiB)
  Activating project at `~/src/Pkg.jl`
  0.000373 seconds (650 allocations: 69.570 KiB)
  Activating project at `~/src/Pkg.jl`
  0.000350 seconds (650 allocations: 69.570 KiB)
  Activating project at `~/src/Pkg.jl`
  0.000341 seconds (650 allocations: 69.570 KiB)
  Activating project at `~/src/Pkg.jl`
  0.000332 seconds (650 allocations: 69.570 KiB)

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

One compilation I noticed is addressed via JuliaLang/julia#50416

@KristofferC
Copy link
Sponsor Member

I don't see any compilation after the first activate call:

❯ julia -e 'using Pkg; for i in 1:5; Pkg.activate("ScriptUtils/examples/Echo.jl"); end' --trace-compile=stderr --startup=no 
precompile(Tuple{Type{Base.Generator{I, F} where F where I}, Pkg.Types.var"#52#55", Array{Any, 1}})
precompile(Tuple{typeof(Base.collect_similar), Array{Any, 1}, Base.Generator{Array{Any, 1}, Pkg.Types.var"#52#55"}})
precompile(Tuple{Pkg.Types.var"#52#55", 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"}, Int64})
precompile(Tuple{typeof(Base.convert), Type{Base.Dict{String, Union{Array{String, 1}, String}}}, Base.Dict{String, Any}})
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt64, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{UInt64}, Base.IdDict{Any, Any}})
precompile(Tuple{Type{Pkg.Registry.RegistryInstance}, String, String, Base.UUID, String, String, Base.Dict{Base.UUID, Pkg.Registry.PkgEntry}, Base.SHA1, Base.Dict{String, String}, Base.Dict{String, Base.UUID}})
  Activating new project at `~/JuliaTests/ScriptUtils/examples/Echo.jl`
  Activating new project at `~/JuliaTests/ScriptUtils/examples/Echo.jl`
  Activating new project at `~/JuliaTests/ScriptUtils/examples/Echo.jl`
  Activating new project at `~/JuliaTests/ScriptUtils/examples/Echo.jl`
  Activating new project at `~/JuliaTests/ScriptUtils/examples/Echo.jl`

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

Here's what I saw from Julia 1.9.0:

$ 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", Array{Any, 1}})
precompile(Tuple{typeof(Base.collect_similar), Array{Any, 1}, Base.Generator{Array{Any, 1}, Pkg.Types.var"#52#55"}})
precompile(Tuple{Pkg.Types.var"#52#55", 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"}, 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.deepcopy_internal), Tuple{String}, Base.IdDict{Any, Any}})
precompile(Tuple{typeof(Base.prettyprint_getunits), Int64, Int64, Int64})
precompile(Tuple{typeof(Base.Ryu.writefixed), Float64, Int64})
  0.117172 seconds (161.46 k allocations: 11.924 MiB, 95.91% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID})
precompile(Tuple{typeof(Base.map), typeof(tuple), Tuple{Int64, Int64}})
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})
precompile(Tuple{typeof(Base.ident_cmp), Tuple{String}, Tuple{String}})
  0.047357 seconds (83.56 k allocations: 5.837 MiB, 93.41% compilation time)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.002882 seconds (5.40 k allocations: 508.227 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.004105 seconds (5.40 k allocations: 507.930 KiB)
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  0.003065 seconds (5.40 k allocations: 507.930 KiB)

@KristofferC
Copy link
Sponsor Member

KristofferC commented Jul 5, 2023

Probably doesn't matter but 1.9.1 is the latest version so always use that. Also, remove @time and run with --startup-file=no for less noise.

From what I see, this PR calls Pkg.activate 8 times? Surely, that can't be needed?

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

Here is Julia 1.9.2 (release-1.9 branch) without @time and --startup-file=no.

$ ./julia -e 'using Pkg; for i in 1:5; Pkg.activate("/home/mkitti/.julia/dev/ScriptUtils/examples/Echo.jl"); end' --trace-compile=stderr --startup-file=no
  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.deepcopy_internal), Tuple{String}, Base.IdDict{Any, Any}})
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID})
precompile(Tuple{typeof(Base.map), typeof(tuple), Tuple{Int64, Int64}})
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})
precompile(Tuple{typeof(Base.ident_cmp), Tuple{String}, Tuple{String}})
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
  Activating project at `~/.julia/dev/ScriptUtils/examples/Echo.jl`
$ ./julia -e "using InteractiveUtils; versioninfo()"
Julia Version 1.9.1
Commit 8ce556d9da* (2023-06-30 20:07 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 8 × AMD FX(tm)-8350 Eight-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, bdver1)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_DEPOT_PATH = /tmp/tmp.298dOvl2Nq

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

I ran the following excerpt with Julia 1.9.2:

test.jl:

import Pkg
test_packages_path = abspath(joinpath(dirname(pathof(Pkg)), ".." ,"test", "test_packages"))
for i in 1:2, test_package in readdir(test_packages_path) Pkg.activate(joinpath(test_packages_path, test_package)) end
`$ time ./julia --trace-compile=stderr --startup-file=no test.jl`
$ time ./julia --trace-compile=stderr --startup-file=no test.jl
precompile(Tuple{typeof(Base.pathof), Module})
  Activating project at `@stdlib/A`
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})
  Activating project at `@stdlib/ActiveProjectInTestSubgraph`
  Activating project at `@stdlib/ArtifactInstallation`
  Activating project at `@stdlib/ArtifactOverrideLoading`
  Activating new project at `@stdlib/ArtifactTOMLSearch`
  Activating project at `@stdlib/AugmentedPlatform`
  Activating project at `@stdlib/BasicCompat`
precompile(Tuple{typeof(Pkg.Types.read_project_compat), Base.Dict{String, Any}, Pkg.Types.Project})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64}})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Pkg.Versions.semver_interval), Base.RegexMatch})
precompile(Tuple{typeof(Base.push!), Array{Pkg.Versions.VersionRange, 1}, Pkg.Versions.VersionRange})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Int64, Vararg{Int64}})
precompile(Tuple{typeof(Pkg.Versions.inequality_interval), Base.RegexMatch})
  Activating project at `@stdlib/BasicSandbox`
  Activating project at `@stdlib/BasicTestTarget`
  Activating project at `@stdlib/BigProject`
  Activating project at `@stdlib/BuildProjectFixedDeps`
  Activating project at `@stdlib/CompatExtras`
  Activating project at `@stdlib/CompatOutOfSync`
  Activating project at `@stdlib/DependsOnExample`
  Activating project at `@stdlib/EmptyPackage`
  Activating project at `@stdlib/Example`
  Activating new project at `@stdlib/ExtensionExamples`
  Activating project at `@stdlib/ExtraDirectDep`
  Activating project at `@stdlib/FailBuild`
  Activating new project at `@stdlib/MainRepo`
  Activating project at `@stdlib/NotUpdated`
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{String}, Base.IdDict{Any, Any}})
  Activating project at `@stdlib/PackageWithDependency`
  Activating project at `@stdlib/SameNameDifferentUUID`
  Activating project at `@stdlib/SandboxFallback2`
  Activating project at `@stdlib/Sandbox_PreservePreferences`
  Activating project at `@stdlib/Sandbox_PreserveTestDeps`
  Activating project at `@stdlib/ShouldPreserveAll`
  Activating project at `@stdlib/ShouldPreserveDirect`
  Activating project at `@stdlib/ShouldPreserveNone`
  Activating project at `@stdlib/ShouldPreserveSemver`
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt64, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{UInt64}, Base.IdDict{Any, Any}})
  Activating project at `@stdlib/SimplePackage`
  Activating project at `@stdlib/Status`
  Activating project at `@stdlib/TOML`
  Activating project at `@stdlib/TestArguments`
  Activating project at `@stdlib/TestDepCompat`
  Activating project at `@stdlib/TestDepTrackingPath`
  Activating project at `@stdlib/TestDepTrackingRepo`
  Activating project at `@stdlib/TestFailure`
  Activating project at `@stdlib/TestSubgraphTrackingRepo`
  Activating project at `@stdlib/TestTarget`
  Activating project at `@stdlib/TestTargetCompat`
  Activating project at `@stdlib/TransferSubgraph`
  Activating project at `@stdlib/Unpruned`
  Activating project at `@stdlib/UnregisteredUUID`
  Activating project at `@stdlib/UnregisteredWithProject`
  Activating new project at `@stdlib/force_latest_compatible_version`
  Activating project at `@stdlib/monorepo`
  Activating project at `@stdlib/x1`
  Activating project at `@stdlib/x2`
  Activating project at `@stdlib/x3`
  Activating project at `@stdlib/A`
precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID})
  Activating project at `@stdlib/ActiveProjectInTestSubgraph`
  Activating project at `@stdlib/ArtifactInstallation`
  Activating project at `@stdlib/ArtifactOverrideLoading`
  Activating new project at `@stdlib/ArtifactTOMLSearch`
  Activating project at `@stdlib/AugmentedPlatform`
  Activating project at `@stdlib/BasicCompat`
  Activating project at `@stdlib/BasicSandbox`
  Activating project at `@stdlib/BasicTestTarget`
  Activating project at `@stdlib/BigProject`
  Activating project at `@stdlib/BuildProjectFixedDeps`
  Activating project at `@stdlib/CompatExtras`
  Activating project at `@stdlib/CompatOutOfSync`
  Activating project at `@stdlib/DependsOnExample`
  Activating project at `@stdlib/EmptyPackage`
  Activating project at `@stdlib/Example`
  Activating new project at `@stdlib/ExtensionExamples`
  Activating project at `@stdlib/ExtraDirectDep`
  Activating project at `@stdlib/FailBuild`
  Activating new project at `@stdlib/MainRepo`
  Activating project at `@stdlib/NotUpdated`
precompile(Tuple{typeof(Base.map), typeof(tuple), Tuple{Int64, Int64}})
precompile(Tuple{typeof(Base.ident_cmp), Tuple{String}, Tuple{String}})
  Activating project at `@stdlib/PackageWithDependency`
  Activating project at `@stdlib/SameNameDifferentUUID`
  Activating project at `@stdlib/SandboxFallback2`
  Activating project at `@stdlib/Sandbox_PreservePreferences`
  Activating project at `@stdlib/Sandbox_PreserveTestDeps`
  Activating project at `@stdlib/ShouldPreserveAll`
  Activating project at `@stdlib/ShouldPreserveDirect`
  Activating project at `@stdlib/ShouldPreserveNone`
  Activating project at `@stdlib/ShouldPreserveSemver`
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})
  Activating project at `@stdlib/SimplePackage`
  Activating project at `@stdlib/Status`
  Activating project at `@stdlib/TOML`
  Activating project at `@stdlib/TestArguments`
  Activating project at `@stdlib/TestDepCompat`
  Activating project at `@stdlib/TestDepTrackingPath`
  Activating project at `@stdlib/TestDepTrackingRepo`
  Activating project at `@stdlib/TestFailure`
  Activating project at `@stdlib/TestSubgraphTrackingRepo`
  Activating project at `@stdlib/TestTarget`
  Activating project at `@stdlib/TestTargetCompat`
  Activating project at `@stdlib/TransferSubgraph`
  Activating project at `@stdlib/Unpruned`
  Activating project at `@stdlib/UnregisteredUUID`
  Activating project at `@stdlib/UnregisteredWithProject`
  Activating new project at `@stdlib/force_latest_compatible_version`
  Activating project at `@stdlib/monorepo`
  Activating project at `@stdlib/x1`
  Activating project at `@stdlib/x2`
  Activating project at `@stdlib/x3`

real	0m0.913s
user	0m0.804s
sys	0m0.293s

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

I could probably be more selective about the test package list if you would like.

Perhaps something like this based on Julia 1.9.2 results?

  Activating project at `@stdlib/A`
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})
  Activating project at `@stdlib/BasicCompat`
precompile(Tuple{typeof(Pkg.Types.read_project_compat), Base.Dict{String, Any}, Pkg.Types.Project})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64}})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Pkg.Versions.semver_interval), Base.RegexMatch})
precompile(Tuple{typeof(Base.push!), Array{Pkg.Versions.VersionRange, 1}, Pkg.Versions.VersionRange})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Int64, Vararg{Int64}})
precompile(Tuple{typeof(Pkg.Versions.inequality_interval), Base.RegexMatch})
  Activating project at `@stdlib/NotUpdated`
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{String}, Base.IdDict{Any, Any}})
  Activating project at `@stdlib/ShouldPreserveSemver`
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt64, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{UInt64}, Base.IdDict{Any, Any}})
  Activating project at `@stdlib/A`
precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID})
  Activating project at `@stdlib/NotUpdated`
precompile(Tuple{typeof(Base.map), typeof(tuple), Tuple{Int64, Int64}})
precompile(Tuple{typeof(Base.ident_cmp), Tuple{String}, Tuple{String}})
  Activating project at `@stdlib/ShouldPreserveSemver`
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})

@mkitti
Copy link
Contributor Author

mkitti commented Jul 5, 2023

On Julia master:

`$ time ./julia --trace-compile=stderr --startup-file=no test.jl` with Julia Version 1.11.0-DEV.14
$ ./julia -e "using InteractiveUtils; versioninfo()"
Julia Version 1.11.0-DEV.14
Commit 23c0418899* (2023-07-05 13:30 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 8 × AMD FX(tm)-8350 Eight-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, bdver1)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_DEPOT_PATH = /tmp/tmp.298dOvl2Nq

$ time ./julia --trace-compile=stderr --startup-file=no test.jl
precompile(Tuple{typeof(Base.pathof), Module})
  Activating project at `@stdlib/A`
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})
  Activating project at `@stdlib/ActiveProjectInTestSubgraph`
  Activating project at `@stdlib/ArtifactInstallation`
  Activating project at `@stdlib/ArtifactOverrideLoading`
  Activating new project at `@stdlib/ArtifactTOMLSearch`
  Activating project at `@stdlib/AugmentedPlatform`
  Activating project at `@stdlib/BasicCompat`
precompile(Tuple{typeof(Pkg.Types.read_project_compat), Base.Dict{String, Any}, Pkg.Types.Project})
precompile(Tuple{typeof(Base.getproperty), Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#4#5"}, Base.BottomRF{typeof(Base.add_sum)}}, Symbol})
precompile(Tuple{Pkg.Versions.var"#4#5", Nothing})
precompile(Tuple{Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#4#5"}, Base.BottomRF{typeof(Base.add_sum)}}, Int64, Nothing})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64}})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Pkg.Versions.semver_interval), Base.RegexMatch})
precompile(Tuple{typeof(Base.push!), Array{Pkg.Versions.VersionRange, 1}, Pkg.Versions.VersionRange})
precompile(Tuple{typeof(Base.getproperty), Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#6#7"}, Base.BottomRF{typeof(Base.add_sum)}}, Symbol})
precompile(Tuple{Pkg.Versions.var"#6#7", Nothing})
precompile(Tuple{Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#6#7"}, Base.BottomRF{typeof(Base.add_sum)}}, Int64, Nothing})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Int64, Vararg{Int64}})
precompile(Tuple{typeof(Pkg.Versions.inequality_interval), Base.RegexMatch})
  Activating project at `@stdlib/BasicSandbox`
  Activating project at `@stdlib/BasicTestTarget`
  Activating project at `@stdlib/BigProject`
  Activating project at `@stdlib/BuildProjectFixedDeps`
  Activating project at `@stdlib/CompatExtras`
  Activating project at `@stdlib/CompatOutOfSync`
  Activating project at `@stdlib/DependsOnExample`
  Activating project at `@stdlib/EmptyPackage`
  Activating project at `@stdlib/Example`
  Activating new project at `@stdlib/ExtensionExamples`
  Activating project at `@stdlib/ExtraDirectDep`
  Activating project at `@stdlib/FailBuild`
  Activating project at `@stdlib/HDF5`
precompile(Tuple{typeof(Base.convert), Type{Base.Dict{String, Union{Array{String, 1}, String}}}, Base.Dict{String, Any}})
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt64, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{UInt64}, Base.IdDict{Any, Any}})
  Activating new project at `@stdlib/MainRepo`
  Activating project at `@stdlib/NotUpdated`
  Activating project at `@stdlib/PackageWithDependency`
  Activating project at `@stdlib/RecurringPrecompile`
  Activating project at `@stdlib/SameNameDifferentUUID`
  Activating project at `@stdlib/SandboxFallback2`
  Activating project at `@stdlib/Sandbox_PreservePreferences`
  Activating project at `@stdlib/Sandbox_PreserveTestDeps`
  Activating project at `@stdlib/ShouldPreserveAll`
  Activating project at `@stdlib/ShouldPreserveDirect`
  Activating project at `@stdlib/ShouldPreserveNone`
  Activating project at `@stdlib/ShouldPreserveSemver`
  Activating project at `@stdlib/SimplePackage`
  Activating project at `@stdlib/Status`
  Activating project at `@stdlib/TOML`
  Activating project at `@stdlib/TestArguments`
  Activating project at `@stdlib/TestDepCompat`
  Activating project at `@stdlib/TestDepTrackingPath`
  Activating project at `@stdlib/TestDepTrackingRepo`
  Activating project at `@stdlib/TestFailure`
  Activating project at `@stdlib/TestSubgraphTrackingRepo`
  Activating project at `@stdlib/TestTarget`
  Activating project at `@stdlib/TestTargetCompat`
  Activating project at `@stdlib/TransferSubgraph`
  Activating project at `@stdlib/Unpruned`
  Activating project at `@stdlib/UnregisteredUUID`
  Activating project at `@stdlib/UnregisteredWithProject`
  Activating new project at `@stdlib/force_latest_compatible_version`
  Activating project at `@stdlib/monorepo`
  Activating project at `@stdlib/x1`
  Activating project at `@stdlib/x2`
  Activating project at `@stdlib/x3`
  Activating project at `@stdlib/A`
precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID})
  Activating project at `@stdlib/ActiveProjectInTestSubgraph`
  Activating project at `@stdlib/ArtifactInstallation`
  Activating project at `@stdlib/ArtifactOverrideLoading`
  Activating new project at `@stdlib/ArtifactTOMLSearch`
  Activating project at `@stdlib/AugmentedPlatform`
  Activating project at `@stdlib/BasicCompat`
  Activating project at `@stdlib/BasicSandbox`
  Activating project at `@stdlib/BasicTestTarget`
  Activating project at `@stdlib/BigProject`
  Activating project at `@stdlib/BuildProjectFixedDeps`
  Activating project at `@stdlib/CompatExtras`
  Activating project at `@stdlib/CompatOutOfSync`
  Activating project at `@stdlib/DependsOnExample`
  Activating project at `@stdlib/EmptyPackage`
  Activating project at `@stdlib/Example`
  Activating new project at `@stdlib/ExtensionExamples`
  Activating project at `@stdlib/ExtraDirectDep`
  Activating project at `@stdlib/FailBuild`
  Activating project at `@stdlib/HDF5`
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})
  Activating new project at `@stdlib/MainRepo`
  Activating project at `@stdlib/NotUpdated`
  Activating project at `@stdlib/PackageWithDependency`
  Activating project at `@stdlib/RecurringPrecompile`
  Activating project at `@stdlib/SameNameDifferentUUID`
  Activating project at `@stdlib/SandboxFallback2`
  Activating project at `@stdlib/Sandbox_PreservePreferences`
  Activating project at `@stdlib/Sandbox_PreserveTestDeps`
  Activating project at `@stdlib/ShouldPreserveAll`
  Activating project at `@stdlib/ShouldPreserveDirect`
  Activating project at `@stdlib/ShouldPreserveNone`
  Activating project at `@stdlib/ShouldPreserveSemver`
  Activating project at `@stdlib/SimplePackage`
  Activating project at `@stdlib/Status`
  Activating project at `@stdlib/TOML`
  Activating project at `@stdlib/TestArguments`
  Activating project at `@stdlib/TestDepCompat`
  Activating project at `@stdlib/TestDepTrackingPath`
  Activating project at `@stdlib/TestDepTrackingRepo`
  Activating project at `@stdlib/TestFailure`
  Activating project at `@stdlib/TestSubgraphTrackingRepo`
  Activating project at `@stdlib/TestTarget`
  Activating project at `@stdlib/TestTargetCompat`
  Activating project at `@stdlib/TransferSubgraph`
  Activating project at `@stdlib/Unpruned`
  Activating project at `@stdlib/UnregisteredUUID`
  Activating project at `@stdlib/UnregisteredWithProject`
  Activating new project at `@stdlib/force_latest_compatible_version`
  Activating project at `@stdlib/monorepo`
  Activating project at `@stdlib/x1`
  Activating project at `@stdlib/x2`
  Activating project at `@stdlib/x3`

real	0m1.044s
user	0m0.889s
sys	0m0.342s

@mkitti
Copy link
Contributor Author

mkitti commented Jul 6, 2023

I narrowed down the list. Here are the precompile statements that I attribute to activating each project.

  Activating project at `@stdlib/A`
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})

  Activating project at `@stdlib/BasicCompat`
precompile(Tuple{typeof(Pkg.Types.read_project_compat), Base.Dict{String, Any}, Pkg.Types.Project})
precompile(Tuple{typeof(Base.getproperty), Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#4#5"}, Base.BottomRF{typeof(Base.add_sum)}}, Symbol})
precompile(Tuple{Pkg.Versions.var"#4#5", Nothing})
precompile(Tuple{Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#4#5"}, Base.BottomRF{typeof(Base.add_sum)}}, Int64, Nothing})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64}})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Pkg.Versions.semver_interval), Base.RegexMatch})
precompile(Tuple{typeof(Base.push!), Array{Pkg.Versions.VersionRange, 1}, Pkg.Versions.VersionRange})
precompile(Tuple{typeof(Base.getproperty), Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#6#7"}, Base.BottomRF{typeof(Base.add_sum)}}, Symbol})
precompile(Tuple{Pkg.Versions.var"#6#7", Nothing})
precompile(Tuple{Base.MappingRF{Base.var"#324#325"{Pkg.Versions.var"#6#7"}, Base.BottomRF{typeof(Base.add_sum)}}, Int64, Nothing})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Int64, Vararg{Int64}})
precompile(Tuple{typeof(Pkg.Versions.inequality_interval), Base.RegexMatch})

  Activating project at `@stdlib/HDF5`
precompile(Tuple{typeof(Base.convert), Type{Base.Dict{String, Union{Array{String, 1}, String}}}, Base.Dict{String, Any}})
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt64, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{UInt64}, Base.IdDict{Any, Any}})

  Activating project at `@stdlib/ImageMorphology`
precompile(Tuple{typeof(Base.setindex!), Base.Dict{String, Union{Array{String, 1}, String}}, Array{String, 1}, String})

  Activating project at `@stdlib/Plots`
precompile(Tuple{typeof(Pkg.Versions.hyphen_interval), Base.RegexMatch})

  Activating project at `@stdlib/A`
precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID})

  Activating project at `@stdlib/HDF5`
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})
precompile(Tuple{Pkg.API.var"##activate#305", Bool, Bool, Bool, Base.TTY, typeof(Pkg.API.activate)})

@oscardssmith
Copy link
Member

should we merge this?

@vchuravy
Copy link
Sponsor Member

Do we really need to check in Manifests?

@mkitti
Copy link
Contributor Author

mkitti commented Oct 18, 2023

We already have several manifests in test/test_packages.

I can check whether it is needed this weekend. I'm currently traveling.

@fredrikekre
Copy link
Member

There are 50+ packages in test/test_packages, and you add 3 more here? Why does Pkg.activate have to be called this many times in the precompile load?

@mkitti
Copy link
Contributor Author

mkitti commented Oct 28, 2023

I had previously selected several packages to target in Julia 1.9, but I'm not sure if those packages are still the optimal set for Julia master.

I'm rather confused on the state of precompilation though now that this is not in the system image.

@mkitti
Copy link
Contributor Author

mkitti commented Oct 28, 2023

#!./julia --trace-compile=stderr
import Pkg

function main()
    for test_packages_path in (
        abspath(joinpath(dirname(pathof(Pkg)), ".." ,"test", "test_packages")),
        joinpath(ENV["HOME"], ".julia/dev")
    )
        for i in 1:3
           @info "Starting activation run" test_packages_path
            @time for test_package in readdir(test_packages_path)
                Pkg.activate(joinpath(test_packages_path, test_package))
            end
            @info "Ending activation run"
        end
    end
end

main()

Here's what I see on the initial pass:

precompile(Tuple{typeof(Base.repeat), Char, Int64})
  Activating project at `@stdlib/A`
precompile(Tuple{typeof(Base.convert), Type{Base.Dict{String, Array{String, 1}}}, Base.Dict{String, Any}})
precompile(Tuple{typeof(Base.TOML.try_return_datetime), Base.TOML.Parser, Vararg{Int64, 7}})
precompile(Tuple{Type{Dates.DateTime}, Vararg{Int64, 7}})
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(Base.reduce_empty), Base.MappingRF{typeof(Base.identity), typeof(Base.max)}, Type{Dates.DateTime}})
precompile(Tuple{typeof(Base.maximum), Array{Dates.DateTime, 1}})
precompile(Tuple{Type{Pair{A, B} where B where A}, String, Dates.DateTime})
precompile(Tuple{typeof(Base.map), Function, Array{Base.Dict{String, Dates.DateTime}, 1}})
precompile(Tuple{typeof(TOML.Internals.Printer.is_array_of_tables), Array{Base.Dict{String, Dates.DateTime}, 1}})
precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:indent, :sorted, :by), Tuple{Int64, Bool, typeof(Base.identity)}}, typeof(Base.invokelatest), Any, Any, Vararg{Any}})
precompile(Tuple{Base.var"##invokelatest#2", Base.Pairs{Symbol, Any, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:indent, :sorted, :by), Tuple{Int64, Bool, typeof(Base.identity)}}}, typeof(Base.invokelatest), Any, Any, Vararg{Any}})
precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:indent, :sorted, :by), Tuple{Int64, Bool, typeof(Base.identity)}}, typeof(TOML.Internals.Printer.print_table), Nothing, Base.IOStream, Base.Dict{String, Dates.DateTime}, Array{String, 1}})
precompile(Tuple{typeof(TOML.Internals.Printer.is_array_of_tables), Dates.DateTime})
precompile(Tuple{Base.var"#774#775"{FileWatching.Pidfile.var"#2#4"{Base.Filesystem.File}, Base.Timer}})
precompile(Tuple{typeof(Base.similar), Array{Any, 1}})
precompile(Tuple{typeof(Base.Iterators.enumerate), Array{Any, 1}})
precompile(Tuple{typeof(Base.similar), Array{String, 1}})
precompile(Tuple{typeof(Base.Iterators.enumerate), Array{String, 1}})
precompile(Tuple{typeof(Base.setindex!), Array{String, 1}, String, Int64})
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{Union{}, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{}, Base.IdDict{Any, Any}})
precompile(Tuple{typeof(Base.deepcopy_internal), Base.Dict{String, Base.UUID}, Base.IdDict{Any, Any}})
precompile(Tuple{typeof(Base.deepcopy_internal), Base.Dict{String, Union{Array{String, 1}, String}}, Base.IdDict{Any, Any}})
precompile(Tuple{typeof(Base.deepcopy_internal), Base.Dict{String, Array{String, 1}}, Base.IdDict{Any, Any}})
precompile(Tuple{Type{GenericMemory{:not_atomic, String, Core.AddrSpace{Core}(0x00)}}, UndefInitializer, Int64})
  Activating project at `@stdlib/ActiveProjectInTestSubgraph`
  Activating project at `@stdlib/ArtifactInstallation`
  Activating project at `@stdlib/ArtifactOverrideLoading`
  Activating new project at `@stdlib/ArtifactTOMLSearch`
  Activating project at `@stdlib/AugmentedPlatform`
  Activating project at `@stdlib/BasicCompat`
precompile(Tuple{typeof(Base.getproperty), Base.MappingRF{Base.var"#341#342"{Pkg.Versions.var"#4#5"}, Base.BottomRF{typeof(Base.add_sum)}}, Symbol})
precompile(Tuple{Pkg.Versions.var"#4#5", Nothing})
precompile(Tuple{Base.MappingRF{Base.var"#341#342"{Pkg.Versions.var"#4#5"}, Base.BottomRF{typeof(Base.add_sum)}}, Int64, Nothing})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64}})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Pkg.Versions.semver_interval), Base.RegexMatch{String}})
precompile(Tuple{typeof(Base.push!), Array{Pkg.Versions.VersionRange, 1}, Pkg.Versions.VersionRange})
precompile(Tuple{typeof(Base.getproperty), Base.MappingRF{Base.var"#341#342"{Pkg.Versions.var"#6#7"}, Base.BottomRF{typeof(Base.add_sum)}}, Symbol})
precompile(Tuple{Pkg.Versions.var"#6#7", Nothing})
precompile(Tuple{Base.MappingRF{Base.var"#341#342"{Pkg.Versions.var"#6#7"}, Base.BottomRF{typeof(Base.add_sum)}}, Int64, Nothing})
precompile(Tuple{Type{Pkg.Versions.VersionBound}, Int64, Vararg{Int64}})
precompile(Tuple{typeof(Pkg.Versions.inequality_interval), Base.RegexMatch{String}})
  Activating project at `@stdlib/BasicSandbox`
  # ...
  Activating project at `@stdlib/CompatOutOfSync`
precompile(Tuple{typeof(Pkg.Types.read_project_uuid), Nothing})
  Activating project at `@stdlib/DependsOnExample`
  # ...
  Activating project at `@stdlib/NotUpdated`
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{String}, Base.IdDict{Any, Any}})
  Activating project at `@stdlib/PackageWithDependency`
  Activating project at `@stdlib/RecurringPrecompile`
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{UInt64, 1}}})
precompile(Tuple{typeof(Base.deepcopy_internal), Tuple{UInt64}, Base.IdDict{Any, Any}})
  Activating project at `@stdlib/SameNameDifferentUUID`

I'm not sure how much of that is cacheable in a pkgimage, but maybe this will be useful if this functionality is moved to Base.

@mkitti
Copy link
Contributor Author

mkitti commented Oct 28, 2023

On the second pass I see

precompile(Tuple{typeof(Base.:(==)), Base.Dict{String, Any}, Base.Dict{String, Any}})
precompile(Tuple{typeof(Base.:(==)), Base.UUID, Base.UUID})
precompile(Tuple{typeof(Base.:(==)), Base.Dict{String, Array{String, 1}}, Base.Dict{String, Array{String, 1}}})
  Activating project at `@stdlib/ActiveProjectInTestSubgraph`
precompile(Tuple{typeof(Base.:(==)), Array{String, 1}, Array{String, 1}})
  Activating project at `@stdlib/BasicCompat`
precompile(Tuple{typeof(Base.ident_cmp), Tuple{String}, Tuple{String}})
  Activating project at `@stdlib/RecurringPrecompile`
precompile(Tuple{typeof(Base.ident_cmp), Tuple{UInt64}, Tuple{UInt64}})
  Activating project at `@stdlib/SameNameDifferentUUID`

@mkitti
Copy link
Contributor Author

mkitti commented Oct 31, 2023

I removed extra packages and manifests. This is pretty straightforward now.

@oscardssmith merge?

src/precompile.jl Outdated Show resolved Hide resolved
Co-authored-by: Ian Butterworth <i.r.butterworth@gmail.com>
src/precompile.jl Outdated Show resolved Hide resolved
@vchuravy vchuravy merged commit 4b8e390 into JuliaLang:master Nov 1, 2023
12 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants