我有一个 OpenCL 内核,用于计算系统中其他粒子对某个粒子施加的总力,然后是另一个积分粒子位置/速度的内核。我想在多个 GPU 上并行化这些内核,基本上为每个 GPU 分配一定数量的粒子。但是,我必须多次运行该内核,并且每个 GPU 的结果都会用于其他 GPU。让我进一步解释一下:
假设 GPU 0 上有粒子 0,GPU 1 上有粒子 1。粒子 0 上的力发生了变化,粒子 1 上的力也发生了变化,然后积分器相应地改变了它们的位置和速度。然后,需要将这些新位置放置在每个 GPU 上(两个 GPU 都需要知道粒子 0 和粒子 1 的位置),并且这些新位置用于在下一步中计算每个粒子上的力,由积分器,其结果用于计算力等。本质上,在力计算进行时,所有缓冲区都需要包含相同的信息。
所以,问题是:考虑到每个 GPU 都有不同的缓冲区,跨 GPU 同步缓冲区的最佳方法是什么?如果我想保持并行性,它们就不能有一个共享缓冲区,根据我的最后一个问题(不过,如果有一种方法可以创建共享缓冲区并仍然保留多个 GPU,我完全赞成)。我怀疑每一步复制结果会导致比跨 GPU 并行算法更慢的速度。
我确实找到了这个线程,但答案并不是很明确,并且仅适用于所有 GPU 上的单个缓冲区。我特别想知道 Nvidia GPU(更具体地说,Tesla M2090)。
EDIT:事实上,按照Khronos 论坛上的这个帖子OpenCL 工作组的一位代表表示,共享上下文上的单个缓冲区确实分布在多个 GPU 上,每个 GPU 都确保其内存中具有最新信息。然而,我在 Nvidia GPU 上没有看到这种行为;当我使用watch -n .5 nvidia-smi
当我的程序在后台运行时,我看到一个 GPU 的内存使用量上升了一段时间,然后下降,而另一个 GPU 的内存使用量上升。有没有人可以指出我正确的方向?也许这只是他们的实施?
听起来您在实施方面遇到了麻烦。
SIGGRAPH 有一个精彩的演示,展示了利用共享内存的多个 GPU 的几种不同方法。幻灯片是here.
我想,在您当前的设置中,您有一个包含多个设备和多个命令队列的上下文。对于您正在做的事情来说,这可能是正确的方法。
附录AOpenCL 1.2 规范说:
OpenCL 内存对象[...]是使用上下文创建的,并且可以在使用同一上下文创建的多个命令队列之间共享。
Further:
应用程序需要在主机处理器上的线程之间实现适当的同步,以确保当多个线程中的多个命令队列正在执行时,共享对象状态的更改以正确的顺序发生更改共享对象的状态。
因此,在我看来,计算粒子位置和速度的内核需要依赖于计算粒子间力的内核。听起来你已经知道了。
为了更具体地表达你的问题:
考虑到每个 GPU 都有不同的缓冲区,跨 GPU 同步缓冲区的最佳方法是什么?
...我认为答案是“不要将缓冲区分开”。使用相同的cl_mem
两个设备之间的对象cl_mem
对象来自相同的上下文。
至于数据实际存在的位置......正如您所指出的,这是实现定义的(至少据我从规范中可以看出)。您可能不应该担心数据所在的位置,而只需从两个命令队列访问数据即可。
我意识到这可能会造成一些严重的性能问题。实现可能会发展并变得更好,因此如果您现在根据规范编写代码,它将来可能会运行得更好。
为了获得更好(或最少不同)的缓冲区共享行为,您可以尝试的另一件事是使粒子数据成为贴图。
如果有帮助的话,我们的设置(一堆带有双 C2070 的节点)似乎相当优化地共享缓冲区。有时,数据仅保存在一台设备上,有时数据可能同时存在于两个位置。
总而言之,我认为这里的答案是按照规范提供的最佳方式进行操作,并希望在实施方面取得最佳效果。
我希望我能有所帮助,
Ryan
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)