仅对英特尔可见 — GUID: sfz1565797370740
Ixiasoft
仅对英特尔可见 — GUID: sfz1565797370740
Ixiasoft
6.8. 循环交叉存取控制(max_interleaving预处理指令)
- 术语提示
- 循环迭代是循环体的单次执行。循环调用是循环迭代流水线化执行的开始。
交叉存取实例 2
// Loop j is pipelined with ii=1 for (int j = 0; j < M; j++) { int a[N]; // Loop i is pipelined with ii=2 for (int i = 1; i < N; i++) { a[i] = foo(i) } }
本实例中,内循环i被流水线化,且II=2。在正常流水线式情况下,这个II意味着内环硬件只能实现50%的利用率,因为i循环每隔一个周期启动一次。为了利用这些空闲周期,编译器会将i循环的二次调用与外层j循环的下一次迭代交错进行。
因为i循环居于j循环内,并且j循环的行程计数为M, 表示i循环被invoked(调用)M次。j循环是最外层循环,仅被调用一次。
下表显示了i循环的正常流水线执行与N=5的交错式执行实例之间的差异。
周期 | 流水线化循环迭代 (j循环,i循环) |
交错循环迭代 (j循环,i循环) |
---|---|---|
0 | (0,0) | (0,0) |
1 | --- | (1,0) |
2 | (0,1) | (0,1) |
3 | --- | (1,1) |
4 | (0,2) | (0,2) |
5 | --- | (1,2) |
6 | (0,3) | (0,3) |
7 | --- | (1,3) |
8 | (0,4) | (0,4) |
9 | --- | (1,4) |
10 | (1,0) | (2,0) |
11 | --- | (3,0) |
12 | (1,1) | (2,1) |
13 | --- | (3,1) |
14 | (1,2) | (2,2) |
15 | --- | (3,2) |
16 | (1,3) | (2,3) |
17 | --- | (3,3) |
18 | (1,4) | (2,4) |
19 | --- | (3,4) |
下表显示为每个周期被启动的每个内循环迭代的值(j,i)。在周期 0 处,两种执行模式都启动i循环的第(0,0)次迭代。正常流水线化执行下,周期1处无i循环迭代被启动。在交错式执行下,最内层循环的第 (1,0) 次迭代,即i循环的下一个 (j=1) 调用的第一次迭代被启动。到周期10时,交错式执行已启动i循环j=0调用,和i循环j=1调用的所有迭代。这就代表它是正常流水线化执行效率的两倍。
有时您可能会发现,相对于启用交错存取所需要的额外FPGA面积而言,进行这种交错存取不会带来性能优势。在这些情况下,您可以限制或约束交错量以减少FPGA面积利用率。
使用max_interleaving指令
要限制内循环中可以同时执行交错存取式调用的次数,请使用max_interleaving指令批注该内循环。被注释的循环必须包含在另一个流水线循环内。
需要的参数(n)指定允许交错的程度上限,即,在给定时间内,对所包含循环的调用能执行多少次被注释的循环。
- #pragma max_interleaving 1
编译器限制注释的(内部)循环在每个外部循环迭代中仅被调用一次。也就是说,内部循环的所有迭代都经过管道后才能调用下一次内部循环。
- #pragma max_interleaving 0
编译器允许流水线包含的内部循环同步调用的次数,与内循环的循环启动间隔 (II) 相等。例如,II为2的内循环可以同时在管道中进行两次调用的迭代。
如果您没有指定max_interleaving指令,则该行为会是编译器的默认行为。
// Loop j is pipelined with ii=1 for (int j = 0; j < M; j++) { int a[N]; // Loop i is pipelined with ii=2 #pragma max_interleaving 1 for (int i = 1; i < N; i++) { a[i] = foo(i) } … }
<quartus_installdir>/hls/examples/tutorials/loop_controls/max_interleaving