将CUDA与Python的ODEInt和并行缩减相结合

时间:2013-05-14 21:25:42

标签: python cuda parallel-processing reduction pycuda

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

我有npN浓度的数组,每个元素都是i+1长度聚合物的浓度。我有一个函数,使用CUDA计算聚合物浓度的变化率,其中每个核计算一个特定长度聚合物的变化率。在此计算过程中,线程需要对(N-i-1)长度数组求和,这大大减慢了我的代码。

做一些阅读和谷歌搜索,我遇到了并行缩减作为一种调用并行性的方法,使得像数组和的串行计算更快。当然,我指的是马克哈里斯的幻灯片。这些都很棒,这看起来像是一种大幅加速我的代码的潜在方式,但我有几个问题:

如果聚合物种类的数量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

你会注意到我们一直在谈论的数组的总和基本上是每个线程的相同数组的较小版本。这让我想知道这是否应该在主持人那里做。

1 个答案:

答案 0 :(得分:1)

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

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

你可以按顺序制作一个简单地依次减少数组的内核。看来你说有N个数组,其中N大约为9000.每个数组有多大?如果阵列足够大,大约GPU的所有功能(粗略地说)可以在每个单独的操作上承担,在这种情况下,一个接一个地减少阵列没有明显的损失。然后内核可以是基本的并行缩减,循环遍历数组。应该非常简单。

如果你有大约9000个阵列需要处理,以交错的方式排序你的数据并不困难,那么你也可以考虑一个9000个线程的数组,其中每个线程总结了串行循环中的单个数组,就像你在CPU代码上天真地做的那样。数据组织在这里至关重要,因为所有这一切的目标是最大限度地利用可用内存带宽。由于每个线程中的循环正在拾取它的下一个要求和的数据元素,因此您需要确保在warp(合并访问)中的线程之间具有连续的数据读取,从而意味着在N个阵列之间存在交错的数据存储布局。如果是这种情况,这种方法也会很快运行。

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