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

将struct数组传递给gpu内核时遇到问题。 我基于这个主题 – cudaMemcpy分段错误 ,我写的是这样的:

#include  #include  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<<>>(dev_test); cudaDeviceSynchronize(); // memory free return 0; } 

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

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

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

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

     cudaMalloc((void**)&(test[i].array), size * sizeof(char)); 

在步骤3之后,您在步骤2中设置的数据完全丢失,无法以任何方式访问。 参考您链接的问题/答案中的步骤3和4:

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

4.cudaMalloc在myhostptr的设备上myhostptr

你还没有这样做。 您没有创建单独的指针。 您重用(擦除,覆盖)现有指针,该指针指向您在主机上关注的数据。 这个问题/答案也与您链接的答案相关联,几乎可以在代码中提供您需要遵循的步骤。

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

 $ cat t755.cu #include  #include  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  #include  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 $