3

我有一个 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)。

编辑:实际上,根据Khronos 论坛上的这个帖子,OpenCL 工作组的一位代表表示,共享上下文上的单个缓冲区确实会分布在多个 GPU 上,每个 GPU 都确保它在内存中拥有最新信息. 但是,我在 Nvidia GPU 上没有看到这种行为。当我watch -n .5 nvidia-smi在后台运行程序时使用时,我看到一个 GPU 的内存使用量上升了一段时间,然后在另一个 GPU 的内存使用量上升时下降。有没有人可以指出我正确的方向?也许这只是他们的实施?

4

1 回答 1

4

听起来您在实施时遇到了麻烦。

SIGGRAPH 有一个很棒的演示文稿,展示了利用共享内存的多个 GPU 的几种不同方法。幻灯片在这里

我想,在您当前的设置中,您有一个包含多个设备和多个命令队列的单一上下文。对于您正在做的事情,这可能是正确的方法。

OpenCL 1.2 规范的附录 A说:

OpenCL 内存对象,[...] 是使用上下文创建的,并且可以在使用相同上下文创建的多个命令队列之间共享。

更远:

应用程序需要在主机处理器上的线程之间实现适当的同步,以确保当多个线程中的多个命令队列正在生成时,共享对象状态的更改 [...] 以正确的顺序发生 [...]更改共享对象的状态。

所以在我看来,计算粒子位置和速度的内核需要依赖于计算粒子间力的内核。听起来你已经知道了。

为了更多地说明您的问题:

考虑到每个 GPU 都有不同的缓冲区,跨 GPU 同步缓冲区的最佳方法是什么?

...我认为答案是“不要让缓冲区分开”。通过使该对象来自相同的上下文cl_mem,在两个设备之间使用相同的对象。cl_mem

至于数据实际存在的位置......正如您所指出的,这是实现定义的(至少据我从规范中可以看出)。您可能不应该担心数据在哪里,只需从两个命令队列中访问数据。

我意识到这可能会产生一些严重的性能问题。实现可能会发展并变得更好,因此如果您现在根据规范编写代码,将来它可能会运行得更好。

为了获得更好(或至少不同)的缓冲区共享行为,您可以尝试的另一件事是将粒子数据制作成地图。

如果有任何帮助,我们的设置(具有双 C2070 的一堆节点)似乎可以相当优化地共享缓冲区。有时,数据只保存在一个设备上,有时数据可能同时存在于两个地方。

总而言之,我认为这里的答案是以规范提供的最佳方式来做,并希望在实施方面做到最好。

我希望我是有帮助的,

瑞安

于 2012-07-25T20:38:01.493 回答