OpenCL 学习(5)---- OpenCL 命令队列

命令队列

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

命令队列中的命令,只能是主机发送给设备,而设备不能发送命令给主机,默认情况下命令队列顺序处理接收到的命令,但是在创建命令队列时可以修改默认行为

命令队列创建

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_CommandQueue

设置 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_CONTEXTcl_context返回命令队列创建时指定的上下文
CL_QUEUE_DEVICEcl_device_id返回命令队列创建时指定的设备
CL_QUEUE_PREFERENCE_COUNTcl_uint返回命令队列的引用计数
CL_QUEUE_PROFILEScl_command_queue_properties返回命令队列当前指定的属性
CL_QUEUE_SIZEcl_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
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值