0

我是一名生物物理学研究生,正在尝试使用 PyCUDA 和 Scipy 编写蛋白质聚合模型ODEInt。在过去的两周内,我已经让代码运行起来了,但是速度很慢。让我看看我是否可以解释我的代码的作用。

我有np一系列N浓度,每个元素都是i+1长度聚合物的浓度。我有一个函数可以计算聚合物浓度的变化率,CUDA其中每个内核计算一种特定长度聚合物的变化率。在此计算过程中,(N-i-1)线程需要对长度数组求和,从而大大降低了我的代码速度。

做一些阅读和谷歌搜索,我遇到了并行减少作为一种调用并行性的方式,以使像数组总和这样的串行计算变得更快。当然,我指的是 Mark Harris 的 powerpoint 幻灯片。这是一本很好的读物,这看起来是一种大幅加快我的代码速度的潜在方法,但我有几个问题:

如果聚合物种类的数量 N 需要为 ~ 8700-9000,是否可以使用 CUDA 同时减少这 N 个阵列?进行快速计算(再次感谢 SO 对如何计算最大并发线程数的出色解释),我得到了我的 GTX Titan 可以同时运行 15 * 64 * 32 = 30720 个线程。如果我一次在 ~8960 个内核上调用我的内核,我应该只剩下 21760 个线程可以使用,对吗?由于您似乎至少需要(数组的长度/ 2)线程才能正确减少它,所以我注定要失败。

我在想,也许我可以通过将剩余的线程分开并一次减少几个大数组来使用剩余的线程。

我不知道……我只是一名物理研究生。在我踏上错误方向的漫长旅程之前,我想我会问专业人士。是否可以轻松有效地告诉内核减少某些东西?

谢谢你,卡斯滕

这是我正在尝试做的事情的代表。

fluxes and concs are np.arrays
dcdt(concs, t)
    Call CUDA to calculate fluxes
        Thread
        0       fluxes[i] = stuff + sum(concs[n] for n from 1 to 9000)
        1       fluxes[i] = stuff + sum(concs[n] for n from 2 to 9000)
        2       fluxes[i] = stuff + sum(concs[n] for n from 3 to 9000)
        ...
        N       fluxes[i] = stuff

您会注意到,我们一直在讨论的数组的总和基本上是每个线程的同一数组的较小版本。这让我想知道这是否是我应该在主机上做的事情。

4

1 回答 1

1

可以想象使用 CUDA 来“并行”减少多个数组。归约(求和)并不是一项非常耗费计算的操作,因此如果数据尚未驻留在 GPU 上,那么将数据传输到 GPU 的成本可能是整体成本的重要部分(大部分)执行时间处理时间。根据您的描述,尚不清楚您是否已经在 GPU 或 CPU 上以某种方式执行此操作。但如果数据在 GPU 上,那么通过并行归约求和将是最快的。

除非单个数组的数据大于~2GB,否则线程数不太可能成为问题。

您可以制作一个内核,它只是按顺序一个接一个地减少数组。您似乎是在说有 N 个数组,其中 N 约为 9000。每个数组有多大?如果阵列足够大,GPU 的几乎所有功能(粗略地说)都可以用于每个单独的操作,在这种情况下,一个接一个地减少阵列不会有明显的损失。然后内核可以是一个基本的并行缩减,它在数组上循环。应该很简单。

如果您有大约 9000 个数组要处理,并且以交错方式对数据进行排序并不难,那么您还可以考虑一个由 9000 个线程组成的数组,其中每个线程在串行循环中对单个数组的元素进行求和,几乎你在 CPU 代码上天真地做这件事的方式。数据组织在这里至关重要,因为所有这些的目标是最大限度地利用可用内存带宽。由于每个线程中的循环都在拾取要求和的下一个数据元素,因此您需要确保在 warp 中的线程之间读取连续的数据(合并访问),从而意味着在您的 N 个数组中进行交错的数据存储安排。如果是这样的话,这种方法也会运行得非常快。

顺便说一句,您可能会看一下相对容易使用的推力,它提供了简单的操作来对数组进行求和。作为原型,在推力代码中编写一个循环将相对容易地对 GPU 上的一系列数组进行迭代求和。

于 2013-05-14T21:43:59.307 回答