我有以下问题:我需要基于 GPU 上的树结构计算值的包容性扫描(例如前缀和)。这些扫描要么来自根节点(自上而下),要么来自叶节点(自下而上)。简单链的情况很容易处理,但是树结构使得并行化很难有效地实现。
例如,在自上而下的包容性扫描之后,(12)
将保持(0)[op](6)[op](7)[op](8)[op](11)[op](12)
,对于自下而上的包容性扫描,(8)
将保持(8)[op](9)[op](10)[op](11)[op](12)
,其中[op]
是给定的二元运算符(矩阵加法、乘法等)。
还需要考虑以下几点:
- 对于一个典型的场景,不同分支的长度不应该太长(~10),大约有 5 到 10 个分支,所以这将在一个块内运行并且工作将在线程之间拆分。不同的块将简单地处理不同的节点值。这对于占用率显然不是最优的,但这是对稍后将要解决的问题的限制。现在,我将依赖指令级并行性。
- 图的结构不能改变(它描述了一个实际的系统),因此不能平衡(或者只能通过改变树的根,例如
(6)
用作新根)。尽管如此,典型的树不应该太不平衡。 - 我目前将 CUDA 用于 GPGPU,因此我对任何可以解决此问题的支持 CUDA 的模板库持开放态度。
- 节点数据已经在全局内存中,结果将被其他 CUDA 内核使用,因此目标只是实现这一点,而不使其成为巨大的瓶颈。
- 没有“循环”,即分支不能沿树合并。
- 树的结构是固定的,并在初始化阶段设置。
- 单个二元运算可能非常昂贵(例如多项式矩阵的乘法,即每个元素都是给定阶数的多项式)。
在这种情况下,解决这个问题的“最佳”数据结构(对于树结构)和最佳算法(对于包容性扫描/前缀和)是什么?