Skip to content

[doc-only] cuda_core: add "10 minutes to cuda.core" tutorial to docs#2289

Merged
Andy-Jost merged 2 commits into
NVIDIA:mainfrom
sri-koundinyan:docs/cuda-core-10min
Jul 8, 2026
Merged

[doc-only] cuda_core: add "10 minutes to cuda.core" tutorial to docs#2289
Andy-Jost merged 2 commits into
NVIDIA:mainfrom
sri-koundinyan:docs/cuda-core-10min

Conversation

@sri-koundinyan

@sri-koundinyan sri-koundinyan commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This adds a beginner-friendly "10 minutes to cuda.core" guide to the cuda.core docs. It walks through the core workflow with small, runnable snippets: selecting a device, compiling a CUDA C++ kernel, allocating memory, copying, launching, timing with events, using multiple streams, capturing a CUDA graph, and interoperating with CuPy and PyTorch. The new page lives at cuda_core/docs/source/10_minutes_to_cuda_core.rst and is added to the docs table of contents between the Installation and Examples sections. All code snippets were verified to run end-to-end on CUDA 13.

@github-actions github-actions Bot added the cuda.core Everything related to the cuda.core module label Jul 1, 2026
@github-actions

This comment has been minimized.

Add a beginner-friendly "10 minutes to cuda.core" guide that walks through
the core workflow (select a device, compile a kernel, allocate memory, copy,
launch, time with events, use multiple streams, capture a CUDA graph, and
interoperate with CuPy/PyTorch), then wire it into the cuda.core docs table of
contents between the installation and examples sections.

Signed-off-by: Sri Koundinyan <skoundinyan@nvidia.com>
@sri-koundinyan sri-koundinyan force-pushed the docs/cuda-core-10min branch from 976cc4d to 046eac2 Compare July 1, 2026 18:40
@leofang leofang added the PR review get-together Mark PRs you'd like the team to review at the weekly PR review get-together. label Jul 6, 2026

@Andy-Jost Andy-Jost 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.

This looks like a great addition to the docs. Blocking merge for a few minor correctness issues but mostly it looks fine to me.

:doc:`examples <examples>` show this scaled up across multiple GPUs.


Capturing work in a CUDA graph

@Andy-Jost Andy-Jost Jul 6, 2026

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.

It's probably worth adding a sentence to note that cuda.core also provides an explicit graph interface. It can be used to build, inspect, and modify graphs (including graphs built via stream capture). There are lots of examples under cuda_core/tests/graph.

@sri-koundinyan sri-koundinyan Jul 8, 2026

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.

Good call, added a short paragraph pointing to the explicit cuda.core.graph interface with a link to the graph tests.


.. code-block:: console

$ pip install cuda-core[cu13]

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.

Square brackets require being quoted in most shells.

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


.. code-block:: python

dev = Device() # device 0 by default; Device(1) selects another GPU

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 comment is misleading. Device() returns the current device, while falling back to device 0 if none is current.

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.

Fixed: now "current device (device 0 if none is current)".

Comment on lines +79 to +81
:class:`Device` objects are thread-local singletons: ``Device(0)`` always hands
you back the same object for device 0 on that thread, so libraries sharing your
process see and use the same GPU. Rich device attributes live under

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 is a false cause-and-effect. Thread-locality is not the reason why libraries can share the same device.

What users may observe is that on a given thread Device(0) always hands back the same object for device 0, so its context, default memory resource, and cached attributes are reused rather than rebuilt on each call.

On different threads, Device(0) returns different objects bound to distinct contexts. This makes it possible to interact with CUDA from multiple threads in cuda.core.

@sri-koundinyan sri-koundinyan Jul 8, 2026

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.

Got it. Updated to include a short note (same-thread Device(0) returns the same object, so repeat calls are cheap) and left the primary-context sharing content to the interop section.

try:
Program(bad, code_type="c++", options=opts).compile("cubin")
except Exception as e:
print(e) # includes: error: identifier "not_a_real_symbol" is undefined

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.

Could say assert 'identifier "not_a_real_symbol" is undefined' in str(e)

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

Capturing work in a CUDA graph
------------------------------

When you launch the same sequence of operations repeatedly, per-launch CPU

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.

We can't use "launch" to refer to an arbitrary CUDA operation. CUDA graphs capture many types of operations, and kernel launches are only one type.

@sri-koundinyan sri-koundinyan Jul 8, 2026

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.

Reworded to "operations" rather than "launches". "launch" now only refers to launching the graph itself.

------------------------------

When you launch the same sequence of operations repeatedly, per-launch CPU
overhead adds up. A CUDA graph lets you record that sequence once and replay it

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.

"Sequence" here is potentially confusing. In general, a graph is not a sequence.

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.

Got it. Removed "sequence" from the prose and the code comment.


When you launch the same sequence of operations repeatedly, per-launch CPU
overhead adds up. A CUDA graph lets you record that sequence once and replay it
with a single launch. Use the stream's graph builder: begin building, issue the

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 graph lets you replay a computation many times without incurring the cost of CUDA API calls each time.

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.

A slight reframing: "record that work once and then launch the whole graph repeatedly, instead of re-issuing each operation every time."

ts = dev.create_stream(PyTorchStreamWrapper(torch.cuda.current_stream()))
launch(ts, config, scale, t.data_ptr(), np.float32(2.0), np.uint64(t.numel()))
ts.sync()
assert torch.allclose(t, torch.full_like(t, 2.0))

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.

Exact comparison is appropriate here. It could match line 342 exactly or at least use torch.equal instead of allclose.

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.

Yes, done

Comment on lines +412 to +414
# or scope a buffer with a with-statement:
with dev.allocate(nbytes, stream=stream) as tmp:
... # tmp is freed at the end of the block

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.

@leofang I'm surprised to see context manager support in Buffer. I'm for it, but I thought we were avoiding context managers in cuda.core. FYI, it was added in PR #1701 ("Make GraphicsResource inherit from Buffer").

Users reading this might expect other cuda.core objects with close members to support this as well. Is that something we can add?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I thought there was a special reason why graphic resource works differently. Are we teaching it here? If not, we should not teach about context managers.

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.

Removed the context-manager example

for _ in range(100):
launch(stream, config, scale, dbuf, np.float32(1.0), np.uint64(n))
stream.record(end)
end.sync()

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.

Should this be stream.sync()?

@sri-koundinyan sri-koundinyan Jul 8, 2026

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.

Thanks. I kept end.sync(). It matches the pattern in the Event docstring. But stream.sync() would also work since end is the last op.

# PyTorch: wrap torch's stream via the __cuda_stream__ protocol
import torch

class PyTorchStreamWrapper:

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 adapter is no longer needed. You can use

ts = dev.create_stream(torch.cuda.current_stream())

below.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But note my comment here: #2305 (comment)

@sri-koundinyan sri-koundinyan Jul 8, 2026

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.

Dropped the wrapper. Now dev.create_stream(torch.cuda.current_stream()) directly.

@leofang leofang added documentation Improvements or additions to documentation P1 Medium priority - Should do labels Jul 7, 2026
Mainly: fix the Device()/thread-local wording for accuracy, simplify the
PyTorch stream example (torch supports __cuda_stream__ natively), stop
teaching Buffer as a context manager, and tidy up the CUDA graph section.

Signed-off-by: Sri Koundinyan <skoundinyan@nvidia.com>

@Andy-Jost Andy-Jost 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.

Looks great, thanks for the updates.

@Andy-Jost Andy-Jost changed the title cuda_core: add "10 minutes to cuda.core" tutorial to docs [doc-only] cuda_core: add "10 minutes to cuda.core" tutorial to docs Jul 8, 2026
@Andy-Jost Andy-Jost added this to the cuda.core v1.1.0 milestone Jul 8, 2026
@Andy-Jost Andy-Jost self-assigned this Jul 8, 2026
@Andy-Jost Andy-Jost mentioned this pull request Jul 8, 2026
14 tasks
@Andy-Jost Andy-Jost merged commit b1c474c into NVIDIA:main Jul 8, 2026
104 of 106 checks passed
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Doc Preview CI
Preview removed because the pull request was closed or merged.

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 documentation Improvements or additions to documentation P1 Medium priority - Should do PR review get-together Mark PRs you'd like the team to review at the weekly PR review get-together.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants