Skip to content

Commit a09bebe

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 a09bebe

29 files changed

Lines changed: 1213 additions & 447 deletions

‎cuda_core/cuda/core/_cpp/resource_handles.cpp‎

Lines changed: 422 additions & 192 deletions
Large diffs are not rendered by default.

‎cuda_core/cuda/core/_cpp/resource_handles.hpp‎

Lines changed: 47 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;
@@ -77,6 +82,7 @@ extern decltype(&cuGreenCtxStreamCreate) p_cuGreenCtxStreamCreate;
7782

7883
extern decltype(&cuStreamCreateWithPriority) p_cuStreamCreateWithPriority;
7984
extern decltype(&cuStreamDestroy) p_cuStreamDestroy;
85+
extern decltype(&cuStreamSynchronize) p_cuStreamSynchronize;
8086

8187
extern decltype(&cuEventCreate) p_cuEventCreate;
8288
extern decltype(&cuEventDestroy) p_cuEventDestroy;
@@ -128,6 +134,7 @@ extern decltype(&cuGraphicsUnregisterResource) p_cuGraphicsUnregisterResource;
128134

129135
// Texture / surface / array (PR #467)
130136
extern decltype(&cuArray3DCreate) p_cuArray3DCreate;
137+
extern decltype(&cuArray3DGetDescriptor) p_cuArray3DGetDescriptor;
131138
extern decltype(&cuArrayDestroy) p_cuArrayDestroy;
132139
extern decltype(&cuMipmappedArrayCreate) p_cuMipmappedArrayCreate;
133140
extern decltype(&cuMipmappedArrayDestroy) p_cuMipmappedArrayDestroy;
@@ -246,6 +253,17 @@ ContextHandle get_primary_context(int device_id);
246253
// Returns empty handle if no context is current (caller must check)
247254
ContextHandle get_current_context();
248255

256+
// Synchronize the provided context.
257+
// Returns CUDA_ERROR_INVALID_CONTEXT for an empty handle.
258+
CUresult context_synchronize(const ContextHandle& h_context) noexcept;
259+
260+
// Query the stream priority range for the provided context.
261+
// Returns CUDA_ERROR_INVALID_CONTEXT for an empty handle.
262+
CUresult context_get_stream_priority_range(
263+
const ContextHandle& h_context,
264+
int* least_priority,
265+
int* greatest_priority) noexcept;
266+
249267
// ============================================================================
250268
// Stream handle functions
251269
// ============================================================================
@@ -371,10 +389,15 @@ DevicePtrHandle deviceptr_alloc_from_pool(
371389
// Returns empty handle on error (caller must check).
372390
DevicePtrHandle deviceptr_alloc_async(size_t size, const StreamHandle& h_stream);
373391

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);
392+
// Allocate device memory synchronously via cuMemAlloc with the provided
393+
// context current. The caller owns the pointer; release it with deviceptr_free.
394+
// Returns CUDA_ERROR_INVALID_CONTEXT for an empty handle.
395+
CUresult deviceptr_alloc_raw(CUdeviceptr* ptr, size_t size,
396+
const ContextHandle& h_context) noexcept;
397+
398+
// Synchronize the provided stream, if any, then release a synchronous
399+
// allocation via cuMemFree.
400+
CUresult deviceptr_free(CUdeviceptr ptr, const StreamHandle& h_stream) noexcept;
378401

379402
// Allocate pinned host memory via cuMemAllocHost.
380403
// When the last reference is released, cuMemFreeHost is called.
@@ -739,7 +762,7 @@ FileDescriptorHandle create_fd_handle_ref(int fd);
739762
// Create an owning CUDA array via cuArray3DCreate.
740763
// When the last reference is released, cuArrayDestroy is called automatically.
741764
// Returns empty handle on error (caller must check).
742-
OpaqueArrayHandle create_array_handle(const CUDA_ARRAY3D_DESCRIPTOR& desc);
765+
OpaqueArrayHandle create_array_handle(const ContextHandle& h_context, const CUDA_ARRAY3D_DESCRIPTOR& desc);
743766

744767
// Create a non-owning array handle (references an existing CUarray).
745768
// Use for arrays owned elsewhere (e.g. graphics interop). Never destroyed here.
@@ -749,6 +772,12 @@ OpaqueArrayHandle create_array_handle_ref(CUarray arr);
749772
// When the last reference is released, cuArrayDestroy is called automatically.
750773
OpaqueArrayHandle create_array_handle_owning(CUarray arr);
751774

775+
// Return the context dependency associated with an array, if known.
776+
ContextHandle get_array_context(const OpaqueArrayHandle& h) noexcept;
777+
778+
// Query an array descriptor.
779+
CUresult get_array_descriptor(const OpaqueArrayHandle& h, CUDA_ARRAY3D_DESCRIPTOR* desc) noexcept;
780+
752781
// Create a non-owning handle to a mipmap level via cuMipmappedArrayGetLevel.
753782
// The level CUarray is owned by the mipmap; the parent MipmappedArrayHandle is
754783
// embedded in the box so it outlives the level view. No destroy in the deleter.
@@ -758,27 +787,35 @@ OpaqueArrayHandle create_array_level_handle(const MipmappedArrayHandle& h_mip, u
758787
// Create an owning mipmapped array via cuMipmappedArrayCreate.
759788
// When the last reference is released, cuMipmappedArrayDestroy is called.
760789
// Returns empty handle on error (caller must check).
761-
MipmappedArrayHandle create_mipmapped_array_handle(const CUDA_ARRAY3D_DESCRIPTOR& desc,
790+
MipmappedArrayHandle create_mipmapped_array_handle(const ContextHandle& h_context,
791+
const CUDA_ARRAY3D_DESCRIPTOR& desc,
762792
unsigned int num_levels);
763793

794+
// Return the context dependency associated with a mipmapped array, if known.
795+
ContextHandle get_mipmapped_array_context(const MipmappedArrayHandle& h) noexcept;
796+
764797
// Create an owning texture object via cuTexObjectCreate, embedding the backing
765798
// resource handle (array / mipmapped array / linear-or-pitch2d device pointer)
766799
// so the backing always outlives the texture. cuTexObjectDestroy runs in the
767800
// deleter. Returns empty handle on error (caller must check).
768-
TexObjectHandle create_tex_object_handle_array(const CUDA_RESOURCE_DESC& res,
801+
TexObjectHandle create_tex_object_handle_array(const ContextHandle& h_context,
802+
const CUDA_RESOURCE_DESC& res,
769803
const CUDA_TEXTURE_DESC& tex,
770804
const OpaqueArrayHandle& h_backing);
771-
TexObjectHandle create_tex_object_handle_mipmap(const CUDA_RESOURCE_DESC& res,
805+
TexObjectHandle create_tex_object_handle_mipmap(const ContextHandle& h_context,
806+
const CUDA_RESOURCE_DESC& res,
772807
const CUDA_TEXTURE_DESC& tex,
773808
const MipmappedArrayHandle& h_backing);
774-
TexObjectHandle create_tex_object_handle_linear(const CUDA_RESOURCE_DESC& res,
809+
TexObjectHandle create_tex_object_handle_linear(const ContextHandle& h_context,
810+
const CUDA_RESOURCE_DESC& res,
775811
const CUDA_TEXTURE_DESC& tex,
776812
const DevicePtrHandle& h_backing);
777813

778814
// Create an owning surface object via cuSurfObjectCreate, embedding the backing
779815
// array handle so it outlives the surface. cuSurfObjectDestroy runs in the
780816
// deleter. Returns empty handle on error (caller must check).
781-
SurfObjectHandle create_surf_object_handle(const CUDA_RESOURCE_DESC& res,
817+
SurfObjectHandle create_surf_object_handle(const ContextHandle& h_context,
818+
const CUDA_RESOURCE_DESC& res,
782819
const OpaqueArrayHandle& h_backing);
783820

784821
// ============================================================================

‎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)