Intel® FPGA SDK for OpenCL™ Pro Edition: 最佳实践实践指南

ID 683521
日期 9/26/2022
Public
文档目录

3.4.4. 循环推测

循环推测是一种优化技术,通过在确定循环是否已经退出之前就允许启动未来的迭代来实现更有效率的循环流水线。请参考以下简单循环的实例:
while (m*m*m < N) {
    m += 1;
}

逻辑上来讲,在确定是否需要启动另一个迭代之前,必须评估迭代的退出条件(m*m*m < N)。这意味着,在没有推测的情况下,循环II不能低于计算退出条件所需要的周期数。被推测的迭代是在完成退出条件计算之前启动的迭代。然而,所有具有副作用的操作,例如存储到存储器,都是由退出条件推测的。换言之,具有副作用的操作仍然等待退出条件的计算完成。当退出条件是阻碍实现较低II的瓶颈时,循环推测就大有益处。在上述显示的循环中,退出条件包含两个无法在单个时钟周期内完成的乘法。但是,循环推测允许该循环实现II=1。

例如,对于具有退出条件Ei的给定迭代i,被推测的迭代次数s是已经启动i之后,但是在评估Ei之前的迭代次数。默认情况下,这个被推测的迭代次数是由编译器基于每个循环确定,并且可以在Loop Analysis报告的每个循环的详细信息中找到。

#pragma speculated_iterations pragma允许您直接控制循环的推测迭代次数。如果退出条件计算成为减低II的瓶颈(如Loop Analysis报告中所示),增加推测迭代的次数可能会提高II(但并不能保证如此,因为可能会有其他瓶颈)。有关#pragma speculated_iterations的详细信息,请参阅Intel FPGA SDK for OpenCL编程指南中的循环推测

推测的迭代会在嵌套循环中引入一些开销,因为直到先前调用的所有推测迭代都完成后才开始循环的新一次调用。在预期会频繁调用具有低延迟的循环体的情况下,(例如,具有短跳变计数的内部循环),使用#pragma speculated_iterations pragma来减少推测迭代的次数。您可以通过将推测的迭代次数乘以循环的II来估算此开销的量。(如Loop Analysis报告中所示)。使用#pragma speculated_iterations pragma可以减少此开销,但请注意,选择太过低的pragma值可能会增加II(因为没有足够的时间评估退出条件)。

请参考如下实例:

kernel void unopt_int_cube_root (global int *dst, int N) {
   int m = 0;
   while (m*m*m < N) {
       m += 1;
   }
   dst[0] = m;
}

kernel void opt_int_cube_root (global int *dst, int N) {
   int m = 0;
   #pragma speculated_iterations 7
   while (m*m*m < N) {
        m += 1;
   }
   dst[0] = m;
}

kernel void unopt2_int_cube_root (global int *dst, int N) {
   int m = 0;
   #pragma speculated_iterations 0
   while (m*m*m < N) {
       m += 1;
   }
   dst[0] = m;
}

该实例中,退出条件具有两个乘法,以及瓶颈阻碍II=1的compare。编译器选择四次迭代导致II=2,因为退出条件需要7个周期(每次乘法都需要三个周期,compare需要一个周期),四次推测迭代乘以2个周期II给出8个周期来涵盖此评估。然后,推测的迭代次数增加到7次,以覆盖7个周期的退出条件计算,使我们能够实现II=1。通过将speculated_iterations pragma设置为0,您可以验证II已增加到7,符合退出条件瓶颈。