Skip to content

Add an integrated profiler to oneAPI.@profile - #730

Merged
maleadt merged 2 commits into
mainfrom
tb/profile-pti
Oct 23, 2026
Merged

maleadt merged 2 commits into
mainfrom
tb/profile-pti

Conversation

@maleadt

@maleadt maleadt commented Oct 21, 2026

Copy link
Copy Markdown
Member

Stacked on #729. Draft until PTI_jll is registered (JuliaPackaging/Yggdrasil#15262).

With external=true (#729), oneAPI.jl can restrict an external profiler to a region, but getting a quick overview of where time goes still requires installing and launching unitrace or VTune. CUDA.jl and Metal.jl have an integrated @profile that shows host and device activity in the REPL.

This adds that on top of Intel's Profiling Tools Interfaces for GPU (PTI), the library behind PyTorch's XPU profiler and the closest analogue to CUPTI's activity API. It records the Level Zero API calls made by the process and the kernels, copies and fills executed on the device, with correlation IDs linking them. Because it hooks the Level Zero loader, it also captures the work oneAPI.jl batches and the work oneMKL submits itself:

julia> oneAPI.@profile begin
           c = a * a
           copyto!(b, c)
       end
Profiled over 5.1 ms.

Host-side activity: 33 Level Zero API calls taking 1.22 ms (24.02% of wall-clock)
[...]

Device-side activity: GPU was busy for 551.25 µs (10.81% of wall-clock)
┌──────────┬────────────┬───────┬────────────────────────────────────┐
│ Time (%) │ Total time │ Calls │ Name                               │
├──────────┼────────────┼───────┼────────────────────────────────────┤
│    9.80% │  499.48 µs │     1 │ sgemm_nocopy_nn_16x16_8x4          │
│    1.02% │   51.77 µs │     1 │ zeCommandListAppendMemoryCopy(D2D) │
└──────────┴────────────┴───────┴────────────────────────────────────┘

trace=true gives a chronological trace, raw=true includes polls for unfinished work, and oneAPI.@bprofile profiles repeated execution. As in CUDA.jl, @profile defaults to the external profiler when Julia runs under one. The display code is adapted from Metal.jl.

PTI calls its buffer callbacks from its own threads, including from a static destructor at exit; with Julia callbacks the process hung at exit. PTI_jll therefore ships a small C library implementing those callbacks, and Julia processes the queued buffers after flushing. PTI_jll's libraries are only loaded on first use. Self-instrumenting with event timestamps (Metal.jl's approach) was rejected: it would reimplement PTI, and miss oneMKL's submissions.

Costs: new dependencies on PTI_jll, PrettyTables, Crayons and Statistics; using oneAPI takes about 50 ms longer (mostly PrettyTables). After a profile, kernel launches are about 1% slower (2.65 vs 2.62 µs), as PTI keeps the tracing layer installed. Integrated profiling is x86_64 Linux only.

Tested on an Arc A770 with Julia 1.10 and 1.13. This needs PTI_jll to be registered first (JuliaPackaging/Yggdrasil#15262).

@maleadt
maleadt force-pushed the tb/profile-pti branch 2 times, most recently from 24c3f9b to 9fde747 Compare October 21, 2026 10:46
@maleadt
maleadt marked this pull request as ready for review October 21, 2026 13:53
@github-actions

Copy link
Copy Markdown
Contributor

Documentation preview: https://juliagpu.github.io/oneAPI.jl/previews/PR730/

@codecov

codecov Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.73684% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.23%. Comparing base (7020223) to head (8135b85).

Files with missing lines Patch % Lines
src/profiling.jl 94.56% 13 Missing ⚠️
lib/pti/PTI.jl 93.10% 2 Missing ⚠️
src/profile.jl 97.22% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #730      +/-   ##
==========================================
+ Coverage   85.08%   85.23%   +0.14%     
==========================================
  Files          53       54       +1     
  Lines        4660     4829     +169     
==========================================
+ Hits         3965     4116     +151     
- Misses        695      713      +18     

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

Base automatically changed from tb/profile-external to main October 22, 2026 10:03
PTI (Profiling Tools Interfaces for GPU) records the Level Zero API calls a
process makes and the kernels, copies and fills that execute on the device,
much like CUPTI's activity API. The wrappers are generated from PTI_jll's
headers like those for Level Zero.

PTI calls its buffer callbacks from its own threads, including while the
process exits, where Julia code would hang. PTI_jll's libpti_buffers
implements them in C instead, and `PTI.foreach_record` processes the queued
buffers. The libraries are only loaded when first used.
Without `external=true`, `oneAPI.@profile` now collects the activity of the
given code with PTI, and shows the Level Zero API calls made by the host and
the kernels, copies and fills that executed on the device, as a summary or,
with `trace=true`, as a chronological trace in which correlation IDs link
the API calls to the operations they submitted. This includes the work that
oneAPI.jl batches and the work that oneMKL submits. `oneAPI.@bprofile` runs
code repeatedly and reports the aggregated results.

Like CUDA.jl, `oneAPI.@profile` defaults to the external profiler when Julia
runs under one. The display code is adapted from Metal.jl's profiler.
@maleadt
maleadt merged commit e00acd7 into main Oct 23, 2026
5 checks passed
@maleadt
maleadt deleted the tb/profile-pti branch October 23, 2026 19:48
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