Skip to content

feat(cuda.core): add host_launch for stream-ordered host functions - #3258

Open
Andy-Jost wants to merge 3 commits into
NVIDIA:mainfrom
Andy-Jost:ajost/host-launch
Open

Andy-Jost wants to merge 3 commits into
NVIDIA:mainfrom
Andy-Jost:ajost/host-launch

Conversation

@Andy-Jost

@Andy-Jost Andy-Jost commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

cuda.core had host callbacks for graphs but no way to enqueue one on a plain stream, so mixed host and device ordering needed cuda.bindings. This PR adds cuda.core.host_launch(stream, fn, *, user_data=None), the stream-side counterpart of GraphBuilder.callback. It enqueues a host function on a stream in stream order through cuLaunchHostFunc: a Python callable, which runs with the GIL, or a ctypes function pointer with the CUhostFn prototype, which cuda.core passes to the driver as is, so a pointer to compiled code runs without the GIL (a ctypes callback that wraps a Python function still acquires it through ctypes). The fn and user_data forms and their validation are the ones the graph callback methods already use, and a GraphBuilder argument forwards to its callback, so the same call works under stream capture.

cuda.core owns the callable and a copied user_data until the function has run. The trampoline hands the launch record to the existing deferred-cleanup queue after the user function returns, so the owners are released on the main thread, never on the driver's callback thread, where releasing a Python object would take the GIL and a finalizer could call CUDA. A plain Stream under active capture raises RuntimeError and points to GraphBuilder.callback, because the record's owners could not be attached to the captured node and the record must not be reused by graph replays. A Python exception inside the callback is reported through sys.unraisablehook and the stream continues, as on the graph path. The docstring states the driver's rules: the function must not call CUDA, and a thread that holds the GIL while blocked in a CUDA wait on the stream deadlocks with a Python callback.

Changes

  • cuda_core/cuda/core/_launcher.pyx: host_launch, exported from cuda.core.
  • cuda_core/cuda/core/_host_callback.pyx, .pxd: the shared callback helper, moved from cuda/core/graph/ unchanged; a core module must not import the graph package at module level. The three graph cimports follow.
  • cuda_core/cuda/core/_cpp/rt/host_launch.cpp: the launch record and trampoline behind one entry point, launch_host_function, declared in api.hpp, _rt.pxd, and _rt.pyx; cuLaunchHostFunc joins the driver table in driver_api.hpp.
  • cuda_core/docs/source/api.rst: host_launch next to launch; _cpp/rt/DESIGN.md and GRAPH_ATTACHMENTS.md name the new file and the queue's second producer.
  • Release-note entry for 1.3.0.
  • cuda_core/examples/host_launch.py: a host function ordered between two kernel launches, linked from docs/source/examples.rst.
  • Tests in cuda_core/tests/test_host_launch.py: ordering between prior and later stream work, release of the callable after it ran, copied bytes user_data, pass-through of an int user_data, the TypeError and ValueError cases, forwarding of a GraphBuilder with two graph launches, rejection of a capturing stream without invalidating the capture, unraisable reporting with the stream still usable, two streams keeping their own data, rejection of None, and the deprecated stream-protocol path.

Related Work

Closes #2058. The host copy function requested in #3256 builds on this.

🤖 Generated with Claude Code

Andy-Jost and others added 2 commits October 27, 2026 16:36
Add cuda.core.host_launch(stream, fn, *, user_data=None), the stream-side
counterpart of GraphBuilder.callback. It enqueues a Python callable or a
ctypes function pointer with the CUhostFn prototype on a stream through
cuLaunchHostFunc; a GraphBuilder argument forwards to its callback. The
callable and a copied user_data stay alive until the function has run and
are released afterwards on the main thread through the deferred-cleanup
queue, never on the driver thread. A plain stream under active capture is
rejected, because the owners could not be attached to the captured node.

The shared callback helper moves from cuda/core/graph/_host_callback to
cuda/core/_host_callback, since a core module must not import the graph
package at module level. The launch record and trampoline live in
_cpp/rt/host_launch.cpp, and cuLaunchHostFunc joins the driver table.

Written by Codex (gpt-6.1-sol); reviewed by Claude.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Andy-Jost Andy-Jost added this to the cuda.core 1.3.0 milestone Oct 27, 2026
@Andy-Jost Andy-Jost added P1 Medium priority - Should do feature New feature or request cuda.core Everything related to the cuda.core module labels Oct 27, 2026
@Andy-Jost Andy-Jost self-assigned this Oct 27, 2026
@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

📝 Summary

Summary by CodeRabbit

  • New Features
    • Added host_launch to enqueue Python callbacks or compatible function pointers in stream order, with optional user data.
    • Callbacks can also be recorded and replayed through graph builders.
    • Callback and user-data lifetimes are maintained until execution; callback errors are reported as unraisable Python exceptions.
    • Added an example demonstrating a host callback between stream-ordered kernel launches.
  • Documentation
    • Added API reference and release-note coverage for host_launch.

The change adds host_launch for stream-ordered Python and ctypes callbacks. It adds a runtime launch path with callback and user-data lifetime handling, forwards GraphBuilder inputs to its callback API, and includes tests, an example, and API documentation.

Changes: Host launch API

Layer / File(s) Summary
Runtime host-function launch
cuda_core/cuda/core/_cpp/rt/api.hpp, cuda_core/cuda/core/_cpp/rt/driver_api.hpp, cuda_core/cuda/core/_cpp/rt/host_launch.cpp, cuda_core/cuda/core/_rt.pxd, cuda_core/cuda/core/_rt.pyx, cuda_core/cuda/core/_cpp/rt/DESIGN.md, cuda_core/cuda/core/_cpp/rt/GRAPH_ATTACHMENTS.md
The runtime adds cuLaunchHostFunc support and retains callback and user-data owners until invocation. The trampoline queues the record for cleanup after the callback returns.
Python API and graph integration
cuda_core/cuda/core/_launcher.pyx, cuda_core/cuda/core/_launcher.pyi, cuda_core/cuda/core/_host_callback.pyi, cuda_core/cuda/core/graph/_graph_builder.pyx, cuda_core/cuda/core/graph/_graph_node.pyx, cuda_core/cuda/core/graph/_subclasses.pyx
host_launch accepts streams and forwards GraphBuilder inputs to GraphBuilder.callback. It resolves callback inputs and rejects active stream capture. Graph modules now import the callback resolver from cuda.core._host_callback.
Validation, example, and API documentation
cuda_core/tests/test_host_launch.py, cuda_core/examples/host_launch.py, cuda_core/docs/source/api.rst, cuda_core/docs/source/examples.rst, cuda_core/docs/source/release/1.3.0-notes.rst
Tests cover ordering, callback lifetime, input validation, graph behavior, exceptions, and streams. The example demonstrates a callback between two kernels. The documentation lists and describes host_launch.

Assessment against linked issues

Objective Addressed Explanation
Add a top-level API for scheduling Python callables or C function pointers in stream order [#2058] ✅
Add a corresponding HostNode type in cuda.core.graph._subclasses [#2058] ❌ The change forwards GraphBuilder inputs to GraphBuilder.callback, but does not add a HostNode type.
Document callback threading restrictions, add an example, and add API reference entries [#2058] ✅

Possibly related issues

Suggested labels: enhancement

Suggested reviewers: mdboom, juenglin

Priority: Normal

Change: Feature

Merge Risk: Low · up to 2c23d

The API already prohibits CUDA calls in callbacks, but its warning should also mention that they can deadlock. The remaining risk is limited to misuse.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@Andy-Jost Andy-Jost changed the title Merge remote-tracking branch 'origin/main' into ajost/host-launch feat(cuda.core): add host_launch for stream-ordered host functions Oct 27, 2026
State that a ctypes callback that wraps a Python function acquires the GIL
through ctypes, so the deadlock rule applies to it; complete the Raises
section; say the driver may reject CUDA calls from the callback rather than
that it does. Upcast the launch record to the cleanup base before the void*
parameter, as the graph producers do. Prove the user_data copy by changing
the caller's buffer while the stream is held, pin the unraisable type and
message, and link the example from the examples page.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 426ec5a and 2c23d6f.

Files selected for processing: 8
  • cuda_core/cuda/core/_cpp/rt/DESIGN.md
  • cuda_core/cuda/core/_cpp/rt/GRAPH_ATTACHMENTS.md
  • cuda_core/cuda/core/_cpp/rt/host_launch.cpp
  • cuda_core/cuda/core/_launcher.pyi
  • cuda_core/cuda/core/_launcher.pyx
  • cuda_core/docs/source/examples.rst
  • cuda_core/docs/source/release/1.3.0-notes.rst
  • cuda_core/tests/test_host_launch.py
Files skipped from review as they are similar to previous changes: 3
  • cuda_core/cuda/core/_cpp/rt/DESIGN.md
  • cuda_core/cuda/core/_cpp/rt/GRAPH_ATTACHMENTS.md
  • cuda_core/docs/source/release/1.3.0-notes.rst

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.

.. warning::

The function must not call CUDA, directly or through a library. The
driver does not permit such calls and may reject them with an error.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor · Stability & Availability · Quick win

suggestion: State that CUDA calls from the callback can deadlock.

The driver does not guarantee an error for a CUDA call from a host callback. Such a call can also deadlock. State that consequence here and regenerate the matching stub documentation. (docs.nvidia.com)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cuda.core Everything related to the cuda.core module feature New feature or request P1 Medium priority - Should do

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[cuda.core] Add support for host_launch (host callback nodes / host function launches)

1 participant