OpenCL优化方法-Single Work-Item Kernel的良好设计实践
Single Work-Item Kernel的良好设计实践
如果您的OpenCL内核包含循环结构,请遵循英特尔推荐的指导方针,以允许OpenCL Offline Compiler的Intel FPGA SDK可以针对内核进行有效分析。指导离线编译器在循环中执行流水线并行执行时,结构良好的循环尤其重要。

1、避免指针别名混淆使用
在指针参数中尽可能插入restrict关键字。在指针参数中包含restrict关键字可防止离线编译器在非冲突读写操作之间创建不必要的内存依赖关系。考虑一个循环,其中每次迭代从一个数组读取数据,然后将数据写入同一物理内存中的另一个数组。在这些指针参数中没有包含restrict关键字时,离线编译器可能会假定两个数组之间存在依赖关系,从而提取较少的流水线并行性。

2、构建“良好格式”的循环
“良好格式”的循环具有限制与整数相比较的退出条件,并且每次迭代具有一个简单的归纳增量。在内核中运用“良好格式”的循环可以提高性能,因为离线编译器可以有效地分析这些循环。
以下是“良好格式”的循环示例:
for(i=0; i < N; i++)
{
//statements
}
Important:“良好格式”的嵌套循环也有助于最大化内核性能。
以下是“良好格式”的嵌套循环结构示例:
for(i=0; i < N; i++)
{
//statements
for(j=0; j < M; j++)
{
//statements
}
}

3、Minimize Loop-Carried Dependencies(最大限度地减少环路依赖)
下面的循环结构创建一个循环依赖结构,因为每个循环迭代读取由上一次迭代写入的数据。导致的结果就是:每次读取操作都不能继续进行,直到前一次迭代的写操作完成。循环依赖关系的存在降低了离线编译器可以实现的流水线并行性的程度,从而降低了内核性能。
for(int i = 0; i < N; i++)
{
A[i] = A[i - 1] + i;
}
离线编译器对循环执行静态内存依赖性分析,以确定其可以实现的并行性程度。在某些情况下,离线编译器可能会假定两个数组访问之间存在依赖关系,从而提取较少的流水线并行性。如果离线编译器由于未知变量而无法解析编译时的依赖关系,或者数组访问涉及复杂寻址,则会假定循环依赖。
为了尽量减少循环携带的依赖关系,请尽可能遵循以下准则:
  • 避免指针算术。
当内核通过解引用从算术运算导出的指针值来访问数组时,编译器输出次最优方案。
例如,避免以下列方式访问数组:
for(int i = 0; i < N; i++)
{
int t = *(A++);
*A = t;
}
  • 使用简单的数组索引。
避免使用以下复杂类型的数组索引,因为离线编译器无法有效地分析它们,这可能会导致次最优的编译器输出:
-数组索引为非常数变量。
例如,A [K + i],其中i是循环索引变量,K是未知变量。
-多个索引变量在相同的下标位置。
例如,A [i + 2×j],其中i和j是双重嵌套循环的循环索引变量。注意:离线编译器可以有效地分析数组索引A [i] [j],因为索引变量在不同的下标位置。
-非线性索引
例如,A [i&C],其中i是循环索引变量,C是常数或非常数变量。
  • 尽可能在内核中使用具有常量边界的循环。
具有常量边界的循环允许离线编译器有效地执行范围分析。

4、Avoid Complex Loop Exit Conditions(避免复杂的循环退出条件)
离线编译器评估循环退出条件以确定后续循环迭代是否可以进入循环流水线(pipeline)。有时离线编译器需要通过内存访问或复杂操作来评估退出条件。在这些情况下,随后的迭代将不会启动,直到评估完成,会导致整体循环性能的降低。

5、Convert Nested Loops into a Single Loop(将嵌套循环转换为单个循环)
为了最大限度地提高性能,尽可能将嵌套循环合并成单个循环的形式。将嵌套循环重组为单个循环会减少循环迭代之间的硬件占用空间和计算开销。
The following code examples illustrate the conversion of a nested loop into a single loop:
Nested Loop Converted Single Loop
for (i = 0; i < N; i++)                                              {                                                                                //statements                                                          for (j = 0; j < M; j++)                                              {                                                                                  //statements                                                    }                                                                            //statements                                                     } for (i = 0; i < N*M; i++)                                            {                                                                                 //statements                                                    }
6、Declare Variables in the Deepest Scope Possible;(尽可能的在最深的嵌套内声明变量)
(a[N]、b[N]占用资源不同,资源占用情况:a>b)
为了减少实现变量所需的硬件资源,请在循环中使用该变量之前声明该变量。在最深的范围内声明变量可能会最小化数据依赖性和硬件使用率,因为离线编译器(the offline compiler)不需要跨不使用变量的循环保留变量数据。
Consider the following example:
int a[N];
for (int i = 0; i < m; ++i)
{
int b[N];
for (int j = 0; j < n; ++j)
{
// statements
}
}
数组a需要比数组b更多的资源来实现。 为了减少使用的硬件资源,尽可能地将数组声明在内部循环之内,除非需要通过外部循环的迭代维护数据时才将数组声明在内部循环之外。在最深的范围内覆盖变量的所有值也可以减少呈现变量所需的资源。
阅读更多
文章标签: opencl FPGA
个人分类: OpenCL
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

OpenCL优化方法-Single Work-Item Kernel的良好设计实践

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭