Skip to content

Commit 11e19ae

Browse files
committed
refactor(cuda.core): resolve buffer contexts in Cython
Resolve allocation and stream contexts at the Buffer boundary so the C++ resource layer only retains and restores explicit context handles.
1 parent 5e3c658 commit 11e19ae

5 files changed

Lines changed: 117 additions & 143 deletions

File tree

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

Lines changed: 25 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ decltype(&cuGreenCtxStreamCreate) p_cuGreenCtxStreamCreate = nullptr;
4444

4545
decltype(&cuStreamCreateWithPriority) p_cuStreamCreateWithPriority = nullptr;
4646
decltype(&cuStreamDestroy) p_cuStreamDestroy = nullptr;
47-
decltype(&cuStreamGetCtx) p_cuStreamGetCtx = nullptr;
4847

4948
decltype(&cuEventCreate) p_cuEventCreate = nullptr;
5049
decltype(&cuEventDestroy) p_cuEventDestroy = nullptr;
@@ -66,7 +65,6 @@ decltype(&cuMemAllocHost) p_cuMemAllocHost = nullptr;
6665
decltype(&cuMemFreeAsync) p_cuMemFreeAsync = nullptr;
6766
decltype(&cuMemFree) p_cuMemFree = nullptr;
6867
decltype(&cuMemFreeHost) p_cuMemFreeHost = nullptr;
69-
decltype(&cuPointerGetAttribute) p_cuPointerGetAttribute = nullptr;
7068

7169
decltype(&cuMemPoolImportPointer) p_cuMemPoolImportPointer = nullptr;
7270

@@ -198,7 +196,7 @@ class ScopedCurrentContext {
198196
explicit ScopedCurrentContext(ContextHandle h_context) noexcept
199197
: h_context_(std::move(h_context)) {
200198
CUcontext target = as_cu(h_context_);
201-
if (!target || !p_cuCtxGetCurrent || !p_cuCtxSetCurrent) {
199+
if (!target) {
202200
return;
203201
}
204202

@@ -944,10 +942,8 @@ struct DevicePtrBox {
944942
// through a const DevicePtrHandle. The stream can be changed after
945943
// allocation (e.g., to synchronize deallocation with a different stream).
946944
mutable StreamHandle h_stream;
947-
// Retain the allocation's context independently of the deallocation
948-
// stream, whose context may change with Buffer.close(stream=...).
949-
ContextHandle h_allocation_context;
950-
mutable ContextHandle h_stream_context;
945+
// Used by MR-backed pointer deleters; native deleters ignore it.
946+
mutable ContextHandle h_context;
951947
};
952948
} // namespace
953949

@@ -967,88 +963,14 @@ StreamHandle deallocation_stream(const DevicePtrHandle& h) noexcept {
967963
return get_box(h)->h_stream;
968964
}
969965

970-
namespace {
971-
972-
ContextHandle context_handle_ref_best_effort(CUcontext ctx) noexcept {
973-
if (!ctx) {
974-
return {};
975-
}
976-
try {
977-
return cuda_core::create_context_handle_ref(ctx);
978-
} catch (...) {
979-
return {};
980-
}
981-
}
982-
983-
ContextHandle current_context_best_effort() noexcept {
984-
if (!p_cuCtxGetCurrent) {
985-
return {};
986-
}
987-
CUcontext ctx = nullptr;
988-
{
989-
GILReleaseGuard gil;
990-
if (p_cuCtxGetCurrent(&ctx) != CUDA_SUCCESS) {
991-
return {};
992-
}
993-
}
994-
return context_handle_ref_best_effort(ctx);
995-
}
996-
997-
ContextHandle stream_context_best_effort(
998-
const StreamHandle& h_stream) noexcept {
999-
if (!h_stream) {
1000-
return {};
1001-
}
1002-
if (ContextHandle h_context = get_stream_context(h_stream)) {
1003-
return h_context;
1004-
}
1005-
if (!p_cuStreamGetCtx) {
1006-
return {};
1007-
}
1008-
1009-
CUcontext ctx = nullptr;
1010-
{
1011-
GILReleaseGuard gil;
1012-
if (p_cuStreamGetCtx(as_cu(h_stream), &ctx) != CUDA_SUCCESS) {
1013-
return {};
1014-
}
1015-
}
1016-
return context_handle_ref_best_effort(ctx);
1017-
}
1018-
1019-
ContextHandle allocation_context_best_effort(CUdeviceptr ptr) noexcept {
1020-
if (ptr && p_cuPointerGetAttribute) {
1021-
CUcontext ctx = nullptr;
1022-
CUresult status;
1023-
{
1024-
GILReleaseGuard gil;
1025-
status = p_cuPointerGetAttribute(
1026-
&ctx, CU_POINTER_ATTRIBUTE_CONTEXT, ptr);
1027-
}
1028-
if (status == CUDA_SUCCESS && ctx) {
1029-
return context_handle_ref_best_effort(ctx);
1030-
}
1031-
}
1032-
// Stream-ordered allocations are not context-associated. Retain the
1033-
// wrapping thread's current context as the operational fallback for a
1034-
// later default-stream deallocation.
1035-
return current_context_best_effort();
1036-
}
1037-
1038-
ContextHandle operation_context(const DevicePtrBox* box) noexcept {
1039-
return box->h_stream_context
1040-
? box->h_stream_context
1041-
: box->h_allocation_context;
1042-
}
1043-
1044-
} // namespace
1045-
1046-
void set_deallocation_stream(const DevicePtrHandle& h, const StreamHandle& h_stream) noexcept {
966+
void set_deallocation_stream(
967+
const DevicePtrHandle& h,
968+
const StreamHandle& h_stream,
969+
const ContextHandle& h_context) noexcept {
1047970
DevicePtrBox* box = get_box(h);
1048971
box->h_stream = h_stream;
1049-
box->h_stream_context = stream_context_best_effort(h_stream);
1050-
if (!box->h_stream_context) {
1051-
box->h_stream_context = current_context_best_effort();
972+
if (!box->h_context) {
973+
box->h_context = h_context;
1052974
}
1053975
}
1054976

@@ -1059,12 +981,9 @@ DevicePtrHandle deviceptr_alloc_from_pool(size_t size, const MemoryPoolHandle& h
1059981
return {};
1060982
}
1061983

1062-
ContextHandle h_context = current_context_best_effort();
1063-
ContextHandle h_stream_context = stream_context_best_effort(h_stream);
1064984
auto box = std::shared_ptr<DevicePtrBox>(
1065-
new DevicePtrBox{ptr, h_stream, h_context, h_stream_context},
985+
new DevicePtrBox{ptr, h_stream, {}},
1066986
[h_pool](DevicePtrBox* b) {
1067-
ScopedCurrentContext context(operation_context(b));
1068987
GILReleaseGuard gil;
1069988
p_cuMemFreeAsync(b->resource, as_cu(b->h_stream));
1070989
delete b;
@@ -1080,12 +999,9 @@ DevicePtrHandle deviceptr_alloc_async(size_t size, const StreamHandle& h_stream)
1080999
return {};
10811000
}
10821001

1083-
ContextHandle h_context = current_context_best_effort();
1084-
ContextHandle h_stream_context = stream_context_best_effort(h_stream);
10851002
auto box = std::shared_ptr<DevicePtrBox>(
1086-
new DevicePtrBox{ptr, h_stream, h_context, h_stream_context},
1003+
new DevicePtrBox{ptr, h_stream, {}},
10871004
[](DevicePtrBox* b) {
1088-
ScopedCurrentContext context(operation_context(b));
10891005
GILReleaseGuard gil;
10901006
p_cuMemFreeAsync(b->resource, as_cu(b->h_stream));
10911007
delete b;
@@ -1101,11 +1017,9 @@ DevicePtrHandle deviceptr_alloc(size_t size) {
11011017
return {};
11021018
}
11031019

1104-
ContextHandle h_context = current_context_best_effort();
11051020
auto box = std::shared_ptr<DevicePtrBox>(
1106-
new DevicePtrBox{ptr, {}, h_context, {}},
1021+
new DevicePtrBox{ptr, {}, {}},
11071022
[](DevicePtrBox* b) {
1108-
ScopedCurrentContext context(operation_context(b));
11091023
GILReleaseGuard gil;
11101024
p_cuMemFree(b->resource);
11111025
delete b;
@@ -1121,12 +1035,9 @@ DevicePtrHandle deviceptr_alloc_host(size_t size) {
11211035
return {};
11221036
}
11231037

1124-
ContextHandle h_context = current_context_best_effort();
11251038
auto box = std::shared_ptr<DevicePtrBox>(
1126-
new DevicePtrBox{
1127-
reinterpret_cast<CUdeviceptr>(ptr), {}, h_context, {}},
1039+
new DevicePtrBox{reinterpret_cast<CUdeviceptr>(ptr), {}, {}},
11281040
[](DevicePtrBox* b) {
1129-
ScopedCurrentContext context(operation_context(b));
11301041
GILReleaseGuard gil;
11311042
p_cuMemFreeHost(reinterpret_cast<void*>(b->resource));
11321043
delete b;
@@ -1137,7 +1048,7 @@ DevicePtrHandle deviceptr_alloc_host(size_t size) {
11371048

11381049
DevicePtrHandle deviceptr_create_ref(CUdeviceptr ptr) {
11391050
auto box = std::make_shared<DevicePtrBox>(
1140-
DevicePtrBox{ptr, {}, {}, {}});
1051+
DevicePtrBox{ptr, {}, {}});
11411052
return DevicePtrHandle(box, &box->resource);
11421053
}
11431054

@@ -1153,7 +1064,7 @@ DevicePtrHandle deviceptr_create_with_owner(CUdeviceptr ptr, PyObject* owner) {
11531064
}
11541065
Py_INCREF(owner);
11551066
auto box = std::shared_ptr<DevicePtrBox>(
1156-
new DevicePtrBox{ptr, {}, {}, {}},
1067+
new DevicePtrBox{ptr, {}, {}},
11571068
[owner](DevicePtrBox* b) {
11581069
GILAcquireGuard gil;
11591070
if (gil.acquired()) {
@@ -1170,12 +1081,9 @@ DevicePtrHandle deviceptr_create_mapped_graphics(
11701081
const GraphicsResourceHandle& h_resource,
11711082
const StreamHandle& h_stream
11721083
) {
1173-
ContextHandle h_context = current_context_best_effort();
1174-
ContextHandle h_stream_context = stream_context_best_effort(h_stream);
11751084
auto box = std::shared_ptr<DevicePtrBox>(
1176-
new DevicePtrBox{ptr, h_stream, h_context, h_stream_context},
1085+
new DevicePtrBox{ptr, h_stream, {}},
11771086
[h_resource](DevicePtrBox* b) {
1178-
ScopedCurrentContext context(operation_context(b));
11791087
GILReleaseGuard gil;
11801088
CUgraphicsResource resource = as_cu(h_resource);
11811089
p_cuGraphicsUnmapResources(1, &resource, as_cu(b->h_stream));
@@ -1195,7 +1103,11 @@ void register_mr_dealloc_callback(MRDeallocCallback cb) {
11951103
mr_dealloc_cb = cb;
11961104
}
11971105

1198-
DevicePtrHandle deviceptr_create_with_mr(CUdeviceptr ptr, size_t size, PyObject* mr) {
1106+
DevicePtrHandle deviceptr_create_with_mr(
1107+
CUdeviceptr ptr,
1108+
size_t size,
1109+
PyObject* mr,
1110+
const ContextHandle& h_context) {
11991111
if (!mr) {
12001112
return deviceptr_create_ref(ptr);
12011113
}
@@ -1205,11 +1117,10 @@ DevicePtrHandle deviceptr_create_with_mr(CUdeviceptr ptr, size_t size, PyObject*
12051117
return deviceptr_create_ref(ptr);
12061118
}
12071119
Py_INCREF(mr);
1208-
ContextHandle h_context = allocation_context_best_effort(ptr);
12091120
auto box = std::shared_ptr<DevicePtrBox>(
1210-
new DevicePtrBox{ptr, {}, h_context, {}},
1121+
new DevicePtrBox{ptr, {}, h_context},
12111122
[mr, size](DevicePtrBox* b) {
1212-
ScopedCurrentContext context(operation_context(b));
1123+
ScopedCurrentContext context(b->h_context);
12131124
GILAcquireGuard gil;
12141125
if (gil.acquired()) {
12151126
if (mr_dealloc_cb) {
@@ -1301,15 +1212,10 @@ DevicePtrHandle deviceptr_import_ipc(const MemoryPoolHandle& h_pool, const void*
13011212
return {};
13021213
}
13031214

1304-
ContextHandle h_context = current_context_best_effort();
1305-
ContextHandle h_stream_context =
1306-
stream_context_best_effort(h_stream);
13071215
auto box = std::shared_ptr<DevicePtrBox>(
1308-
new DevicePtrBox{
1309-
ptr, h_stream, h_context, h_stream_context},
1216+
new DevicePtrBox{ptr, h_stream, {}},
13101217
[h_pool, key](DevicePtrBox* b) {
13111218
ipc_ptr_cache.unregister_handle(key);
1312-
ScopedCurrentContext context(operation_context(b));
13131219
GILReleaseGuard gil;
13141220
p_cuMemFreeAsync(b->resource, as_cu(b->h_stream));
13151221
delete b;
@@ -1326,14 +1232,9 @@ DevicePtrHandle deviceptr_import_ipc(const MemoryPoolHandle& h_pool, const void*
13261232
return {};
13271233
}
13281234

1329-
ContextHandle h_context = current_context_best_effort();
1330-
ContextHandle h_stream_context =
1331-
stream_context_best_effort(h_stream);
13321235
auto box = std::shared_ptr<DevicePtrBox>(
1333-
new DevicePtrBox{
1334-
ptr, h_stream, h_context, h_stream_context},
1236+
new DevicePtrBox{ptr, h_stream, {}},
13351237
[h_pool](DevicePtrBox* b) {
1336-
ScopedCurrentContext context(operation_context(b));
13371238
GILReleaseGuard gil;
13381239
p_cuMemFreeAsync(b->resource, as_cu(b->h_stream));
13391240
delete b;

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ extern decltype(&cuGreenCtxStreamCreate) p_cuGreenCtxStreamCreate;
7777

7878
extern decltype(&cuStreamCreateWithPriority) p_cuStreamCreateWithPriority;
7979
extern decltype(&cuStreamDestroy) p_cuStreamDestroy;
80-
extern decltype(&cuStreamGetCtx) p_cuStreamGetCtx;
8180

8281
extern decltype(&cuEventCreate) p_cuEventCreate;
8382
extern decltype(&cuEventDestroy) p_cuEventDestroy;
@@ -99,7 +98,6 @@ extern decltype(&cuMemAllocHost) p_cuMemAllocHost;
9998
extern decltype(&cuMemFreeAsync) p_cuMemFreeAsync;
10099
extern decltype(&cuMemFree) p_cuMemFree;
101100
extern decltype(&cuMemFreeHost) p_cuMemFreeHost;
102-
extern decltype(&cuPointerGetAttribute) p_cuPointerGetAttribute;
103101

104102
extern decltype(&cuMemPoolImportPointer) p_cuMemPoolImportPointer;
105103

@@ -405,11 +403,15 @@ using MRDeallocCallback = void (*)(PyObject* mr, CUdeviceptr ptr,
405403
void register_mr_dealloc_callback(MRDeallocCallback cb);
406404

407405
// Create a device pointer handle whose destructor calls mr.deallocate()
408-
// via the registered callback. The pointer's allocation context is retained
409-
// when discoverable and made current for the callback. The mr's refcount is
410-
// incremented and decremented when the handle is released.
406+
// via the registered callback. The supplied context is retained and made
407+
// current for the callback. The mr's refcount is incremented and decremented
408+
// when the handle is released.
411409
// If mr is nullptr, equivalent to deviceptr_create_ref.
412-
DevicePtrHandle deviceptr_create_with_mr(CUdeviceptr ptr, size_t size, PyObject* mr);
410+
DevicePtrHandle deviceptr_create_with_mr(
411+
CUdeviceptr ptr,
412+
size_t size,
413+
PyObject* mr,
414+
const ContextHandle& h_context);
413415

414416
// Import a device pointer from IPC via cuMemPoolImportPointer.
415417
// When the last reference is released, cuMemFreeAsync is called on the stored stream.
@@ -425,7 +427,11 @@ DevicePtrHandle deviceptr_import_ipc(
425427
StreamHandle deallocation_stream(const DevicePtrHandle& h) noexcept;
426428

427429
// Set the deallocation stream for a device pointer handle.
428-
void set_deallocation_stream(const DevicePtrHandle& h, const StreamHandle& h_stream) noexcept;
430+
// If the handle has no cleanup context, use the supplied stream context.
431+
void set_deallocation_stream(
432+
const DevicePtrHandle& h,
433+
const StreamHandle& h_stream,
434+
const ContextHandle& h_context) noexcept;
429435

430436
// ============================================================================
431437
// Library handle functions

0 commit comments

Comments
 (0)