Files
project_6/cccl_upstream/thrust/testing/device_ptr.cu
EngineX CI 56fd68e7dd [INFRA] Import NVIDIA/CCCL upstream as optimization reference library
CCCL (CUDA C++ Core Libraries) provides:
- CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk)
- Thrust: high-level parallel algorithms (transform_reduce, sort, scan)
- libcudacxx: CUDA C++ standard library (atomics, barriers, memory)
- cudax: experimental features (memory resources, allocators)
- Tuning policies: per-SM hardware-specific algorithm parameters

Competition optimization vectors mapped to CCCL:
- Output TPS (83% weight): warp_reduce, block_reduce, device_topk
- Input TPS (14% weight): device_scan, block_load, prefetch
- Cache TPS (3% weight): prefix caching strategy patterns
- Memory (0.9 util): pooled/cached/buddy allocators

Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only)
License: Apache-2.0
2026-07-30 09:35:51 +00:00

283 lines
8.6 KiB
Plaintext

#include <thrust/device_ptr.h>
#include <thrust/device_vector.h>
#include <cuda/std/iterator>
#include <iterator>
#include <unittest/unittest.h>
#ifdef __cpp_lib_concepts
static_assert(std::indirectly_writable<thrust::device_ptr<uint8_t>, uint8_t>);
#endif // __cpp_lib_concepts
static_assert(cuda::std::indirectly_writable<thrust::device_ptr<uint8_t>, uint8_t>);
void TestDevicePointerManipulation()
{
thrust::device_vector<int> data(5);
thrust::device_ptr<int> begin(&data[0]);
thrust::device_ptr<int> end(&data[0] + 5);
ASSERT_EQUAL(end - begin, 5);
begin++;
begin--;
ASSERT_EQUAL(end - begin, 5);
begin += 1;
begin -= 1;
ASSERT_EQUAL(end - begin, 5);
begin = begin + (int) 1;
begin = begin - (int) 1;
ASSERT_EQUAL(end - begin, 5);
begin = begin + (unsigned int) 1;
begin = begin - (unsigned int) 1;
ASSERT_EQUAL(end - begin, 5);
begin = begin + (size_t) 1;
begin = begin - (size_t) 1;
ASSERT_EQUAL(end - begin, 5);
begin = begin + (ptrdiff_t) 1;
begin = begin - (ptrdiff_t) 1;
ASSERT_EQUAL(end - begin, 5);
begin = begin + (thrust::device_ptr<int>::difference_type) 1;
begin = begin - (thrust::device_ptr<int>::difference_type) 1;
ASSERT_EQUAL(end - begin, 5);
}
DECLARE_UNITTEST(TestDevicePointerManipulation);
void TestMakeDevicePointer()
{
using T = int;
T* raw_ptr = nullptr;
thrust::device_ptr<T> p0 = thrust::device_pointer_cast(raw_ptr);
ASSERT_EQUAL(thrust::raw_pointer_cast(p0), raw_ptr);
thrust::device_ptr<T> p1 = thrust::device_pointer_cast(p0);
ASSERT_EQUAL(p0, p1);
}
DECLARE_UNITTEST(TestMakeDevicePointer);
template <typename Vector>
void TestRawPointerCast()
{
using T = typename Vector::value_type;
Vector vec(3);
T* first;
T* last;
first = thrust::raw_pointer_cast(&vec[0]);
last = thrust::raw_pointer_cast(&vec[3]);
ASSERT_EQUAL(last - first, 3);
first = thrust::raw_pointer_cast(&vec.front());
last = thrust::raw_pointer_cast(&vec.back());
ASSERT_EQUAL(last - first, 2);
// Do we want these to work?
// first = thrust::raw_pointer_cast(vec.begin());
// last = thrust::raw_pointer_cast(vec.end());
// ASSERT_EQUAL(last - first, 3);
}
DECLARE_VECTOR_UNITTEST(TestRawPointerCast);
template <typename T>
void TestDevicePointerNullptrCompatibility()
{
thrust::device_ptr<T> p0(nullptr);
ASSERT_EQUAL_QUIET(nullptr, p0);
ASSERT_EQUAL_QUIET(p0, nullptr);
p0 = nullptr;
ASSERT_EQUAL_QUIET(nullptr, p0);
ASSERT_EQUAL_QUIET(p0, nullptr);
}
DECLARE_GENERIC_UNITTEST(TestDevicePointerNullptrCompatibility);
template <typename T>
void TestDevicePointerBoolConversion()
{
thrust::device_ptr<T> p0(nullptr);
auto const b = bool(p0);
ASSERT_EQUAL_QUIET(false, b);
}
DECLARE_GENERIC_UNITTEST(TestDevicePointerBoolConversion);
void TestDevicePointerCompare()
{
using T1 = int;
thrust::device_vector<T1> v1 = {42, 1337};
{ // test same element type
using device_ptr = thrust::device_ptr<T1>;
device_ptr ptr1 = v1.data();
device_ptr ptr2 = ptr1 + 1;
// Equality
ASSERT_EQUAL(true, (ptr1 == ptr1));
ASSERT_EQUAL(false, (ptr1 != ptr1));
ASSERT_EQUAL(false, (ptr1 == ptr2));
ASSERT_EQUAL(true, (ptr1 != ptr2));
// Relations
ASSERT_EQUAL(true, (ptr1 < ptr2));
ASSERT_EQUAL(true, (ptr1 <= ptr2));
ASSERT_EQUAL(true, (ptr2 > ptr1));
ASSERT_EQUAL(true, (ptr2 >= ptr1));
ASSERT_EQUAL(false, (ptr2 < ptr1));
ASSERT_EQUAL(false, (ptr2 <= ptr1));
ASSERT_EQUAL(false, (ptr1 > ptr2));
ASSERT_EQUAL(false, (ptr1 >= ptr2));
}
using T2 = float;
{ // Ensure different element types are not comparable
using device_ptr = thrust::device_ptr<T1>;
using other_ptr = thrust::device_ptr<T2>;
static_assert(thrust::detail::is_pointer_system_convertible_v<device_ptr, other_ptr>);
static_assert(!::cuda::std::__is_cpp17_equality_comparable_v<device_ptr, other_ptr>);
static_assert(!::cuda::std::__is_cpp17_less_than_comparable_v<device_ptr, other_ptr>);
}
{ // test different pointer types
using device_ptr = thrust::device_ptr<T1>;
using other_ptr =
thrust::pointer<T1, thrust::device_system_tag, thrust::tagged_reference<T1, thrust::device_system_tag>>;
static_assert(!::cuda::std::is_same_v<device_ptr, other_ptr>);
device_ptr ptr1 = v1.data();
other_ptr ptr2{other_ptr{thrust::raw_pointer_cast(ptr1 + 1)}};
// Equality
ASSERT_EQUAL(true, (ptr1 == ptr1));
ASSERT_EQUAL(false, (ptr1 != ptr1));
ASSERT_EQUAL(false, (ptr1 == ptr2));
ASSERT_EQUAL(true, (ptr1 != ptr2));
// Relations
ASSERT_EQUAL(true, (ptr1 < ptr2));
ASSERT_EQUAL(true, (ptr1 <= ptr2));
ASSERT_EQUAL(true, (ptr2 > ptr1));
ASSERT_EQUAL(true, (ptr2 >= ptr1));
ASSERT_EQUAL(false, (ptr2 < ptr1));
ASSERT_EQUAL(false, (ptr2 <= ptr1));
ASSERT_EQUAL(false, (ptr1 > ptr2));
ASSERT_EQUAL(false, (ptr1 >= ptr2));
}
{ // ensure that different pointer types with different element types are not comparable
using device_ptr = thrust::device_ptr<T1>;
using other_ptr =
thrust::pointer<T2, thrust::device_system_tag, thrust::tagged_reference<T1, thrust::device_system_tag>>;
static_assert(thrust::detail::is_pointer_system_convertible_v<device_ptr, other_ptr>);
static_assert(!::cuda::std::__is_cpp17_equality_comparable_v<device_ptr, other_ptr>);
static_assert(!::cuda::std::__is_cpp17_less_than_comparable_v<device_ptr, other_ptr>);
}
// For the non-cuda backends host_system_tag and device_system_tag are comparable
#if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
{ // ensure that pointers with different tags are not comparable
using device_ptr = thrust::device_ptr<T1>;
using other_ptr =
thrust::pointer<T1, thrust::host_system_tag, thrust::tagged_reference<T1, thrust::host_system_tag>>;
static_assert(!thrust::detail::is_pointer_system_convertible_v<device_ptr, other_ptr>);
static_assert(!::cuda::std::__is_cpp17_equality_comparable_v<device_ptr, other_ptr>);
static_assert(!::cuda::std::__is_cpp17_less_than_comparable_v<device_ptr, other_ptr>);
}
#endif // THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
{ // ensure that different pointers with different tags and types are not comparable
using device_ptr = thrust::device_ptr<T1>;
using other_ptr =
thrust::pointer<T2, thrust::host_system_tag, thrust::tagged_reference<T1, thrust::host_system_tag>>;
// For the non-cuda backends host_system_tag and device_system_tag are comparable
static_assert(thrust::detail::is_pointer_system_convertible_v<device_ptr, other_ptr>
== (THRUST_DEVICE_SYSTEM != THRUST_DEVICE_SYSTEM_CUDA));
static_assert(!::cuda::std::__is_cpp17_equality_comparable_v<device_ptr, other_ptr>);
static_assert(!::cuda::std::__is_cpp17_less_than_comparable_v<device_ptr, other_ptr>);
}
}
DECLARE_UNITTEST(TestDevicePointerCompare);
template <typename Vector>
void TestToAddress()
{
using T = typename Vector::value_type;
Vector vec(3);
T* first;
T* last;
first = cuda::std::to_address(&vec[0]);
last = cuda::std::to_address(&vec[2]);
ASSERT_EQUAL(last - first, 2);
first = cuda::std::to_address(&vec.front());
last = cuda::std::to_address(&vec.back());
ASSERT_EQUAL(last - first, 2);
first = cuda::std::to_address(vec.begin());
last = cuda::std::to_address(vec.end());
ASSERT_EQUAL(last - first, 3);
}
DECLARE_VECTOR_UNITTEST(TestToAddress);
// Verify that cuda::std::pointer_traits<device_ptr<T>>::rebind produces the
// correct pointer type, not a nested struct. This is required for
// cuda::std::allocator_traits to correctly compute void_pointer when an
// allocator uses device_ptr as its pointer type (e.g. rmm::mr::thrust_allocator).
// See GitHub issue #8485.
struct device_char_allocator
{
using value_type = char;
using pointer = thrust::device_ptr<char>;
pointer allocate(std::size_t n);
void deallocate(pointer p, std::size_t);
};
// pointer_traits::rebind should produce a pointer type, not a rebind struct.
static_assert(
cuda::std::is_same_v<cuda::std::pointer_traits<thrust::device_ptr<char>>::rebind<void>, thrust::device_ptr<void>>,
"pointer_traits<device_ptr<char>>::rebind<void> should be device_ptr<void>");
static_assert(
cuda::std::is_same_v<cuda::std::pointer_traits<thrust::device_ptr<int>>::rebind<float>, thrust::device_ptr<float>>,
"pointer_traits<device_ptr<int>>::rebind<float> should be device_ptr<float>");
// allocator_traits::void_pointer must resolve to device_ptr<void> for allocators
// whose pointer type is device_ptr<T>.
static_assert(
cuda::std::is_same_v<cuda::std::allocator_traits<device_char_allocator>::void_pointer, thrust::device_ptr<void>>,
"allocator_traits::void_pointer should be device_ptr<void> for device_ptr-based allocators");