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

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

7.1. 指定最大工作组大小或者需要的工作组大小

尽可能为内核指定max_work_group_size或者reqd_work_group_size属性。这些属性使得 Intel® FPGA SDK for OpenCL™ Offline Compiler执行更积极的优化来以使内核与硬件资源相匹配,而无需任何多余的逻辑。
提示: 对于oneAPI DPC++的具体细节,请参阅 Intel® oneAPI Toolkits的FPGA优化指南中的指定工作组大小主题。

离线编译器根据编译时间和运行时施加的某些约束,假定您内核的默认工作组大小。

离线编译器在编译时施加以下约束:

  • 如果您为reqd_work_group_size属性指定了一个值,那么该工作组必须与该值匹配。
  • 如果您为max_work_group_size属性指定了一个值,那么工作组的大小不得超过该值。
  • 如果您未指定reqd_work_group_sizemax_work_group_size的值,并且内核包含barrier,那么离线编译器默认最大工作组大小为256个work-item。
  • 如果您没有指定这两个属性的值并且内核不包含任何barrier,那么离线编译器不会在编译时施加任何约束。
提示:clGetKernelWorkGroupInfo API调用使用CL_KERNEL_WORK_GROUP_SIZECL_KERNEL_COMPILE_WORK_GROUP_SIZE查询来确定离线编译器在编译时对特定内核施加的工作组大小约束。

OpenCL™标准在运行时施加以下约束:

  • 每个维度中的工作组大小必须平均划分成每个维度中请求的NDRange大小。
  • 工作组大小不得超出对clGetDeviceInfo API调用使用的CL_DEVICE_MAX_WORK_GROUP_SIZECL_DEVICE_MAX_WORK_ITEM_SIZES查询所指定的器件约束。
警告:
如果您为请求的NDRange内核执行指定的工作组大小不能满足上述所有约束,clEnqueueNDRangeKernel API调用失败并出现错误CL_INVALID_WORK_GROUP_SIZE

如果您未指定reqd_work_group_sizemax_work_group_size属性的值,运行时会按如下方式确定默认工作组的大小:

  • 如果内核包含barrier或者引用局部work-item ID,又或者如果您在主机代码中使用clGetKernelWorkGroupInfoclGetDeviceInfo API调用来查询工作组大小,运行时(runtime)默认工作组的大小为1个work-item。
  • 如果内核中不包含barrier或者未引用局部work-item ID,又或者如果您的主机代码没有查询工作组大小,默认工作组大小就是全局NDRange大小。

排队NDRange内核(即,不是单个工作组)时,如下条件下需要指定明确的工作组大小:

  • 如果您的内核使用存储器barrier、局部存储器或者局部work-item ID。
  • 如果您的主机程序查询工作组大小。

如果您的内核使用存储器barriers,请执行以下任务之一来最小化硬件资源:

  • reqd_work_group_size属性指定一个值。
  • 将适合您所有运行时工作组请求的最小工作组大小分配给max_work_group_size属性。
警告:
在您的NDRange内核的末端包含的存储器barrier导致编译失败。

指定一个小于运行时(runtime)默认工作组的工作组可能会导致过多的硬件消耗。因此,如果您需要不同于默认工作组的工作组大小,请指定max_work_group_size属性设置一个最大工作组大小。如果工作组大小在所有内核调用中保持不变,请通过包含reqd_work_group_size属性来指定需要的工作组大小。 reqd_work_group_size属性指示离线编译器准确分配正确数量的硬件来管理您指定的每个工作组的work-item。该分配可以节省硬件资源并提高内核计算单元的执行效率。通过指定reqd_work_group_size属性,您还可以防止离线编译器实现其它硬件支持未知大小的工作组。

例如,如下代码片段将64个work-item的固定工作组大小分配给内核:

__attribute__((reqd_work_group_size(64,1,1)))
__kernel void sum (__global const float * restrict a,
                   __global const float * restrict b,
                   __global float * restrict answer)
{
  size_t gid = get_global_id(0);

  answer[gid] = a[gid] + b[gid];
}