Skip to content

Recycle command lists submitted to explicit queues - #713

Merged
maleadt merged 2 commits into
mainfrom
tb/explicit-queue-cmdlists
Oct 19, 2026
Merged

maleadt merged 2 commits into
mainfrom
tb/explicit-queue-cmdlists

Conversation

@maleadt

@maleadt maleadt commented Oct 19, 2026

Copy link
Copy Markdown
Member

oneL0.execute!(f, queue::ZeCommandQueue) created a command list for every submission and left its destruction to the finalizer. Each list holds about 1.3 MB of driver memory (NEO 26.35, Linux) that Julia's GC doesn't know about. NEO also keeps that memory around for reuse after the list is destroyed. So a loop of `@oneapi` queue=... launches used gigabytes of host memory before a GC happened to run, and didn't get it back afterwards. This is #327. #610 already fixed it for the default submission path; the explicit-queue path still had it.

The queue now keeps the lists it submitted, each with a fence. Once a list's fence has signaled, the list is reset and reused. The fences are raw handles owned by the queue, because Level Zero requires them to be destroyed before their queue. Lists that fail to submit are kept but never reused. Passing a fence or list keyword arguments still creates a fresh list, since a submission can carry only one fence.

Measured on an Iris Xe, launching a kernel 5000 times with queue=ZeCommandQueue(...):

system memory used after GC.gc(true)
main 6.5 GB 6.0 GB
this PR no growth (within ±150 MB noise)

The first commit only moves the queue-side execute! methods into cmdqueue.jl and includes cmdlist.jl first, so the queue type can refer to ZeCommandList.

Fixes #327

Moves the execute! methods that submit to a ZeCommandQueue next to the
queue type, so that the queue can refer to command lists.
execute!(f, queue) created a command list per submission and left its
destruction to the GC, which doesn't know about the driver memory each
list holds (about 1.3 MB with NEO on Linux). Launching a kernel in a loop
with `@oneapi` queue=... thus used gigabytes of host memory before a GC
happened to run, and NEO keeps that memory for reuse rather than returning
it. #610 removed this from the default submission path; the explicit-queue
path still did it.

Keep the submitted lists on the queue with a fence each, and reset and
reuse them once the fence has signaled. A list per submission is still
created when the caller passes its own fence or list flags.

Fixes #327
@maleadt maleadt added the bug label Oct 19, 2026
@maleadt maleadt added runtime Host runtime: devices, queues/streams, synchronization, memory management, multi-device, profiling. and removed bug labels Oct 19, 2026
@codecov

codecov Bot commented Oct 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.57%. Comparing base (e95e38f) to head (d2b5ac1).

Files with missing lines Patch % Lines
lib/level-zero/cmdqueue.jl 95.45% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #713      +/-   ##
==========================================
- Coverage   84.08%   83.57%   -0.51%     
==========================================
  Files          52       51       -1     
  Lines        4386     4299      -87     
==========================================
- Hits         3688     3593      -95     
- Misses        698      706       +8     

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

@maleadt
maleadt merged commit 0555e0d into main Oct 19, 2026
6 of 7 checks passed
@maleadt
maleadt deleted the tb/explicit-queue-cmdlists branch October 19, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

runtime Host runtime: devices, queues/streams, synchronization, memory management, multi-device, profiling.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leak when running GPU broadcast in a loop

1 participant