ZHCU881D May 2020 – May 2024
在进行软件流水线的某些情况下,编译器无法重叠循环的连续迭代以获得最佳性能。当编译器不能重叠循环的连续迭代时,性能则会受到影响:启动间隔(前述所述 ii
)将大于预期间隔,并且同时使用的功能单元也很少。
几乎所有的情况下,这都是由于循环携带依赖造成的。循环携带依赖在一定程度上阻止了迭代 i+1
的执行与迭代 i
重叠。循环携带依赖限制 是软件流水线循环启动间隔的下限(因此也限制了软件流水线循环速度)。由于循环中的一组指令集存在排序约束(依赖性)周期,所以会出现循环携带依赖限制。在循环中的所有这些周期长度中,最大的循环携带依赖周期就是循环携带依赖限制。即使有大量的可用功能单元并行执行若干迭代,也会发生这种情况。
如果循环携带依赖限制大于分区资源限制,则循环携带依赖之一会减慢循环,因为启动间隔始终至少是分区资源限制和循环携带依赖限制中的最大者。
为了减少或消除有问题的循环携带依赖,必须确定周期,然后找到一种方法以缩短或打破该周期。
以下示例显示了循环携带依赖有问题的循环。
void weighted_sum(int * a, int * b, int * out,
int weight_a, int weight_b, int n)
{
#pragma UNROLL(1)
#pragma MUST_ITERATE(1024, ,32)
for (int i = 0; i < n; i++)
{
out[i] = a[i] * weight_a + b[i] * weight_b;
}
}
本例中编译器生成的汇编代码(如下所示)显示了在汇编代码的软件流水线信息部分中,循环携带依赖限制为 7 个周期。
;*----------------------------------------------------------------------------*
;* SOFTWARE PIPELINE INFORMATION
;*
;* Loop found in file : weighted_vector_sum_v3.cpp
;* Loop source line : 10
;* Loop opening brace source line : 11
;* Loop closing brace source line : 13
;* Known Minimum Iteration Count : 1024
;* Known Max Iteration Count Factor : 32
;* Loop Carried Dependency Bound(^) : 12
;* Unpartitioned Resource Bound : 2
;* Partitioned Resource Bound : 2 (pre-sched)
;*
;* Searching for software pipeline schedule at ...
;* ii = 12 Schedule found with 2 iterations in parallel
. . .
;*----------------------------------------------------------------------------*
;* SINGLE SCHEDULED ITERATION
;*
;* ||$C$C51||:
;* 0 TICK ; [A_U]
;* 1 LDW .D2 *D1++(4),BM0 ; [A_D2] |12| ^
;* || LDW .D1 *D2++(4),BM1 ; [A_D1] |12| ^
;* 2 NOP 0x5 ; [A_B]
;* 7 MPYWW .M2 BM2,BM0,BL0 ; [B_M2] |12| ^
;* || MPYWW .N2 BM3,BM1,BL1 ; [B_N2] |12| ^
;* 8 NOP 0x3 ; [A_B]
;* 11 ADDW .L2 BL1,BL0,B0 ; [B_L2] |12| ^
;* 12 STW .D1X B0,*D0++(4) ; [A_D1] |12| ^
;* || BNL .B1 ||$C$C51|| ; [A_B] |10|
;* 13 ; BRANCHCC OCCURS {||$C$C51||} ; [] |10|
;*----------------------------------------------------------------------------*
软件流水线循环的最终软件流水线启动间隔至少是循环携带依赖限制和分区资源限制中的较大者。当循环携带依赖限制值大于分区资源限制值时,表示代码中存在可能需要解决的循环携带依赖限制问题。也就是说,当循环携带依赖限制大于分区资源限制时,如果消除了循环携带依赖限制,软件流水线循环可能会运行得更快。因此,在本例中,由于分区资源限制是 2,循环携带依赖限制是 12,所以此代码中存在应被调查的问题。
为了确定该问题,我们需要查看循环携带依赖中涉及的指令。这些指令在编译器生成的汇编文件的注释块中,以脱字符“^
”标记这些指令。请注意,加载和存储指令是以插入符号标记的。由此可知,编译器认为连续迭代之间可能 存在循环携带依赖的关系。这可能是因为编译器无法证明存储指令正在写入与加载指令所加载的位置无关的存储器区域。在缺少有关指针、数组和地址访问模式的位置信息时,编译器必须假定连续迭代可从前一次迭代的存储位置加载。有关循环携带依赖及其识别方法的更多信息,请参阅手动调优 TMS320C6000 上的循环和控制代码 (SPRA666)。