我必须在GPU
中实现以下算法for(int I = 0; I < 1000; I++){
VAR1[I+1] = VAR1[I] + VAR2[2*K+(I-1)];//K is a constant
}
每次迭代都依赖于之前的版本,因此并行化很困难。我不确定原子操作在这里是否有效。我该怎么办?
修改
VAR1 和 VAR2 都是1D数组。
VAR1[0] = 1
答案 0 :(得分:5)
这是一类名为recurrence relations的问题。根据递归关系的结构,可能存在封闭形式的解决方案,其描述了如何单独地(即并行地,没有递归地)计算每个元素。其中一篇早期开创性论文(关于并行计算)是Kogge and Stone,并且存在用于并行化特定形式的方法和策略。
有时递归关系是如此简单,以至于我们可以通过一点点&#34;检查&#34;来识别封闭形式的公式或算法。这个short tutorial给了这个想法更多的处理。
在您的情况下,让我们看看我们是否可以通过确定VAR1
的前几个词应该是什么来发现任何内容,将之前的词替换为更新的词:
i VAR1[i]
___________________
0 1
1 1 + VAR2[2K-1]
2 1 + VAR2[2K-1] + VAR2[2K]
3 1 + VAR2[2K-1] + VAR2[2K] + VAR2[2K+1]
4 1 + VAR2[2K-1] + VAR2[2K] + VAR2[2K+1] + VAR2[2K+2]
...
希望突然发现的是,上面的VAR2[]
条款遵循prefix sum的模式。
这意味着可以通过以下方式给出一种可能的解决方法:
VAR1[i] = 1+prefix_sum(VAR2[2K + (i-2)]) (for i > 0) notes:(1) (2)
VAR1[i] = 1 (for i = 0)
现在,前缀总和可以并行完成(这不是真正完全独立的操作,但它可以并行化。我不想在这里过多地讨论术语或纯度。我&#39;为你提出的问题提供并行化的一种可能的方法,而不是唯一的方法。)要在GPU上并行执行前缀和,我会使用像CUB这样的库或Thrust。或者你可以write your own虽然我不推荐它。
注意:
使用-1或-2作为前缀和i
的偏移量可能取决于您使用inclusive
或exclusive
扫描或前缀总和操作
VAR2
才能使其合理化。但是,您的问题陈述中隐含了该要求。
这是一个简单的工作示例。在这种情况下,由于VAR2
索引术语2K+(I-1)
仅代表I
(2K-1
)的固定偏移量,因此我们只是将偏移量0用于演示目的,因此VAR2
只是与VAR1
在同一个域中的一个简单数组。为了演示目的,我将VAR2
定义为只是所有1
的数组。 gpu并行计算发生在VAR1
向量中,CPU等效计算只是在cpu
变量中即时计算,用于验证目的:
$ cat t1056.cu
#include <thrust/scan.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/transform.h>
#include <iostream>
const int dsize = 1000;
using namespace thrust::placeholders;
int main(){
thrust::device_vector<int> VAR2(dsize, 1); // initialize VAR2 array to all 1's
thrust::device_vector<int> VAR1(dsize);
thrust::exclusive_scan(VAR2.begin(), VAR2.end(), VAR1.begin(), 0); // put prefix sum of VAR2 into VAR1
thrust::transform(VAR1.begin(), VAR1.end(), VAR1.begin(), _1 += 1); // add 1 to every term
int cpu = 1;
for (int i = 1; i < dsize; i++){
int gpu = VAR1[i];
cpu += VAR2[i];
if (cpu != gpu) {std::cout << "mismatch at: " << i << " was: " << gpu << " should be: " << cpu << std::endl; return 1;}
}
std::cout << "Success!" << std::endl;
return 0;
}
$ nvcc -o t1056 t1056.cu
$ ./t1056
Success!
$
有关扫描操作用于解决线性递归问题的其他参考,请参阅Blelloch的论文here第1.4节。