Files
project_6/cccl_upstream/thrust/testing/cuda/scan_by_key.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

230 lines
7.1 KiB
Plaintext

#include <thrust/execution_policy.h>
#include <thrust/functional.h>
#include <thrust/scan.h>
#include <unittest/unittest.h>
#ifdef THRUST_TEST_DEVICE_SIDE
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Iterator3>
__global__ void inclusive_scan_by_key_kernel(
ExecutionPolicy exec, Iterator1 keys_first, Iterator1 keys_last, Iterator2 values_first, Iterator3 result)
{
thrust::inclusive_scan_by_key(exec, keys_first, keys_last, values_first, result);
}
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Iterator3>
__global__ void exclusive_scan_by_key_kernel(
ExecutionPolicy exec, Iterator1 keys_first, Iterator1 keys_last, Iterator2 values_first, Iterator3 result)
{
thrust::exclusive_scan_by_key(exec, keys_first, keys_last, values_first, result);
}
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Iterator3, typename T>
__global__ void exclusive_scan_by_key_kernel(
ExecutionPolicy exec, Iterator1 keys_first, Iterator1 keys_last, Iterator2 values_first, Iterator3 result, T init)
{
thrust::exclusive_scan_by_key(exec, keys_first, keys_last, values_first, result, init);
}
template <typename ExecutionPolicy>
void TestScanByKeyDevice(ExecutionPolicy exec)
{
size_t n = 1000;
thrust::host_vector<int> h_keys(n);
for (size_t i = 0, k = 0; i < n; i++)
{
h_keys[i] = static_cast<int>(k);
if (rand() % 10 == 0)
{
k++;
}
}
thrust::device_vector<int> d_keys = h_keys;
thrust::host_vector<int> h_vals = unittest::random_integers<int>(n);
for (size_t i = 0; i < n; i++)
{
h_vals[i] = i % 10;
}
thrust::device_vector<int> d_vals = h_vals;
thrust::host_vector<int> h_output(n);
thrust::device_vector<int> d_output(n);
thrust::inclusive_scan_by_key(h_keys.begin(), h_keys.end(), h_vals.begin(), h_output.begin());
inclusive_scan_by_key_kernel<<<1, 1>>>(exec, d_keys.begin(), d_keys.end(), d_vals.begin(), d_output.begin());
{
cudaError_t const err = cudaDeviceSynchronize();
ASSERT_EQUAL(cudaSuccess, err);
}
ASSERT_EQUAL(d_output, h_output);
thrust::exclusive_scan_by_key(h_keys.begin(), h_keys.end(), h_vals.begin(), h_output.begin());
exclusive_scan_by_key_kernel<<<1, 1>>>(exec, d_keys.begin(), d_keys.end(), d_vals.begin(), d_output.begin());
{
cudaError_t const err = cudaDeviceSynchronize();
ASSERT_EQUAL(cudaSuccess, err);
}
ASSERT_EQUAL(d_output, h_output);
thrust::exclusive_scan_by_key(h_keys.begin(), h_keys.end(), h_vals.begin(), h_output.begin(), 11);
exclusive_scan_by_key_kernel<<<1, 1>>>(exec, d_keys.begin(), d_keys.end(), d_vals.begin(), d_output.begin(), 11);
{
cudaError_t const err = cudaDeviceSynchronize();
ASSERT_EQUAL(cudaSuccess, err);
}
ASSERT_EQUAL(d_output, h_output);
// in-place scans: in/out values aliasing
h_output = h_vals;
d_output = d_vals;
thrust::inclusive_scan_by_key(h_keys.begin(), h_keys.end(), h_output.begin(), h_output.begin());
inclusive_scan_by_key_kernel<<<1, 1>>>(exec, d_keys.begin(), d_keys.end(), d_output.begin(), d_output.begin());
{
cudaError_t const err = cudaDeviceSynchronize();
ASSERT_EQUAL(cudaSuccess, err);
}
ASSERT_EQUAL(d_output, h_output);
h_output = h_vals;
d_output = d_vals;
thrust::exclusive_scan_by_key(h_keys.begin(), h_keys.end(), h_output.begin(), h_output.begin(), 11);
exclusive_scan_by_key_kernel<<<1, 1>>>(exec, d_keys.begin(), d_keys.end(), d_output.begin(), d_output.begin(), 11);
{
cudaError_t const err = cudaDeviceSynchronize();
ASSERT_EQUAL(cudaSuccess, err);
}
ASSERT_EQUAL(d_output, h_output);
// in-place scans: keys/values aliasing
thrust::inclusive_scan_by_key(h_keys.begin(), h_keys.end(), h_vals.begin(), h_output.begin());
inclusive_scan_by_key_kernel<<<1, 1>>>(exec, d_keys.begin(), d_keys.end(), d_vals.begin(), d_keys.begin());
{
cudaError_t const err = cudaDeviceSynchronize();
ASSERT_EQUAL(cudaSuccess, err);
}
ASSERT_EQUAL(d_keys, h_output);
d_keys = h_keys;
thrust::exclusive_scan_by_key(h_keys.begin(), h_keys.end(), h_vals.begin(), h_output.begin(), 11);
exclusive_scan_by_key_kernel<<<1, 1>>>(exec, d_keys.begin(), d_keys.end(), d_vals.begin(), d_keys.begin(), 11);
{
cudaError_t const err = cudaDeviceSynchronize();
ASSERT_EQUAL(cudaSuccess, err);
}
ASSERT_EQUAL(d_keys, h_output);
}
void TestScanByKeyDeviceSeq()
{
TestScanByKeyDevice(thrust::seq);
}
DECLARE_UNITTEST(TestScanByKeyDeviceSeq);
void TestScanByKeyDeviceDevice()
{
TestScanByKeyDevice(thrust::device);
}
DECLARE_UNITTEST(TestScanByKeyDeviceDevice);
#endif
void TestInclusiveScanByKeyCudaStreams()
{
using Vector = thrust::device_vector<int>;
using T = Vector::value_type;
using Iterator = Vector::iterator;
Vector keys{0, 1, 1, 1, 2, 3, 3};
Vector vals{1, 2, 3, 4, 5, 6, 7};
Vector output(7, 0);
cudaStream_t s;
cudaStreamCreate(&s);
Iterator iter =
thrust::inclusive_scan_by_key(thrust::cuda::par.on(s), keys.begin(), keys.end(), vals.begin(), output.begin());
cudaStreamSynchronize(s);
ASSERT_EQUAL_QUIET(iter, output.end());
Vector ref{1, 2, 5, 9, 5, 6, 13};
ASSERT_EQUAL(output, ref);
thrust::inclusive_scan_by_key(
thrust::cuda::par.on(s),
keys.begin(),
keys.end(),
vals.begin(),
output.begin(),
::cuda::std::equal_to<T>(),
::cuda::std::multiplies<T>());
cudaStreamSynchronize(s);
ref = {1, 2, 6, 24, 5, 6, 42};
ASSERT_EQUAL(output, ref);
thrust::inclusive_scan_by_key(
thrust::cuda::par.on(s), keys.begin(), keys.end(), vals.begin(), output.begin(), ::cuda::std::equal_to<T>());
cudaStreamSynchronize(s);
ref = {1, 2, 5, 9, 5, 6, 13};
ASSERT_EQUAL(output, ref);
cudaStreamDestroy(s);
}
DECLARE_UNITTEST(TestInclusiveScanByKeyCudaStreams);
void TestExclusiveScanByKeyCudaStreams()
{
using Vector = thrust::device_vector<int>;
using T = Vector::value_type;
using Iterator = Vector::iterator;
Vector keys{0, 1, 1, 1, 2, 3, 3};
Vector vals{1, 2, 3, 4, 5, 6, 7};
Vector output(7, 0);
cudaStream_t s;
cudaStreamCreate(&s);
Iterator iter =
thrust::exclusive_scan_by_key(thrust::cuda::par.on(s), keys.begin(), keys.end(), vals.begin(), output.begin());
cudaStreamSynchronize(s);
ASSERT_EQUAL_QUIET(iter, output.end());
Vector ref{0, 0, 2, 5, 0, 0, 6};
ASSERT_EQUAL(output, ref);
thrust::exclusive_scan_by_key(thrust::cuda::par.on(s), keys.begin(), keys.end(), vals.begin(), output.begin(), T(10));
cudaStreamSynchronize(s);
ref = {10, 10, 12, 15, 10, 10, 16};
ASSERT_EQUAL(output, ref);
thrust::exclusive_scan_by_key(
thrust::cuda::par.on(s),
keys.begin(),
keys.end(),
vals.begin(),
output.begin(),
T(10),
::cuda::std::equal_to<T>(),
::cuda::std::multiplies<T>());
cudaStreamSynchronize(s);
ref = {10, 10, 20, 60, 10, 10, 60};
ASSERT_EQUAL(output, ref);
thrust::exclusive_scan_by_key(
thrust::cuda::par.on(s), keys.begin(), keys.end(), vals.begin(), output.begin(), T(10), ::cuda::std::equal_to<T>());
cudaStreamSynchronize(s);
ref = {10, 10, 12, 15, 10, 10, 16};
ASSERT_EQUAL(output, ref);
}
DECLARE_UNITTEST(TestExclusiveScanByKeyCudaStreams);