[CCCL] 瘦身 + 补全: 移除 cudax/python/libcudacxx-tests 冗余文件, 新增 c2h 测试助手 + cmake 构建系统 + 8 个 CUDA thrust examples

变更摘要:
- 删除: cudax/ (783 files, 7.2M) — 实验性组件,竞赛不需要
- 删除: python/ (226 files, 2.0M) — Python 绑定,竞赛不需要
- 删除: libcudacxx/{test,benchmarks,codegen,cmake,share} (4432 files, 31M)
  保留: libcudacxx/include/ (1463 headers, cuda::std 编译依赖)
- 新增: c2h/ (27 files) — CUB Catch2 测试辅助头文件,编译 243 个测试必需
- 新增: cmake/ (29 files) — CCCL 原生 CMake 构建系统
- 新增: thrust/examples/cuda/ (7 files) + cpp_integration/ (1 file)
  async_reduce, custom_temporary_allocation, explicit_cuda_stream,
  global_device_vector, range_view, unwrap_pointer, wrap_pointer, device

结果: cccl_upstream 从 74M→35M (瘦身 53%), 核心内容 100% 保留:
  27/27 tuning headers, 78 benchmarks, 243 tests,
  60 thrust examples, 18 CUB examples, 全部编译头文件
This commit is contained in:
muh-bot
2026-08-03 12:39:26 +00:00
parent a2a5dd8f00
commit 24ef6a91b5
5439 changed files with 0 additions and 719516 deletions

View File

@@ -1,85 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
/**
* @file
*
* @brief Example of task implementing a chain of CUDA kernels with dynamic dependencies (add_deps)
*
*/
#include <cuda/experimental/stf.cuh>
using namespace cuda::experimental::stf;
__global__ void axpy(double a, slice<const double> x, slice<double> y)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int i = tid; i < x.size(); i += nthreads)
{
y(i) += a * x(i);
}
}
double X0(int i)
{
return sin((double) i);
}
double Y0(int i)
{
return cos((double) i);
}
int main()
{
context ctx = graph_ctx();
const size_t N = 16;
double X[N], Y[N];
for (size_t i = 0; i < N; i++)
{
X[i] = X0(i);
Y[i] = Y0(i);
}
double alpha = 3.14;
double beta = 4.5;
double gamma = -4.1;
auto lX = ctx.logical_data(X);
auto lY = ctx.logical_data(Y);
/* Compute Y = Y + alpha X, Y = Y + beta X and then Y = Y + gamma X */
auto t = ctx.cuda_kernel_chain();
t.add_deps(lX.read());
t.add_deps(lY.rw());
t->*[&]() {
auto dX = t.template get<slice<double>>(0);
auto dY = t.template get<slice<double>>(1);
// clang-format off
return std::vector<cuda_kernel_desc> {
{ axpy, 16, 128, 0, alpha, dX, dY },
{ axpy, 16, 128, 0, beta, dX, dY },
{ axpy, 16, 128, 0, gamma, dX, dY }
};
// clang-format on
};
ctx.finalize();
for (size_t i = 0; i < N; i++)
{
assert(fabs(Y[i] - (Y0(i) + (alpha + beta + gamma) * X0(i))) < 0.0001);
assert(fabs(X[i] - X0(i)) < 0.0001);
}
}

View File

@@ -1,89 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
/**
* @file
*
* @brief Example of task implementing a chain of CUDA kernels with dynamic dependencies (add_deps)
*
*/
#include <cuda/experimental/stf.cuh>
using namespace cuda::experimental::stf;
__global__ void axpy(double a, slice<const double> x, slice<double> y)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int i = tid; i < x.size(); i += nthreads)
{
y(i) += a * x(i);
}
}
double X0(int i)
{
return sin((double) i);
}
double Y0(int i)
{
return cos((double) i);
}
int main()
{
context ctx = graph_ctx();
const size_t N = 16;
double X[N], Y[N];
for (size_t i = 0; i < N; i++)
{
X[i] = X0(i);
Y[i] = Y0(i);
}
double alpha = 3.14;
double beta = 4.5;
double gamma = -4.1;
auto lX = ctx.logical_data(X);
auto lY = ctx.logical_data(Y);
/* Compute Y = Y + alpha X, Y = Y + beta X and then Y = Y + gamma X */
auto t = ctx.cuda_kernel_chain();
t.add_deps(lX.read());
t.add_deps(lY.rw());
t.start();
auto dX = t.template get<slice<double>>(0);
auto dY = t.template get<slice<double>>(1);
::std::vector<cuda_kernel_desc> descs;
descs.resize(3);
// Configure with types
descs[0].configure(axpy, 16, 128, 0, alpha, dX, dY);
descs[1].configure(axpy, 16, 128, 0, beta, dX, dY);
// Configure with low level API
const void* args[3] = {&gamma, &dX, &dY};
descs[2].configure_raw(axpy, 16, 128, 0, 3, args);
t.add_kernel_desc(descs);
t.end();
ctx.finalize();
for (size_t i = 0; i < N; i++)
{
assert(fabs(Y[i] - (Y0(i) + (alpha + beta + gamma) * X0(i))) < 0.0001);
assert(fabs(X[i] - X0(i)) < 0.0001);
}
}

View File

@@ -1,55 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
/**
* @file
*
* @brief Make sure we can compile with no arguments in CUDA kernel
*
*/
#include <cuda/experimental/stf.cuh>
using namespace cuda::experimental::stf;
__global__ void dummy() {}
double X0(int i)
{
return sin((double) i);
}
double Y0(int i)
{
return cos((double) i);
}
int main()
{
context ctx = graph_ctx();
const size_t N = 16;
double X[N], Y[N];
for (size_t i = 0; i < N; i++)
{
X[i] = X0(i);
Y[i] = Y0(i);
}
auto lX = ctx.logical_data(X);
auto lY = ctx.logical_data(Y);
// Ensure this works without arguments in the kernel
ctx.cuda_kernel(lX.read(), lY.rw())->*[&](auto, auto) {
return cuda_kernel_desc{dummy, 16, 128, 0};
};
ctx.finalize();
}

View File

@@ -1,82 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
template <typename T>
__global__ void axpy(size_t n, T a, const T* x, T* y)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int ind = tid; ind < n; ind += nthreads)
{
y[ind] += a * x[ind];
}
}
template <typename T>
__global__ void setup_vectors(size_t n, T* x, T* y)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (size_t ind = tid; ind < n; ind += nthreads)
{
x[ind] = 1.0 * ind;
y[ind] = 2.0 * ind - 3.0;
}
}
template <typename Ctx>
void run()
{
Ctx ctx;
const size_t n = 12;
const double alpha = 2.0;
double *dX, *dY;
cuda_safe_call(cudaMalloc((void**) &dX, n * sizeof(double)));
cuda_safe_call(cudaMalloc((void**) &dY, n * sizeof(double)));
// Use a kernel to setup values
setup_vectors<<<16, 16>>>(n, dX, dY);
cuda_safe_call(cudaDeviceSynchronize());
// We here provide device addresses and memory node 1 (which is assumed to
// be device 0)
auto handle_X = ctx.logical_data(make_slice(dX, n), data_place::device(0));
auto handle_Y = ctx.logical_data(make_slice(dY, n), data_place::device(0));
ctx.task(handle_X.read(), handle_Y.rw())->*[&](cudaStream_t stream, auto X, auto Y) {
axpy<<<16, 128, 0, stream>>>(n, alpha, X.data_handle(), Y.data_handle());
};
// Access Ask to use X, Y and Z on the host
ctx.host_launch(handle_X.read(), handle_Y.read())->*[&](auto X, auto Y) {
for (size_t ind = 0; ind < n; ind++)
{
// X unchanged
EXPECT(fabs(X(ind) - 1.0 * ind) < 0.00001);
// Y = Y + alpha X
EXPECT(fabs(Y(ind) - (-3.0 + ind * (2.0 + alpha))) < 0.00001);
}
};
ctx.finalize();
}
int main()
{
run<stream_ctx>();
run<graph_ctx>();
}

View File

@@ -1,97 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
template <typename T>
__global__ void axpy(int N, T a, const T* x, T* y)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int ind = tid; ind < N; ind += nthreads)
{
y[ind] += a * x[ind];
}
}
template <typename T>
__global__ void setup_vectors(int N, T* x, T* y, T* z)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int ind = tid; ind < N; ind += nthreads)
{
x[ind] = 1.0 * ind;
y[ind] = 2.0 * ind - 3.0;
z[ind] = 7.0 * ind + 6.0;
}
}
template <typename Ctx>
void run()
{
Ctx ctx;
const double alpha = 2.0;
const int N = 12;
double *dX, *dY, *dZ;
cuda_safe_call(cudaMalloc((void**) &dX, N * sizeof(double)));
cuda_safe_call(cudaMalloc((void**) &dY, N * sizeof(double)));
cuda_safe_call(cudaMalloc((void**) &dZ, N * sizeof(double)));
// Use a kernel to setup values
setup_vectors<<<16, 16>>>(N, dX, dY, dZ);
cuda_safe_call(cudaDeviceSynchronize());
// We here provide device addresses and memory node 1 (which is assumed to
// be device 0)
auto handle_X = ctx.logical_data(make_slice(dX, N), data_place::device(0));
auto handle_Y = ctx.logical_data(make_slice(dY, N), data_place::device(0));
auto handle_Z = ctx.logical_data(make_slice(dZ, N), data_place::device(0));
ctx.task(handle_X.read(), handle_Y.rw())->*[&](cudaStream_t stream, auto X, auto Y) {
axpy<<<16, 128, 0, stream>>>(N, alpha, X.data_handle(), Y.data_handle());
};
ctx.task(handle_X.read(), handle_Z.rw())->*[&](cudaStream_t stream, auto X, auto Z) {
axpy<<<16, 128, 0, stream>>>(N, alpha, X.data_handle(), Z.data_handle());
};
ctx.task(handle_Y.read(), handle_Z.rw())->*[&](cudaStream_t stream, auto Y, auto Z) {
axpy<<<16, 128, 0, stream>>>(N, alpha, Y.data_handle(), Z.data_handle());
};
// Access Ask to use X, Y and Z on the host
ctx.host_launch(handle_X.read(), handle_Y.read(), handle_Z.read())->*[&](auto X, auto Y, auto Z) {
for (size_t ind = 0; ind < N; ind++)
{
// X unchanged
EXPECT(fabs(X(ind) - 1.0 * ind) < 0.00001);
// Y = Y + alpha X
EXPECT(fabs(Y(ind) - (-3.0 + ind * (2.0 + alpha))) < 0.00001);
// Z = Z + alpha (X + alpha Y)
EXPECT(fabs(Z(ind) - ((6.0 - 3 * alpha) + ind * (7.0 + 3 * alpha + alpha * alpha))) < 0.00001);
}
};
ctx.finalize();
}
int main()
{
run<stream_ctx>();
run<graph_ctx>();
}

View File

@@ -1,78 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
/*
* This test makes sure write-back works even if the original data place was a device
*/
template <typename T>
__global__ void setup(slice<T> s)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int ind = tid; ind < s.size(); ind += nthreads)
{
s(ind) = 1.0 * ind;
}
}
template <typename T>
__global__ void check(T* x, size_t n)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int ind = tid; ind < n; ind += nthreads)
{
assert(x[ind] == 2.0 * ind + 1.0);
}
}
template <typename Ctx>
void run()
{
Ctx ctx;
const size_t n = 12;
double* dX;
cuda_safe_call(cudaMalloc((void**) &dX, n * sizeof(double)));
// We here provide device addresses and memory node 1 (which is assumed to
// be device 0)
auto handle_X = ctx.logical_data(make_slice(dX, n), data_place::device(0));
ctx.task(handle_X.write())->*[&](cudaStream_t stream, auto X) {
setup<<<16, 128, 0, stream>>>(X);
};
ctx.host_launch(handle_X.rw())->*[&](auto X) {
for (size_t ind = 0; ind < n; ind++)
{
X(ind) = 2.0 * X(ind) + 1.0;
}
};
ctx.finalize();
// Check if data was properly written-back with a blocking kernel
check<<<16, 128>>>(dX, n);
}
int main()
{
run<stream_ctx>();
run<graph_ctx>();
}

View File

@@ -1,100 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
// #include <cuda/experimental/__stf/graph/interfaces/slice.cuh>
using namespace cuda::experimental::stf;
template <typename T>
__global__ void axpy(int N, T a, const T* x, T* y)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int ind = tid; ind < N; ind += nthreads)
{
y[ind] += a * x[ind];
}
}
template <typename T>
__global__ void setup_vectors(int N, T* x, T* y, T* z)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (int ind = tid; ind < N; ind += nthreads)
{
x[ind] = 1.0 * ind;
y[ind] = 2.0 * ind - 3.0;
z[ind] = 7.0 * ind + 6.0;
}
}
int main(int argc, char** argv)
{
graph_ctx ctx;
const int N = 12;
const double alpha = 2.0;
double *dX, *dY, *dZ;
cuda_safe_call(cudaMalloc((void**) &dX, N * sizeof(double)));
cuda_safe_call(cudaMalloc((void**) &dY, N * sizeof(double)));
cuda_safe_call(cudaMalloc((void**) &dZ, N * sizeof(double)));
// Use a kernel to setup values
setup_vectors<<<16, 16>>>(N, dX, dY, dZ);
cuda_safe_call(cudaDeviceSynchronize());
// We here provide device addresses and memory node 1 (which is assumed to
// be device 0)
auto handle_X = ctx.logical_data(make_slice(dX, N), data_place::device(0));
auto handle_Y = ctx.logical_data(make_slice(dY, N), data_place::device(0));
auto handle_Z = ctx.logical_data(make_slice(dZ, N), data_place::device(0));
// Y = Y + alpha X
ctx.task(handle_X.read(), handle_Y.rw())->*[&](cudaStream_t stream, auto dX, auto dY) {
axpy<<<16, 16, 0, stream>>>(N, alpha, dX.data_handle(), dY.data_handle());
};
// Z = Z + alpha X
ctx.task(handle_X.read(), handle_Z.rw())->*[&](cudaStream_t stream, auto dX, auto dZ) {
axpy<<<16, 16, 0, stream>>>(N, alpha, dX.data_handle(), dZ.data_handle());
};
// Z = Z + alpha Y
ctx.task(handle_Y.read(), handle_Z.rw())->*[&](cudaStream_t stream, auto dY, auto dZ) {
axpy<<<16, 16, 0, stream>>>(N, alpha, dY.data_handle(), dZ.data_handle());
};
ctx.host_launch(handle_X.read(), handle_Y.read(), handle_Z.read())->*[&](auto hX, auto hY, auto hZ) {
for (size_t ind = 0; ind < N; ind++)
{
// X unchanged
EXPECT(fabs(hX(ind) - 1.0 * ind) < 0.00001);
// Y = Y + alpha X
EXPECT(fabs(hY(ind) - (-3.0 + ind * (2.0 + alpha))) < 0.00001);
// Z = Z + alpha (X + alpha Y)
EXPECT(fabs(hZ(ind) - ((6.0 - 3 * alpha) + ind * (7.0 + 3 * alpha + alpha * alpha))) < 0.00001);
}
};
ctx.submit();
if (argc > 1)
{
std::cout << "Generating DOT output in " << argv[1] << '\n';
ctx.print_to_dot(argv[1]);
}
ctx.finalize();
}

View File

@@ -1,388 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
//! \file
//! \brief Tests for the host_launch untyped dispatch path (host_launch_deps)
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
// ---------------------------------------------------------------------------
// stream_ctx tests
// ---------------------------------------------------------------------------
void test_stream_basic()
{
const size_t N = 64;
double X[N];
for (size_t i = 0; i < N; i++)
{
X[i] = static_cast<double>(i);
}
stream_ctx ctx;
auto lX = ctx.logical_data(X);
auto scope = ctx.host_launch();
scope.add_deps(task_dep_untyped(lX, access_mode::read));
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 1);
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
EXPECT(sX(i) == static_cast<double>(i));
}
};
ctx.finalize();
}
void test_stream_multiple_deps()
{
const size_t N = 32;
double X[N], Y[N];
for (size_t i = 0; i < N; i++)
{
X[i] = static_cast<double>(i);
Y[i] = static_cast<double>(i * 10);
}
stream_ctx ctx;
auto lX = ctx.logical_data(X);
auto lY = ctx.logical_data(Y);
auto scope = ctx.host_launch();
scope.add_deps(task_dep_untyped(lX, access_mode::read));
scope.add_deps(task_dep_untyped(lY, access_mode::read));
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 2);
auto sX = deps.get<slice<double>>(0);
auto sY = deps.get<slice<double>>(1);
for (size_t i = 0; i < 32; i++)
{
EXPECT(sX(i) == static_cast<double>(i));
EXPECT(sY(i) == static_cast<double>(i * 10));
}
};
ctx.finalize();
}
void test_stream_user_data()
{
stream_ctx ctx;
struct my_ctx
{
int magic;
double value;
};
my_ctx uctx{42, 3.14};
auto scope = ctx.host_launch();
scope.set_user_data(&uctx, sizeof(uctx));
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 0);
EXPECT(deps.user_data() != nullptr);
EXPECT(deps.user_data_size() == sizeof(my_ctx));
auto* u = static_cast<my_ctx*>(deps.user_data());
EXPECT(u->magic == 42);
EXPECT(u->value == 3.14);
};
ctx.finalize();
}
void test_stream_write_back()
{
const size_t N = 64;
double X[N];
for (size_t i = 0; i < N; i++)
{
X[i] = 0.0;
}
stream_ctx ctx;
auto lX = ctx.logical_data(X);
auto scope = ctx.host_launch();
scope.add_deps(task_dep_untyped(lX, access_mode::rw));
scope->*[](reserved::host_launch_deps& deps) {
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
sX(i) = static_cast<double>(i * 2);
}
};
ctx.host_launch(lX.read())->*[](auto sX) {
for (size_t i = 0; i < 64; i++)
{
EXPECT(sX(i) == static_cast<double>(i * 2));
}
};
ctx.finalize();
}
void test_stream_no_user_data()
{
stream_ctx ctx;
auto scope = ctx.host_launch();
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 0);
EXPECT(deps.user_data() == nullptr);
EXPECT(deps.user_data_size() == 0);
};
ctx.finalize();
}
void test_stream_chained()
{
const size_t N = 64;
double X[N];
for (size_t i = 0; i < N; i++)
{
X[i] = 1.0;
}
stream_ctx ctx;
auto lX = ctx.logical_data(X);
auto s1 = ctx.host_launch();
s1.add_deps(task_dep_untyped(lX, access_mode::rw));
s1->*[](reserved::host_launch_deps& deps) {
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
sX(i) *= 2.0;
}
};
auto s2 = ctx.host_launch();
s2.add_deps(task_dep_untyped(lX, access_mode::rw));
s2->*[](reserved::host_launch_deps& deps) {
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
sX(i) += 10.0;
}
};
ctx.host_launch(lX.read())->*[](auto sX) {
for (size_t i = 0; i < 64; i++)
{
EXPECT(sX(i) == 12.0);
}
};
ctx.finalize();
}
// ---------------------------------------------------------------------------
// graph_ctx tests
// ---------------------------------------------------------------------------
void test_graph_basic()
{
const size_t N = 64;
double X[N];
for (size_t i = 0; i < N; i++)
{
X[i] = static_cast<double>(i);
}
graph_ctx ctx;
auto lX = ctx.logical_data(X);
auto scope = ctx.host_launch();
scope.add_deps(task_dep_untyped(lX, access_mode::read));
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 1);
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
EXPECT(sX(i) == static_cast<double>(i));
}
};
ctx.finalize();
}
void test_graph_multiple_deps()
{
const size_t N = 32;
double X[N], Y[N];
for (size_t i = 0; i < N; i++)
{
X[i] = static_cast<double>(i);
Y[i] = static_cast<double>(i * 10);
}
graph_ctx ctx;
auto lX = ctx.logical_data(X);
auto lY = ctx.logical_data(Y);
auto scope = ctx.host_launch();
scope.add_deps(task_dep_untyped(lX, access_mode::read));
scope.add_deps(task_dep_untyped(lY, access_mode::read));
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 2);
auto sX = deps.get<slice<double>>(0);
auto sY = deps.get<slice<double>>(1);
for (size_t i = 0; i < 32; i++)
{
EXPECT(sX(i) == static_cast<double>(i));
EXPECT(sY(i) == static_cast<double>(i * 10));
}
};
ctx.finalize();
}
void test_graph_user_data()
{
graph_ctx ctx;
struct my_ctx
{
int magic;
double value;
};
my_ctx uctx{42, 3.14};
auto scope = ctx.host_launch();
scope.set_user_data(&uctx, sizeof(uctx));
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 0);
EXPECT(deps.user_data() != nullptr);
EXPECT(deps.user_data_size() == sizeof(my_ctx));
auto* u = static_cast<my_ctx*>(deps.user_data());
EXPECT(u->magic == 42);
EXPECT(u->value == 3.14);
};
ctx.finalize();
}
void test_graph_write_back()
{
const size_t N = 64;
double X[N];
for (size_t i = 0; i < N; i++)
{
X[i] = 0.0;
}
graph_ctx ctx;
auto lX = ctx.logical_data(X);
auto scope = ctx.host_launch();
scope.add_deps(task_dep_untyped(lX, access_mode::rw));
scope->*[](reserved::host_launch_deps& deps) {
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
sX(i) = static_cast<double>(i * 2);
}
};
ctx.host_launch(lX.read())->*[](auto sX) {
for (size_t i = 0; i < 64; i++)
{
EXPECT(sX(i) == static_cast<double>(i * 2));
}
};
ctx.finalize();
}
void test_graph_no_user_data()
{
graph_ctx ctx;
auto scope = ctx.host_launch();
scope->*[](reserved::host_launch_deps& deps) {
EXPECT(deps.size() == 0);
EXPECT(deps.user_data() == nullptr);
EXPECT(deps.user_data_size() == 0);
};
ctx.finalize();
}
void test_graph_chained()
{
const size_t N = 64;
double X[N];
for (size_t i = 0; i < N; i++)
{
X[i] = 1.0;
}
graph_ctx ctx;
auto lX = ctx.logical_data(X);
auto s1 = ctx.host_launch();
s1.add_deps(task_dep_untyped(lX, access_mode::rw));
s1->*[](reserved::host_launch_deps& deps) {
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
sX(i) *= 2.0;
}
};
auto s2 = ctx.host_launch();
s2.add_deps(task_dep_untyped(lX, access_mode::rw));
s2->*[](reserved::host_launch_deps& deps) {
auto sX = deps.get<slice<double>>(0);
for (size_t i = 0; i < 64; i++)
{
sX(i) += 10.0;
}
};
ctx.host_launch(lX.read())->*[](auto sX) {
for (size_t i = 0; i < 64; i++)
{
EXPECT(sX(i) == 12.0);
}
};
ctx.finalize();
}
int main()
{
// stream_ctx
test_stream_basic();
test_stream_multiple_deps();
test_stream_user_data();
test_stream_write_back();
test_stream_no_user_data();
test_stream_chained();
// graph_ctx
test_graph_basic();
test_graph_multiple_deps();
test_graph_user_data();
test_graph_write_back();
test_graph_no_user_data();
test_graph_chained();
return 0;
}

View File

@@ -1,87 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
/**
* @file
* @brief Test that we can use a local graph context within a task of the
* stream backend
*/
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
template <typename T>
__global__ void setup(slice<T> s)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (size_t ind = tid; ind < s.size(); ind += nthreads)
{
s(ind) = T(ind);
}
}
template <typename T>
__global__ void add(slice<T> s, T val)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (size_t ind = tid; ind < s.size(); ind += nthreads)
{
s(ind) += val;
}
}
int main()
{
stream_ctx ctx;
constexpr int N = 12;
int X[N];
for (int i = 0; i < N; i++)
{
X[i] = i;
}
auto lX = ctx.logical_data(X);
ctx.task(lX.rw())->*[](cudaStream_t stream, auto sX) {
graph_ctx gctx;
auto lX_alias = gctx.logical_data(sX, data_place::current_device());
// X(i) = (i + 17)
gctx.task(lX_alias.rw())->*[](cudaStream_t stream2, auto sX) {
add<<<16, 128, 0, stream2>>>(sX, 17);
};
// X(i) = 2*(i + 17) + 1
gctx.host_launch(lX_alias.rw())->*[&](auto sX) {
for (int ind = 0; ind < N; ind++)
{
sX(ind) = 2 * sX(ind) + 1;
}
};
gctx.submit(stream);
// no sync !
};
ctx.finalize();
for (int ind = 0; ind < N; ind++)
{
EXPECT(X[ind] == 2 * (ind + 17) + 1);
}
}

View File

@@ -1,119 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
/**
* @file
* @brief Test that we can use a local graph context within a task of the
* stream backend to create a CUDA graph that we can launch multiple
* times.
*/
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
template <typename T>
__global__ void setup(slice<T> s)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (size_t ind = tid; ind < s.size(); ind += nthreads)
{
s(ind) = T(ind);
}
}
template <typename T>
__global__ void add(slice<T> s, T val)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (size_t ind = tid; ind < s.size(); ind += nthreads)
{
s(ind) += val;
}
}
__global__ void slice_add(slice<const int> s_from, slice<int> s_to)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (size_t ind = tid; ind < s_from.size(); ind += nthreads)
{
s_to(ind) += s_from(ind);
}
}
int main()
{
stream_ctx ctx;
const int N = 12;
const size_t K = 10;
int X[N];
int Y[N];
for (int i = 0; i < N; i++)
{
X[i] = i;
Y[i] = -i;
}
auto lX = ctx.logical_data(X);
auto lY = ctx.logical_data(Y);
/*
* Create a CUDA graph from a single task, and launch it many times
*/
ctx.task(lX.rw(), lY.rw())->*[&](cudaStream_t stream, auto sX, auto sY) {
graph_ctx gctx;
auto lX_alias = gctx.logical_data(sX, data_place::current_device());
auto lY_alias = gctx.logical_data(sY, data_place::current_device());
for (size_t ii = 0; ii < 10; ii++)
{
gctx.task(lX_alias.rw())->*[](cudaStream_t stream2, auto sX) {
add<<<16, 128, 0, stream2>>>(sX, 17);
};
gctx.task(lY_alias.rw())->*[](cudaStream_t stream2, auto sY) {
add<<<16, 128, 0, stream2>>>(sY, 17);
};
gctx.task(lX_alias.read(), lY_alias.rw())->*[](cudaStream_t stream2, auto sX, auto sY) {
slice_add<<<16, 128, 0, stream2>>>(sX, sY);
};
gctx.task(lX_alias.rw())->*[](cudaStream_t stream2, auto sX) {
add<<<16, 128, 0, stream2>>>(sX, 17);
};
gctx.task(lY_alias.rw())->*[](cudaStream_t stream2, auto sY) {
add<<<16, 128, 0, stream2>>>(sY, 17);
};
}
// gctx.host_launch(lX_alias.rw())->*[&](auto sX) {
// for (size_t ind = 0; ind < N; ind++) {
// sX(ind) = 2 * sX(ind) + 1;
// }
// };
// gctx.print_to_dot("gctx" + std::to_string(iter));
auto exec_graph = gctx.instantiate();
for (size_t iter = 0; iter < K; iter++)
{
cudaGraphLaunch(*exec_graph, stream);
}
};
ctx.finalize();
}

View File

@@ -1,64 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
template <typename T>
class foo
{
public:
template <typename Ctx>
foo(Ctx& ctx, T* array, size_t n)
: h(ctx.logical_data(array, n))
{}
private:
logical_data_untyped h;
};
template <typename Ctx>
void run()
{
Ctx ctx;
const int N = 16;
double X[N], Y[N], Z[N];
for (size_t ind = 0; ind < N; ind++)
{
X[ind] = 0.0;
Y[ind] = 0.0;
Z[ind] = 0.0;
}
// Move logical_data_untyped directly
logical_data_untyped h1 = ctx.logical_data(X);
logical_data_untyped h2(std::move(h1));
// Ensures the methodology used in the move ctor of logical_data_untyped is working
// with multiple handles...
logical_data_untyped h3 = ctx.logical_data(Y);
logical_data_untyped h4(std::move(h3));
// Make sure a class containing a logical_data_untyped is movable
foo A = foo(ctx, &Z[0], N);
foo B = std::move(A);
ctx.finalize();
}
int main()
{
run<stream_ctx>();
run<graph_ctx>();
}

View File

@@ -1,71 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
template <typename T>
__global__ void scal(size_t n, T a, T* x)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
int nthreads = gridDim.x * blockDim.x;
for (size_t ind = tid; ind < n; ind += nthreads)
{
x[ind] = a * x[ind];
}
}
double x_init(int i)
{
return cos((double) i);
}
template <typename Ctx>
void run()
{
Ctx ctx;
const int n = 4096;
double X[n];
for (int ind = 0; ind < n; ind++)
{
X[ind] = x_init(ind);
}
auto handle_X = ctx.logical_data(X);
double alpha = 2.0;
int niter = 4;
for (int iter = 0; iter < niter; iter++)
{
ctx.task(handle_X.rw())->*[&](cudaStream_t s, auto sX) {
scal<<<16, 128, 0, s>>>(sX.size(), alpha, sX.data_handle());
};
}
// Ask to use Y on the host
ctx.host_launch(handle_X.read())->*[&](auto sX) {
for (int ind = 0; ind < n; ind++)
{
EXPECT(fabs(sX(ind) - pow(alpha, niter) * (x_init(ind))) < 0.00001);
}
};
ctx.finalize();
}
int main()
{
run<stream_ctx>();
run<graph_ctx>();
}

View File

@@ -1,124 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/graph/graph_ctx.cuh>
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
static __global__ void scalar_div(const double* a, const double* b, double* c)
{
*c = (*a) / (*b);
}
static __global__ void scalar_minus(const double* a, double* res)
{
*res = -(*a);
}
/**
* This class is an example of class to issue tasks when accessing a scalar
* value.
*
* This is not meant to be the most efficient approach, but this is
* supposedly convenient.
*
*/
template <typename Ctx>
class scalar
{
public:
scalar(Ctx* ctx, bool is_tmp = false)
: ctx(ctx)
{
size_t s = sizeof(double);
if (is_tmp)
{
// There is no physical backing for this temporary vector
h_addr = NULL;
}
else
{
h_addr = (double*) malloc(s);
cuda_safe_call(cudaHostRegister(h_addr, s, cudaHostRegisterPortable));
}
data_place d = is_tmp ? data_place::invalid() : data_place::host();
handle = ctx->logical_data(make_slice(h_addr), d);
}
// Copy constructor
scalar(const scalar& a)
: ctx(a.ctx)
{
h_addr = NULL;
handle = ctx->logical_data(make_slice((double*) nullptr));
ctx->task(handle.write(), a.handle.read())->*[](cudaStream_t stream, auto dst, auto src) {
// There are likely much more efficient ways.
cuda_safe_call(
cudaMemcpyAsync(dst.data_handle(), src.data_handle(), sizeof(double), cudaMemcpyDeviceToDevice, stream));
};
}
scalar operator/(scalar const& rhs) const
{
// Submit a task that computes this/rhs
scalar res(ctx);
ctx->task(handle.read(), rhs.handle.read(), res.handle.write())
->*[](cudaStream_t stream, auto x, auto y1, auto result) {
scalar_div<<<1, 1, 0, stream>>>(x.data_handle(), y1.data_handle(), result.data_handle());
};
return res;
}
scalar operator-() const
{
// Submit a task that computes -s
scalar res(ctx);
ctx->task(handle.read(), res.handle.write())->*[](cudaStream_t stream, auto x, auto result) {
scalar_minus<<<1, 1, 0, stream>>>(x.data_handle(), result.data_handle());
};
return res;
}
Ctx* ctx;
mutable logical_data<slice<double, 0>> handle;
double* h_addr;
};
template <typename Ctx>
void run()
{
Ctx ctx;
scalar a(&ctx);
scalar b(&ctx);
*a.h_addr = 42.0;
*b.h_addr = 12.3;
scalar c = (-a) / b;
ctx.host_launch(c.handle.read())->*[](auto x) {
EXPECT(fabs(*x.data_handle() - (-42.0) / 12.3) < 0.001);
};
ctx.finalize();
}
int main()
{
run<stream_ctx>();
run<graph_ctx>();
}

View File

@@ -1,72 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
/**
* @file
*
* @brief Ensure that the scalar data interface works on both stream and graph backends
*
*/
#include <cuda/experimental/stf.cuh>
using namespace cuda::experimental::stf;
void test_shape_from_scalar_view()
{
double x = 0;
scalar_view<double> sv(&x);
shape_of<scalar_view<double>> s = shape(sv);
EXPECT(s.size() == sizeof(double));
size_t n = 0;
scalar_view<size_t> sv_n(&n);
shape_of<scalar_view<size_t>> s_n = shape(sv_n);
EXPECT(s_n.size() == sizeof(size_t));
}
template <typename Ctx>
void run()
{
Ctx ctx;
double a = 42.0;
double b = 12.3;
auto la = ctx.logical_data(scalar_view<double>(&a)).set_symbol("a");
auto lb = ctx.logical_data(scalar_view<double>(&b)).set_symbol("b");
auto lc = ctx.logical_data(shape_of<scalar_view<double>>()).set_symbol("c");
ctx.parallel_for(box(1), la.read(), lb.read(), lc.write())->*[] __device__(size_t, auto a, auto b, auto c) {
*c.addr = *a.addr + *b.addr;
};
ctx.host_launch(lc.read())->*[](auto x) {
EXPECT(fabs(*x.addr - (42.0 + 12.3)) < 0.001);
};
// Exercise logical_data(la.shape()) when la is scalar_view-backed (uses shape_of from scalar_view)
auto ld = ctx.logical_data(la.shape()).set_symbol("d");
ctx.parallel_for(box(1), la.read(), ld.write())->*[] __device__(size_t, auto a, auto d) {
*d.addr = *a.addr;
};
ctx.host_launch(ld.read())->*[](auto x) {
EXPECT(fabs(*x.addr - 42.0) < 0.001);
};
ctx.finalize();
}
int main()
{
test_shape_from_scalar_view();
run<stream_ctx>();
run<graph_ctx>();
}

View File

@@ -1,50 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDASTF in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//
#include <cuda/experimental/__stf/stream/stream_ctx.cuh>
using namespace cuda::experimental::stf;
void host_inc(cudaStream_t /*unused*/, cudaError_t /*unused*/, void* userData)
{
/* Retrieve a pointer to the arguments and destroy it */
int* var = static_cast<int*>(userData);
*var = *var + 1;
}
int main()
{
int cnt = 0;
stream_ctx ctx;
auto h_cnt = ctx.logical_data(make_slice(&cnt, 1));
int NITER = 2;
for (int iter = 0; iter < NITER; iter++)
{
// Enqueue a dummy GPU task
ctx.task(h_cnt.rw())->*[&](cudaStream_t /*unused*/, auto /*unused*/) {
// no-op
};
// Enqueue a host callback
ctx.task(exec_place::host(), h_cnt.rw())->*[&](cudaStream_t stream, auto s_cnt) {
cuda_safe_call(cudaStreamAddCallback(stream, host_inc, s_cnt.data_handle(), 0));
cuda_safe_call(cudaGetLastError());
};
}
// Ask to use Y on the host
ctx.host_launch(h_cnt.read())->*[&](auto s_cnt) {
EXPECT(s_cnt(0) == NITER);
};
ctx.finalize();
}