我刚刚开始 CUDA 编程,并试图执行下面显示的代码。这个想法是将一个二维数组复制到设备,计算所有元素的总和并在之后检索总和(我知道这个算法不是并行化的。实际上它正在做更多的工作,然后是必要的。但这只是打算作为 memcopy 的练习)。
#include<stdio.h>
#include<cuda.h>
#include <iostream>
#include <cutil_inline.h>
#define height 50
#define width 50
using namespace std;
// Device code
__global__ void kernel(float* devPtr, int pitch,int* sum)
{
int tempsum = 0;
for (int r = 0; r < height; ++r) {
int* row = (int*)((char*)devPtr + r * pitch);
for (int c = 0; c < width; ++c) {
int element = row[c];
tempsum = tempsum + element;
}
}
*sum = tempsum;
}
//Host Code
int main()
{
int testarray[2][8] = {{4,4,4,4,4,4,4,4},{4,4,4,4,4,4,4,4}};
int* sum =0;
int* sumhost = 0;
sumhost = (int*)malloc(sizeof(int));
cout << *sumhost << endl;
float* devPtr;
size_t pitch;
cudaMallocPitch((void**)&devPtr, &pitch, width * sizeof(int), height);
cudaMemcpy2D(devPtr,pitch,testarray,0,8* sizeof(int),4,cudaMemcpyHostToDevice);
cudaMalloc((void**)&sum, sizeof(int));
kernel<<<1, 4>>>(devPtr, pitch, sum);
cutilCheckMsg("kernel launch failure");
cudaMemcpy(sumhost, sum, sizeof(int), cudaMemcpyDeviceToHost);
cout << *sumhost << endl;
return 0;
}
这段代码编译得很好(在 4.0 sdk 候选版本上)。但是,一旦我尝试执行,我就会得到
0
cpexample.cu(43) : cutilCheckMsg() CUTIL CUDA error : kernel launch failure : invalid pitch argument.
这是不幸的,因为我不知道如何修复它;-(。据我所知,间距是内存中的偏移量,以允许更快地复制数据。但是这样的间距仅用于设备内存,而不是在主机内存中,不是吗?因此我的主机内存的间距应该是0,不是吗?
另外我还想问另外两个问题:
最佳答案
在这行代码中:
cudaMemcpy2D(devPtr,pitch,testarray,0,8* sizeof(int),4,cudaMemcpyHostToDevice);
您是说
testarray
的 source-pitch 值等于 0
,但是当 pitch 公式是 T* elem = (T*)((char*)base_address + row * pitch) + column
时,这怎么可能呢?如果我们在该公式中将 0
的值替换为 pitch,那么在某些二维 (x,y) 有序对偏移量处查找地址时,我们将无法获得正确的值。需要考虑的一件事是音高值的规则是 pitch = width + padding
。在主机上,填充通常等于 0
,但宽度不是 0
,除非您的数组中没有任何内容。在硬件方面可能会有额外的填充,这就是为什么 pitch 的值可能不等于数组的声明宽度。因此,您可以根据填充值得出 pitch >= width
的结论。所以即使在主机端,源间距的值也应该至少是每行的字节大小,这意味着在 testarray
的情况下,它应该是 8*sizeof(int)
。最后,宿主中二维数组的高度也只是 2
行,而不是 4
。作为关于分配的指针会发生什么的问题的答案,如果您使用
malloc()
分配一个指针,那么该指针将被赋予一个驻留在主机内存中的地址值。因此,您可以在主机端取消引用它,但不能在设备端取消引用。另一方面,使用 cudaMalloc()
分配的指针被赋予一个指向驻留在设备上的内存的指针。因此,如果您在主机上取消引用它,它不会指向主机上已分配的内存,并且会出现不可预测的结果。可以将此指针地址传递给设备上的内核,因为当它在设备端取消引用时,它指向设备本地可访问的内存。总的来说,CUDA 运行时将这两个内存位置分开,提供内存复制功能,将在设备和主机之间来回复制,并根据所需的方向使用来自这些指针的地址值作为复制的源和/或目标(主机到设备或设备到主机)。现在,如果您使用相同的 int*
,并首先使用 malloc()
分配它,然后(希望在指针上调用 free()
之后)使用 cudaMalloc()
,您的指针将首先有一个指向主机内存的地址,然后是设备内存。您必须跟踪它的状态,以避免因取消引用设备或主机上的地址而产生不可预测的结果,这取决于它是在主机代码还是设备代码中取消引用。关于c++ - CUDA - memcpy2d - 错误的音高,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6034342/