Skip to content

Capture work forked onto other streams during stream capture - #1529

Open
pvelesko wants to merge 3 commits into
2026-08-29-hipgraph-kokkos-fixesfrom
2026-08-29-github-1523-cross-stream-capture
Open

Capture work forked onto other streams during stream capture#1529
pvelesko wants to merge 3 commits into
2026-08-29-hipgraph-kokkos-fixesfrom
2026-08-29-github-1523-cross-stream-capture

Conversation

@pvelesko

Copy link
Copy Markdown
Collaborator

Stream capture now follows event dependencies onto other streams, following the ROCm clr implementation in hip_event.cpp, hip_stream.cpp and hip_graph.cpp. hipEventRecord on a capturing stream tags the event with the stream's current capture dependencies instead of adding a node, hipStreamWaitEvent on such an event joins the waiting stream into the same capture (or, for a stream already in it, merges the event's nodes into its dependencies, which is how a fork joins back), and hipStreamEndCapture returns hipErrorStreamCaptureUnmatched on a forked stream and hipErrorStreamCaptureUnjoined when a fork was never joined. The reproducer TestFix1523CrossStreamCapture forks two streams, launches one kernel on each of three streams, joins, replays the graph and checks the unjoined error; it failed with work ran during capture, slots are 0 1 1 before the fix. On OpenCL CPU the fix also makes Unit_hipStreamBeginCapture_nestedStreamCapture, Unit_hipStreamBeginCapture_streamReuse and 12 further catch graph tests pass with no new failures against the base branch. Stacked on #1522.

Fixes #1523

Capture on one stream, fork two more streams through hipEventRecord plus
hipStreamWaitEvent, launch a kernel on each, join back, end capture, and
expect nothing to have run, three nodes in the graph, all three writes
after launch, and hipErrorStreamCaptureUnjoined for a fork that never
joins. Today the forked kernels run eagerly and only the origin stream's
kernel is recorded (github issue 1523).
A stream capture records into the origin stream only; an event recorded on
the capturing stream and waited on from another stream was captured as an
event record node plus an event wait node, and the work then launched on
the other stream ran eagerly outside the graph.

Follow the CUDA/HIP cross-stream capture semantics as implemented in ROCm
clr (hip_event.cpp, hip_stream.cpp, hip_graph.cpp): hipEventRecord on a
capturing stream adds no node and instead tags the event with the stream's
current capture dependencies; hipStreamWaitEvent on such an event joins the
waiting stream into the same capture (same graph, no dependencies yet) or,
when the stream is already part of it, merges the event's nodes into its
dependencies, so a fork joins back by recording an event on the fork and
waiting on it from the origin; hipStreamEndCapture is refused with
hipErrorStreamCaptureUnmatched on a forked stream, and with
hipErrorStreamCaptureUnjoined when a leaf of the graph is not among the
origin's dependencies (a fork that never joined). Ending the capture resets
every forked stream and the events recorded during it; destroying a stream
or an event mid capture detaches it. The per queue LastNode_ becomes the
dependency set CaptureDeps_ because a join yields several dependencies.
Waiting with hipEventWaitExternal, and waiting on an event not recorded in
a capture, still record an event wait node as before.
Both pass now that stream capture follows event dependencies onto other
streams (github issue 1523).
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