Parallel processing 改进的并行扫描

Parallel processing 改进的并行扫描,parallel-processing,gpgpu,Parallel Processing,Gpgpu,这与其说是编程问题,不如说是算法问题。我想知道是否可以修改前缀和(或任何)并行算法来完成以下任务。我希望在不到O(N)的时间内从GPU上的两个输入列表生成一个结果 规则是:从数据中取出第一个数字,直到键中的相同索引包含较小的值 每当我尝试将其映射到并行扫描时,它都不起作用,因为我无法确定要在upsweep中传播哪些数据值,因为无法知道之前的哪些数据可能已经足够远,可以与当前键进行比较。这个问题让我想起了一个涟漪进位,我们需要考虑当前索引和所有过去的索引。 同样,并行扫描不需要代码(尽管那会很好)

这与其说是编程问题,不如说是算法问题。我想知道是否可以修改前缀和(或任何)并行算法来完成以下任务。我希望在不到O(N)的时间内从GPU上的两个输入列表生成一个结果

规则是:从数据中取出第一个数字,直到键中的相同索引包含较小的值

每当我尝试将其映射到并行扫描时,它都不起作用,因为我无法确定要在upsweep中传播哪些数据值,因为无法知道之前的哪些数据可能已经足够远,可以与当前键进行比较。这个问题让我想起了一个涟漪进位,我们需要考虑当前索引和所有过去的索引。 同样,并行扫描不需要代码(尽管那会很好),更多的是想了解如何完成或为什么不能完成

int data[N] = {5, 6, 5, 5, 3, 1, 5, 5};
int keys[N] = {5, 6, 5, 5, 4, 2, 5, 5};
int result[N];

serial_scan(N, keys, data, result);
// Print result.  should be {5, 5, 5, 5, 3, 1, 1, 1, }
进行串行扫描的代码如下:

void serial_scan(int N, int *k, int *d, int *r)
{
  r[0] = d[0];
  for(int i=1; i<N; i++) 
    {
      if (k[i] >= r[i-1]) {
        r[i] = r[i-1];
      } else if (k[i] >= d[i]) {
        r[i] = d[i];
      } else {
        r[i] = 0;
      }
    }
}
void串行_扫描(int N,int*k,int*d,int*r)
{
r[0]=d[0];
对于(int i=1;i=r[i-1]){
r[i]=r[i-1];
}如果(k[i]>=d[i]){
r[i]=d[i];
}否则{
r[i]=0;
}
}
}

可以找到并行扫描的一般技术,在函数式语言标准ML中进行了描述。这可以对任何关联运算符执行,我认为您的操作符合要求

一个直观的例子是,通过递归计算数组的两半之和并将它们相加,可以计算O(log(n))跨度(无限处理器的运行时间)内数组的和。在计算扫描时,您只需要知道当前点之前数组的和

我们可以计算并行进行两半的阵列扫描:使用上述技术计算前半部分的总和。然后依次计算两部分的扫描;上半部分从0开始,下半部分从您之前计算的总和开始。完整的算法有点复杂,但使用了相同的思想

下面是一些用不同语言进行并行扫描的伪代码(对于int和addition的特定情况,但对于任何关联运算符,逻辑都是相同的):

//假设input.length是2的幂
int[]扫描添加(int[]输入){
if(input.length==1)
返回输入
否则{
//计算一个新的折叠序列,该序列是连续偶数/奇数对的总和
//假设这个for循环是并行完成的
int[]折叠=新int[input.length/2]
为了
//assume input.length is a power of 2

int[] scanadd( int[] input) {
  if (input.length == 1)
    return input 
  else { 
    //calculate a new collapsed sequence which is the sum of sequential even/odd pairs 
    //assume this for loop is done in parallel

    int[] collapsed = new int[input.length/2]
    for (i <- 0 until collapsed.length) 
      collapsed[i] = input[2 * i] + input[2*i+1]

    //recursively scan collapsed values
    int[] scancollapse = scanadd(collapse)

    //now we can use the scan of the collapsed seq to calculate the full sequence

    //also assume this for loop is in parallel
    int[] output = int[input.length]
    for (i <- 0 until input.length) 
      //if an index is even then we can just look into the collapsed sequence and get the value
      // otherwise we can look just before it and add the value at the current index

      if (i %2 ==0) 
        output[i] = scancollapse[i/2]
      else 
        output[i] = scancollapse[(i-1)/2] + input[i]

    return output
  } 
}