我正在尝试在__device__
变量上应用内核函数,根据规范,它在全局内存中驻留""
#include <stdio.h>
#include "sys_data.h"
#include "my_helper.cuh"
#include "helper_cuda.h"
#include <cuda_runtime.h>
double X[10] = {1,-2,3,-4,5,-6,7,-8,9,-10};
double Y[10] = {0};
__device__ double DEV_X[10];
int main(void) {
checkCudaErrors(cudaMemcpyToSymbol(DEV_X, X,10*sizeof(double)));
vector_projection<double><<<1,10>>>(DEV_X, 10);
getLastCudaError("oops");
checkCudaErrors(cudaMemcpyFromSymbol(Y, DEV_X, 10*sizeof(double)));
return 0;
}
核心函数vector_projection
在my_helper.cuh
中定义如下:
template<typename T> __global__ void vector_projection(T *dx, int n) {
int tid;
tid = threadIdx.x + blockIdx.x * blockDim.x;
if (tid < n) {
if (dx[tid] < 0)
dx[tid] = (T) 0;
}
}
如您所见,我使用cudaMemcpyToSymbol
和cudaMemcpyFromSymbol
与设备之间传输数据。但是,我收到以下错误:
CUDA error at ../src/vectorAdd.cu:19 code=4(cudaErrorLaunchFailure)
"cudaMemcpyFromSymbol(Y, DEV_X, 10*sizeof(double))"
脚注:我当然可以避免使用__device__
个变量,然后选择能正常工作的like this;我只想看看如何用__device__
变量做同样的事情(如果可能的话)。
更新:cuda-memcheck
的输出可在http://pastebin.com/AW9vmjFs找到。我得到的错误消息如下:
========= Invalid __global__ read of size 8
========= at 0x000000c8 in /home/ubuntu/Test0001/Debug/../src/my_helper.cuh:75:void vector_projection<double>(double*, int)
========= by thread (9,0,0) in block (0,0,0)
========= Address 0x000370e8 is out of bounds
答案 0 :(得分:6)
问题的根源在于你是not allowed to take the address of a device variable in ordinary host code:
vector_projection<double><<<1,10>>>(DEV_X, 10);
^
虽然这似乎可以正确编译,但传递的实际地址是垃圾。
要在主机代码中获取设备变量的地址,我们可以使用cudaGetSymbolAddress
这是一个为我编译和运行正常的实例:
$ cat t577.cu
#include <stdio.h>
double X[10] = {1,-2,3,-4,5,-6,7,-8,9,-10};
double Y[10] = {0};
__device__ double DEV_X[10];
template<typename T> __global__ void vector_projection(T *dx, int n) {
int tid;
tid = threadIdx.x + blockIdx.x * blockDim.x;
if (tid < n) {
if (dx[tid] < 0)
dx[tid] = (T) 0;
}
}
int main(void) {
cudaMemcpyToSymbol(DEV_X, X,10*sizeof(double));
double *my_dx;
cudaGetSymbolAddress((void **)&my_dx, DEV_X);
vector_projection<double><<<1,10>>>(my_dx, 10);
cudaMemcpyFromSymbol(Y, DEV_X, 10*sizeof(double));
for (int i = 0; i < 10; i++)
printf("%d: %f\n", i, Y[i]);
return 0;
}
$ nvcc -arch=sm_35 -o t577 t577.cu
$ cuda-memcheck ./t577
========= CUDA-MEMCHECK
0: 1.000000
1: 0.000000
2: 3.000000
3: 0.000000
4: 5.000000
5: 0.000000
6: 7.000000
7: 0.000000
8: 9.000000
9: 0.000000
========= ERROR SUMMARY: 0 errors
$
这不是解决这个问题的唯一方法。在设备代码中获取设备变量的地址是合法的,因此您可以使用以下行来修改内核:
T *dx = DEV_X;
并放弃将设备变量作为内核参数传递。根据评论中的建议,您还可以修改代码以使用Unified Memory。
关于错误检查,如果您偏离proper cuda error checking并且在偏差方面不小心,结果可能会令人困惑。除了由自己的行为引起的错误之外,大多数cuda API调用都可以返回由于某些先前的CUDA异步活动(通常是内核调用)而导致的错误。