Skip to content

Commit 838f850

Browse files
committed
cuda.core: make Device methods use their bound context
Run context-sensitive Device operations against the Device's bound context while preserving caller state. Centralize context-aware cleanup and synchronous allocation handling so resource lifetimes remain correct.
1 parent 392f4e9 commit 838f850

29 files changed

Lines changed: 1178 additions & 448 deletions

cuda_core/cuda/core/_cpp/resource_handles.cpp

Lines changed: 404 additions & 194 deletions
Large diffs are not rendered by default.

cuda_core/cuda/core/_cpp/resource_handles.hpp

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,15 @@ void clear_last_error() noexcept;
6464
// function pointers extracted from cuda.bindings.cydriver.__pyx_capi__.
6565
// ============================================================================
6666

67+
extern decltype(&cuGetErrorName) p_cuGetErrorName;
68+
extern decltype(&cuGetErrorString) p_cuGetErrorString;
69+
6770
extern decltype(&cuDevicePrimaryCtxRetain) p_cuDevicePrimaryCtxRetain;
6871
extern decltype(&cuDevicePrimaryCtxRelease) p_cuDevicePrimaryCtxRelease;
6972
extern decltype(&cuCtxGetCurrent) p_cuCtxGetCurrent;
7073
extern decltype(&cuCtxSetCurrent) p_cuCtxSetCurrent;
74+
extern decltype(&cuCtxSynchronize) p_cuCtxSynchronize;
75+
extern decltype(&cuCtxGetStreamPriorityRange) p_cuCtxGetStreamPriorityRange;
7176
extern decltype(&cuGreenCtxCreate) p_cuGreenCtxCreate;
7277
extern decltype(&cuGreenCtxDestroy) p_cuGreenCtxDestroy;
7378
extern decltype(&cuCtxFromGreenCtx) p_cuCtxFromGreenCtx;
@@ -128,6 +133,7 @@ extern decltype(&cuGraphicsUnregisterResource) p_cuGraphicsUnregisterResource;
128133

129134
// Texture / surface / array (PR #467)
130135
extern decltype(&cuArray3DCreate) p_cuArray3DCreate;
136+
extern decltype(&cuArray3DGetDescriptor) p_cuArray3DGetDescriptor;
131137
extern decltype(&cuArrayDestroy) p_cuArrayDestroy;
132138
extern decltype(&cuMipmappedArrayCreate) p_cuMipmappedArrayCreate;
133139
extern decltype(&cuMipmappedArrayDestroy) p_cuMipmappedArrayDestroy;
@@ -246,6 +252,17 @@ ContextHandle get_primary_context(int device_id);
246252
// Returns empty handle if no context is current (caller must check)
247253
ContextHandle get_current_context();
248254

255+
// Synchronize the provided context.
256+
// Returns CUDA_ERROR_INVALID_CONTEXT for an empty handle.
257+
CUresult context_synchronize(const ContextHandle& h_context) noexcept;
258+
259+
// Query the stream priority range for the provided context.
260+
// Returns CUDA_ERROR_INVALID_CONTEXT for an empty handle.
261+
CUresult context_get_stream_priority_range(
262+
const ContextHandle& h_context,
263+
int* least_priority,
264+
int* greatest_priority) noexcept;
265+
249266
// ============================================================================
250267
// Stream handle functions
251268
// ============================================================================
@@ -371,10 +388,11 @@ DevicePtrHandle deviceptr_alloc_from_pool(
371388
// Returns empty handle on error (caller must check).
372389
DevicePtrHandle deviceptr_alloc_async(size_t size, const StreamHandle& h_stream);
373390

374-
// Allocate device memory synchronously via cuMemAlloc.
375-
// When the last reference is released, cuMemFree is called.
376-
// Returns empty handle on error (caller must check).
377-
DevicePtrHandle deviceptr_alloc(size_t size);
391+
// Allocate device memory synchronously via cuMemAlloc with the provided
392+
// context current. The caller owns the pointer and releases it with cuMemFree.
393+
// Returns CUDA_ERROR_INVALID_CONTEXT for an empty handle.
394+
CUresult deviceptr_alloc_raw(CUdeviceptr* ptr, size_t size,
395+
const ContextHandle& h_context) noexcept;
378396

379397
// Allocate pinned host memory via cuMemAllocHost.
380398
// When the last reference is released, cuMemFreeHost is called.
@@ -739,7 +757,7 @@ FileDescriptorHandle create_fd_handle_ref(int fd);
739757
// Create an owning CUDA array via cuArray3DCreate.
740758
// When the last reference is released, cuArrayDestroy is called automatically.
741759
// Returns empty handle on error (caller must check).
742-
OpaqueArrayHandle create_array_handle(const CUDA_ARRAY3D_DESCRIPTOR& desc);
760+
OpaqueArrayHandle create_array_handle(const ContextHandle& h_context, const CUDA_ARRAY3D_DESCRIPTOR& desc);
743761

744762
// Create a non-owning array handle (references an existing CUarray).
745763
// Use for arrays owned elsewhere (e.g. graphics interop). Never destroyed here.
@@ -749,6 +767,12 @@ OpaqueArrayHandle create_array_handle_ref(CUarray arr);
749767
// When the last reference is released, cuArrayDestroy is called automatically.
750768
OpaqueArrayHandle create_array_handle_owning(CUarray arr);
751769

770+
// Return the context dependency associated with an array, if known.
771+
ContextHandle get_array_context(const OpaqueArrayHandle& h) noexcept;
772+
773+
// Query an array descriptor.
774+
CUresult get_array_descriptor(const OpaqueArrayHandle& h, CUDA_ARRAY3D_DESCRIPTOR* desc) noexcept;
775+
752776
// Create a non-owning handle to a mipmap level via cuMipmappedArrayGetLevel.
753777
// The level CUarray is owned by the mipmap; the parent MipmappedArrayHandle is
754778
// embedded in the box so it outlives the level view. No destroy in the deleter.
@@ -758,27 +782,35 @@ OpaqueArrayHandle create_array_level_handle(const MipmappedArrayHandle& h_mip, u
758782
// Create an owning mipmapped array via cuMipmappedArrayCreate.
759783
// When the last reference is released, cuMipmappedArrayDestroy is called.
760784
// Returns empty handle on error (caller must check).
761-
MipmappedArrayHandle create_mipmapped_array_handle(const CUDA_ARRAY3D_DESCRIPTOR& desc,
785+
MipmappedArrayHandle create_mipmapped_array_handle(const ContextHandle& h_context,
786+
const CUDA_ARRAY3D_DESCRIPTOR& desc,
762787
unsigned int num_levels);
763788

789+
// Return the context dependency associated with a mipmapped array, if known.
790+
ContextHandle get_mipmapped_array_context(const MipmappedArrayHandle& h) noexcept;
791+
764792
// Create an owning texture object via cuTexObjectCreate, embedding the backing
765793
// resource handle (array / mipmapped array / linear-or-pitch2d device pointer)
766794
// so the backing always outlives the texture. cuTexObjectDestroy runs in the
767795
// deleter. Returns empty handle on error (caller must check).
768-
TexObjectHandle create_tex_object_handle_array(const CUDA_RESOURCE_DESC& res,
796+
TexObjectHandle create_tex_object_handle_array(const ContextHandle& h_context,
797+
const CUDA_RESOURCE_DESC& res,
769798
const CUDA_TEXTURE_DESC& tex,
770799
const OpaqueArrayHandle& h_backing);
771-
TexObjectHandle create_tex_object_handle_mipmap(const CUDA_RESOURCE_DESC& res,
800+
TexObjectHandle create_tex_object_handle_mipmap(const ContextHandle& h_context,
801+
const CUDA_RESOURCE_DESC& res,
772802
const CUDA_TEXTURE_DESC& tex,
773803
const MipmappedArrayHandle& h_backing);
774-
TexObjectHandle create_tex_object_handle_linear(const CUDA_RESOURCE_DESC& res,
804+
TexObjectHandle create_tex_object_handle_linear(const ContextHandle& h_context,
805+
const CUDA_RESOURCE_DESC& res,
775806
const CUDA_TEXTURE_DESC& tex,
776807
const DevicePtrHandle& h_backing);
777808

778809
// Create an owning surface object via cuSurfObjectCreate, embedding the backing
779810
// array handle so it outlives the surface. cuSurfObjectDestroy runs in the
780811
// deleter. Returns empty handle on error (caller must check).
781-
SurfObjectHandle create_surf_object_handle(const CUDA_RESOURCE_DESC& res,
812+
SurfObjectHandle create_surf_object_handle(const ContextHandle& h_context,
813+
const CUDA_RESOURCE_DESC& res,
782814
const OpaqueArrayHandle& h_backing);
783815

784816
// ============================================================================

cuda_core/cuda/core/_device.pyi

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -579,14 +579,17 @@ class Device:
579579
def memory_resource(self, mr: MemoryResource) -> None: ...
580580
@property
581581
def default_stream(self) -> Stream:
582-
"""Return default CUDA :obj:`~_stream.Stream` associated with this device.
582+
"""Return a default CUDA :obj:`~_stream.Stream` token.
583583
584584
The type of default stream returned depends on if the environment
585585
variable CUDA_PYTHON_CUDA_PER_THREAD_DEFAULT_STREAM is set.
586586
587587
If set, returns a per-thread default stream. Otherwise returns
588588
the legacy stream.
589589
590+
A default-stream token uses the device that is current when the token
591+
is used.
592+
590593
"""
591594
def __int__(self) -> int:
592595
"""Return device_id."""
@@ -611,7 +614,9 @@ class Device:
611614
Returns
612615
-------
613616
:obj:`~_context.Context`, optional
614-
Popped context.
617+
The previous context, or ``None`` if no context was current. When
618+
returned, its ``device_id`` identifies the device that was
619+
previously current.
615620
616621
Examples
617622
--------
@@ -643,7 +648,7 @@ class Device:
643648
644649
"""
645650
def create_stream(self, obj: IsStreamType | None=None, options: StreamOptions | None=None) -> Stream:
646-
"""Create a :obj:`~_stream.Stream` object.
651+
"""Create or wrap a :obj:`~_stream.Stream` object.
647652
648653
New stream objects can be created in two different ways:
649654
@@ -655,7 +660,7 @@ class Device:
655660
656661
Note
657662
----
658-
Device must be initialized.
663+
Device must be initialized. New streams are created on this device.
659664
660665
Parameters
661666
----------
@@ -671,7 +676,7 @@ class Device:
671676
672677
"""
673678
def create_event(self, options: EventOptions | None=None) -> Event:
674-
"""Create an :obj:`~_event.Event` object without recording it to a :obj:`~_stream.Stream`.
679+
"""Create an :obj:`~_event.Event` on this device without recording it to a :obj:`~_stream.Stream`.
675680
676681
Note
677682
----
@@ -714,15 +719,15 @@ class Device:
714719
715720
"""
716721
def sync(self) -> None:
717-
"""Synchronize the device.
722+
"""Synchronize this device.
718723
719724
Note
720725
----
721726
Device must be initialized.
722727
723728
"""
724729
def create_graph_builder(self) -> GraphBuilder:
725-
"""Create a new :obj:`~graph.GraphBuilder` object.
730+
"""Create a new :obj:`~graph.GraphBuilder` on this device.
726731
727732
Returns
728733
-------
@@ -731,12 +736,10 @@ class Device:
731736
732737
"""
733738
def create_opaque_array(self, options: OpaqueArrayOptions) -> OpaqueArray:
734-
"""Create an :obj:`~cuda.core.texture.OpaqueArray` on the current device.
739+
"""Create an :obj:`~cuda.core.texture.OpaqueArray` on this device.
735740
736741
Allocates an opaque, hardware-laid-out CUDA array for texture/surface
737-
access. The array is created in the current CUDA context, so make this
738-
device current with :meth:`set_current` before calling (mirroring
739-
:meth:`create_stream` / :meth:`create_event`).
742+
access.
740743
741744
Note
742745
----
@@ -755,12 +758,10 @@ class Device:
755758
.. versionadded:: 1.1.0
756759
"""
757760
def create_mipmapped_array(self, options: MipmappedArrayOptions) -> MipmappedArray:
758-
"""Create a :obj:`~cuda.core.texture.MipmappedArray` on the current device.
761+
"""Create a :obj:`~cuda.core.texture.MipmappedArray` on this device.
759762
760763
Allocates a mipmapped CUDA array for texture/surface access across
761-
levels. The array is created in the current CUDA context, so make this
762-
device current with :meth:`set_current` before calling (mirroring
763-
:meth:`create_stream` / :meth:`create_event`).
764+
levels.
764765
765766
Note
766767
----
@@ -779,15 +780,13 @@ class Device:
779780
.. versionadded:: 1.1.0
780781
"""
781782
def create_texture_object(self, *, resource: ResourceDescriptor, options: TextureObjectOptions | None=None) -> TextureObject:
782-
"""Create a :obj:`~cuda.core.texture.TextureObject` on the current device.
783+
"""Create a :obj:`~cuda.core.texture.TextureObject` on this device.
783784
784785
Binds a resource (an :obj:`~cuda.core.texture.OpaqueArray` /
785786
:obj:`~cuda.core.texture.MipmappedArray` / linear or pitch2d
786787
:obj:`~cuda.core.Buffer`, wrapped in a
787788
:obj:`~cuda.core.texture.ResourceDescriptor`) as a bindless texture for
788-
kernel-side sampled reads. The object is created in the current CUDA
789-
context, so make this device current with :meth:`set_current` before
790-
calling (mirroring :meth:`create_stream` / :meth:`create_event`).
789+
kernel-side sampled reads. The resource must belong to this device.
791790
792791
Note
793792
----
@@ -808,15 +807,12 @@ class Device:
808807
.. versionadded:: 1.1.0
809808
"""
810809
def create_surface_object(self, *, resource: ResourceDescriptor) -> SurfaceObject:
811-
"""Create a :obj:`~cuda.core.texture.SurfaceObject` on the current device.
810+
"""Create a :obj:`~cuda.core.texture.SurfaceObject` on this device.
812811
813812
Binds an :obj:`~cuda.core.texture.OpaqueArray` (via a
814813
:obj:`~cuda.core.texture.ResourceDescriptor`) as a bindless surface for
815814
kernel-side typed load/store. The backing array must have been created
816-
with ``is_surface_load_store=True``. The object is created in the
817-
current CUDA context, so make this device current with
818-
:meth:`set_current` before calling (mirroring :meth:`create_stream` /
819-
:meth:`create_event`).
815+
with ``is_surface_load_store=True`` and must belong to this device.
820816
821817
Note
822818
----

0 commit comments

Comments
 (0)