嵌套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];
}
}
这个例子中,loop1
、loop1_1
、loop2
都能很好的pipeline。
内层循环
蓝色框表示内层循环体loop1_1
;L表示Latency
;一个粉色块表示一次迭代;这里启动了四次迭代(size=4)。
可以看到,第0次迭代已经要输出结果了,而第3次迭代则刚刚启动,第2和第1次迭代处于中间态。如果size大于4,那么,到下一个cycle时,1将输出,4将进入,而3和2将变成中间态。
pipeline-21
嵌套循环
把loop1
和loop1_1
一起考虑,执行过程如下图所示:
pipeline-32
可以看到,内层循环pipeline中间没有任何气泡,外层循环其实是在可以做插入的地方做内插,只要内层循环II为1且没有气泡,外层循环即使II值不恒为1,也能保证稳定态时每个时钟周期输出一个结果。
但当 Trip_count_inner_loop * II_inner_loop < II_outer_loop
时,就不能不考虑外层循环的II
了。
现在,我们来算一下执行loop1
和loop1_1
的总时钟周期数:
k_size * (size * II_inner_loop) Latency_inner_loop Latency_outer_loop
要注意的是,嵌套循环中内层循环是critical loop
,我们要首先保证的就是内层循环的性能,但当遇到下面这种情况时,哪个才是critical loop
呢?
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_1
和loop2
,只能串行执行,等一个结束后下一个才开始。
pipeline-33
如果一个for循环内部嵌套着两个并列的for循环:
代码语言:javascript复制kernel void test(){
while(i<N){
...
for(j=0; j<M; j ){
...
}
for(j=0; j<P; j ){
...
}
}
}
首先要根据N
和P
的大小来确定哪个是critical loop
,内层两个循环串行执行,外层循环在可以做内插的地方做内插。
pipeline-34
参考
Intel FPGA SDK for OpenCL Best Practices Guide