你能做 C++ 风格的 CUDA 吗?

Can you do C++-style CUDA?

我遵循一些准则来处理 C++ 中的内存管理。一些例子:我从不使用 malloc。我几乎从不需要或使用 newdelete。我用智能指针,几乎不用写析构函数

我想学习CUDA。我一直在网上寻找符合我的 C++ 编程风格的教程,但一切看起来都是 C 风格的。 我不清楚这种 C 编程风格何时是必要的,何时只是作者的风格。例如,这里有一段代码来自 a NVIDIA tutorial:

int main(void)
{
  int N = 1<<20;
  float *x, *y, *d_x, *d_y;
  x = (float*)malloc(N*sizeof(float));
  y = (float*)malloc(N*sizeof(float));

  cudaMalloc(&d_x, N*sizeof(float)); 
  cudaMalloc(&d_y, N*sizeof(float));

//...

  printf("Max error: %f\n", maxError);

  cudaFree(d_x);
  cudaFree(d_y);
  free(x);
  free(y);
}

此代码使用 mallocfree、拥有原始指针和 C 风格数组。这些都是必须的吗?我可以编写现代 C++ 风格的 CUDA 吗?

CUDA 最初(十多年前)是一个主要是 C 风格的实体。随着时间的推移,该语言主要迁移为 C++ variant/definition。为了理解,我们应该划定设备代码和主机代码之间的讨论。

对于设备代码,CUDA claims compliance to a particular C++ standard, subject to various restrictions. One of the particular restrictions is that there is no general support for standard libraries

对于设备代码,(与主机代码有一些重叠)有an evolution underway提供一组STL-like libraries/features。但作为示例,std::vector 在 CUDA 设备代码中不可用(您可以在 CUDA 设备代码中使用 new)。

对于主机代码,实际上没有任何东西是 out-of-bounds,只要我们谈论的是严格的主机代码。例外情况是不时出现的未记录的问题 for example with boost and perhaps many other libraries. These aren't intentional omissions, but arise via the fact that CUDA uses a special preprocessor/front-end,即使对于主机代码也是如此,再加上针对人们可能想要使用的每个可以想象的库进行的不完整测试。

关于 user-supplied 库(相对于标准库或系统库),CUDA 通常需要适当修饰函数才能在设备代码中使用,这可能也值得一提。无论我们谈论的是编译库还是 header-only 库,这些库通常应该可以在主机代码中使用(根据上面的警告),但不一定可以在设备代码中使用,除非该库已针对 CUDA 使用进行了专门修饰。

在主机代码与设备代码交互的地方,您需要严格遵守这些限制。同样,std::vector 容器不能轻易传递给设备代码函数调用(CUDA 内核)。但是正如评论中已经提到的,您可以使用 CUDA 工具包安装中包含的 thrust library 来做类似的事情。

Are these all necessary?

mallocfree 不是必需的。您可以类似地使用 newdelete,或者使用推力容器。

关于原始指针和相关的 C-style 数组的使用,这可能是 more-or-less 不可避免的,因为它们是 C++ 的一部分并且 C++ 中没有更高级别的容器,除了在标准库中,AFAIK。至少在 host-device 接口上使用原始指针当然是典型的。例如,如果您使用 thrust::device_vector,您仍然需要提取一个原始指针以传递给内核。

来自 einpoklum/eyalroz 的 CUDA runtime and driver APIs still have largely a C-style feel to them. It's not formally part of CUDA, but others have created wrappers to make things more "C++ like". One such example is this library。我对它没有亲身体验,但它的维护似乎比较有活力,持续经营。正如评论中所暗示的那样,通过 C++ 重载和例如各种容器和库构造中的可替换功能,您可能可以构建一个容器或构造来执行您想要的操作,也许通过替换标准分配器等。

如前所述,thrust 打算提供一种 container/algorithm 方法来在 CUDA 环境中利用这些类型的 C++ 概念。

它不是 CUDA 的一部分,但 NVIDIA 也提供了一种加速方法 standard C++ code