Cuda GPU实现中的顺序操作

Cuda GPU实现中的顺序操作,cuda,parallel-processing,gpu,Cuda,Parallel Processing,Gpu,我必须在GPU中实现以下算法 for(int I = 0; I < 1000; I++){ VAR1[I+1] = VAR1[I] + VAR2[2*K+(I-1)];//K is a constant } 这属于一类问题,称为。根据递归关系的结构,可能存在描述如何单独计算每个元素(即并行计算,无递归)的封闭形式解决方案。早期的开创性论文之一(关于并行计算)是,并且存在将特定形式并行化的方法和策略 有时,递归关系非常简单,我们可以通过一点“检查”来识别一个封闭形式的公式或算法。这

我必须在GPU中实现以下算法

for(int I = 0; I < 1000; I++){
    VAR1[I+1] = VAR1[I] + VAR2[2*K+(I-1)];//K is a constant
}

这属于一类问题,称为。根据递归关系的结构,可能存在描述如何单独计算每个元素(即并行计算,无递归)的封闭形式解决方案。早期的开创性论文之一(关于并行计算)是,并且存在将特定形式并行化的方法和策略

有时,递归关系非常简单,我们可以通过一点“检查”来识别一个封闭形式的公式或算法。这给了这个想法更多的处理

在您的例子中,我们看看是否可以通过绘制
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[]
术语遵循一种模式

这意味着可以通过以下方式给出一种可能的解决方法:

VAR1[i] = 1+prefix_sum(VAR2[2K + (i-2)])   (for i > 0) notes:(1) (2)
VAR1[i] = 1                                (for i = 0)
现在,前缀和可以并行完成(这不是一个真正的完全独立的操作,但它可以并行化。我不想在这里就术语或纯度争论太多。我提供了一种可能的并行化方法,这不是唯一的方法。)在GPU上并行完成前缀和,我会使用一个图书馆,就像或。或者你可以,尽管我不推荐

注:

  • 使用-1或-2作为前缀和的
    i
    的偏移量,可能取决于使用
    包含的
    排除的
    扫描或前缀和操作

  • 必须在适当的域上定义
    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!
    $
    
    $cat t1056.cu
    #包括
    #包括
    #包括
    #包括
    #包括
    常数int dsize=1000;
    使用命名空间推力::占位符;
    int main(){
    推力::device_vector VAR2(dsize,1);//将VAR2数组初始化为所有1
    推力:设备矢量VAR1(dsize);
    独占扫描(VAR2.begin(),VAR2.end(),VAR1.begin(),0);//将VAR2的前缀和放入VAR1
    推力::变换(VAR1.begin(),VAR1.end(),VAR1.begin(),_1+=1);//向每个术语添加1
    int cpu=1;
    对于(int i=1;i如果(cpu!=gpu){std::cout这属于一类问题。根据递归关系的结构,可能存在描述如何单独计算每个元素(即并行计算,无递归)的闭式解。早期开创性论文之一(关于并行计算)是的,并且存在并行化特定形式的方法和策略

    有时,递归关系非常简单,我们可以通过一点“检查”来识别一个封闭形式的公式或算法。这给了这个想法更多的处理

    在您的例子中,我们看看是否可以通过绘制
    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[]
    术语遵循一种模式

    这意味着可以通过以下方式给出一种可能的解决方法:

    VAR1[i] = 1+prefix_sum(VAR2[2K + (i-2)])   (for i > 0) notes:(1) (2)
    VAR1[i] = 1                                (for i = 0)
    
    现在,前缀和可以并行完成(这不是一个真正完全独立的操作,但它可以并行化。我不想在这里对术语或纯度争论太多。我为您所述的问题提供一种可能的并行化方法,而不是唯一的方法。)要在GPU上并行进行前缀求和,我会使用像或这样的库。或者你也可以,尽管我不推荐这样做

    注:

  • 使用-1或-2作为前缀和的
    i
    的偏移量,可能取决于使用
    包含的
    排除的
    扫描或前缀和操作

  • 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!
    $
    
    $cat t1056.cu
    #包括
    #包括
    #包括
    #包括
    #包括
    常数int dsize=1000;
    使用命名空间推力::占位符;
    int main(){
    推力::device_vector VAR2(dsize,1);//将VAR2数组初始化为所有1
    推力:设备矢量VAR1(dsize);
    独占扫描(VAR2.begin(),VAR2.end(),VAR1.begin(),0);//将VAR2的前缀和放入VAR1
    推力::变换(VAR1.begin(),VAR1.end(),VAR1.begin(),_1+=1);//向每个术语添加1
    int cpu=1;
    对于(int i=1;i