OpenCL与OpenMP性能比较

33
有没有对比OpenCL和OpenMP性能的研究?具体来说,我想了解使用OpenCL启动线程的开销成本,例如,如果将域分解为大量单个工作项(每个工作项由运行小任务的线程执行)与使用OpenMP中较重的线程相比,其中域被分解为与核心数相等的子域。
似乎OpenCL编程模型更加针对大规模并行芯片(例如GPU),而不是只有少数但功能更强大的核心的CPU。
OpenCL能否有效替代OpenMP?

1
我也很想知道在什么情况下同时使用OpenMP和OpenCL是有效的。OpenCL是线程安全的(除了clSetKernelArg()方法),因此似乎有利用两种技术的空间。 - Jonathan DeCarlo
如果你对“有效性”的定义包括可读性和演进性,那么答案必须是“不行”。OpenCL不能像OpenMP那样被插入到现有代码中,并且与OpenMP相比,它具有相当大的语法膨胀。另一方面,编写能够高效利用内存层次结构的OpenMP代码通常比在OpenCL中相同的代码更难以阅读。 - Jeff Hammond
1
在这里可以找到一篇关于OpenMP和OpenCL的良好而科学的比较:OpenMP和OpenCL并行处理技术的比较,作者是Krishnahari Thouti和S.R.Sathe。 - chjortlund
你的问题需要更加具体。你是想比较GPU和多线程CPU,还是OpenMP和OpenCL?要比较这两种语言,它们必须在相同的架构上运行。否则,就像苹果和橙子一样无法比较。 - orodbhen
2个回答

30
我看到的基准测试表明,OpenCL和OpenMP在相同硬件上运行时性能通常是可比较的,或者OpenMP的性能略微更好。然而,我没有看到任何我认为是确凿的基准测试,因为它们大多缺乏详细解释其方法。但是,有一些有用的事情需要考虑:
- OpenCL在运行时编译内核时总会有一些额外的开销。任何基准测试都需要将此时间列出来、使用预编译的本地内核,或者运行足够长的时间,以使内核编译变得无关紧要。 - OpenCL的实现将有所不同。GPU供应商如NVidia没有动力确保其基于CPU的OpenCL实现尽可能快。所有OpenCL实现都不太可能像良好的OpenMP实现一样成熟。 - OpenCL规范基本上没有关于基于CPU的实现如何在底层使用线程的说明,因此有关线程是相对轻量级还是重量级的任何讨论必然是特定于实现的。 - 当您在CPU上运行OpenCL代码时,您的工作项不必非常小而且数量众多。您可以按照与OpenMP相同的方式分解问题。
即使OpenCL有一些额外的开销,也可能有其他原因选择它。
- 显然,如果您的代码可以很好地利用GPU,那么您将需要一个OpenCL实现。在CPU上,OpenCL的性能可能足够好,以至于不值得为那些没有强大GPU的用户维护OpenMP回退代码路径。 - 良好的基于CPU的OpenCL实现意味着您将自动获得CPU和OpenCL实现支持的任何指令集扩展的好处。使用OpenMP,您必须做额外的工作,以确保您的可执行文件包括SSEx和AVX代码路径。 - OpenCL向量原语有助于您表达一些显式并行性,而不会牺牲可移植性和可读性,这是使用SSE内部函数所必需的。

我想知道没有GPU的用户案例是否真的那么实用。与维护OpenMP回退代码不同,您必须维护OpenCL回退代码,因为CPU不支持2D本地工作大小,存在__local内存等问题。如果您有优化的GPU内核,则不会获得太多收益。 - w-m
2
你认为为什么基于CPU的实现不能支持2D本地工作组大小或本地内存?在CPU上,缓存内存由硬件而非软件管理,因此全局和本地内存之间唯一的区别就是是否需要锁定才能访问它。对于NUMA系统,工作组大小将相当于调度提示。是的,OpenCL代码中投入大量优化工作以使其在GPU上运行良好的部分不会影响CPU性能,但也不会破坏代码。任何可以在GPU上运行的内核都可以在符合规范的CPU实现上运行。 - user57368
@user57368:补充一下,在GPU上使用像明确使用本地内存这样的优化是有意义的。在CPU上,使用这些优化“可能会”影响性能,至少在使用Intel OpenCL实现x86 CPU时是如此。 - usman
@user57368:也许英特尔SDK是这样工作的。苹果的不是。在Mac OS 10.6下,我的Core2Duo的CL_DEVICE_MAX_WORK_ITEM_SIZES为{1,1,1},在10.7下至少为{1024,1,1},但仍然不是2D。此外,任何具有多个本地变量的内核都会使编译器在10.6下放弃 - 我会称之为破坏代码。 - w-m
1
@w.m 你可以优化针对CPU的OpenCL代码,不使用本地内存等等 - 其性能可与OpenMP相媲美。由于内核通常很小,因此您仍然可以共享主机代码并将其用于实现更高的性能(如果系统具有可用的GPU),只需切换内核(到针对GPU进行优化的内核)和少量参数作为工作组大小即可。这说明不要保留回退代码 - 很大一部分在主机代码中,并且这是共享的。 - Radim Vansa

7
我有一个程序,在某些关键瓶颈处可以选择使用OpenCL或OpenMP,基本上是添加向量和执行归约。
在我的情况下,在CPU上,OpenMP需要13秒,而OpenCL只需要10秒。我的Intel I5。到目前为止,最快的配置是使用OpenCL GPU添加向量,并在OpenMP上执行归约,将时间缩短到7秒。如果我在GPU上使用OpenCL内核进行归约,则总共需要8秒。从我的经验来看,可能取决于用途以及您可以优化OpenCL内核的程度。

在这里,“reduction”具体指什么意思? - nbro
1
“Reduction”是指将大量元素(例如一个长度为10,000的数组a[0]到a[9999])进行处理,以得到一个较小的数据。例如:计算数组中的“最大值”,或者计算a[0]+a[1]+a[2]+...+a[9999]的值。最常见的缩减操作是“最大值”、“最小值”和“求和”,但是在并行编程中,将大量数据并行处理以输出单个数字(或至少代表整个数据的较少数字)的概念是一种常见的“模式”。 - Dragontamer5788

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接