Intel OpenCL 之 Pipeline(二)For循环的执行机制

2020-07-29 11:09:00 浏览数 (2)

嵌套for循环的pipeline机制

看下面的例子:

代码语言:javascript复制
#define k_size 20
#define size 4

kernel void accum_swg (global int* a
                      ,global int* c)
{
    int sum[1024];

loop1:    for (int k = 0; k < k_size;   k) {
loop1_1:        for (int i = 0; i < size;   i) {

                    int j = k * size   i;
                    sum[k]  = a[j];
                }
          }

loop2:    for (int k = 0; k < k_size;   k) {
               c[k] = sum[k];
          }
}

这个例子中,loop1loop1_1loop2都能很好的pipeline。

内层循环

蓝色框表示内层循环体loop1_1;L表示Latency;一个粉色块表示一次迭代;这里启动了四次迭代(size=4)。

可以看到,第0次迭代已经要输出结果了,而第3次迭代则刚刚启动,第2和第1次迭代处于中间态。如果size大于4,那么,到下一个cycle时,1将输出,4将进入,而3和2将变成中间态。

pipeline-21

嵌套循环

loop1loop1_1一起考虑,执行过程如下图所示:

pipeline-32

可以看到,内层循环pipeline中间没有任何气泡,外层循环其实是在可以做插入的地方做内插,只要内层循环II为1且没有气泡,外层循环即使II值不恒为1,也能保证稳定态时每个时钟周期输出一个结果。

但当 Trip_count_inner_loop * II_inner_loop < II_outer_loop 时,就不能不考虑外层循环的II了。

现在,我们来算一下执行loop1loop1_1的总时钟周期数:

k_size * (size * II_inner_loop) Latency_inner_loop Latency_outer_loop

要注意的是,嵌套循环中内层循环是critical loop,我们要首先保证的就是内层循环的性能,但当遇到下面这种情况时,哪个才是critical loop呢?

代码语言:javascript复制
for(unsigned i=0; i<N; i  ){
  for(unsigned j=0; j<M; j  ){
    ...
  }
  for(unsigned j=0; j<P; j  ){
    ...
  }
}

这时候要比较M和P的大小,大的为 critical loop,而另一个loop的II值可以适当放宽要求(在 P * II_inner_loop_P < M 条件下)。

并列for循环的执行机制

如下图所示,并列的两个for循环如例子中的loop1, loop1_1loop2,只能串行执行,等一个结束后下一个才开始。

pipeline-33

如果一个for循环内部嵌套着两个并列的for循环:

代码语言:javascript复制
kernel void test(){
    while(i<N){
        ...
        for(j=0; j<M; j  ){
            ...
        }
        for(j=0; j<P; j  ){
            ...
        }
    }
}

首先要根据NP的大小来确定哪个是critical loop,内层两个循环串行执行,外层循环在可以做内插的地方做内插

pipeline-34

参考

Intel FPGA SDK for OpenCL Best Practices Guide

0 人点赞