命令队列
命令队列就是主机和计算设备之间的交互方式,以 GPU 作为计算设备为例,命令队列就是主机提交给GPU的计算类型的任务
命令队列中操作可能包含主机和设备间,设备间的数据拷贝,内核执行等,命令提交到命令队列,命令队列把需要执行的命令发送给设备
注意每个命令队列只能关联一个设备,如果要同时使用多个设备,则需要创建多个命令队列,每个命令队列关联到一个设备

命令队列中的命令,只能是主机发送给设备,而设备不能发送命令给主机,默认情况下命令队列顺序处理接收到的命令,但是在创建命令队列时可以修改默认行为
命令队列创建
opencl 使用 clCreateCommandQueueWithProperties 创建命令队列
extern CL_API_ENTRY cl_command_queue CL_API_CALL
clCreateCommandQueueWithProperties(cl_context /* context */,
cl_device_id /* device */,
const cl_queue_properties * /* properties */,
cl_int * /* errcode_ret */);
返回值为cl_command_queue, 这里比较复杂的参数是 cl_queue_properties,指定了命令队列的属性及其对应的值,每个属性名称后面紧紧跟着对应的值,列表是以0结尾,properties 属性名称及其对应描述如下表所示:

设置 CL_QUEUR_PROFILING_ENABLE,可以接收命令队列中命令被处理的时间事件,通过这个开发人员可以分析程序性能参数
默认情况下,命令队列里的命令遵循先进先出(FIFO)的原则,设置 CL_QUEUE_OUT_OF_OERDER_EXEC_MADE_ENABLE,计算设备将乱序执行内核,比如设备将会在前一个内核执行命令完成之前执行其他内核,对于数据有前后依赖的两个内核来说,这就需要同步,可以使用时间进行同步
在 OpenCL 2.0 中,允许设备向命令队列提交命令,这个过程不需要主机参与,这样的命令队列,需要设置为 CL_QUEUE_ON_DEVICE|CL_QUEUE_ON_DEVICE_DEFAULT
下面是创建命令队列的代码:
cl_command_queue queue = clCreateCommandQueue(context, device_id, 0, &err);
CHECK(CL_SUCCESS == err);
CHECK(NULL != queue);
printf("[%s] Created Command queue attached to selected device \n", __FUNCTION__);
查询命令队列
对于已经创建的命令队列 可以通过下列函数查询命令队列各个属性信息
extern CL_API_ENTRY cl_int CL_API_CALL
clGetCommandQueueInfo(cl_command_queue /* command_queue */,
cl_command_queue_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
参数 param_name 为查询的属性名称,取值见下表,参数 param_value 返回命令队列的查询属性信息:
cl_command_queue_info | 返回类型 | 描述 |
|---|---|---|
CL_QUEUE_CONTEXT | cl_context | 返回命令队列创建时指定的上下文 |
CL_QUEUE_DEVICE | cl_device_id | 返回命令队列创建时指定的设备 |
CL_QUEUE_PREFERENCE_COUNT | cl_uint | 返回命令队列的引用计数 |
CL_QUEUE_PROFILES | cl_command_queue_properties | 返回命令队列当前指定的属性 |
CL_QUEUE_SIZE | cl_uint | 返回命令队列当前指定大小,该查询值支持设备命令队列 |
参考代码如下:
void demonstrate_clGetCommandQueueInfo(cl_command_queue command_queue) {
cl_int err;
cl_command_queue_properties properties;
cl_device_id device;
cl_context context;
cl_uint ref_count;
size_t size_ret;
printf("========== clGetCommandQueueInfo 演示 ==========\n");
// 1. 获取命令队列属性 (CL_QUEUE_PROPERTIES)
err = clGetCommandQueueInfo(command_queue, CL_QUEUE_PROPERTIES,
sizeof(properties), &properties, NULL);
if (err == CL_SUCCESS) {
printf("CL_QUEUE_PROPERTIES: 0x%llx\n", (unsigned long long)properties);
printf(" - Out-of-order execution: %s\n",
(properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) ? "Enabled" : "Disabled");
printf(" - Profiling: %s\n",
(properties & CL_QUEUE_PROFILING_ENABLE) ? "Enabled" : "Disabled");
}
// 2. 获取命令队列关联的设备 (CL_QUEUE_DEVICE)
err = clGetCommandQueueInfo(command_queue, CL_QUEUE_DEVICE,
sizeof(device), &device, NULL);
if (err == CL_SUCCESS) {
char device_name[128];
clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name), device_name, NULL);
printf("CL_QUEUE_DEVICE: %s\n", device_name);
}
// 3. 获取命令队列关联的上下文 (CL_QUEUE_CONTEXT)
err = clGetCommandQueueInfo(command_queue, CL_QUEUE_CONTEXT,
sizeof(context), &context, NULL);
if (err == CL_SUCCESS) {
printf("CL_QUEUE_CONTEXT: Successfully retrieved context\n");
}
// 4. 获取命令队列引用计数 (CL_QUEUE_REFERENCE_COUNT)
err = clGetCommandQueueInfo(command_queue, CL_QUEUE_REFERENCE_COUNT,
sizeof(ref_count), &ref_count, NULL);
if (err == CL_SUCCESS) {
printf("CL_QUEUE_REFERENCE_COUNT: %u\n", ref_count);
}
// 5. 获取命令队列大小 (CL_QUEUE_SIZE) - OpenCL 1.2+
#ifdef CL_VERSION_1_2
err = clGetCommandQueueInfo(command_queue, CL_QUEUE_SIZE,
sizeof(ref_count), &ref_count, &size_ret);
if (err == CL_SUCCESS) {
printf("CL_QUEUE_SIZE: %u (最大命令队列中的命令数)\n", ref_count);
}
#endif
printf("\n");
}
/*
========== clGetCommandQueueInfo 演示 ==========
CL_QUEUE_PROPERTIES: 0x0
- Out-of-order execution: Disabled
- Profiling: Disabled
CL_QUEUE_DEVICE: gfx902
CL_QUEUE_CONTEXT: Successfully retrieved context
CL_QUEUE_REFERENCE_COUNT: 1
*/
5569

被折叠的 条评论
为什么被折叠?



