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

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

4.8. 避免昂贵的函数

有些函数在FPGA中实现起来很昂贵。昂贵的函数可能会降低内核性能或者需要大量硬件来实现。

以下函数很昂贵:

  • 整数除法和模数(余数)操作符
  • 除了加法、乘法、绝对值和比较之外的大多数浮点运算符
    注: 有关优化浮点运算的更多信息,请参阅优化浮点操作小节。
  • 原子函数

相反,廉价的函数对内核性能的影响很小,并且实现它们仅消耗很少的硬件。

以下函数不昂贵:

  • 二进制逻辑操作,例如AND、NAND、OR、NOR、XOR和XNOR
  • 带有一个常数自变量的逻辑运算
  • 按常数移位
  • 整数乘法乘以和除法除以一个常数,该常数是2的幂。

如果昂贵函数对工作组中的每个work-item生成一条新数据,那么在内核中写它的代码就是有益的。相反地,以下代码实例显示了NDRange中每个work-item执行的昂贵浮点运算(除法)的情况:

__kernel void myKernel (__global const float * restrict a,
                        __global float * restrict b,
                        const float c, const float d)
{
   size_t gid = get_global_id(0);
   
   //inefficient since each work-item must calculate c divided by d
   b[gid] = a[gid] * (c / d); 
}

该计算的结果始终相同。为了避免这种冗余以及硬件资源密集型运算,请在主机应用程序中执行该运算,然后将结果作为自变量传递给内核,以供NDRange中所有work-items使用。修改后的代码如下所示:

__kernel void myKernel (__global const float * restrict a,
                        __global float * restrict b,
                        const float c_divided_by_d)
{
   size_t gid = get_global_id(0);

   /*host calculates c divided by d once and passes it into  
   kernel to avoid redundant expensive calculations*/   
   b[gid] = a[gid] * c_divided_by_d;  						
}

Intel® FPGA SDK for OpenCL™ Offline Compiler将整个NDRange中不依赖于work-item的运算合并到单个运算中。然后在所有work-item中共享该结果。在第一个代码实例中,离线编译器创建一个由所有work-item共享的单个除法器(divider)块,因为c除以d在所有work-item中保持不变。这种优化有助于最大限度地减少冗余硬件的数量。然而,整数除法的实现需要大量的硬件资源。因此,将除法运算从主机处理器卸除,然后再将结果作为自变量传递给内核,有益于节省硬件资源。