Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

First kernel launch recompiles ~2.7 s of precompiled compiler code on Julia 1.12

Open
#593 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
julia

Research direction

Start by reproducing the first-launch compile timing with the Julia snippet on 1.12.7 and 1.13.2, then inspect the listed invalidation sources: GPUArrays src/host/mapreduce.jl, LLVM.jl src/core/type.jl, and OpenCL.jl src/compiler/precompile.jl. The issue identifies fixes across GPUArrays, Base.Compiler, LLVM.jl, and OpenCL.jl, so first trace which invalidations still occur. Done means addressing the invalidations and adding a fresh-session test that verifies the first kernel launch does not recompile.

Written by the indexing model from the issue text.

Description

On Julia 1.12, the first kernel launch of a fresh session spends 2.6–2.7 s recompiling code that was already precompiled. Most of that is GPUCompiler's inference code, which gets invalidated when GPUArrays is loaded.

using OpenCL, pocl_jll
a = CLArray([1f0])
Base.cumulative_compile_timing(true)
c0, r0 = Base.cumulative_compile_time_ns()
t = @elapsed (b = a .+ 1f0; Array(b))
c1, r1 = Base.cumulative_compile_time_ns()
println(VERSION, ": first broadcast ", round(Int, t*1000), " ms, compile ", round(Int, (c1-c0)/1e6), " ms, recompile ", round(Int, (r1-r0)/1e6), " ms")

OpenCL.jl 1.0.0, pocl_jll 7.2.2, GPUCompiler 2.18.0, GPUArrays 12.1.1, KernelAbstractions 0.10.3, on an M3 Pro (PoCL CPU device):

1.12.7: first broadcast 5668 ms, compile 5586 ms, recompile 2630 ms
1.13.2: first broadcast 3794 ms, compile 3755 ms, recompile 221 ms

--trace-compile-timing on 1.12.7 shows these entries marked # recompile:

2202.2 ms  Base.Compiler.typeinf_local(::GPUCompiler.GPUInterpreter{CachedMethodTable{StackedMethodTable{…}}}, …)
 135.2 ms  GPUCompiler.AddKernelState(::LLVM.Module)
  22.3 ms  GPUCompiler.LowerKernelState(::LLVM.Function)
   7.6 ms  GPUCompiler.LinkRuntime(::LLVM.Module)
   6.7 ms  Base.Compiler.finish_nocycle(::GPUInterpreter{…}, …)
   3.6 ms  kwcall(typeinf_type; interp::GPUInterpreter{…})

What gets invalidated, from SnoopCompile on using OpenCL, pocl_jll:

  • typeinf_local and friends (1.12 only). KernelAbstractions' precompile workload compiles a kernel for its POCL back-end, which puts typeinf_local(::GPUInterpreter{…}) into KA's package image. The interpreter type is the same one OpenCL.jl uses. GPUArrays, which loads after KA, adds any(f::Function, A::AnyGPUArray; dims) (src/host/mapreduce.jl:180). That method supersedes the any(::closure, ::AbstractArray) instances that Base.Compiler's inference calls (compileable_specialization and others), 1627 invalidations in total. It is the only inserted method whose invalidation tree reaches typeinf_local(::GPUInterpreter…). On 1.13 it no longer reaches it. The fix probably belongs in GPUArrays (a narrower any signature) or in Base.Compiler (a concretely typed any), not in OpenCL.jl.
  • AddKernelState and LowerKernelState, on 1.12 and 1.13. They are invalidated by the kernel_state_type(::CompilerJob{SPIRVCompilerTarget, …}) methods that KernelAbstractions' POCL back-end and OpenCL.jl add.
  • compile_or_lookup(::CompilerJob{SPIRVCompilerTarget, OpenCLCompilerParams}), which src/compiler/precompile.jl precompiles, is also invalidated, when AcceleratedKernels' OpenCLExt adds reduce_tuning(::OpenCLBackend, ::Type). The abstract call that leads there is in LLVM.jl: isemptytype(::StructType) = all(isemptytype, elements(T)) (src/core/type.jl:630) recurses into itself, so inference widens it to all(::Function, ::StructTypeElementSet), which reaches GPUArrays' and AcceleratedKernels' reductions. CUDA.jl, oneAPI.jl and Metal.jl are affected by the same thing on 1.12. Rewriting it as a loop fixes it there; for CUDA.jl that removes ~300 ms of recompilation from the first launch.

Separately, OpenCL.jl's precompile workload doesn't compile or launch a kernel, so the first launch always compiles clfunction's lookup and link path from scratch. Before adding that to the workload, the invalidations above need to be fixed, or that code would be recompiled anyway. Metal.jl went through this in JuliaGPU/Metal.jl#1116, which also adds a test that the first launch in a fresh session doesn't recompile anything.

Dominant language
Julia
Stars
313
Forks
50
Avg merge
1d 9h
Merged PRs (30d)
43

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from JuliaGPU/OpenCL.jl

All issues in JuliaGPU/OpenCL.jl

Similar issues

More Julia issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.