Skip to content

Commit 73725e6

Browse files
Monishver11leofang
andauthored
Fix/default stream singletons (#1496)
* fix: Make legacy_default() and per_thread_default() return singletons - Fixes #1494 Signed-off-by: Monishver Chandrasekaran <monishverchandrasekaran@gmail.com> * fix to avoid the circular initialization issue Signed-off-by: Monishver Chandrasekaran <monishverchandrasekaran@gmail.com> * Revert "feat: Make legacy_default and per_thread_default public - Fixes #1445" This reverts commit 61b5de2. * Made LEGACY_DEFAULT_STREAM and PER_THREAD_DEFAULT_STREAM available from cuda.core namespace & Reverted helper methods to private (_legacy_default, _per_thread_default) Signed-off-by: Monishver Chandrasekaran <monishverchandrasekaran@gmail.com> * Added release/0.6.0-notes.rst Signed-off-by: Monishver Chandrasekaran <monishverchandrasekaran@gmail.com> --------- Signed-off-by: Monishver Chandrasekaran <monishverchandrasekaran@gmail.com> Co-authored-by: Leo Fang <leof@nvidia.com>
1 parent d5a9757 commit 73725e6

4 files changed

Lines changed: 47 additions & 61 deletions

File tree

cuda_core/cuda/core/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@
6161
)
6262
from cuda.core._module import Kernel, ObjectCode # noqa: E402
6363
from cuda.core._program import Program, ProgramOptions # noqa: E402
64-
from cuda.core._stream import Stream, StreamOptions # noqa: E402
64+
from cuda.core._stream import ( # noqa: E402
65+
LEGACY_DEFAULT_STREAM,
66+
PER_THREAD_DEFAULT_STREAM,
67+
Stream,
68+
StreamOptions,
69+
)

cuda_core/cuda/core/_stream.pyx

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -104,49 +104,13 @@ cdef class Stream:
104104
return s
105105

106106
@classmethod
107-
def legacy_default(cls):
108-
"""Return the legacy default stream.
109-
110-
The legacy default stream is an implicit stream which synchronizes
111-
with all other streams in the same CUDA context except for non-blocking
112-
streams. When any operation is launched on the legacy default stream,
113-
it waits for all previously launched operations in blocking streams to
114-
complete, and all subsequent operations in blocking streams wait for
115-
the legacy default stream operation to complete.
116-
117-
Returns
118-
-------
119-
Stream
120-
The legacy default stream instance for the current context.
121-
122-
See Also
123-
--------
124-
per_thread_default : Per-thread default stream alternative.
125-
126-
"""
107+
def _legacy_default(cls):
108+
"""Return the legacy default stream (supports subclassing)."""
127109
return Stream._from_handle(cls, get_legacy_stream())
128110

129111
@classmethod
130-
def per_thread_default(cls):
131-
"""Return the per-thread default stream.
132-
133-
The per-thread default stream is local to both the calling thread and
134-
the CUDA context. Unlike the legacy default stream, it does not
135-
synchronize with other streams and behaves like an explicitly created
136-
non-blocking stream. This allows for better concurrency in multi-threaded
137-
applications.
138-
139-
Returns
140-
-------
141-
Stream
142-
The per-thread default stream instance for the current thread
143-
and context.
144-
145-
See Also
146-
--------
147-
legacy_default : Legacy default stream alternative.
148-
149-
"""
112+
def _per_thread_default(cls):
113+
"""Return the per-thread default stream (supports subclassing)."""
150114
return Stream._from_handle(cls, get_per_thread_stream())
151115

152116
@classmethod
@@ -405,8 +369,8 @@ cdef class Stream:
405369

406370

407371
# c-only python objects, not public
408-
cdef Stream C_LEGACY_DEFAULT_STREAM = Stream.legacy_default()
409-
cdef Stream C_PER_THREAD_DEFAULT_STREAM = Stream.per_thread_default()
372+
cdef Stream C_LEGACY_DEFAULT_STREAM = Stream._legacy_default()
373+
cdef Stream C_PER_THREAD_DEFAULT_STREAM = Stream._per_thread_default()
410374

411375
# standard python objects, public
412376
LEGACY_DEFAULT_STREAM = C_LEGACY_DEFAULT_STREAM
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
.. SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
.. SPDX-License-Identifier: Apache-2.0
3+
4+
.. currentmodule:: cuda.core
5+
6+
``cuda.core`` 0.6.0 Release Notes
7+
==================================
8+
9+
New features
10+
------------
11+
12+
- Added public access to default CUDA streams via module-level constants ``LEGACY_DEFAULT_STREAM`` and ``PER_THREAD_DEFAULT_STREAM``
13+
14+
Users can now access default streams directly from the ``cuda.core`` namespace:
15+
16+
.. code-block:: python
17+
18+
from cuda.core import LEGACY_DEFAULT_STREAM, PER_THREAD_DEFAULT_STREAM
19+
20+
# Use legacy default stream (synchronizes with all blocking streams)
21+
LEGACY_DEFAULT_STREAM.sync()
22+
23+
# Use per-thread default stream (non-blocking, thread-local)
24+
PER_THREAD_DEFAULT_STREAM.sync()
25+
26+
The legacy default stream synchronizes with all blocking streams in the same CUDA context, ensuring strict ordering but potentially limiting concurrency. The per-thread default stream is local to the calling thread and does not synchronize with other streams, enabling concurrent execution in multi-threaded applications.
27+
28+
This replaces the previous undocumented workaround of using ``Stream.from_handle(0)`` to access the legacy default stream.
29+
30+
Fixes and enhancements
31+
-----------------------
32+
33+
None.

cuda_core/tests/test_stream.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -117,34 +117,18 @@ def test_stream_legacy_default_subclassing():
117117
class MyStream(Stream):
118118
pass
119119

120-
stream = MyStream.legacy_default()
120+
stream = MyStream._legacy_default()
121121
assert isinstance(stream, MyStream)
122122

123123

124124
def test_stream_per_thread_default_subclassing():
125125
class MyStream(Stream):
126126
pass
127127

128-
stream = MyStream.per_thread_default()
128+
stream = MyStream._per_thread_default()
129129
assert isinstance(stream, MyStream)
130130

131131

132-
def test_stream_legacy_default_public_api(init_cuda):
133-
"""Test public legacy_default() method."""
134-
stream = Stream.legacy_default()
135-
assert isinstance(stream, Stream)
136-
# Verify it's the same as LEGACY_DEFAULT_STREAM
137-
assert stream == LEGACY_DEFAULT_STREAM
138-
139-
140-
def test_stream_per_thread_default_public_api(init_cuda):
141-
"""Test public per_thread_default() method."""
142-
stream = Stream.per_thread_default()
143-
assert isinstance(stream, Stream)
144-
# Verify it's the same as PER_THREAD_DEFAULT_STREAM
145-
assert stream == PER_THREAD_DEFAULT_STREAM
146-
147-
148132
# ============================================================================
149133
# Stream Equality Tests
150134
# ============================================================================

0 commit comments

Comments
 (0)