[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:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user