CUDA:一种用于在总和减少期间计算所有部分总和的方法

时间:2018-11-06 23:20:55

标签: cuda thrust

我在CUDA中一遍又一遍地遇到了这个问题。对于一组元素,我已经进行了一些GPU计算。这会导致某些值具有线性含义(例如,就内存而言):

element_sizes = [ 10, 100, 23, 45 ]

现在,对于GPU的下一阶段,我需要以下值:

memory_size = sum(element_sizes)
memory_offsets = [ 0, 10, 110, 133 ]

我可以使用NVIDIA提供的精简代码在我的GPU上以80 gbps的速度计算memory_size。但是,我不能使用此代码,因为它使用了不构成内存偏移量数组的分支技术。我已经尝试了很多事情,但是我发现简单地将elements_sizes复制到主机并使用simd for循环计算偏移量是最简单,最快的方法:

// in pseudo code
host_element_sizes = copy_to_host(element_sizes);
host_offsets = (... *) malloc(...);

int total_size = 0;
for(int i = 0; i < ...; ...){
    host_offsets[i] = total_size;
    total_size += host_element_sizes[i];
}

device_offsets = (... *) device_malloc(...);
device_offsets = copy_to_device(host_offsets,...);

但是,我现在已经做过很多次了,它开始成为瓶颈。这似乎是一个典型的问题,但是我没有找到解决方法。

CUDA程序员解决此问题的预期方式是什么?

1 个答案:

答案 0 :(得分:2)

我认为您要寻找的算法是prefix sum。向量上的前缀和产生另一个向量,该向量包含输入向量的累积和值。前缀和至少存在两个变体-排他扫描或包含扫描。从概念上讲,这些是相似的。

如果您的element_sizes向量已存放在GPU全局内存中(似乎是基于您的伪代码的情况),则存在可以在此时调用的在GPU上运行的库函数,以产生memory_offsets数据(向量),并且可以从向量中的最后一个值简单地获取memory_size值,根据您进行的是包含式扫描还是排他式扫描,略有变化。 / p>

这是一个使用thrust的简单示例:

$ cat t319.cu
#include <thrust/scan.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/copy.h>
#include <iostream>



int main(){

  const int element_sizes[] = { 10, 100, 23, 45 };
  const int ds = sizeof(element_sizes)/sizeof(element_sizes[0]);
  thrust::device_vector<int> dv_es(element_sizes, element_sizes+ds);
  thrust::device_vector<int> dv_mo(ds);
  thrust::exclusive_scan(dv_es.begin(), dv_es.end(), dv_mo.begin());
  std::cout << "element_sizes:" << std::endl;
  thrust::copy_n(dv_es.begin(), ds, std::ostream_iterator<int>(std::cout, ","));
  std::cout << std::endl << "memory_offsets:" << std::endl;
  thrust::copy_n(dv_mo.begin(), ds, std::ostream_iterator<int>(std::cout, ","));
  std::cout << std::endl << "memory_size:" << std::endl << dv_es[ds-1] + dv_mo[ds-1] << std::endl;
}
$ nvcc -o t319 t319.cu
$ ./t319
element_sizes:
10,100,23,45,
memory_offsets:
0,10,110,133,
memory_size:
178
$