__CUDA_ARCH__ 带有 Thrust 执行策略的标志
__CUDA_ARCH__ flag with Thrust execution policy
我有一个 __host__ __device__
函数,它是调用 thrust 库的 "sort" 函数的包装器。在这个包装器中,我使用 __CUDA_ARCH__
标志将执行策略设置为 "thrust::device"(当从主机调用时)和 "thrust::seq"(当从设备调用时)。以下代码生成运行时错误 -
#ifndef __CUDA_ARCH__
thrust::stable_sort(thrust::device, data, data + num, customGreater<T>());
#else
thrust::stable_sort(thrust::seq, data, data + num, customGreater<T>());
#endif
错误是-
意外的标准异常:
What() is:merge_sort:第二步失败:无效的设备功能
据我理解,CUDA_ARCH可以用于条件编译。我请求帮助理解为什么会抛出此错误。
您似乎正在使用某些算法(包括排序)的 this issue. In a nutshell, thrust uses CUB 功能。您在代码中使用了 __CUDA_ARCH__
宏,它环绕着使用 CUB 的推力算法调用,这会干扰期望能够将此宏用于所有路径的 CUB 代码。
一个可能的解决方法是 "your own dispatch":
$ cat t142.cu
#include <iostream>
#include <thrust/sort.h>
#include <thrust/execution_policy.h>
template <typename T>
struct customGreater {
__host__ __device__ bool operator()(T &t1, T &t2){
return (t1 > t2);}
};
template <typename T>
__host__ __device__
void my_sort_wrapper(T *data, size_t num){
int hostdev = 0; // 0=device code
#ifndef __CUDA_ARCH__
hostdev = 1; // 1=host code
#endif
if (hostdev == 0) thrust::stable_sort(thrust::seq, data, data + num, customGreater<T>());
else thrust::stable_sort(thrust::device, data, data + num, customGreater<T>());
}
template <typename T>
__global__ void my_dev_sort(T *data, size_t num){
my_sort_wrapper(data, num);
}
typedef int mytype;
const size_t sz = 10;
int main(){
mytype *d_data;
cudaMalloc(&d_data, sz*sizeof(mytype));
cudaMemset(d_data, 0, sz*sizeof(mytype));
my_sort_wrapper(d_data, sz);
my_dev_sort<<<1,1>>>(d_data, sz);
cudaDeviceSynchronize();
}
$ nvcc t142.cu -o t142
$ cuda-memcheck ./t142
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
$
通过这种实现,__CUDA_ARCH__
宏的使用不会干扰推力算法的编译。
另一种可能的解决方法是对这两种情况简单地使用 thrust::device
策略(不分派 - 仅调用推力算法)。除了 CUDA 动态并行的情况外,thrust::device
在设备代码中使用时将 "decay" 到 thrust::seq
。
我预计只有当推力算法在底层实现中使用 CUB 功能时,这些建议才会 necessary/relevant。
如果您不喜欢这种行为,可以提交 thrust issue。
很遗憾,我们无法在 Thrust 中修复此问题。这里的麻烦是 NVCC 编译器需要在主机编译期间查看所有 __global__
函数模板实例化(例如,当 __CUDA_ARCH__
未定义时),否则内核将被视为未使用并被丢弃。有关详细信息,请参阅 this CUB GitHub issue。
正如罗伯特所建议的那样,像这样的解决方法应该没问题:
#include <iostream>
#include <thrust/sort.h>
#include <thrust/execution_policy.h>
template <typename T>
struct customGreater {
__host__ __device__ bool operator()(T &t1, T &t2){
return (t1 > t2);}
};
#if defined(__CUDA_ARCH__)
#define DEVICE_COMPILATION 1
#else
#define DEVICE_COMPILATION 0
#endif
template <typename T>
__host__ __device__
void my_sort(T *data, size_t num){
if (DEVICE_COMPILATION)
thrust::stable_sort(thrust::device, data, data + num, customGreater<T>());
else
thrust::stable_sort(thrust::seq, data, data + num, customGreater<T>());
}
template <typename T>
__global__ void my_dev_sort(T *data, size_t num){
my_sort(data, num);
}
typedef int mytype;
const size_t sz = 10;
int main(){
mytype *d_data;
cudaMallocManaged(&d_data, sz*sizeof(mytype));
cudaMemset(d_data, 0, sz*sizeof(mytype));
my_sort(d_data, sz);
my_dev_sort<<<1,1>>>(d_data, sz);
cudaFree(d_data);
cudaDeviceSynchronize();
}
我有一个 __host__ __device__
函数,它是调用 thrust 库的 "sort" 函数的包装器。在这个包装器中,我使用 __CUDA_ARCH__
标志将执行策略设置为 "thrust::device"(当从主机调用时)和 "thrust::seq"(当从设备调用时)。以下代码生成运行时错误 -
#ifndef __CUDA_ARCH__
thrust::stable_sort(thrust::device, data, data + num, customGreater<T>());
#else
thrust::stable_sort(thrust::seq, data, data + num, customGreater<T>());
#endif
错误是-
意外的标准异常: What() is:merge_sort:第二步失败:无效的设备功能
据我理解,CUDA_ARCH可以用于条件编译。我请求帮助理解为什么会抛出此错误。
您似乎正在使用某些算法(包括排序)的 this issue. In a nutshell, thrust uses CUB 功能。您在代码中使用了 __CUDA_ARCH__
宏,它环绕着使用 CUB 的推力算法调用,这会干扰期望能够将此宏用于所有路径的 CUB 代码。
一个可能的解决方法是 "your own dispatch":
$ cat t142.cu
#include <iostream>
#include <thrust/sort.h>
#include <thrust/execution_policy.h>
template <typename T>
struct customGreater {
__host__ __device__ bool operator()(T &t1, T &t2){
return (t1 > t2);}
};
template <typename T>
__host__ __device__
void my_sort_wrapper(T *data, size_t num){
int hostdev = 0; // 0=device code
#ifndef __CUDA_ARCH__
hostdev = 1; // 1=host code
#endif
if (hostdev == 0) thrust::stable_sort(thrust::seq, data, data + num, customGreater<T>());
else thrust::stable_sort(thrust::device, data, data + num, customGreater<T>());
}
template <typename T>
__global__ void my_dev_sort(T *data, size_t num){
my_sort_wrapper(data, num);
}
typedef int mytype;
const size_t sz = 10;
int main(){
mytype *d_data;
cudaMalloc(&d_data, sz*sizeof(mytype));
cudaMemset(d_data, 0, sz*sizeof(mytype));
my_sort_wrapper(d_data, sz);
my_dev_sort<<<1,1>>>(d_data, sz);
cudaDeviceSynchronize();
}
$ nvcc t142.cu -o t142
$ cuda-memcheck ./t142
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
$
通过这种实现,__CUDA_ARCH__
宏的使用不会干扰推力算法的编译。
另一种可能的解决方法是对这两种情况简单地使用 thrust::device
策略(不分派 - 仅调用推力算法)。除了 CUDA 动态并行的情况外,thrust::device
在设备代码中使用时将 "decay" 到 thrust::seq
。
我预计只有当推力算法在底层实现中使用 CUB 功能时,这些建议才会 necessary/relevant。
如果您不喜欢这种行为,可以提交 thrust issue。
很遗憾,我们无法在 Thrust 中修复此问题。这里的麻烦是 NVCC 编译器需要在主机编译期间查看所有 __global__
函数模板实例化(例如,当 __CUDA_ARCH__
未定义时),否则内核将被视为未使用并被丢弃。有关详细信息,请参阅 this CUB GitHub issue。
正如罗伯特所建议的那样,像这样的解决方法应该没问题:
#include <iostream>
#include <thrust/sort.h>
#include <thrust/execution_policy.h>
template <typename T>
struct customGreater {
__host__ __device__ bool operator()(T &t1, T &t2){
return (t1 > t2);}
};
#if defined(__CUDA_ARCH__)
#define DEVICE_COMPILATION 1
#else
#define DEVICE_COMPILATION 0
#endif
template <typename T>
__host__ __device__
void my_sort(T *data, size_t num){
if (DEVICE_COMPILATION)
thrust::stable_sort(thrust::device, data, data + num, customGreater<T>());
else
thrust::stable_sort(thrust::seq, data, data + num, customGreater<T>());
}
template <typename T>
__global__ void my_dev_sort(T *data, size_t num){
my_sort(data, num);
}
typedef int mytype;
const size_t sz = 10;
int main(){
mytype *d_data;
cudaMallocManaged(&d_data, sz*sizeof(mytype));
cudaMemset(d_data, 0, sz*sizeof(mytype));
my_sort(d_data, sz);
my_dev_sort<<<1,1>>>(d_data, sz);
cudaFree(d_data);
cudaDeviceSynchronize();
}