Skip to content

ensurecompiled: load the packages instead of precompiling them - #1127

Closed
levy wants to merge 1 commit into
JuliaLang:masterfrom
levy:pr-ensurecompiled
Closed

levy wants to merge 1 commit into
JuliaLang:masterfrom
levy:pr-ensurecompiled

Conversation

@levy

@levy levy commented Sep 14, 2026

Copy link
Copy Markdown

ensurecompiled only has to leave a cache that the sysimage build can read. That build runs with --pkgimages=no, so it needs the source-only cache, and loading the packages writes it.

Pkg.precompile() gets there too, but it scans the depot first and rejects every pkgimage-backed cache under that flag. The cost then tracks the depot, not the project: 45.6 s on a depot of 15 324 files, against 0.45 s with pkgimages, for a call that precompiled nothing.

Assisted-by: Claude Code (Opus 5)

@KristofferC

Copy link
Copy Markdown
Member

not the project: 45.6 s on a depot of 15 324 files, against 0.45 s with pkgimages, for a call that precompiled nothing.

This seems kind of crazy numbers... A no-op Pkg.precompile() takes 45 seconds? And loading a package has to do the same search as Pkg.precompile for already existing valid precompile images to load so what is the savings coming from. Something here seems a bit odd.

@codecov

codecov Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.32%. Comparing base (89b8b25) to head (0101903).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1127      +/-   ##
==========================================
- Coverage   84.11%   74.32%   -9.79%     
==========================================
  Files           3        3              
  Lines         900      892       -8     
==========================================
- Hits          757      663      -94     
- Misses        143      229      +86     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@levy

levy commented Sep 15, 2026

Copy link
Copy Markdown
Author

not the project: 45.6 s on a depot of 15 324 files, against 0.45 s with pkgimages, for a call that precompiled nothing.

This seems kind of crazy numbers... A no-op Pkg.precompile() takes 45 seconds? And loading a package has to do the same search as Pkg.precompile for already existing valid precompile images to load so what is the savings coming from. Something here seems a bit odd.

Oh, I'll check this again and come back with the results.

`ensurecompiled` only has to leave a cache that the sysimage build can read.
That build runs with `--pkgimages=no`, so it needs the source-only cache, and
loading the packages writes it.

`Pkg.precompile()` reaches the same state, but under `--pkgimages=no` Pkg's own
native code is not available, so the first call in a process compiles Pkg's
precompile path from IR. `ensurecompiled` starts a fresh process every build,
so it pays that every time.

On `examples/MyApp` with a warm depot of 381 packages, all with
`--pkgimages=no`: `using Pkg; Pkg.precompile()` takes 28.7 s and 26.8 s on
repeat, `import MyApp` takes 0.6 s and 0.6 s. In one process the first
`Pkg.precompile()` costs 21.1 s and the second 0.0 s.

Assisted-by: Claude Code (Opus 5)
@levy
levy force-pushed the pr-ensurecompiled branch from 75183e6 to 0101903 Compare September 15, 2026 10:12
@levy

levy commented Sep 15, 2026

Copy link
Copy Markdown
Author

not the project: 45.6 s on a depot of 15 324 files, against 0.45 s with pkgimages, for a call that precompiled nothing.

This seems kind of crazy numbers... A no-op Pkg.precompile() takes 45 seconds? And loading a package has to do the same search as Pkg.precompile for already existing valid precompile images to load so what is the savings coming from. Something here seems a bit odd.

Disclaimer: the following is an AI response which I reviewed and verified. I admit that I'm not fully sure if we are correct and this really is an issue to be fixed. If you still believe we are on the wrong track here then let me know and I'll close this PR. Edited AI response follows:

Fair challenge, the explanation was wrong but the number holds.

It is not a depot scan because a scan would repeat. Three calls in one process with --pkgimages=no: 21.06 s, then 0.0 s, then 0.0 s. Under that flag Pkg's native code is not available, so the first call compiles Pkg's own precompile path from IR. using Pkg alone is 0.5 s, so it is not the loading either. With pkgimages the same call is 0.4 s.

import never enters that machinery — loading is Base's job and Base has its native code in the sysimage. On examples/MyApp, --pkgimages=no, warm depot of 381 packages: Pkg.precompile() 28.7 s then 26.8 s; import MyApp 0.6 s then 0.6 s. ensurecompiled starts a fresh process per build, so it pays that build.

I have fixed the comment and the description, which both said "scans the depot".

These are the measurements which support the claim:

projectured@valarmorghulis:~/workspace/omnet-julia$ mkdir -p /tmp/pkgtest/empty
printf 'name = "EmptyProj"\nuuid = "aaaaaaaa-1111-2222-3333-444444444444"\n' > /tmp/pkgtest/empty/Project.toml
export JULIA_DEPOT_PATH="/tmp/pkgtest/depot:$HOME/.julia:"
export JULIA_LOAD_PATH="/tmp/pkgtest/empty:@stdlib"
projectured@valarmorghulis:~/workspace/omnet-julia$ # 1. the headline, on a project with no dependencies at all
time julia --startup-file=no                -e 'using Pkg; Pkg.precompile()'
time julia --startup-file=no --pkgimages=no -e 'using Pkg; Pkg.precompile()'

# 2. it is not the loading of Pkg
time julia --startup-file=no --pkgimages=no -e 'using Pkg'

# 3. it is not a scan, and it is compilation — this is the one that proves it
julia --startup-file=no --pkgimages=no -e '
using Pkg
print("first  "); @time Pkg.precompile()
print("second "); @time Pkg.precompile()'
     Project No packages added to or removed from `/tmp/pkgtest/empty/Project.toml`
    Manifest No packages added to or removed from `/tmp/pkgtest/empty/Manifest.toml`

real	0m0.934s
user	0m1.911s
sys	0m0.135s

real	0m24.990s
user	0m25.955s
sys	0m0.361s

real	0m0.470s
user	0m1.743s
sys	0m0.071s
first   20.854511 seconds (17.73 M allocations: 974.606 MiB, 1.20% gc time, 99.98% compilation time)
second   0.000996 seconds (2.20 k allocations: 155.484 KiB)
projectured@valarmorghulis:~/workspace/omnet-julia$ export JULIA_LOAD_PATH="/home/projectured/workspace/package-compiler-pr/examples/MyApp:@stdlib"
time julia --startup-file=no --pkgimages=no -e 'using Pkg; Pkg.precompile()'
time julia --startup-file=no --pkgimages=no -e 'import MyApp'
Precompiling packages finished.
  7 dependencies successfully precompiled in 2 seconds. 32 already precompiled.

real	0m27.895s
user	0m30.456s
sys	0m0.933s

real	0m0.578s
user	0m1.828s
sys	0m0.077s

@KristofferC

Copy link
Copy Markdown
Member

#1131 should be the better version of this, feel free to try it out

@levy

levy commented Sep 16, 2026

Copy link
Copy Markdown
Author

I tried your version and it works as expected. You can close this PR once the other one gets merged in.

Thank you!

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.

3 participants