使用本地/共享内存作为全局

时间:2017-09-12 13:47:42

标签: cuda opencl

我有一个图像处理内核,它使用的标志缓冲区太大而无法放入本地内存。以可预测的光栅模式(左上角到右下角)访问标志。

我的想法是将标志存储在全局内存中,并使用本地内存作为全局缓存。因此,当我沿着栅格模式前进时,我想读取从全局到本地的标志,进行一些处理,然后将标志写回全局。但是,我想隐藏所涉及的延迟。

因此,假设我将图像作为一系列位置访问:a1,a2,a3...... 我想做以下事情:

  1. 获取a1标志
  2. 获取a2标志
  3. 正在获取a2标记,处理a1位置并存储回来 全球记忆
  4. 获取a3标志
  5. 正在获取a3标记,处理a2位置并存储回来 全球记忆
  6. 我应该如何构建代码以确保隐藏延迟? 我需要使用vload/vstore来执行此操作吗?或者GPU硬件 自动隐藏延迟?

4 个答案:

答案 0 :(得分:3)

CUDA Surface概念可能是适合您案例的好工具。访问模式针对图像处理进行了优化,并且它使用纹理缓存,因此无需自己执行缓存。纹理缓存是每个块,因此您可能希望使用2D线程分布来使单个块处理小方块。

隐藏延迟自然是通过调度比硬件可以同时处理的更多线程和块来完成的。根据设备的Compute Capability“每个多处理器的最大驻留线程数”(自CC 3.0以来的2048)与每个SM的CUDA核心数之间的比率将为您提供良好的提示,以计算您想要安排的线程总数(线程*块),以最好地隐藏延迟。请注意,最佳实际取决于代码本身,内核需要的寄存器数等等。

答案 1 :(得分:2)

无需手动执行此操作。 GPU设备已经为您完成了这项工作。

计算核心批量执行一些工作项(warp),当批处理由于等待全局内存而无法继续时,它会同时启动另一批处理并使该批处理进入休眠状态。

答案 2 :(得分:1)

关键是要确保你的读取被合并 - 这是获得峰值内存带宽的唯一方法。然后,保持内核复杂性足够低,以便占用率足够高,以确保所有计算都隐藏在内存访问之后。那么你将尽可能快地运行。

答案 3 :(得分:1)

看起来你确实拥有拥有高效内核的所有要求。 您可以预测数据访问模式,从gmem合并读取,并且您确实进行了复杂的处理。

因此,硬件将通过选择驻留块中的扭曲来自动隐藏全局加载延迟"在飞行中"在停滞的扭曲加载值的同时进行处理,但你必须要有足够的强力经线。我想你可以在这里处理两个挑战:

  • 没有足够的线程/块(你的占用率可能很低) 意味着硬件将无法选择准备处理的warp而另一个warp正在从全局加载值(即使因为你的内核使用了太多的资源来启动它也可能发生,所以只有少数可以由处理器来处理曾经,或者因为你刚刚推出一些);
  • 并行处理是不够的,所以即使你有一个很好的访问模式,但你的内核有很多"顺序"处理或执行依赖,甚至大量的同步,因此warp将停止,直到值被完全处理,并且因为所有的warp都被停止,因此即使需要执行大量处理,你也可能表现不佳;

很难说你有哪一个,但有些实验可以帮到你。 Achieved OccupancyInstruction StatisticsBranch StatisticsIssue Efficiency应该可以帮助您查明内核限制。你甚至可以碰到processo pipeline limitation

请注意," local"内存是片外(作为全局内存),但某些硬件允许它在L1中缓存。看起来您甚至可以使用共享内存来改善处理,如example

所以基本上只要你有超过80%的弹性经线,你就不应该有隐藏鲁棒性的问题。