cuda::experimental::stf::launchable_graph_handle#

class launchable_graph_handle#

Handle to a cudaGraphExec_t produced by stackable_ctx::pop_prologue().

Returned by stackable_ctx::pop_prologue(), this handle exposes the graph built from the nested context and lets the user launch it repeatedly before committing the pop via pop_epilogue(). The underlying cudaGraphExec_t is instantiated lazily on the first exec()/launch() call.

All public methods assert that the handle is still valid: copying is allowed but a copy does not prolong validity. Every outstanding handle (original or copy) becomes invalid the moment pop_epilogue() runs.

Usage:

stackable_ctx ctx;
ctx.push();
// ... build graph ...
auto h = ctx.pop_prologue();
for (int i = 0; i < N; ++i) h.launch();
ctx.pop_epilogue();

Public Functions

launchable_graph_handle() = default#
inline cudaGraphExec_t exec() const#

Underlying executable graph.

Aborts if the handle is invalid.

On the first call, lazily instantiates the graph (cache lookup + cudaGraphInstantiate if not cached) and orders stream() behind the nested context’s freeze/get events (dep A) so that callers can legally drive the graph manually via cudaGraphLaunch(exec(), stream()). Subsequent calls (and any calls after a prior launch()) skip both steps.

Note: unlike graph(), calling exec() does force instantiation. Callers that only want to embed the graph as a child node in another graph should use graph() and avoid exec() entirely.

inline cudaStream_t stream() const#

Support stream the graph was prepared against.

Aborts if invalid.

Does NOT perform any stream synchronization - it is purely observational. If you plan to drive the graph manually, call exec() first (it will lazily sync), or use launch() which does both in one step.

inline void launch()#

Launch the graph once on the support stream.

On the first call, waits for the nested context’s freeze/get events (dep A). Subsequent calls skip the sync and issue the launch directly.

inline cudaGraph_t graph() const#

Underlying (non-executable) CUDA graph topology.

Returns the finalized cudaGraph_t built from the nested context, for callers who want to embed it as a child node into another graph via cudaGraphAddChildGraphNode instead of launching the pre-instantiated executable graph returned by exec().

The graph is owned by the stackable_ctx and stays valid only until pop_epilogue() is called. If you need it to outlive the epilogue, clone it with cudaGraphClone.

Unlike exec(), this accessor does NOT trigger cudaGraphInstantiate. Callers that only need the graph topology (embedding as a child graph, inspecting nodes, etc.) pay no instantiation cost as long as neither exec() nor launch() is ever called on this handle.

On the first call, graph() does perform the same lazy dep-A sync as exec() / launch() (it orders stream() behind the nested context’s freeze events). This makes handle.stream() a valid event source for ordering an outer launch stream: record an event on stream() and wait on it from your launch stream before launching the outer graph that embeds this child.

Ordering caveat: pop_epilogue() only synchronizes the support stream (dep A); it does NOT wait on whatever stream you launch the embedding outer graph on. You are therefore responsible for ensuring the embedded work has completed (e.g. via cudaStreamSynchronize on your launch stream) before calling pop_epilogue(), otherwise the unfreeze of the pushed data will race the child graph.

inline bool valid() const#

True iff the owning stackable_ctx has not yet run pop_epilogue().

inline explicit operator bool() const#