如何管理 OpenCL/SYCL 工作组中所有工作项共享的本地内存中的有状态数据结构

问题描述 投票:0回答:1

我正在尝试使用本地内存优化 OpenCL/SYCL 中的内存限制数值模拟内核,以允许工作项之间的数据共享,以便减少冗余的全局内存流量。

当本地内存中几乎没有数据依赖性时,填充本地内存很简单 - 我们可以简单地细分本地内存的索引空间,并使用合适的索引计算方程为每个工作项分配一部分,因此所有工作项共同加载数据从全局内存到本地内存到适当的位置。然后,使用屏障来分隔每个工作项的“加载”阶段和“计算”阶段。通信仅发生在“计算”阶段,并且仅隐式发生,因为它们共享内存 - 在“加载”阶段,不需要同步、通信甚至逻辑。 但是,我的内核有一个不平凡的数据依赖链(计算数据依赖本身就是组合学的练习),因为这是在本地内存空间限制内允许高度数据重用的唯一方法。待加载到本地内存的数据被细分为2x2x2的blocks,这些块之间存在不规则的数据依赖关系。例如,要计算接下来的3个块,您需要前1个块,要计算接下来的6个块,您需要前3个块,要计算接下来的10个块,您需要前6个块,计算接下来的15个块块,您需要前 10 个块等。这些块需要动态“映射”到工作项。 出于超出此问题范围的考虑,我现在的计划是使用 1024 个工作项组大小在 AMD GCN 上达到占用率 4,同时仍然能够使用 64 KiB 本地内存。如果每个工作项负责计算 2x2x2 块中的单个点,则意味着要使 GPU 完全饱和,我必须始终一次将 128 个块加载到本地内存,因此正在处理的点数为 2x2x2x128 = 1024。 这个要求使本地内存管理的逻辑变得非常复杂:

本地内存必须用作环形缓冲区,我需要在淘汰旧块后立即将新块加载到本地内存。我需要操作几个指针和计数器。

理想情况下,必须一次将 128 个块加载到本地内存中,但这进一步受到数据依赖性的限制。

  1. 加载和退出块时,不得破坏相邻迭代之间的数据依赖关系。

  2. 在这种情况下,填充和管理本地内存的最佳方法是什么?

  3. 不可能以规则且无通信的方式将块划分到每个工作项。我看到教程中的常见解决方案是使用
  4. if/else

    ,以便只有一个工作项负责加载本地内存或管理内核状态。然而,我觉得这大大减少了可用的全局内存带宽,因为只有一个工作项(例如

    if (id == 0)
  5. )正在发出内存请求,这不足以使内存控制器饱和。它还引入了工作项分歧,这可能会损害性能。一个相关的解决方案是在波前边界(例如
if (id < 64)

)划分工作,并且应该表现更好。

总之,我的问题是:管理工作组中所有工作项共享的有状态全局状态或全局数据结构的一般策略是什么?

    
重新思考问题后,我现在看到的最好的解决方案是预先计划。由于工作组仅处理固定数量的块,具有固定的大小和依赖链,因此每个工作项执行的操作可能可以由内核程序员在编码期间或内核启动之前预先计算 - 而不是要求工作组计算出在运行时输出。
使用此方法,所有环形缓冲区操作,包括每个工作项执行的指针和内存加载/存储都是预先确定的。如果这种方法有效,在最终内核中,每个工作项将使用展开的循环或查找表遵循预先计划的路径,而不需要任何其他复杂的逻辑来维护全局工作组状态。块退役和环形缓冲区刷新之间只需要一些障碍。

opencl gpgpu sycl
1个回答
0
投票

例如,如果您在体积计算逻辑中构建粒子的邻居列表,则可以根据其邻居 id 值对工作项进行排序,以便在排序后它们同时访问具有相似 id 值的粒子,这很好对于 L1/L2 缓存,您不必显式使用本地内存。

© www.soinside.com 2019 - 2024. All rights reserved.