Cuda 结构到设备内存和从设备内存的深度复制

Cuda 结构到设备内存和从设备内存的深度复制,cuda,Cuda,我在cuda代码中遇到了一个结构数组的深层拷贝问题,该数组中动态分配了成员变量。我认为这是因为&deviceHistogram指向主机上的地址,而不是设备上的地址。我试着像中那样制作一个中间指针变量,但没有成功;如何正确复制整个结构数组,以便从makeHistogram函数中修改它 #include <stdlib.h> #include <stdio.h> #include "cuda.h" typedef struct histogramBin { int*

我在cuda代码中遇到了一个结构数组的深层拷贝问题,该数组中动态分配了成员变量。我认为这是因为
&deviceHistogram
指向主机上的地址,而不是设备上的地址。我试着像中那样制作一个中间指针变量,但没有成功;如何正确复制整个结构数组,以便从
makeHistogram
函数中修改它

#include <stdlib.h>
#include <stdio.h>
#include "cuda.h"

typedef struct histogramBin {
    int* items;
    int count;
} histogramBin;

__host__ __device__ void outputHistogram(histogramBin* histogram, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d: ", i);
        if (!histogram[i].count) {
            printf("EMPTY");
        } else {
            for (int j = 0; j < histogram[i].count; j++) {
                printf("%d ", histogram[i].items[j]);
            }
        }
        printf("\n");
    }
}


// This function embeds PTX code of CUDA to extract bit field from x. 
   __device__ uint bfe(uint x, uint start, uint nbits) {
    uint bits;
    asm("bfe.u32 %0, %1, %2, %3;"
        : "=r"(bits)
        : "r"(x), "r"(start), "r"(nbits));
    return bits;
}

__global__ void makeHistogram(histogramBin** histogram, int* rH, int rSize, int bit) {
    for (int r = 0; r < rSize; r++) {
        int thisBin = bfe(rH[r], bit, 1);
        int position = (*histogram)[thisBin].count; // **** out of memory access here****
        (*histogram)[thisBin].items[position] = rH[r];
        (*histogram)[thisBin].count++;
    }
}

void histogramDriver(histogramBin* histogram, int* rH, int rSize, int bit) {
    int n = 8;
    int* deviceRH;
    histogramBin* deviceHistogram;

    cudaMalloc((void**)&deviceRH, rSize * sizeof(int));
    cudaMemcpy(deviceRH, rH, rSize * sizeof(int), cudaMemcpyHostToDevice);

    cudaMalloc((void**)&deviceHistogram, n * sizeof(histogramBin));
    cudaMemcpy(deviceHistogram, histogram, n * sizeof(histogramBin), cudaMemcpyHostToDevice);

    int* tempData[n];
    for (int i = 0; i < n; i++) {
        cudaMalloc(&(tempData[i]), rSize * sizeof(int));
    }
    for (int i = 0; i < n; i++) {
        cudaMemcpy(&(deviceHistogram[i].items), &(tempData[i]), sizeof(int*), cudaMemcpyHostToDevice);
    }
    for (int i = 0; i < n; i++) {
        cudaMemcpy(tempData[i], histogram[i].items, rSize * sizeof(int), cudaMemcpyHostToDevice);
    }

    makeHistogram<<<1, 1>>>(&deviceHistogram, deviceRH, rSize, bit);
    cudaDeviceSynchronize();
}


int main(){
    int rSize = 5;
    int rH[rSize] = {1, 2, 3, 4, 5};

    histogramBin * histogram = (histogramBin*)malloc(sizeof(histogramBin) * 8);
    for(int i = 0; i < 8; i++){
        histogram[i].items = (int*)calloc(sizeof(int), rSize);
        histogram[i].count = 0;
    }
    histogramDriver(histogram, rH, rSize, 0);
    return 0;
}
这是我期望的结果

当我从
histogramDriver
调用
outputHistogram(直方图,8)
(在
cudaDeviceSynchronize()
之后)时,我看到以下内容:

0: 2 4 
1: 1 3 5 
2: EMPTY
3: EMPTY
4: EMPTY
5: EMPTY
6: EMPTY
7: EMPTY
0: EMPTY
1: EMPTY
2: EMPTY
3: EMPTY
4: EMPTY
5: EMPTY
6: EMPTY
7: EMPTY
显然,我没有正确地将值从设备复制回主机

我尝试过从
historogramdriver
中的复制过程进行反向复制:

for(int i = 0; i < n; i++){
    cudaMemcpy(&(tempData[i]), &(deviceHistogram[i].items), sizeof(int*), cudaMemcpyDeviceToHost);
}
for (int i = 0; i < n; i++) {
    cudaMemcpy(histogram[i].items, tempData[i], rSize * sizeof(int), cudaMemcpyDeviceToHost);
}
for(int i=0;i

但是
outputHistogram
调用
histogramDriver
的输出保持不变。

正如@talonmies所指出的,这里最大的问题是内核的设计。没有理由/需要为直方图使用双指针(事实上,您发布的代码的第一次迭代在内核原型中没有,尽管它是不完整的)

通过删除双指针特性,代码运行时不会出现任何运行时错误

#include <stdlib.h>
#include <stdio.h>
#include "cuda.h"

typedef struct histogramBin {
    int* items;
    int count;
} histogramBin;

// This function embeds PTX code of CUDA to extract bit field from x.
   __device__ uint bfe(uint x, uint start, uint nbits) {
    uint bits;
    asm("bfe.u32 %0, %1, %2, %3;"
        : "=r"(bits)
        : "r"(x), "r"(start), "r"(nbits));
    return bits;
}

__global__ void makeHistogram(histogramBin* histogram, int* rH, int rSize, int bit) {
    for (int r = 0; r < rSize; r++) {
        int thisBin = bfe(rH[r], bit, 1);
        int position = histogram[thisBin].count; 
        histogram[thisBin].items[position] = rH[r];
        histogram[thisBin].count++;
    }
}

void histogramDriver(histogramBin* histogram, int* rH, int rSize, int bit) {
    int n = 8;
    int* deviceRH;
    histogramBin* deviceHistogram;

    cudaMalloc((void**)&deviceRH, rSize * sizeof(int));
    cudaMemcpy(deviceRH, rH, rSize * sizeof(int), cudaMemcpyHostToDevice);

    cudaMalloc((void**)&deviceHistogram, n * sizeof(histogramBin));
    cudaMemcpy(deviceHistogram, histogram, n * sizeof(histogramBin), cudaMemcpyHostToDevice);

    int* tempData[n];
    for (int i = 0; i < n; i++) {
        cudaMalloc(&(tempData[i]), rSize * sizeof(int));
    }
    for (int i = 0; i < n; i++) {
        cudaMemcpy(&(deviceHistogram[i].items), &(tempData[i]), sizeof(int*), cudaMemcpyHostToDevice);
    }
    for (int i = 0; i < n; i++) {
        cudaMemcpy(tempData[i], histogram[i].items, rSize * sizeof(int), cudaMemcpyHostToDevice);
    }

    makeHistogram<<<1, 1>>>(deviceHistogram, deviceRH, rSize, bit);
    cudaDeviceSynchronize();
}


int main(){
    const int rSize = 5;
    int rH[rSize] = {1, 2, 3, 4, 5};

    histogramBin * histogram = (histogramBin*)malloc(sizeof(histogramBin) * 8);
    for(int i = 0; i < 8; i++){
        histogram[i].items = (int*)calloc(sizeof(int), rSize);
        histogram[i].count = 0;
    }
    histogramDriver(histogram, rH, rSize, 0);
    return 0;
}
$ nvcc t1452.cu -o t1452
$ cuda-memcheck ./t1452
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
$
#包括
#包括
#包括“cuda.h”
类型定义结构histogramBin{
国际*项目;
整数计数;
}组织grambin;
//该函数嵌入CUDA的PTX代码,从x中提取位字段。
__设备设备bfe(设备x、设备启动、设备nbits){
单位位元;
asm(“bfe.u32%0、%1、%2、%3
:“=r”(位)
:“r”(x),“r”(开始),“r”(nbits));
返回位;
}
__全局无效生成直方图(histogramBin*直方图,int*rH,int rSize,int位){
for(int r=0;r
请注意,这里唯一的更改是对内核代码本身的更改,加上删除了内核调用上的符号,再加上我在
rSize
的定义中添加了
const
,以获得要编译的内容


我不知道它是否产生正确的输出,因为您没有包括检查输出的方法,也没有指出您期望的输出是什么。如果您对此感兴趣,那么在您的MVE中加入这些内容将是一件好事。

这是一份深入的副本,在
cuda
标签上有许多问题可以讨论。这是一个答案,列出了步骤并链接到几个示例。这是一个后续问题和答案。这是另一个答案,讨论了各种方法以及与几个示例的链接。请参阅2D分配。注意,第1项您应该提供一份您所展示的不是一份。它应该是一个完整的代码。
makeHistogram(&deviceHistogram,…
显然是错误的。通过将主机变量的地址传递到内核,您希望实现什么?@RobertCrovella我已编辑添加了一个MVE。感谢您提供有关术语和参考的提示!这里的基本问题是犬舍的设计,而不是您如何复制这些天。我看不到任何有效的理由关于
histogramBin**histogramBin**histogram
。为什么需要传递指向该犬舍的指针地址?谢谢你,罗伯特!我为不完整的MVE表示歉意;我已对其进行编辑,以便按照你的建议添加预期输出。