我刚刚开始 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,不是吗?

另外我还想问另外两个问题:
  • 如果我声明了一个像 int* sumhost 这样的变量(见上文),这个指针指向哪里?首先到主机内存,然后在 cudaMalloc 到设备内存?
  • 在这种情况下,
  • cutilCheckMsg 非常方便。是否有类似的调试功能我应该知道?
  • 最佳答案

    在这行代码中:

    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/

    10-10 21:23