Intel® FPGA SDK for OpenCL™ Pro Edition: 最佳实践实践指南

ID 683521
日期 9/26/2022
Public
文档目录

8.7. 静态存储器合并

静态存储器合并是一种 Intel® FPGA SDK for OpenCL™ Offline Compiler优化步骤,它尝试减少内核访问非专用(non-private)存储器的次数。

下图显示了内核性能可能受益于静态存储器合并的常见情况:

图 87. 静态存储器合并


请参考如下矢量化内核:

__attribute__((num_simd_work_items(4)))
__attribute__((reqd_work_group_size(64,1,1)))
__kernel void sum (__global const float * restrict a,
                   __global const float * restrict b,
                   __global float * restrict answer)
{
   size_t gid = get_global_id(0);

   answer[gid] = a[gid] + b[gid];
}

OpenCL™内核执行四次加载操作,访问存储器中的连续位置。而离线编译器将四次加载合并成单个更宽的矢量加载,所以并非是执行四次存储器访问导致位置争用。该优化减少了多存储器系统的访问次数,并可能导向更好的存储器访问模式。

尽管离线编译器在矢量化内核时会自动执行静态存储器合并,但您应该尽可能使用较宽的矢量加载并存储在您的OpenCL代码中,以确保高效的存储器访问。要手动实现静态存储器合并,您必须以编译时识别顺序访问模式的这种方式编写代码。上图中显示的原始内核代码可以受益于静态存储器合并,因为缓冲区ab中的所有索引都随着编译时已知的偏移量递增。相反,以下代码不允许静态存储器合并发生:

__kernel void test (__global float * restrict a,
		          __global float * restrict b,
                    __global float * restrict answer;
		          __global int * restrict offsets)
{
 size_t gid = get_global_id(0);

 answer[gid*4 + 0] = a[gid*4 + 0 + offsets[gid]] + b[gid*4 + 0];
 answer[gid*4 + 1] = a[gid*4 + 1 + offsets[gid]] + b[gid*4 + 1];
 answer[gid*4 + 2] = a[gid*4 + 2 + offsets[gid]] + b[gid*4 + 2];
 answer[gid*4 + 3] = a[gid*4 + 3 + offsets[gid]] + b[gid*4 + 3];
}

offsets[gid]在编译时是未知的。因此,离线编译器无法静态合并对缓冲区a的访问。