工作组
在 OpenCL 中,工作区大小、工作组大小和工作项的大小是通过调用 OpenCL API 函数(如 clEnqueueNDRangeKernel)来设置的。这些参数决定了并行计算的分布和调度方式,因此正确设置它们对性能优化至关重要。
三种概念:工作区大小、工作组大小、工作项大小¶
- 工作区大小(Global Work Size, 全局工作区)
- 全局工作区表示所有工作项的总数,是整个计算任务的规模。
- 它通常是一个多维数组,指定了每个维度上的工作项总数。
-
例如,如果全局工作区大小是
(16, 16),表示有 256 个工作项。 -
工作组大小(Local Work Size, 局部工作区)
- 每个工作组中包含的工作项数量。
- 工作组是 OpenCL 中的基本调度单元,所有工作项在一个工作组内共享局部内存。
-
工作组大小通常是全局工作区大小的一个因数(即可以整除全局工作区)。
-
工作项(Work Item)
- 工作项是 OpenCL 中的最小计算单元,代表一段内核代码的运行实例。
- 每个工作项由全局 ID 标识(通过
get_global_id()获取),并且在其所在的工作组内也有局部 ID(通过get_local_id()获取)。
设置工作区大小和工作组大小¶
1. 使用 API clEnqueueNDRangeKernel 设置¶
在 OpenCL 中,通过 clEnqueueNDRangeKernel 来设置全局工作区大小和局部工作区大小。函数的原型如下:
C
cl_int clEnqueueNDRangeKernel(
cl_command_queue command_queue, // 命令队列
cl_kernel kernel, // 内核对象
cl_uint work_dim, // 工作区的维度(1D, 2D, 3D)
const size_t *global_work_offset,// 全局偏移量(通常为 NULL)
const size_t *global_work_size, // 全局工作区大小
const size_t *local_work_size, // 局部工作区大小(可为 NULL,表示由 OpenCL 自动决定)
cl_uint num_events_in_wait_list, // 等待的事件数
const cl_event *event_wait_list, // 等待事件列表
cl_event *event // 输出事件
);
2. 参数说明¶
work_dim:指定工作区的维度(1D、2D 或 3D),例如 1 表示 1D,2 表示 2D。global_work_offset:全局偏移量,通常为NULL,表示从全局坐标(0, 0, 0)开始计算。global_work_size:全局工作区大小,指定每个维度的工作项总数。local_work_size:局部工作区大小,指定每个维度的工作组大小。如果为NULL,OpenCL 运行时会选择合适的大小。
设置示例¶
1. 一维工作区¶
C
size_t global_work_size = 1024; // 全局工作区大小为 1024 个工作项
size_t local_work_size = 64; // 每个工作组包含 64 个工作项
clEnqueueNDRangeKernel(
command_queue, kernel, 1, NULL,
&global_work_size, &local_work_size,
0, NULL, NULL
);
- 全局工作区有 1024 个工作项。
- 每个工作组有 64 个工作项,因此会生成
1024 / 64 = 16个工作组。
2. 二维工作区¶
C
size_t global_work_size[2] = {16, 16}; // 全局工作区大小为 16x16
size_t local_work_size[2] = {4, 4}; // 每个工作组大小为 4x4
clEnqueueNDRangeKernel(
command_queue, kernel, 2, NULL,
global_work_size, local_work_size,
0, NULL, NULL
);
- 全局工作区有
16x16 = 256个工作项。 - 每个工作组有
4x4 = 16个工作项,总共会生成256 / 16 = 16个工作组。
3. 自动分配工作组大小¶
如果不指定工作组大小(将 local_work_size 设置为 NULL),OpenCL 会自动选择一个合适的工作组大小:
C
size_t global_work_size[2] = {16, 16}; // 全局工作区大小为 16x16
clEnqueueNDRangeKernel(
command_queue, kernel, 2, NULL,
global_work_size, NULL,
0, NULL, NULL
);
- OpenCL 会自动决定工作组大小,但这可能不是最优的选择。
注意事项¶
- 全局工作区大小必须是工作组大小的倍数
- 如果
global_work_size不是local_work_size的整数倍,OpenCL 会报错。 -
解决方法是调整全局工作区大小,或在内核代码中处理越界问题。
-
工作组大小的限制
- 每个设备对工作组大小有硬件限制,可以通过
clGetDeviceInfo获取: -
如果工作组大小超过设备限制,程序会报错。
-
选择合适的工作组大小
- 工作组大小应尽量与硬件的计算单元(如 GPU 的线程块)对齐,以优化性能。
-
通常选择 32、64、128 或 256 这样的值,具体取决于设备架构。
-
使用对齐的全局工作区大小
- 全局工作区大小通常设置为工作组大小的整数倍,以避免处理边界条件。
总结¶
- 全局工作区大小:决定总共需要多少个工作项来完成计算。
- 局部工作区大小:决定每个工作组中包含多少个工作项。
- 设置方法:通过
clEnqueueNDRangeKernel指定global_work_size和local_work_size。 - 优化建议:根据硬件架构选择合适的工作组大小(通常是 32、64、128 等倍数)。