给定元素数组、子列表的偏移量和长度的有效部分约简

Efficient partial reductions given arrays of elements, offsets to and lengths of sublists

本文关键字:有效部 偏移量 数组 元素 列表      更新时间:2023-10-16

对于我的应用程序,我必须处理一堆对象(比如ints),这些对象随后被划分并排序到更小的桶中。为此,我将元素存储在单个连续阵列中

arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14...}

并且关于桶(子列表)的信息通过对相应桶中的第一元素的偏移和子列表的长度来给出。

例如,给定

offsets = {0,3,8,..}
sublist_lengths = {3,5,2,...}

将导致以下分裂:

0 1 2 || 3 4 5 6 7 || 8 9 || ...

我正在寻找一种通用而高效的方法,只使用自定义内核或thrust库在bucket上运行算法,如reduction。桶的总和应给出:

3 || 25 || 17 || ...

我想到了什么:

  • 选项1:自定义内核需要大量的修补、复制到共享内存、正确选择块和网格大小以及自己的算法实现,如扫描、减少等。此外,每个操作都需要自己的自定义内核。一般来说,我很清楚如何做到这一点,但在过去几天使用thrust后,我觉得可能有一种更聪明的方法

  • 选项2:根据偏移量(上例中为{0,0,0,1,1,1,1,1,2,2,3,...})生成一个键数组,并使用thrust::reduce_by_key。不过,我不喜欢额外生成列表。

  • 选项3:使用thrust::transform_iteratorthrust::counting_iterator来动态生成上述给定的密钥列表。不幸的是,我无法想出一个不需要对设备上的偏移列表增加索引并破坏并行性的实现。

实现这一点最明智的方法是什么?

在Thrust中,我想不出比选项2更好的解决方案了。性能不会很糟糕,但肯定不是最佳的。

您的数据结构与用于存储稀疏矩阵的压缩稀疏行(CSR)格式相似,因此如果您想要更好的性能,可以使用为计算此类矩阵的稀疏矩阵向量乘(SpMV)而开发的技术。请注意,CSR格式的"offset"数组的长度为(N+1),用于具有N行的矩阵(在您的情况下为bucket),其中最后一个偏移值为arr的长度。Cusp中的CSR-SpMV代码有点复杂,但它是内核的一个很好的起点。只需从代码中删除对Ajx的任何引用,并将offsetsarr分别传递到ApAv自变量中。

您没有提到水桶有多大。如果bucket足够大,也许您可以将偏移量和sublist_length复制到主机,对它们进行迭代,并为每个bucket执行单独的Thrust调用。费米可以同时有16个内核在飞行,所以在这种架构中,你可能能够处理更小的桶,并且仍然可以获得良好的利用率。