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

Posted

技术标签:

【中文标题】给定元素数组、子列表的偏移量和长度的有效部分缩减【英文标题】:Efficient partial reductions given arrays of elements, offsets to and lengths of sublists 【发布时间】:2012-02-23 20:01:29 【问题描述】:

对于我的应用程序,我必须处理一堆对象(比如说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 库在桶上。对桶求和应该给出:

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 即时生成上述给定的密钥列表。不幸的是,我想不出一个不需要增加设备上偏移列表的索引并且破坏并行性的实现。

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

【问题讨论】:

【参考方案1】:

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

您的数据结构与用于存储稀疏矩阵的Compressed Sparse Row (CSR) 格式相似,因此如果您想要更好的性能,可以使用为此类矩阵计算sparse matrix-vector multiplies (SpMV) 开发的技术。请注意,CSR 格式的“偏移”数组的长度为 (N+1),用于具有 N 行的矩阵(即您的情况下的存储桶),其中最后一个偏移值是 arr 的长度。 Cusp 中的 CSR SpMV code 有点复杂,但它可以作为内核的一个很好的起点。只需从代码中删除对Ajx 的任何引用,然后将offsetsarr 分别传递给ApAv 参数。

【讨论】:

压缩稀疏行矩阵的相似性也让我印象深刻。【参考方案2】:

你没有提到桶有多大。如果存储桶足够大,也许您可​​以将偏移量和子列表长度复制到主机,遍历它们并为每个存储桶执行单独的推力调用。 Fermi 可以同时运行 16 个内核,因此在该架构上,您可能能够处理较小的存储桶并仍然获得良好的利用率。

【讨论】:

感谢您的回答。我将解决一个相对较小的固定桶大小,以便每个桶都在一个块内使用共享内存进行处理。你能指出我关于产生多个内核的限制的文献吗?谢谢!

以上是关于给定元素数组、子列表的偏移量和长度的有效部分缩减的主要内容,如果未能解决你的问题,请参考以下文章

存储过程与数组连接查询

ClickHouse 截取数组的部分元素,得到一个新的子数组: arraySlice (array, offset[, length])...

字符串操作优化

第82题给定一个数组,求所有偶数长度子数组的元素的和

查找具有给定排名的所有固定长度子数组

从只有 3 个有效移动的数组中制作最大长度升序子数组