将二维数组发送到Cuda内核

6
我有点难以理解如何将2D数组发送到Cuda。我的程序解析一个每行有30个数据点的大文件。我一次读取10行,然后为每行和每个项目创建矩阵(因此,在我的示例中,有10行,每行30个数据点,它将是int list [10] [30];)。我的目标是将这个数组发送到我的内核,并让每个块处理一行(在普通的C语言中,我已经完美地实现了这一点,但Cuda有点更具挑战性)。
到目前为止,这是我所做的,但没有成功(注意:sizeofbucket = 行数,sizeOfBucketsHoldings = 每行的项目数...我知道我应该获得奇怪变量名称奖项):
    int list[sizeOfBuckets][sizeOfBucketsHoldings]; //this is created at the start of the file and I can confirmed its filled with the correct data
#define sizeOfBuckets 10 //size of buckets before sending to process list
#define sizeOfBucketsHoldings  30
    //Cuda part
                //define device variables
                int *dev_current_list[sizeOfBuckets][sizeOfBucketsHoldings];
                //time to malloc the 2D array on device
                size_t pitch;
                cudaMallocPitch((int**)&dev_current_list,  (size_t *)&pitch, sizeOfBucketsHoldings * sizeof(int), sizeOfBuckets);

                //copy data from host to device
                cudaMemcpy2D( dev_current_list, pitch, list, sizeOfBuckets * sizeof(int), sizeOfBuckets * sizeof(int), sizeOfBucketsHoldings * sizeof(int),cudaMemcpyHostToDevice );

                process_list<<<count,1>>> (sizeOfBuckets, sizeOfBucketsHoldings, dev_current_list, pitch);
                //free memory of device
                cudaFree( dev_current_list );


    __global__ void process_list(int sizeOfBuckets, int sizeOfBucketsHoldings, int *current_list, int pitch) {
        int tid = blockIdx.x;
        for (int r = 0; r < sizeOfBuckets; ++r) {
            int* row = (int*)((char*)current_list + r * pitch);
            for (int c = 0; c < sizeOfBucketsHoldings; ++c) {
                 int element = row[c];
            }
        }

我收到的错误信息是:
main.cu(266): error: argument of type "int *(*)[30]" is incompatible with parameter of type "int *"
1 error detected in the compilation of "/tmp/tmpxft_00003f32_00000000-4_main.cpp1.ii".

第266行是内核调用process_list<<<count,1>>> (count, countListItem, dev_current_list, pitch);。我认为问题在于我尝试在函数中创建一个int *类型的数组,但我还能以其他方式创建它吗?在我的纯C代码中,我使用int current_list[num_of_rows][num_items_in_row],这可以工作,但我无法让相同的结果在CUDA中工作。

我的最终目标很简单,我只想让每个块处理每一行(sizeOfBuckets),然后让它循环遍历该行中的所有项目(sizeOfBucketHoldings)。最初我只是做了普通的cudamalloc和cudaMemcpy,但它没有起作用,所以我四处寻找,发现了MallocPitch和2dcopy(这两者都不在我的cuda by example书中),我一直在尝试研究示例,但它们似乎给我带来了同样的错误(我目前正在阅读的CUDA_C编程指南在第22页上找到了这个想法,但仍然没有运气)。 有什么想法吗?或建议去哪里看?

编辑: 为了测试这个,我只想把每一行的值加起来(我从cuda by example数组加法示例中复制了逻辑)。 我的内核:

__global__ void process_list(int sizeOfBuckets, int sizeOfBucketsHoldings, int *current_list, size_t pitch, int *total) {
    //TODO: we need to flip the list as well
    int tid = blockIdx.x;
    for (int c = 0; c < sizeOfBucketsHoldings; ++c) {
        total[tid] = total + current_list[tid][c];
    }
}

这是我在主函数中声明总数组的方法: ```html

这是我在主函数中声明总数组的方法:

```
int *dev_total;
cudaMalloc( (void**)&dev_total, sizeOfBuckets * sizeof(int) );
1个回答

5

你的代码有一些错误。

  • 当你将主机数组复制到设备时,应该传递一维主机指针。请参见function signature
  • 你不需要为设备内存分配静态二维数组。它会在主机内存中创建静态数组,然后你将其重新创建为设备数组。记住它必须是一维数组。请参见function signature

这个例子应该帮助你进行内存分配:

__global__ void process_list(int sizeOfBucketsHoldings, int* total, int* current_list, int pitch)
{
    int tid = blockIdx.x;
    total[tid] = 0;
    for (int c = 0; c < sizeOfBucketsHoldings; ++c)
    {
        total[tid] += *((int*)((char*)current_list + tid * pitch) + c);
    }
}

int main()
{
    size_t sizeOfBuckets         = 10;
    size_t sizeOfBucketsHoldings = 30;

    size_t width = sizeOfBucketsHoldings * sizeof(int);//ned to be in bytes
    size_t height = sizeOfBuckets;

    int* list = new int [sizeOfBuckets * sizeOfBucketsHoldings];// one dimensional
    for (int i = 0; i < sizeOfBuckets; i++)
        for (int j = 0; j < sizeOfBucketsHoldings; j++)
            list[i *sizeOfBucketsHoldings + j] = i;

    size_t pitch_h = sizeOfBucketsHoldings * sizeof(int);// always in bytes

    int* dev_current_list;
    size_t pitch_d;
    cudaMallocPitch((int**)&dev_current_list, &pitch_d, width, height);

    int *test;
    cudaMalloc((void**)&test, sizeOfBuckets * sizeof(int));
    int* h_test = new int[sizeOfBuckets];

    cudaMemcpy2D(dev_current_list, pitch_d, list, pitch_h, width, height, cudaMemcpyHostToDevice);

    process_list<<<10, 1>>>(sizeOfBucketsHoldings, test, dev_current_list, pitch_d);
    cudaDeviceSynchronize();

    cudaMemcpy(h_test, test, sizeOfBuckets * sizeof(int), cudaMemcpyDeviceToHost);

    for (int i = 0; i < sizeOfBuckets; i++)
        printf("%d %d\n", i , h_test[i]);
    return 0;
}

要在内核中访问您的2D数组,您应该使用模式base_addr + y * pitch_d + x警告:pitvh始终以字节为单位。 您需要将指针转换为byte*


一如既往地感谢你,Marina。我尝试了你的设置,但当我尝试启动内核时仍然会出现相同的错误:“error: argument of type "int ()[sizeOfBucketsHoldings]" is incompatible with parameter of type "int *"”,我是否正确发送了数组? - Lostsoul
抱歉,我现在明白你在做什么了。我将主机(host)更改为列表(list)后,在编译时没有出现错误,但是却遇到了“分段错误: 11”的问题,但可能与我的测试内核有关。 - Lostsoul
请更新你的问题代码,以便让我知道你当前遇到的问题在哪里。 - geek
谢谢Marina。我更新了我的内核以显示我的简单代码。如果这是我的内核的问题,我可以解决它,我只是想知道问题出在哪里(主机代码还是设备)。我的10行有30个数字,我所尝试做的就是启动10个块,并让每个块将其行中的30个数字相加并报告结果。 - Lostsoul
谢谢Marina。我不知道数组是扁平化的。我以为它就像普通的C语言一样,可以使用嵌套的for循环来访问数组的每个新维度。但是当我运行它时,仍然会出现“Segmentation fault: 11”的错误(编译没有问题,只是有一些关于如何打印一些字符串的警告,但与Cuda无关)。有没有办法排除故障或找出错误来自哪里(即具体的行号)? - Lostsoul
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接