【问题标题】:Explanation of CUDA C and C++CUDA C和C++的解释
【发布时间】:2012-04-08 10:41:15
【问题描述】:

谁能给我一个关于 CUDA C 和 C++ 的性质的很好的解释?据我了解,CUDA 应该是带有 NVIDIA GPU 库的 C。截至目前,CUDA C 支持一些 C++ 特性,但不支持其他特性。

NVIDIA 的计划是什么?他们是否会在 C 基础上构建并添加自己的库(例如 Thrust 与 STL)与 C++ 的库平行?他们最终会支持所有的 C++ 吗?在.cu 文件中使用 C++ 标头是不是很糟糕?

【问题讨论】:

  • 我不认为他们会努力支持在 GPU 硬件上性能不佳的 C++ 功能,例如异常,因为 CUDA 是围绕高性能数值计算设计的。
  • 我们能否将标题改写为:“CUDA C/C++ 和 ISO C/C++ 有什么区别”?这已经是实际答案了,NVIDIA会不会做也只能猜测了。

标签: c++ c cuda nvidia


【解决方案1】:

CUDA 是一个平台(架构、编程模型、汇编虚拟机、编译工具等),而不仅仅是一种单一的编程语言。 CUDA C 只是在此平台上构建的众多语言系统之一(CUDA C、C++、CUDA Fortran、PyCUDA 等等。)

CUDA C++

当前 CUDA C++ 支持 CUDA C Programming Guide 的附录 D(“C/C++ 语言支持”)中描述的 C++ 子集。

仅举几例:

  • __device__ 成员函数(包括构造函数和析构函数)
  • 继承/派生类
  • 虚函数
  • 类和函数模板
  • 运算符和重载
  • 函子类

编辑:从 CUDA 7.0 开始,CUDA C++ 在 __device__ 代码(在 GPU 上运行的代码)中包含对 C++11 标准的大多数语言特性的支持,包括 auto、lambda 表达式、基于范围的for 循环、初始化列表、静态断言等。

上面链接的同一附录中也详细说明了示例和特定限制。作为一个非常成熟的使用 CUDA 的 C++ 示例,我建议您查看Thrust

未来计划

(披露:我为 NVIDIA 工作。)

我无法明确说明未来的版本和时间安排,但我可以说明几乎每个 CUDA 版本都添加了额外的语言功能以使 CUDA C++ 支持达到其当前(在我看来非常有用)状态的趋势。我们计划在改进对 C++ 的支持方面继续这一趋势,但我们自然会优先考虑在大规模并行计算架构 (GPU) 上有用且高性能的功能。

【讨论】:

  • 您好@harrism,是否可以更新此答案以反映 CUDA 中 C++ 的当前状态以及 2015 年之后的未来计划?
  • CUDA Fortran 和 PyCUDA 实际上是 Fortran 和 Python 的内核版本,可以编译在 GPU 上运行吗?还是只托管 API?
  • CUDA Fortran 是一个带有 CUDA 扩展的 Fortran 编译器,以及一个主机 API。 PyCUDA 更像是一个主机 API 和便利实用程序,但内核仍然必须用 CUDA C++ 编写。 “CUDA Python”是 Numba 的一部分,是一个用于在 GPU 上运行 CUDA 注释的 Python 的编译器。
【解决方案2】:

CUDA C 是一种具有 C 语法的编程语言。从概念上讲,它与 C 完全不同。

它试图解决的问题是为多个处理器编写多个(相似的)指令流。

CUDA 提供的不仅仅是单指令多数据 (SIMD) 向量处理,而是数据流>>指令流,或者好处少得多。

CUDA 提供了一些机制来做到这一点,并隐藏了一些复杂性。

CUDA 未针对多核 x86 等多种指令流进行优化。 CUDA 不限于 x86 向量指令等单一指令流,也不限于 x86 向量指令等特定数据类型。

CUDA 支持可以并行执行的“循环”。这是它最关键的特点。 CUDA 系统将划分“循环”的执行,并在一组相同的处理器上同时运行“循环”主体,同时提供一些正常顺序循环的错觉(特别是 CUDA 管理循环“索引”)。开发人员需要了解 GPU 机器结构才能有效地编写“循环”,但几乎所有管理都由 CUDA 运行时处理。效果是数百(甚至数千)个“循环”与一个“循环”同时完成。

CUDA 支持看起来像 if 的分支。只有运行与 if 测试匹配的代码的处理器才能处于活动状态,因此对于 if 测试的每个“分支”,处理器的子集都将处于活动状态。例如,这个if... else if ... else ... 有三个分支。每个处理器将只执行一个分支,并在 if 完成时“重新同步”以与其余处理器继续前进。可能是某些分支条件没有被任何处理器匹配。所以没有必要执行那个分支(例如,三个分支是最坏的情况)。然后只依次执行一两个分支,更快地完成整个if

没有“魔法”。程序员必须意识到代码将在 CUDA 设备上运行,并有意识地为其编写代码。

CUDA 不采用旧的 C/C++ 代码,并且自动神奇地跨处理器阵列运行计算。 CUDA 可以按顺序编译和运行普通 C 和大部分 C++,但这样做的好处很少(什么都没有?),因为它将按顺序运行,而且比现代 CPU 更慢。这意味着某些库中的代码(尚未)与 CUDA 功能很好地匹配。一个 CUDA 程序可以同时对多 kByte 位向量进行操作。 CUDA 无法神奇地自动将现有的顺序 C/C++ 库代码转换为可以做到这一点的东西。

CUDA 确实提供了一种相对简单的方式来编写代码,使用熟悉的 C/C++ 语法,添加一些额外的概念,并生成将跨处理器阵列运行的代码。它有可能提供超过 10 倍的加速比,例如多核 x86。

编辑 - 计划:我不为 NVIDIA 工作

为了获得最佳性能,CUDA 需要在编译时获得信息。

所以模板机制是最有用的,因为它为开发人员提供了一种在编译时表达事物的方式,CUDA 编译器可以使用这种方式。举个简单的例子,如果在编译时将矩阵定义(实例化)为 2D 和 4 x 8,那么 CUDA 编译器可以使用它来跨处理器组织程序。如果该大小是动态的,并且在程序运行时发生变化,那么编译器或运行时系统就很难完成一项非常有效的工作。

编辑: CUDA 有类和函数模板。 如果人们读到这篇文章说 CUDA 没有,我深表歉意。我同意我不清楚。

我相信 CUDA GPU 端的模板实现并不完整 w.r.t。 C++。

用户 harrism 评论说我的回答具有误导性。 harrism 适用于 NVIDIA,所以我会等待建议。希望这已经更清楚了。

跨多个处理器高效地做的最困难的事情是动态地向下分支许多替代路径,因为这可以有效地序列化代码;在最坏的情况下,一次只能执行一个处理器,这浪费了 GPU 的优势。所以虚函数似乎很难做好。

有一些非常智能的整体程序分析工具可以推断出比开发人员可能理解的更多的类型信息。现有工具可能会推断出足以消除虚函数,从而将分支分析转移到编译时间。还有一些用于检测程序执行的技术,这些技术直接反馈到程序的重新编译中,这可能会达到更好的分支决策。

AFAIK(模反馈)CUDA 编译器在这些领域还不是最先进的。

(恕我直言,任何有兴趣的人都值得花几天时间,使用支持 CUDA 或 OpenCL 的系统来调查它们,并做一些实验。我也认为,对于对这些领域感兴趣的人,值得付出努力用 Haskell 做实验,看看Data Parallel Haskell)

【讨论】:

  • 感谢大家的回答。我刚刚开始学习 CUDA,还没有完全掌握 GPU 编程的细节。
  • @xiongtx - 我很乐意提供帮助。我花了一些时间才弄清楚。我有点难过,他们从一开始就没有很好地解释它。相反,他们痴迷于它的聪明程度。
  • 这个答案是错误的和不正确的。作为错误答案的示例,CUDA 不会自动并行化 for 循环,并且它已经支持模板(除了继承、虚函数、运算符重载、引用、设备上的新建/删除以及许多其他 C++ 功能)。
  • @harrism - 如果我对“模板”的错误描述具有误导性,我深表歉意。我试图保持在高水平。我很乐意尝试改进它。我没有说CUDA没有模板,但可以看出我并不清楚。我曾相信模板仍然受到限制(与 C++ 相比),例如部分模板专业化可以提供处理一般情况的方法,但会针对特定情况进行改进。如果这不是真的,请您指点我的例子吗?你是什​​么意思“不会自动并行化”我没有写。 CUDA 做不到,所以我想修正一下我的话。
  • 我再次道歉,我故意写了“循环”而不是循环来理解采用 for 循环并对其进行转换的想法。我认为内核这个词无济于事,但我可以再试一次。我宁愿有一个明确的答案。 OP 询问“谁能给我一个关于 CUDA C 和 C++ 的性质的很好的解释”,我特别标记了第一部分 C,以便将内核和控制流的概念分开,可以(是)使用 'vanilla ' CUDA 中的 C(当然除了 >>)。至于 CUDA 模板支持与 C++,CUDA 是否支持所有 C++(不是 C++11)模板?
【解决方案3】:

很多人没有意识到,CUDA 实际上是两种新的编程语言,都源自 C++。一种是编写在 GPU 上运行的代码,它是 C++ 的子集。它的功能类似于 HLSL (DirectX) 或 Cg (OpenGL),但具有更多的功能和与 C++ 的兼容性。我无需提及各种与 GPGPU/SIMT/性能相关的问题。另一个是所谓的“Runtime API”,它几乎不是传统意义上的“API”。 Runtime API 用于编写在主机 CPU 上运行的代码。它是 C++ 的超集,可以更轻松地链接和启动 GPU 代码。它需要 NVCC 预编译器,然后调用平台的 C++ 编译器。相比之下,Driver API(和 OpenCL)是一个纯粹的标准 C 库,使用起来更加冗长(同时提供的附加功能很少)。

创建一种新的主​​机端编程语言是 NVIDIA 的一项大胆举措。它使 CUDA 入门更容易,编写代码更优雅。然而,真正出色的并不是将其作为一种新语言进行营销。

【讨论】:

    【解决方案4】:

    有时您听说 CUDA 是 C 和 C++,但我认为不是,原因很简单,这是不可能的。从他们的编程指南中引用:

    对于主机代码,nvcc 支持 C++ ISO/IEC 的任何部分 主机 c++ 编译器支持的 14882:2003 规范。

    对于设备代码,nvcc 支持章节中说明的特性 D.1 与第 D.2 节中描述的一些限制;它不是 支持运行时类型信息 (RTTI)、异常处理和 C++ 标准库。

    正如我所见,它仅指 C++,并且仅支持 C,而这恰好是 C 和 C++ 的交集。因此,最好将其视为对设备部分进行扩展的 C++,而不是 C。如果您习惯于 C,这可以避免很多麻烦。

    【讨论】:

      【解决方案5】:

      NVIDIA 的计划是什么?

      我相信总的趋势是 CUDA 和 OpenCL 对于许多应用程序来说被认为是太低级的技术。目前,Nvidia 正在大力投资OpenACC,它可以粗略地描述为 GPU 的 OpenMP。它遵循声明式方法,并在更高级别解决 GPU 并行化问题。这就是我对 Nvidia 计划的完全主观印象。

      【讨论】:

      • 如果有一个用于 GPU 编程的功能接口,背后有一个智能库将计算转移到 GPU 上,那就太酷了。
      • @quant_dev:它必须是非常智能的,因为它需要能够识别足够大的连续计算量来分摊开销,并隐藏延迟。
      • 为什么?该任务与编写 BLAS 实现没有太大区别。
      • @quant_dev:使用加速的 BLAS 实现,您(程序员)通常必须显式调用加速例程(或通过 Thrust 等间接调用)。运行时 (AFAIK) 不会决定在 CPU 或 GPU 上执行每个工作项是否更有益。
      • @quant_dev 我在 AccelerEyes 工作,我们正是这样做的。查看 ArrayFire (www.accelereyes.com/arrayfire) 基本功能可以免费使用。如果您需要更多信息,可以通过我的电子邮件地址(在我的个人资料中)与我联系。
      猜你喜欢
      • 1970-01-01
      • 2015-03-16
      • 2012-05-25
      • 1970-01-01
      • 2012-11-20
      • 2012-06-10
      • 1970-01-01
      • 2021-03-05
      • 1970-01-01
      相关资源
      最近更新 更多