Skip to content

[SYCL] Release deferred resources after event and queue waits - #23344

Merged
KornevNikita merged 5 commits into
intel:syclfrom
ldorau:SYCL_Proactively_release_deferred_resources_after_event_wait
Oct 9, 2026
Merged

KornevNikita merged 5 commits into
intel:syclfrom
ldorau:SYCL_Proactively_release_deferred_resources_after_event_wait

Conversation

@ldorau

@ldorau ldorau commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Deferred buffers, images and auxiliary resources can otherwise remain
alive until later scheduler activity or runtime shutdown. Release completed
resources after event waits, and sweep deferred resources after queue waits
so completed resources attached to other events are released too.

Use event-indexed auxiliary cleanup for targeted event waits, keeping
unrelated incomplete events from being polled. Destroy extracted resources
outside their mutex to allow destructor-triggered nested waits. Recheck
resources after slow-path waits and avoid reserving space for the entire
auxiliary-resource map when only a few entries are complete.

Publish the Scheduler pointer atomically and guard its lifetime during
wait-triggered cleanup. Preserve cleanup in wait tracing and avoid waiting
for scheduler-access guards during Windows process termination.

Add scheduler tests for nested waits, slow-path registration, targeted
event polling, scheduler lifetime synchronization, and queue-wait cleanup.

This is an improvement in resource lifetime and cleanup behavior.
It releases completed deferred resources after waits
instead of leaving them alive until later scheduler activity
or runtime shutdown. That can reduce memory retained
by long-running applications and avoid resources -
and the queues or contexts they keep alive - persisting through shutdown.

Fixes: #22233
Fixes: #20852

@ldorau
ldorau requested a review from slawekptak October 1, 2026 10:43
@ldorau

ldorau commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Please review @slawekptak

@ldorau

ldorau commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

All Windows CI jobs passed. Now enabling all CI jobs ...

@ldorau
ldorau force-pushed the SYCL_Proactively_release_deferred_resources_after_event_wait branch from c477d64 to 397cf0f Compare October 2, 2026 06:29
@ldorau
ldorau marked this pull request as ready for review October 2, 2026 06:29
@ldorau
ldorau requested a review from a team as a code owner October 2, 2026 06:29
@slawekptak
slawekptak requested a balanced review from Copilot October 2, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The lock-free scheduler lookup introduces a data race and possible dangling-pointer access.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Proactively releases completed SYCL scheduler resources after event::wait() to avoid deferred lifetime leaks.

Changes:

  • Tracks deferred resources with an atomic counter.
  • Triggers non-blocking cleanup after applicable event waits.
  • Adds unit coverage and re-enables Windows leak tests.
File Description
sycl/​source/​detail/​event_impl.cpp Initiates deferred cleanup after waits.
sycl/​source/​detail/​global_handler.hpp Declares scheduler lookup API.
sycl/​source/​detail/​global_handler.cpp Implements scheduler lookup.
sycl/​source/​detail/​scheduler/​scheduler.hpp Adds deferred-resource tracking.
sycl/​source/​detail/​scheduler/​scheduler.cpp Maintains the resource counter.
sycl/​unittests/​scheduler/​GraphCleanup.cpp Tests wait-triggered cleanup.
sycl/​test-e2e/​Reduction/​reduction_resource_leak_usm.cpp Re-enables Windows coverage.
sycl/​test-e2e/​Reduction/​reduction_resource_leak_dw.cpp Re-enables Windows coverage.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread sycl/source/detail/global_handler.cpp Outdated

@iclsrc iclsrc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the proactive deferred-resource release in event_impl::wait() plus the supporting Scheduler::MDeferredResourcesCount atomic counter and GlobalHandler::getSchedulerIfAlive() accessor. I traced every increment/decrement site for the counter (cleanupCommands, deferMemObjRelease, cleanupDeferredMemObjects, takeAuxiliaryResources, registerAuxiliaryResources, cleanupAuxiliaryResources) against each insertion/removal from MDeferredCleanupCommands, MDeferredMemObjRelease, and MAuxiliaryResources, including the takeAuxiliaryResources merge-into-existing-entry edge case, and the bookkeeping is balanced throughout. The WaitedViaScheduler short-circuit in event_impl::wait() correctly avoids a redundant release pass when Scheduler::waitForEvent() already performed one via cleanupCommands. getSchedulerIfAlive() mirrors the existing lock-free isSchedulerAlive() pattern, so no new thread-safety concern is introduced. Relaxed memory ordering on the counter is appropriate given it's documented as a best-effort hint, with actual releases still happening under the respective mutexes. The new AuxiliaryResourcesReleasedOnWait unit test and the re-enabled Windows E2E tests (reduction_resource_leak_dw.cpp, reduction_resource_leak_usm.cpp) are consistent with and validate the stated goal. No correctness, security, or test-coverage issues found.

@ldorau
ldorau requested review from iclsrc and a balanced review from Copilot October 2, 2026 08:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The cleanup path introduces re-entrant deadlock and Scheduler lifetime risks, while also ending XPTI tracing prematurely.

Review effort: Balanced
Findings: 3 High severity

Open (3)
Previously missed (1)

In code that hasn't changed since last review

Low severity Wait-end trace emitted before resource release completes

sycl/​source/​detail/​event_impl.cpp:429

trace_wait_end is emitted before this newly added work, so XPTI reports event::wait() as finished while releaseResources() is still running. Contention or cleanup cost will therefore be omitted from wait profiles and the trace's call ordering can precede the actual return. Move the instrumentation epilog after this cleanup, as queue_impl::wait() does after all of its wait work.

Comment thread sycl/source/detail/event_impl.cpp Outdated
Comment thread sycl/source/detail/global_handler.cpp Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Windows shutdown can spin indefinitely when a terminated thread leaves a scheduler access count outstanding.

Review effort: Balanced
Findings: 2 High severity

Open (2)
Resolved since last review (2)

Comment thread sycl/source/detail/global_handler.cpp Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The new scheduler teardown synchronization lacks deterministic concurrency coverage.

Review effort: Balanced
Findings: 1 High severity · 1 Medium severity

Open (2)
Resolved since last review (1)

Comment thread sycl/source/detail/global_handler.cpp

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Auxiliary-resource destruction can deadlock during nested waits, and slow-path waits can still leave newly deferred resources unreleased.

Review effort: Balanced
Findings: 2 High severity · 1 Medium severity

Open (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Slow-path wait can retain resources after cleanup

sycl/​source/​detail/​event_impl.cpp:410

The scheduler slow path is not guaranteed to leave the deferred sets empty. waitForEvent() calls cleanupCommands(), which drains deferred resources before deleting the commands; those deletions can themselves defer new memory objects (the post-cleanup case documented in Scheduler::releaseResources()). Marking every slow-path wait as already cleaned therefore skips the only final pass and can still retain resources after the application's last wait. Check the counter after both wait paths; it remains lock-free and avoids the extra pass when cleanup really completed.

Comment thread sycl/source/detail/scheduler/scheduler.cpp

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Blocking auxiliary cleanup can still release resources while holding its mutex, allowing nested waits to deadlock.

Review effort: Balanced
Findings: 2 High severity · 1 Medium severity

Open (3)
Resolved since last review (1)

Comment thread sycl/source/detail/scheduler/scheduler.cpp
@ldorau ldorau changed the title [SYCL] Proactively release deferred resources after event::wait() [SYCL] Release deferred resources after event and queue waits Oct 5, 2026
@ldorau
ldorau force-pushed the SYCL_Proactively_release_deferred_resources_after_event_wait branch from 191958f to 86615be Compare October 5, 2026 07:42
Deferred buffers, images and auxiliary resources can otherwise remain
alive until later scheduler activity or runtime shutdown. Release completed
resources after event waits, and sweep deferred resources after queue waits
so completed resources attached to other events are released too.

Use event-indexed auxiliary cleanup for targeted event waits, keeping
unrelated incomplete events from being polled. Destroy extracted resources
outside their mutex to allow destructor-triggered nested waits. Recheck
resources after slow-path waits and avoid reserving space for the entire
auxiliary-resource map when only a few entries are complete.

Publish the Scheduler pointer atomically and guard its lifetime during
wait-triggered cleanup. Preserve cleanup in wait tracing and avoid waiting
for scheduler-access guards during Windows process termination.

Add scheduler tests for nested waits, slow-path registration, targeted
event polling, scheduler lifetime synchronization, and queue-wait cleanup.

Fixes: intel#22233
Fixes: intel#20852

Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Scheduler lifetime synchronization and Windows shutdown behavior are concurrency-sensitive and warrant final human review.

Review effort: Balanced
Findings: None

@iclsrc iclsrc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round-2 review: Re-examined the SchedulerAccess RAII guard (GlobalHandler), the atomic generation/counter bookkeeping added to Scheduler (MDeferredResourcesCount, MAuxiliaryResourcesGeneration), and the Windows shutdown-ordering fix (ProcessTerminating / stopSchedulerAccess). All increment/decrement pairs across cleanupCommands, cleanupDeferredMemObjects, registerAuxiliaryResources, takeAuxiliaryResources, and both blocking/non-blocking cleanupAuxiliaryResources paths (including the exception-retry path) are consistent. The Windows skip-wait path during process termination is correctly scoped to the case where other threads are already OS-terminated, matching the existing CanJoinThreads semantics in this file. No Critical or Important issues found in this round.

@slawekptak

Copy link
Copy Markdown
Contributor

With the additional logic added to event::wait(), could you please make sure there is no performance impact for the fast path benchmarks we have (probably it makes sense to focus on the tests which include the completion path)?

@ldorau

ldorau commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

SYCL benchmarks started: https://github.com/intel/llvm/actions/runs/37304711992

@ldorau

ldorau commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

@sys-ce-bb

Copy link
Copy Markdown
Contributor

@intel/llvm-gatekeepers please consider merging

@ldorau

ldorau commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Could you review this PR? @uditagarwal97 @KseniyaTikhomirova @sergey-semenov

@bratpiorka
bratpiorka marked this pull request as draft October 7, 2026 09:25
@ldorau

ldorau commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

This PR is marked as a draft, because it is waiting for review from: @sergey-semenov

@sergey-semenov sergey-semenov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach LGTM, just a few non-blocking nitpicks

GraphProcessor::waitForEvent(Event, Lock, ToCleanUp,
/*LockTheLock=*/false, Success);
cleanupCommands(ToCleanUp);
cleanupCommands(ToCleanUp, false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cleanupCommands(ToCleanUp, false);
cleanupCommands(ToCleanUp, /*ScanAuxiliaryResources*/false);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

bool ScanAuxiliaryResources) {
const uint64_t Generation =
MAuxiliaryResourcesGeneration.load(std::memory_order_relaxed);
cleanupCommands({}, false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


#pragma once

#include <atomic>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This belongs with the rest of the standard library includes below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@ldorau
ldorau marked this pull request as ready for review October 8, 2026 20:27
@ldorau

ldorau commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

The approach LGTM, just a few non-blocking nitpicks

I have applied them all. Thank you very much!

- Name the ScanAuxiliaryResources argument at cleanupCommands() call sites.
- Move #include <atomic> to the standard library includes.
@ldorau

ldorau commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

The two tests which this patch was supposed to fix failed again in the same way - converting to draft ...

@ldorau
ldorau marked this pull request as draft October 9, 2026 11:51
The L0 loader on Windows CI (v1.32.0) does not count events created with
the core zeEventCounterBasedCreate API, so their zeEventDestroy calls are
reported by the UR_L0_LEAKS_DEBUG leak checker as a negative leak
("LEAK = -7"). This makes the re-enabled reduction_resource_leak_dw.cpp
and reduction_resource_leak_usm.cpp tests fail on Windows with
a false-positive leak.

Apply the same temporary workaround as in commit 3733672
("[SYCL][E2E] Temporarily ignore negative L0 leak counts on Windows"), see
intel@3733672
on Windows ignore only negative leak counts, so real (positive) leaks are
still detected; Linux keeps the full check. The workaround should be
reverted once the L0 loader on Windows CI is updated.

Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
@ldorau
ldorau marked this pull request as ready for review October 9, 2026 13:50
@ldorau

ldorau commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

The two tests which this patch was supposed to fix failed again in the same way - converting to draft ...

It was caused by too old version of L0 loader on Windows - see d800470.

@ldorau

ldorau commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Please merge @intel/llvm-gatekeepers

@KornevNikita
KornevNikita merged commit 14d7548 into intel:sycl Oct 9, 2026
45 of 46 checks passed
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.

test-e2e/Regression/reduction_resource_leak_usm.cpp fails on Win Regression/reduction_resource_leak_dw.cpp failing on Win

7 participants