有没有一种好方法在cuda上使用只读的hashmap?

时间:2012-06-08 17:57:15

标签: cuda

我真的很喜欢编程和Cuda很抱歉,如果这很明显。基本上我有一个C函数读取数据列表然后根据hashmap检查每个项目(我在C中使用uthash)。它运行良好,但我想在Cuda中运行这个过程(一旦它获得了散列键的值,那么它会进行很多处理),但我不确定创建尽可能快的只读散列函数的最佳方法在库达。

背景:

基本上我正试图尽快评估一大批投资组合。我不断得到数百万个投资组合,这些投资组合是两个列表。一个有股票名称,另一个有权重。然后,我使用股票名称查找哈希表以获取其他数据(值,%更改等),然后根据权重处理它。在普通C的CPU上大约需要8分钟,所以我很有兴趣在GPU上尝试它。我已经阅读并完成了cuda by example中的示例,所以我相信我知道除了哈希函数之外该怎么做(除了哈希函数之外还有一个,但它似乎专注于添加它,而我真的只想要它一个参考,因为它永远不会改变。我可能在cuda for example的边缘粗糙,所以也许有一些我遗漏的东西在这种情况下对我有帮助,比如使用文本或一些特殊形式的记忆这个)。如果每个块都有自己对hashmap的访问权限,或者每个线程是否足以满足整个GPU的要求,我将如何构建此结果以获得最佳结果?

任何能够更好地理解这一点的想法,示例或资源都会很棒。

谢谢!

编辑:很抱歉只是为了澄清,我只是使用C.最糟糕的情况我愿意使用另一种语言,但理想情况下我想要一些我可以原生地放在GPU上的东西,并且所有未来的线程都会被读取因为要处理我的数据,我需要在几个大批量中完成。

3 个答案:

答案 0 :(得分:8)

这是关于在GPU上使用哈希映射的潜在性能问题的一些想法,以备份关于将哈希映射保留在CPU上的评论。

NVIDIA GPU以32个线程为一组运行线程,称为warps。为了获得良好的性能,warp中的每个线程必须基本上做同样的事情。也就是说,它们必须运行相同的指令,并且必须从彼此接近的存储器位置读取。

我认为哈希映射可能会破坏这两个规则,可能会降低GPU的速度,以至于无法将哈希映射保留在GPU上。

考虑一下warp中的32个线程运行时会发生什么:

  • 首先,每个线程都必须创建股票名称的哈希值。如果这些名称的长度不同,则在散列循环中将针对不同的长度涉及不同数量的轮次,并且warp中的所有线程必须等待最长名称的散列才能完成。根据散列算法,代码可以在散列算法中采用不同的路径。每当warp中的不同线程需要采用不同的路径时,相同的代码必须运行多次(每个代码路径一次)。这称为经线发散。

  • 当warp中的所有线程都获得了哈希时,每个线程必须从慢速全局内存中的不同位置读取(由哈希指定)。当经线中的32个线程中的每个线程以紧密,连贯的模式读取时,GPU以最佳方式运行。但现在,每个线程都从内存中基本上随机的位置读取。这可能导致GPU必须序列化所有线程,可能会将性能降低到潜在的1/32。

  • 线程读取的内存位置是散列桶。每个可能包含不同数量的哈希值,再次导致warp中的线程必须执行不同的操作。然后,他们可能必须再次分支,每个分支到一个随机位置,以获得映射的实际结构。

如果您将库存名称和数据结构保留在CPU上的哈希映射中,则可以使用CPU将存储在GPU擅长处理的精确模式中的信息数组放在一起。根据CPU的繁忙程度,您可以在GPU处理先前提交的工作时执行此操作。

这也让您有机会将CPU上的结构数组(AoS)更改为GPU的数组结构(SoA)。如果你不熟悉这个概念,基本上你转换:

my_struct {
  int a;
  int b;
};
my_struct my_array_of_structs[1000];

为:

struct my_struct {
  int a[1000];
  int b[1000];
} my_struct_of_arrays;

这使得所有a彼此相邻在内存中,这样当warp中的32个线程到达读取a的指令时,所有值都整齐地排列在旁边彼此,导致整个warp能够非常快速地加载值。当然,b也是如此。

答案 1 :(得分:2)

cuda-thrust-extensions库中有一个CUDA Thrust的hash_map扩展名。我没试过。

答案 2 :(得分:0)

由于你的哈希映射是如此之大,我认为它可以被数据库取代,mysql或其他产品都可以,他们可能会比哈希地图设计快。我同意Roger的观点,它不适合将它转移到GPU,它消耗太大的设备内存(可能无法包含它),而且内核功能访问设备上的全局内存非常慢。

此外,您的程序的哪一部分需要8分钟,在哈希映射或重量过程中查找?如果是后者,可能会被GPU加速。

祝你好运!