关于指针:如何将 C 结构数组传递给 CUDA 设备?

How can I pass a C++ array of structs to a CUDA device?

我花了 2 天时间试图弄清楚这一点,但一无所获。假设我有一个看起来像这样的结构:

1
2
3
4
struct Thing {
    bool is_solid;
    double matrix[9];
}

我想创建一个名为 things 的结构数组,然后在 GPU 上处理该数组。类似于:

1
2
3
4
5
6
7
Thing *things;
int num_of_things = 100;
cudaMallocManaged((void **)&things, num_of_things * sizeof(Thing));

// Something missing here? Malloc individual structs? Everything I try doesn't work.

things[10].is_solid = true; // Segfaults

最好的做法是这样做而不是传递具有 num_of_things 大数组的单个结构?在我看来,这可能会变得非常讨厌,尤其是当你已经有数组时(比如 matrix,它需要是 9 * num_of_things.

任何信息将不胜感激!


在评论中的一些对话之后,OP 发布的代码似乎没有问题。我能够成功编译并运行围绕该代码构建的测试用例,OP:

也是如此

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ cat t1005.cu
#include <iostream>

struct Thing {
    bool is_solid;
    double matrix[9];
};

int main(){

  Thing *things;
  int num_of_things = 100;
  cudaError_t ret = cudaMallocManaged((void **)&things, num_of_things * sizeof(Thing));
  if (ret != cudaSuccess) {
    std::cout << cudaGetErrorString(ret) << std::endl;
    return 1;}
  else {
    things[10].is_solid = true;
    std::cout <<"Success!" << std::endl;
    return 0;}
}
$ nvcc -arch=sm_30 -o t1005 t1005.cu
$ ./t1005
Success!
$

关于这个问题:

Is it even best practice to do it this way rather than pass a single struct with arrays that are num_of_things large?

是的,这是一种明智的做法,无论是否使用托管内存都可以使用。可以使用单个 cudaMemcpy 调用以简单的方式将一个或多或少任何不包含指向其他地方动态分配的数据的嵌入式指针的任何结构的数组传输到 GPU(例如,如果未使用托管内存。)

解决关于 cudaMallocManaged 的第三个 (flags) 参数的问题:

  • 如果已指定,则传递零是不正确的(尽管 OP 发布的代码没有提供任何证据。)您应该使用记录的选择之一。
  • 如果未指定,则仍然有效,并提供默认参数 cudaMemAttachGlobal。这可以通过查看 cuda_runtime.h 文件或简单地编译/运行上面的测试代码来确认。这一点似乎是文档中的一个疏忽,我已经向 NVIDIA 提交了一个内部问题来查看它。因此,文档可能会在未来对此进行更改。
  • 最后,当您遇到 CUDA 代码问题时,始终需要进行适当的 cuda 错误检查,使用此类检查可能会发现所发生的任何错误。 OP 在代码注释中报告的段错误几乎可以肯定是由于 cudaMallocManaged 调用失败(可能是因为错误地提供了零参数),因此有问题的指针 (things) 没有实际分配。该指针的后续使用将导致段错误。我的测试代码演示了如何避免该段错误,即使 cudaMallocManaged 调用由于某种原因失败,关键是正确的错误检查。