GPU上的内存分配用于动态结构数组

时间:2015-05-06 16:55:20

标签: c struct cuda dynamic-memory-allocation

我将结构数组传递给gpu内核时遇到问题。我基于这个主题 - cudaMemcpy segmentation fault,我写的是这样的:

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

struct Test {
    char *array;
};

__global__ void kernel(Test *dev_test) {
    for(int i=0; i < 5; i++) {
        printf("Kernel[0][i]: %c \n", dev_test[0].array[i]);
    }
}

int main(void) {

    int n = 4, size = 5;
    Test *dev_test, *test;

    test = (Test*)malloc(sizeof(Test)*n);
    for(int i = 0; i < n; i++)
        test[i].array = (char*)malloc(size * sizeof(char));

    for(int i=0; i < n; i++) {
        char temp[] = { 'a', 'b', 'c', 'd' , 'e' };
        memcpy(test[i].array, temp, size * sizeof(char));
    }

    cudaMalloc((void**)&dev_test, n * sizeof(Test));
    cudaMemcpy(dev_test, test, n * sizeof(Test), cudaMemcpyHostToDevice);
    for(int i=0; i < n; i++) {
        cudaMalloc((void**)&(test[i].array), size * sizeof(char));
        cudaMemcpy(&(dev_test[i].array), &(test[i].array), size * sizeof(char), cudaMemcpyHostToDevice);
    }

    kernel<<<1, 1>>>(dev_test);
    cudaDeviceSynchronize();

    //  memory free
    return 0;
}

没有错误,但内核中显示的值不正确。我做错了什么?提前感谢您的帮助。

1 个答案:

答案 0 :(得分:6)

  1. 这是分配一个指向主机内存的新指针:

    test[i].array = (char*)malloc(size * sizeof(char));
    
  2. 这是将数据复制到主机内存中的该区域:

    memcpy(test[i].array, temp, size * sizeof(char));
    
  3. 这是覆盖先前分配给主机内存的指针(来自上面的步骤1),并带有 new 指向设备内存的指针:

    cudaMalloc((void**)&(test[i].array), size * sizeof(char));
    
  4. 在第3步之后,您在步骤2中设置的数据完全丢失,无法再以任何方式访问。请参阅您链接的question/answer中的第3步和第4步:

      

    3.在主机上创建一个单独的int指针,让我们称之为myhostptr

         

    4.cudaMalloc在设备上存储myhostptr

    你还没有做到这一点。您没有创建单独的指针。您重复使用(擦除,覆盖)现有指针,该指针指向您在主机上关注的数据。 This question/answer也与您链接的答案相关联,几乎可以提供您需要遵循的步骤 in code

    这里是您的代码的修改版本,它正确地实现了您未根据您链接的问题/答案正确实现的缺失步骤3和4(和5):(请参阅描述的评论步骤3,4,5)

    $ cat t755.cu
    #include <stdio.h>
    #include <stdlib.h>
    
    struct Test {
        char *array;
    };
    
    __global__ void kernel(Test *dev_test) {
        for(int i=0; i < 5; i++) {
            printf("Kernel[0][i]: %c \n", dev_test[0].array[i]);
        }
    }
    
    int main(void) {
    
        int n = 4, size = 5;
        Test *dev_test, *test;
    
        test = (Test*)malloc(sizeof(Test)*n);
        for(int i = 0; i < n; i++)
            test[i].array = (char*)malloc(size * sizeof(char));
    
        for(int i=0; i < n; i++) {
            char temp[] = { 'a', 'b', 'c', 'd' , 'e' };
            memcpy(test[i].array, temp, size * sizeof(char));
        }
    
        cudaMalloc((void**)&dev_test, n * sizeof(Test));
        cudaMemcpy(dev_test, test, n * sizeof(Test), cudaMemcpyHostToDevice);
    
        // Step 3:
        char *temp_data[n];
        // Step 4:
        for (int i=0; i < n; i++)
          cudaMalloc(&(temp_data[i]), size*sizeof(char));
        // Step 5:
        for (int i=0; i < n; i++)
          cudaMemcpy(&(dev_test[i].array), &(temp_data[i]), sizeof(char *), cudaMemcpyHostToDevice);
        // now copy the embedded data:
        for (int i=0; i < n; i++)
          cudaMemcpy(temp_data[i], test[i].array, size*sizeof(char), cudaMemcpyHostToDevice);
    
        kernel<<<1, 1>>>(dev_test);
        cudaDeviceSynchronize();
    
        //  memory free
        return 0;
    }
    
    $ nvcc -o t755 t755.cu
    $ cuda-memcheck ./t755
    ========= CUDA-MEMCHECK
    Kernel[0][i]: a
    Kernel[0][i]: b
    Kernel[0][i]: c
    Kernel[0][i]: d
    Kernel[0][i]: e
    ========= ERROR SUMMARY: 0 errors
    $
    

    由于上述方法对初学者来说可能具有挑战性,通常的建议不是这样做,而是扁平化您的数据结构。展平通常意味着重新排列数据存储,以便删除必须单独分配的嵌入指针。

    扁平化这种数据结构的一个简单例子就是使用它:

    struct Test {
        char array[5];
    };
    

    当然,我们认识到这种特定的方法不会用于所有目的,但它应该说明一般的想法/意图。通过该修改,作为示例,代码变得更加简单:

    $ cat t755.cu
    #include <stdio.h>
    #include <stdlib.h>
    
    struct Test {
        char array[5];
    };
    
    __global__ void kernel(Test *dev_test) {
        for(int i=0; i < 5; i++) {
            printf("Kernel[0][i]: %c \n", dev_test[0].array[i]);
        }
    }
    
    int main(void) {
    
        int n = 4, size = 5;
        Test *dev_test, *test;
    
        test = (Test*)malloc(sizeof(Test)*n);
    
        for(int i=0; i < n; i++) {
            char temp[] = { 'a', 'b', 'c', 'd' , 'e' };
            memcpy(test[i].array, temp, size * sizeof(char));
        }
    
        cudaMalloc((void**)&dev_test, n * sizeof(Test));
        cudaMemcpy(dev_test, test, n * sizeof(Test), cudaMemcpyHostToDevice);
    
        kernel<<<1, 1>>>(dev_test);
        cudaDeviceSynchronize();
    
        //  memory free
        return 0;
    }
    $ nvcc -o t755 t755.cu
    $ cuda-memcheck ./t755
    ========= CUDA-MEMCHECK
    Kernel[0][i]: a
    Kernel[0][i]: b
    Kernel[0][i]: c
    Kernel[0][i]: d
    Kernel[0][i]: e
    ========= ERROR SUMMARY: 0 errors
    $