【问题标题】:cudaMalloc of a structure and an element of same structure一个结构的 cudaMalloc 和一个相同结构的元素
【发布时间】:2014-04-05 01:52:21
【问题描述】:

我想知道当我分配一个结构然后 allocate(?) 并复制同一结构的指针元素时设备上会发生什么(内存方面)。

我还需要元素 *acudaMalloc 吗?

示例代码:

typedef struct {
  int *a;
  ...
} StructA;

int main() 
{
  int row, col, numS = 10; // defined at runtime

  StructA *d_A = (StructA*)malloc(numS * sizeof(StructA));
  int *h_A = d_a->a;

  cudaMalloc( (void**)&(d_A), numS * sizeof(StructA) );

  cudaMalloc( &(d_A->a), row*col*sizeof(int) ); // no (void**) needed?
  cudaMemcpy( d_A->a, h_A, row*col*sizeof(int), cudaMemcpyHostToDevice );

  kernel<<<grid, block>>>(d_A); // Passing pointer to StructA in device
  ...
}

内核定义:

__global__ kernel(StructA *d_A)
{
  d_A->a = ...;
  ...
}

此问题是this question 的另一个扩展,与this question 有关。

【问题讨论】:

    标签: c++ c memory-management cuda


    【解决方案1】:

    我建议您通过适当的 cuda 错误检查来编译和运行您的代码。学习解释编译器输出和运行时输出将使您成为更好、更聪明、更高效的编码器。我还建议查看我之前在here 指出您的文章。它处理这个确切的主题,并包括链接的工作示例。这个问题与那个问题重复。

    有各种错误:

    StructA *d_A = (StructA*)malloc(numS * sizeof(StructA));
    

    上面的代码行在 host 内存中为大小为 StructA 的结构创建分配,并设置指针 d_A 指向该分配的开始。目前没有任何问题。

    cudaMalloc( (void**)&(d_A), numS * sizeof(StructA) );
    

    上面的代码行在 device 内存中创建了一个大小为StructA 的分配,并将指针d_A 设置为指向该分配的开始。这有效地消除了先前的指针和分配。 (之前的主机分配还在某处,但你无法访问它。它基本上丢失了。)当然这不是你的意图。

    int *h_A = d_a->a;
    

    现在d_A(我假设您的意思是d_A,而不是d_a)已被分配为设备内存指针,-&gt; 操作将取消引用该指针以定位元素a。这在主机代码中是非法的,并且会抛出错误(段错误)。

    cudaMalloc( &(d_A->a), row*col*sizeof(int) );
    

    这行代码也有类似的问题。我们不能cudaMalloc 存在于设备内存中的指针。 cudaMalloc 创建位于主机内存中但引用设备内存中的位置的指针。此操作&amp;(d_A-&gt;a) 正在取消引用设备指针,这在主机代码中是非法的。

    正确的代码应该是这样的:

    $ cat t363.cu
    #include <stdio.h>
    
    typedef struct {
      int *a;
      int foo;
    } StructA;
    
    __global__ void kernel(StructA *data){
    
      printf("The value is %d\n", *(data->a + 2));
    }
    
    int main()
    {
      int  numS = 1; // defined at runtime
    
      //allocate host memory for the structure storage
      StructA *h_A = (StructA*)malloc(numS * sizeof(StructA));
      //allocate host memory for the storage pointed to by the embedded pointer
      h_A->a = (int *)malloc(10*sizeof(int));
      // initialize data pointed to by the embedded pointer
      for (int i = 0; i <10; i++) *(h_A->a+i) = i;
      StructA *d_A;  // pointer for device structure storage
      //allocate device memory for the structure storage
      cudaMalloc( (void**)&(d_A), numS * sizeof(StructA) );
      // create a pointer for cudaMalloc to use for embedded pointer device storage
      int *temp;
      //allocate device storage for the embedded pointer storage
      cudaMalloc((void **)&temp, 10*sizeof(int));
      //copy this newly created *pointer* to it's proper location in the device copy of the structure
      cudaMemcpy(&(d_A->a), &temp, sizeof(int *), cudaMemcpyHostToDevice);
      //copy the data pointed to by the embedded pointer from the host to the device
      cudaMemcpy(temp, h_A->a, 10*sizeof(int), cudaMemcpyHostToDevice);
    
      kernel<<<1, 1>>>(d_A); // Passing pointer to StructA in device
      cudaDeviceSynchronize();
    }
    $ nvcc -arch=sm_20 -o t363 t363.cu
    $ cuda-memcheck ./t363
    ========= CUDA-MEMCHECK
    The value is 2
    ========= ERROR SUMMARY: 0 errors
    $
    

    您会注意到我还没有解决您正在处理StructA 数组(即numS > 1)的情况,这将需要一个循环。我将把它留给你来处理我在这里和previous linked answer 中提出的逻辑,看看你是否可以计算出该循环的细节。此外,为了清楚/简洁起见,我已经放弃了通常的cuda error checking,但请在您的代码中使用它。最后,如果您还没有得出结论,这个过程(有时称为“深拷贝操作”)在普通 CUDA 中有些乏味。以前的建议是“扁平化”此类结构(以便它们不包含指针),但您也可以探索cudaMallocManaged,即Unified Memory in CUDA 6

    【讨论】:

    • 谢谢!这是我对cudaMalloc 的终极解释。我非常感谢您花时间回答问题。使用malloc 与下一个cudaMalloc 进行的分配丢失是我以前没有想到或知道的。
    • 我在玩你的示例代码。由于我处于计算能力 1.3 的环境中,并且无法从设备打印,因此我正在尝试复制修改后的(例如:data-&gt;a[2] = 5;)结构。但是,我无法复制回来(我以为是:cudaMemcpy(h_A, d_A, 10*sizeof(StructA), cudaMemcpyDeviceToHost);
    • 这可以复制回结构,但不会复制回嵌入指针指向的数据。如果您查看将数据复制到设备的代码行,您应该能够反转它以从设备中检索该数据。如果您想取得任何进展,您需要对 C 结构、指针和动态分配有一个合理的理解。复制指针(即结构中的内容)不会复制指针指向的数据。
    • 我尝试执行以下cudaMemcpy(h_A-&gt;a, d_A-&gt;a, 10*sizeof(int), cudaMemcpyDeviceToHost);(除其他外)。但是,我得到分段错误。谢谢你的建议,我会跟着他们继续刷我的知识(很久没有练习了)。
    • d_A-&gt;a 需要取消引用 d_A,这会触发 seg 错误。尝试改用temp 指针。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多