Memory CUDA内存分配和访问出现问题
我现在正在学习CUDA。我有一些MPI的基本经验,所以我想我应该从一些非常简单的向量操作开始。我想写一个并行点积的东西。我无法将内存分配/写入CUDA设备,或者无法将其正确带回主机cudaMemcpyMemory CUDA内存分配和访问出现问题,memory,gpgpu,cuda,Memory,Gpgpu,Cuda,我现在正在学习CUDA。我有一些MPI的基本经验,所以我想我应该从一些非常简单的向量操作开始。我想写一个并行点积的东西。我无法将内存分配/写入CUDA设备,或者无法将其正确带回主机cudaMemcpy /*Code for a CUDA test project doing a basic dot product with doubles * * * */ #include <stdio.h> #include
/*Code for a CUDA test project doing a basic dot product with doubles
*
*
*
*/
#include <stdio.h>
#include <cuda.h>
__global__ void GPU_parallelDotProduct(double *array_a, double *array_b, double *dot){
dot[0] += array_a[threadIdx.x] * array_b[threadIdx.x];
}
__global__ void GPU_parallelSetupVector(double *vector, int dim, int incrSize, int start){
if(threadIdx.x<dim){
vector[threadIdx.x] = start + threadIdx.x * incrSize;
}
}
__host__ void CPU_serialDot(double *first, double *second, double *dot, int dim){
for(int i=0; i<dim; ++i){
dot[0] += first[i] * second[i];
}
}
__host__ void CPU_serialSetupVector(double *vector, int dim, int incrSize, int start){
for(int i=0; i<dim; ++i){
vector[i] = start + i * incrSize;
}
}
int main(){
//define array size to be used
//int i,j;
int VECTOR_LENGTH = 8;
int ELEMENT_SIZE = sizeof(double);
//arrays for dot product
//host
double *array_a = (double*) malloc(VECTOR_LENGTH * ELEMENT_SIZE);
double *array_b = (double*) malloc(VECTOR_LENGTH * ELEMENT_SIZE);
double *dev_dot_product = (double*) malloc(ELEMENT_SIZE);
double host_dot_product = 0.0;
//fill with values
CPU_serialSetupVector(array_a, VECTOR_LENGTH, 1, 0);
CPU_serialSetupVector(array_b, VECTOR_LENGTH, 1, 0);
//host dot
CPU_serialDot(array_a, array_b, &host_dot_product, VECTOR_LENGTH);
//device
double *dev_array_a;
double *dev_array_b;
double *dev_dot;
//allocate cuda memory
cudaMalloc((void**)&dev_array_a, ELEMENT_SIZE * VECTOR_LENGTH);
cudaMalloc((void**)&dev_array_b, ELEMENT_SIZE * VECTOR_LENGTH);
cudaMalloc((void**)&dev_dot, ELEMENT_SIZE);
//copy to from host to device
cudaMemcpy(dev_array_a, array_a, ELEMENT_SIZE * VECTOR_LENGTH, cudaMemcpyHostToDevice);
cudaMemcpy(dev_array_b, array_b, ELEMENT_SIZE * VECTOR_LENGTH, cudaMemcpyHostToDevice);
cudaMemcpy(dev_dot, &dev_dot_product, ELEMENT_SIZE, cudaMemcpyHostToDevice);
//init vectors
//GPU_parallelSetupVector<<<1, VECTOR_LENGTH>>>(dev_array_a, VECTOR_LENGTH, 1, 0);
//GPU_parallelSetupVector<<<1, VECTOR_LENGTH>>>(dev_array_b, VECTOR_LENGTH, 1, 0);
//GPU_parallelSetupVector<<<1, 1>>>(dev_dot, VECTOR_LENGTH, 0, 0);
//perform CUDA dot product
GPU_parallelDotProduct<<<1, VECTOR_LENGTH>>>(dev_array_a, dev_array_b, dev_dot);
//get computed product back to the machine
cudaMemcpy(dev_dot, dev_dot_product, ELEMENT_SIZE, cudaMemcpyDeviceToHost);
FILE *output = fopen("test_dotProduct_1.txt", "w");
fprintf(output, "HOST CALCULATION: %f \n", host_dot_product);
fprintf(output, "DEV CALCULATION: %f \n", dev_dot_product[0]);
fprintf(output, "PRINTING DEV ARRAY VALS: ARRAY A\n");
for(int i=0; i<VECTOR_LENGTH; ++i){
fprintf(output, "value %i: %f\n", i, dev_array_a[i]);
}
free(array_a);
free(array_b);
cudaFree(dev_array_a);
cudaFree(dev_array_b);
cudaFree(dev_dot);
return(0);
}
最好检查CUDA运行时调用的状态,如cudaMalloc、cudaMemcpy和内核启动。您可以在每次这样的调用之后执行以下操作,或者将其包装在某种宏中,并将CUDA运行时调用包装在宏中
if (cudaSuccess != cudaGetLastError())
printf( "Error!\n" );
现在,我不确定这是否是你的问题,但这样做可以消除明显的障碍。我可以看到两个问题: 您的GPU dot产品在此处包含内存竞争:
dot[0] += array_a[threadIdx.x] * array_b[threadIdx.x];
这是不安全的-块中的每个线程都将尝试使用其结果写入/覆盖相同的内存位置。编程模型无法保证当多个线程尝试将不同的值写入同一块内存时会发生什么情况
您的代码正试图直接访问设备内存位置
在主机中打印向量时。我很惊讶
代码不会产生segfault或保护错误。
dev_array_a不能由主机直接访问,它是一个
GPU内存中的指针。必须使用设备将副本托管到有效的主机
如果要检查dev_array_a的内容,请选择主机位置。
另一个答案中关于错误检查的建议也是一个很好的观点。每个API调用都会返回一个状态,您应该检查所有调用的状态,以确认在运行时没有错误或故障发生。是的,我现在意识到了这一点。我得更加小心。我想这可能就是问题所在。CUDA是否有类似MPI_的缩减?或者最好将每个值写入第三个数组,然后压缩第三个数组?现在我想知道这是否会更快,我现在回到线性时间。SDK包含了一个非常有用的简化示例和白皮书,值得一看。或者,推力模板库,它与CUDA工具包的最新版本一起使用C++实现了一个并行的还原,它在一个类似STL的向量类上工作,它隐藏了大部分设备内存管理,并将您的示例减少到大约十几行代码。每一个CUDA电话都有。设置CUDA或我的卡时,我是否缺少什么?您使用的CUDA驱动程序和编译器版本是什么?从中获取最新版本总是一个好主意
dot[0] += array_a[threadIdx.x] * array_b[threadIdx.x];