截至 2013 年底,CUDA 与 OpenCL

计算科学 高性能计算 显卡 库达 开放式
2021-12-01 20:03:35

从程序员的角度来看,截至 2013 年底,CUDA 和 OpenCL 如何相互比较?我的团队正在考虑尝试使用 GPU 计算。选择只支持 OpenCL 但不支持 CUDA 的硬件会大大限制我们自己吗?

更具体地说,以下假设是否正确?

  • 在 CUDA 中可能发生的一切,在 OpenCL 中也可能发生

  • 只要我们不使用库,在其中任何一个中执行给定任务都不会容易(或更难)

  • CUDA 的主要优势是库的可用性

  • 两者都对所有三个主要平台(Win/OSX/Linux)都有很好的支持

1个回答

我将尝试总结我在开发 ViennaCL 的过程中获得的经验,我们有 CUDA 和 OpenCL 后端,大部分计算内核都是 1:1 转换的。根据您的问题,我还假设我们在这里主要讨论 GPU。

性能可移植性。首先,没有性能可移植内核之类的东西,因为您编写一次内核,它就会在每个硬件上高效运行。不在 OpenCL 中,由于支持的硬件范围更广,这一点更加明显,但在 CUDA 中也没有。在 CUDA 中,由于支持的硬件范围较小,因此不太明显,但即使在这里,我们也必须区分至少三种硬件架构(pre-Fermi、Fermi、Kepler)。这些性能波动很容易导致 20% 的性能变化,这取决于您如何编排线程以及您选择的工作组大小,即使内核就像缓冲区副本一样简单。值得一提的是,在 pre-Fermi 和 Fermi GPU 上,可以直接在 CUDA 中编写快速矩阵-矩阵乘法内核,而对于最新的 Kepler GPU,似乎必须使用 PTX 伪汇编语言才能接近 CUBLAS 的性能。因此,即使是供应商控制的语言(如 CUDA)似乎也存在跟上硬件开发步伐的问题。此外,当您运行 nvcc 时,所有 CUDA 代码都会静态编译,这在某种程度上需要通过 -arch 标志进行平衡,而 OpenCL 内核是在运行时从即时编译器编译的,因此您原则上可以定制内核直至特定计算设备的细节。然而,后者相当复杂,并且通常只有随着代码的成熟和经验的积累才会成为一个非常有吸引力的选择。付出的代价是即时编译所需的 O(1) 时间,这在某些情况下可能是个问题。OpenCL 2。

调试和分析。CUDA 调试和分析工具是最适用于 GPGPU 的。AMD 的工具也不错,但它们不包括像 cuda-gdb 或 cuda-memcheck 这样的 gem。此外,直到今天,NVIDIA 仍为 GPGPU 提供最强大的驱动程序和 SDK,对于 OpenCL 和 CUDA,由于内核错误导致系统冻结确实是例外,而不是规则。出于我可能不需要在这里解释的原因,NVIDIA 不再为带有 CUDA 5.0 及更高版本的 OpenCL 提供调试和分析功能。

可访问性和便利性。启动和运行第一个 CUDA 代码要容易得多,特别是因为 CUDA 代码与主机代码很好地集成在一起。(我稍后会讨论要付出的代价。)网络上有很多教程以及优化指南和一些库。使用 OpenCL,您必须执行大量初始化代码并将内核写入字符串,因此您只会在将源代码提供给 jit 编译器时在执行期间发现编译错误。因此,使用 OpenCL 完成一个代码/编译/调试周期需要更长的时间,因此在初始开发阶段您的工作效率通常较低。

软件库方面。虽然之前的项目支持 CUDA,但与其他软件的集成对 OpenCL 来说是一大优势。您可以通过与共享的 OpenCL 库链接来使用 OpenCL,仅此而已,而使用 CUDA,您需要拥有整个 CUDA 工具链。更糟糕的是,您需要使用正确的主机编译器才能使 nvcc 工作。如果您曾经尝试将 CUDA 4.2 与 GCC 4.6 或更高版本一起使用,那么您将很难让事情正常工作。一般来说,如果你碰巧使用了比 CUDA SDK 更新的编译器,很可能会出现问题。与 CMake 等构建系统的集成是另一个令人头疼的问题(您还可以在PETSc等方面找到大量证据)邮件列表)。在您拥有完全控制权的您自己的机器上,这可能不是问题,但是一旦您分发代码,您就会遇到用户在他们的软件堆栈中受到一定限制的情况。换句话说,使用 CUDA,您不再可以自由选择自己喜欢的主机编译器,而是 NVIDIA 规定您可以使用哪些编译器。

其他方面。CUDA 更接近硬件(例如扭曲),但我在线性代数方面的经验是,你很少能从中获得显着的好处。CUDA 有更多的软件库,但越来越多的库使用多个计算后端。ViennaCLVexCLParalution 同时都支持 OpenCL 和 CUDA 后端,在其他领域的库中也可以看到类似的趋势。

GPGPU 不是银弹。GPGPU 已被证明可以为结构化操作和计算受限的任务提供良好的性能。但是,对于具有不可忽略的顺序处理份额的算法,GPGPU 无法神奇地克服阿姆达尔定律在这种情况下,您最好使用可用的最佳算法的良好 CPU 实现,而不是尝试在您的问题上抛出并行但不太合适的算法。此外,PCI-Express 是一个严重的瓶颈,因此您需要提前检查 GPU 的节省是否可以补偿来回移动数据的开销。

我的建议。请考虑 CUDAOpenCL 而不是 CUDAOpenCL。没有必要将自己限制在一个平台上,而是两全其美。对我有用的是在 CUDA 中设置初始实现,对其进行调试、分析,然后通过简单的字符串替换将其移植到 OpenCL。(您甚至可以对 OpenCL 内核字符串生成例程进行参数化,以便具有一定的灵活性调整到目标硬件。)这种移植工作通常会占用不到 10% 的时间,但也使您能够在其他硬件上运行。您可能会对非 NVIDIA 硬件在某些情况下的性能表现感到惊讶。最重要的是,尽可能地考虑库中功能的重用。虽然快速& 某些功能的肮脏重新实现通常对于在 CPU 上的单线程执行来说是可以接受的,它通常会给你在大规模并行硬件上的性能不佳。理想情况下,您甚至可以将所有内容卸载到库中,而不必关心它们是在内部使用 CUDA、OpenCL 还是两者兼而有之。就我个人而言,我永远不敢为几年后我想要依赖的东西编写供应商锁定的代码,但是这个意识形态方面应该单独讨论。