Skip to content

Compile a representative kernel in the precompilation workload - #1070

Open
maleadt wants to merge 2 commits into
mainfrom
tb/precompile-native
Open

maleadt wants to merge 2 commits into
mainfrom
tb/precompile-native

Conversation

@maleadt

@maleadt maleadt commented Oct 28, 2026

Copy link
Copy Markdown
Member

GPUCompiler's precompilation workload only compiled an empty kernel, so many of the LLVM.jl and GPUCompiler methods that every back-end runs while compiling a kernel (IR walkers, metadata and debug-info accessors, exception lowering) ended up in GPUCompiler's package image as inferred code without native code. Back-ends reach these through dynamic dispatch, and a downstream package image can't add native code to a CodeInstance that already lives in an upstream image (JuliaLang/julia#58465), so the first kernel of every session JIT-compiles them. On Julia 1.12/1.13 that is a large part of the ~250 ms the first @metal kernel takes on an M1, of which only ~15 ms is GPU-side work.

The workload now compiles a kernel with bounds-checked accesses to a minimal device array (so exceptions get lowered), a loop, Float16 arithmetic and a few math intrinsics, still for the native target with the dummy job. It doesn't link the runtime (the #601 Windows workaround stays), so the dummy job declares the runtime's gpu_* functions as intrinsics for validation. This removes about 20 methods from what both Metal.jl and CUDA.jl compile for their first kernel: on an M1 with Julia 1.13 the first new kernel goes from ~360 to ~300 ms (1.12: ~335 to ~245 ms; measured under load, so noisy), for 554 kB more image and about a second more precompilation. Load time is unchanged.

Most of what is still compiled at run time is reached from back-end-specific code in GPUCompiler (src/metal.jl, src/ptx.jl) through dynamic dispatch, which no generic workload can cover; making those call sites type-stable is a separate change.

The second commit loads the tree-sitter grammars from HighlightsExt, their only user, instead of when loading GPUCompiler (~10 ms of using GPUCompiler). They stay regular dependencies so that they're installed for the extension.

The workload only compiled an empty kernel, so many LLVM.jl and
GPUCompiler methods that every back-end calls while compiling a kernel
(IR walkers, debug-info and metadata accessors, exception lowering)
were only inferred into GPUCompiler's package image, without native
code. Back-ends reach them through dynamic dispatch, and their own
images cannot provide that code (JuliaLang/julia#58465), so the first
kernel of every session compiled them.

Compile a kernel with bounds-checked array accesses, a loop, Float16
arithmetic and math intrinsics instead. This removes about 20 methods
from what Metal.jl and CUDA.jl compile for their first kernel.
Loading the four grammar JLLs took about 10 ms of every `using
GPUCompiler`, while only HighlightsExt uses them. They stay regular
dependencies so that they're installed for the extension, which loads
them instead.
@maleadt
maleadt force-pushed the tb/precompile-native branch from 01acfc4 to 482f804 Compare October 28, 2026 15:11
@codecov

codecov Bot commented Oct 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.83333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.49%. Comparing base (daab6f8) to head (482f804).

Files with missing lines Patch % Lines
src/precompile.jl 95.23% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1070   +/-   ##
=======================================
  Coverage   92.49%   92.49%           
=======================================
  Files          31       31           
  Lines        7313     7332   +19     
=======================================
+ Hits         6764     6782   +18     
- Misses        549      550    +1     

☔ 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.

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.

1 participant