From a2508bf7e6ed78402708c4bdc42d65958e50e581 Mon Sep 17 00:00:00 2001 From: fbusato Date: Mon, 8 Dec 2025 14:41:47 -0800 Subject: [PATCH 1/5] add relaxed is_device_accessible --- .../memory/is_pointer_accessible.rst | 13 +++--- .../cuda/__memory/is_pointer_accessible.h | 43 +++++++++++++++++++ .../memory/is_pointer_accessible.pass.cpp | 5 +++ 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst b/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst index e68dcf7339a..469a6d75194 100644 --- a/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst +++ b/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst @@ -13,16 +13,19 @@ Defined in the ```` header. bool is_host_accessible(const void* ptr); // (1) [[nodiscard]] inline - bool is_device_accessible(const void* ptr, device_ref device); // (2) + bool is_device_accessible(const void* ptr); // (2) [[nodiscard]] inline - bool is_managed(const void* ptr); // (3) + bool is_device_accessible(const void* ptr, device_ref device); // (3) + + [[nodiscard]] inline + bool is_managed(const void* ptr); // (4) } // namespace cuda -Determines whether the memory referenced by ``ptr`` is accessible from the host (1), from the specified ``device`` (2), or is backed by Unified Memory (managed memory) (3). +Determines whether the memory referenced by ``ptr`` is accessible from the host (1), from the device (2) (3), or is backed by Unified Memory (managed memory) (4). -- ``is_device_accessible()`` also checks whether the memory is peer-accessible or allocated from a memory pool accessible to the specified ``device``. +- ``is_device_accessible()`` (2) (3) also checks whether the memory is peer-accessible or allocated from a memory pool. - ``is_host_accessible()`` also checks whether the memory is allocated from a memory pool accessible to the host. ---- @@ -30,7 +33,7 @@ Determines whether the memory referenced by ``ptr`` is accessible from the host **Parameters** - ``ptr``: A pointer to the memory location to query. -- ``device``: A ``device_ref`` that denotes the device to query. (2) +- ``device``: A ``device_ref`` that denotes the device to query. (3) **Return value** diff --git a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h index 371dca490a6..615bef726eb 100644 --- a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h +++ b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h @@ -100,6 +100,49 @@ _CCCL_HOST_API inline bool is_host_accessible(const void* __p) return false; } +/** + * @brief Checks if a pointer is a device accessible pointer. + * + * @param __p The pointer to check. + * @return `true` if the pointer is a device accessible pointer, `false` otherwise. + */ +[[nodiscard]] +_CCCL_HOST_API inline bool is_device_accessible(const void* __p) +{ + if (__p == nullptr) + { + return false; + } + ::CUpointer_attribute __attrs[4] = { + ::CU_POINTER_ATTRIBUTE_MEMORY_TYPE, + ::CU_POINTER_ATTRIBUTE_IS_MANAGED, + ::CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL, + ::CU_POINTER_ATTRIBUTE_MEMPOOL_HANDLE}; + auto __memory_type = static_cast<::CUmemorytype>(0); + int __is_managed = 0; + int __ptr_dev_id = 0; + ::CUmemoryPool __mempool = nullptr; + void* __results[4] = {&__memory_type, &__is_managed, &__ptr_dev_id, &__mempool}; + const auto __status = ::cuda::__driver::__pointerGetAttributesNoThrow(__attrs, __results, __p); + if (__status != ::cudaSuccess) + { + ::cuda::__throw_cuda_error(__status, "is_device_accessible() failed", _CCCL_BUILTIN_PRETTY_FUNCTION()); + } + // (1) check if the pointer is unregistered + if (__memory_type == static_cast<::CUmemorytype>(0)) + { + return false; + } + // (2) check if the pointer is a device accessible pointer or managed memory + if (__mempool != nullptr) + { + ::CUmemLocation __prop{::CU_MEM_LOCATION_TYPE_DEVICE, __ptr_dev_id}; + const unsigned __pool_flags = ::cuda::__driver::__mempoolGetAccess(__mempool, &__prop); + return __pool_flags & unsigned{::CU_MEM_ACCESS_FLAGS_PROT_READ}; + } + return __is_managed || __memory_type == ::CU_MEMORYTYPE_DEVICE; +} + /** * @brief Checks if a pointer is a device accessible pointer. * diff --git a/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp b/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp index f171b3b177c..78cc4cdacd9 100644 --- a/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp @@ -28,11 +28,13 @@ void test_accessible_pointer( { assert(cuda::is_host_accessible(ptr) == is_host_accessible); assert(cuda::is_device_accessible(ptr, device) == is_device_accessible); + assert(cuda::is_device_accessible(ptr) == is_device_accessible); assert(cuda::is_managed(ptr) == is_managed_accessible); if constexpr (!cuda::std::is_same_v && !cuda::std::is_same_v) { assert(cuda::is_host_accessible(ptr + 1) == is_host_accessible); assert(cuda::is_device_accessible(ptr + 1, device) == is_device_accessible); + assert(cuda::is_device_accessible(ptr + 1) == is_device_accessible); assert(cuda::is_managed(ptr + 1) == is_managed_accessible); } } @@ -149,6 +151,7 @@ bool test_multiple_devices() /// DEVICE 1 CONTEXT cuda::__ensure_current_context ctx1(dev1); + assert(cuda::is_device_accessible(device_ptr0) == true); assert(cuda::is_device_accessible(device_ptr0, dev0) == true); assert(cuda::is_device_accessible(device_ptr0, dev1) == false); @@ -158,6 +161,7 @@ bool test_multiple_devices() { return true; } + assert(cuda::is_device_accessible(device_ptr0) == true); assert(cuda::is_device_accessible(device_ptr0, dev1) == false); assert(cudaDeviceEnablePeerAccess(dev1.get(), 0) == cudaSuccess); @@ -186,6 +190,7 @@ bool test_multiple_devices_from_pool() return true; } assert(cuda::is_device_accessible(ptr, dev1) == false); + assert(cuda::is_device_accessible(ptr) == true); assert(cudaDeviceEnablePeerAccess(dev1.get(), 0) == cudaSuccess); assert(cuda::is_device_accessible(ptr, dev0) == true); From 1b92c8592658a323fc90b39ba2c830aa2a601f3f Mon Sep 17 00:00:00 2001 From: fbusato Date: Wed, 10 Dec 2025 09:54:08 -0800 Subject: [PATCH 2/5] keep it internal --- .../extended_api/memory/is_pointer_accessible.rst | 13 +++++-------- .../include/cuda/__memory/is_pointer_accessible.h | 9 +++++---- .../cuda/memory/is_pointer_accessible.pass.cpp | 10 +++++----- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst b/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst index 469a6d75194..e68dcf7339a 100644 --- a/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst +++ b/docs/libcudacxx/extended_api/memory/is_pointer_accessible.rst @@ -13,19 +13,16 @@ Defined in the ```` header. bool is_host_accessible(const void* ptr); // (1) [[nodiscard]] inline - bool is_device_accessible(const void* ptr); // (2) + bool is_device_accessible(const void* ptr, device_ref device); // (2) [[nodiscard]] inline - bool is_device_accessible(const void* ptr, device_ref device); // (3) - - [[nodiscard]] inline - bool is_managed(const void* ptr); // (4) + bool is_managed(const void* ptr); // (3) } // namespace cuda -Determines whether the memory referenced by ``ptr`` is accessible from the host (1), from the device (2) (3), or is backed by Unified Memory (managed memory) (4). +Determines whether the memory referenced by ``ptr`` is accessible from the host (1), from the specified ``device`` (2), or is backed by Unified Memory (managed memory) (3). -- ``is_device_accessible()`` (2) (3) also checks whether the memory is peer-accessible or allocated from a memory pool. +- ``is_device_accessible()`` also checks whether the memory is peer-accessible or allocated from a memory pool accessible to the specified ``device``. - ``is_host_accessible()`` also checks whether the memory is allocated from a memory pool accessible to the host. ---- @@ -33,7 +30,7 @@ Determines whether the memory referenced by ``ptr`` is accessible from the host **Parameters** - ``ptr``: A pointer to the memory location to query. -- ``device``: A ``device_ref`` that denotes the device to query. (3) +- ``device``: A ``device_ref`` that denotes the device to query. (2) **Return value** diff --git a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h index 615bef726eb..4702e3ef241 100644 --- a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h +++ b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h @@ -101,13 +101,13 @@ _CCCL_HOST_API inline bool is_host_accessible(const void* __p) } /** - * @brief Checks if a pointer is a device accessible pointer. + * @brief Checks if a pointer is a device pointer. * * @param __p The pointer to check. - * @return `true` if the pointer is a device accessible pointer, `false` otherwise. + * @return `true` if the pointer is a device pointer, `false` otherwise. */ [[nodiscard]] -_CCCL_HOST_API inline bool is_device_accessible(const void* __p) +_CCCL_HOST_API inline bool __is_device_memory(const void* __p) { if (__p == nullptr) { @@ -133,13 +133,14 @@ _CCCL_HOST_API inline bool is_device_accessible(const void* __p) { return false; } - // (2) check if the pointer is a device accessible pointer or managed memory + // (2) check if a memory pool is associated with the pointer if (__mempool != nullptr) { ::CUmemLocation __prop{::CU_MEM_LOCATION_TYPE_DEVICE, __ptr_dev_id}; const unsigned __pool_flags = ::cuda::__driver::__mempoolGetAccess(__mempool, &__prop); return __pool_flags & unsigned{::CU_MEM_ACCESS_FLAGS_PROT_READ}; } + // (3) check if the pointer is a device accessible pointer or managed memory return __is_managed || __memory_type == ::CU_MEMORYTYPE_DEVICE; } diff --git a/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp b/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp index 78cc4cdacd9..8ea9d35d872 100644 --- a/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp @@ -28,13 +28,13 @@ void test_accessible_pointer( { assert(cuda::is_host_accessible(ptr) == is_host_accessible); assert(cuda::is_device_accessible(ptr, device) == is_device_accessible); - assert(cuda::is_device_accessible(ptr) == is_device_accessible); + assert(cuda::__is_device_memory(ptr) == is_device_accessible); assert(cuda::is_managed(ptr) == is_managed_accessible); if constexpr (!cuda::std::is_same_v && !cuda::std::is_same_v) { assert(cuda::is_host_accessible(ptr + 1) == is_host_accessible); assert(cuda::is_device_accessible(ptr + 1, device) == is_device_accessible); - assert(cuda::is_device_accessible(ptr + 1) == is_device_accessible); + assert(cuda::__is_device_memory(ptr + 1) == is_device_accessible); assert(cuda::is_managed(ptr + 1) == is_managed_accessible); } } @@ -151,7 +151,7 @@ bool test_multiple_devices() /// DEVICE 1 CONTEXT cuda::__ensure_current_context ctx1(dev1); - assert(cuda::is_device_accessible(device_ptr0) == true); + assert(cuda::__is_device_memory(device_ptr0) == true); assert(cuda::is_device_accessible(device_ptr0, dev0) == true); assert(cuda::is_device_accessible(device_ptr0, dev1) == false); @@ -161,7 +161,7 @@ bool test_multiple_devices() { return true; } - assert(cuda::is_device_accessible(device_ptr0) == true); + assert(cuda::__is_device_memory(device_ptr0) == true); assert(cuda::is_device_accessible(device_ptr0, dev1) == false); assert(cudaDeviceEnablePeerAccess(dev1.get(), 0) == cudaSuccess); @@ -190,7 +190,7 @@ bool test_multiple_devices_from_pool() return true; } assert(cuda::is_device_accessible(ptr, dev1) == false); - assert(cuda::is_device_accessible(ptr) == true); + assert(cuda::__is_device_memory(ptr) == true); assert(cudaDeviceEnablePeerAccess(dev1.get(), 0) == cudaSuccess); assert(cuda::is_device_accessible(ptr, dev0) == true); From c8a3135b8eb547093b4b500b6d564b39e8bb5877 Mon Sep 17 00:00:00 2001 From: fbusato Date: Wed, 10 Dec 2025 16:38:59 -0800 Subject: [PATCH 3/5] make it noexcept --- libcudacxx/include/cuda/__memory/is_pointer_accessible.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h index 4702e3ef241..725b9892ce3 100644 --- a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h +++ b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h @@ -107,7 +107,7 @@ _CCCL_HOST_API inline bool is_host_accessible(const void* __p) * @return `true` if the pointer is a device pointer, `false` otherwise. */ [[nodiscard]] -_CCCL_HOST_API inline bool __is_device_memory(const void* __p) +_CCCL_HOST_API inline bool __is_device_memory(const void* __p) noexcept { if (__p == nullptr) { @@ -126,7 +126,7 @@ _CCCL_HOST_API inline bool __is_device_memory(const void* __p) const auto __status = ::cuda::__driver::__pointerGetAttributesNoThrow(__attrs, __results, __p); if (__status != ::cudaSuccess) { - ::cuda::__throw_cuda_error(__status, "is_device_accessible() failed", _CCCL_BUILTIN_PRETTY_FUNCTION()); + return false; } // (1) check if the pointer is unregistered if (__memory_type == static_cast<::CUmemorytype>(0)) From 03f8112f3e565730875d8cd543039cc78d4d4ad7 Mon Sep 17 00:00:00 2001 From: fbusato Date: Wed, 10 Dec 2025 16:46:09 -0800 Subject: [PATCH 4/5] don't check the access --- libcudacxx/include/cuda/__memory/is_pointer_accessible.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h index 725b9892ce3..010dba6913c 100644 --- a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h +++ b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h @@ -137,8 +137,7 @@ _CCCL_HOST_API inline bool __is_device_memory(const void* __p) noexcept if (__mempool != nullptr) { ::CUmemLocation __prop{::CU_MEM_LOCATION_TYPE_DEVICE, __ptr_dev_id}; - const unsigned __pool_flags = ::cuda::__driver::__mempoolGetAccess(__mempool, &__prop); - return __pool_flags & unsigned{::CU_MEM_ACCESS_FLAGS_PROT_READ}; + return static_cast(::cuda::__driver::__mempoolGetAccess(__mempool, &__prop)); } // (3) check if the pointer is a device accessible pointer or managed memory return __is_managed || __memory_type == ::CU_MEMORYTYPE_DEVICE; From 6c856caf7338c46e28b705aeabbc044cc34f0c0a Mon Sep 17 00:00:00 2001 From: fbusato Date: Fri, 12 Dec 2025 10:43:59 -0800 Subject: [PATCH 5/5] use __is_device_or_managed_memory --- .../include/cuda/__memory/is_pointer_accessible.h | 6 +++++- .../cuda/memory/is_pointer_accessible.pass.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h index 010dba6913c..e6ccb2be8dc 100644 --- a/libcudacxx/include/cuda/__memory/is_pointer_accessible.h +++ b/libcudacxx/include/cuda/__memory/is_pointer_accessible.h @@ -103,11 +103,15 @@ _CCCL_HOST_API inline bool is_host_accessible(const void* __p) /** * @brief Checks if a pointer is a device pointer. * + * This internal-only function can be used when the device id is not known. + * The main difference between this function and is_device_accessible() is that this function does not check if the + * pointer is peer accessible from a specified device. + * * @param __p The pointer to check. * @return `true` if the pointer is a device pointer, `false` otherwise. */ [[nodiscard]] -_CCCL_HOST_API inline bool __is_device_memory(const void* __p) noexcept +_CCCL_HOST_API inline bool __is_device_or_managed_memory(const void* __p) noexcept { if (__p == nullptr) { diff --git a/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp b/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp index 8ea9d35d872..960f9214ba6 100644 --- a/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/memory/is_pointer_accessible.pass.cpp @@ -28,13 +28,13 @@ void test_accessible_pointer( { assert(cuda::is_host_accessible(ptr) == is_host_accessible); assert(cuda::is_device_accessible(ptr, device) == is_device_accessible); - assert(cuda::__is_device_memory(ptr) == is_device_accessible); + assert(cuda::__is_device_or_managed_memory(ptr) == is_device_accessible); assert(cuda::is_managed(ptr) == is_managed_accessible); if constexpr (!cuda::std::is_same_v && !cuda::std::is_same_v) { assert(cuda::is_host_accessible(ptr + 1) == is_host_accessible); assert(cuda::is_device_accessible(ptr + 1, device) == is_device_accessible); - assert(cuda::__is_device_memory(ptr + 1) == is_device_accessible); + assert(cuda::__is_device_or_managed_memory(ptr + 1) == is_device_accessible); assert(cuda::is_managed(ptr + 1) == is_managed_accessible); } } @@ -151,7 +151,7 @@ bool test_multiple_devices() /// DEVICE 1 CONTEXT cuda::__ensure_current_context ctx1(dev1); - assert(cuda::__is_device_memory(device_ptr0) == true); + assert(cuda::__is_device_or_managed_memory(device_ptr0) == true); assert(cuda::is_device_accessible(device_ptr0, dev0) == true); assert(cuda::is_device_accessible(device_ptr0, dev1) == false); @@ -161,7 +161,7 @@ bool test_multiple_devices() { return true; } - assert(cuda::__is_device_memory(device_ptr0) == true); + assert(cuda::__is_device_or_managed_memory(device_ptr0) == true); assert(cuda::is_device_accessible(device_ptr0, dev1) == false); assert(cudaDeviceEnablePeerAccess(dev1.get(), 0) == cudaSuccess); @@ -190,7 +190,7 @@ bool test_multiple_devices_from_pool() return true; } assert(cuda::is_device_accessible(ptr, dev1) == false); - assert(cuda::__is_device_memory(ptr) == true); + assert(cuda::__is_device_or_managed_memory(ptr) == true); assert(cudaDeviceEnablePeerAccess(dev1.get(), 0) == cudaSuccess); assert(cuda::is_device_accessible(ptr, dev0) == true);