• OpenCL-2-OpenCL事件


    原文地址:http://coderdock.com

    本节介绍OpenCL的事件的相关知识。

      由上一节我们已经清楚了宿主机通过命令队列向计算设备传递命令。计算设备计算后返回。但是宿主机需要管理多个计算设备,多个命令队列。那么宿主机是如何管理、调度这些对象的呢。没错,就是事件(event)。

    1.事件定义

      事件是与命令的状态相关联的对象。命令队列中的命令会产生事件,其他命令在执行之前需要等待某个事件。如我们下面条之前需要查看水开了没有,那么水开了就是一个事件。

    根据场景的不同,可以分为内核端事件和宿主机端事件:

    • 内核端事件:主要负责异步执行命令的同步操作(多个处理单元的阶段同步)和全局内核和本地内存的同步。(内核端事件类似于个人自扫门前雪的意味,因为人民内部矛盾内部解决嘛)。
    • 宿主机端事件:完成命令队列之间的同步操作(统筹各个计算设备的操作)。

      同时事件还可以划分为命令事件用户自定义事件

    2.事件分类

    2.1命令事件

      事件在命令之间传递状态信息。命令的状态即事件的值可以取以下:

    • CL_QUEUED:命令已经加入命令队列。
    • CL_SUBMITTED:命令已经有宿主机提交给与所在命令队列相关联的设备。
    • CL_RUNNING:该命令正在执行。
    • CL_COMPLETE:命令已经完成
    • ERROR_CORE:负数,指代不同的错误情况。

      创建事件的方法有很多,最常见的还是命令在状态发生变化时。如下面的命令是将内核加入队列的API,那么就会产生一个CL_QUEUED命令。

    
    cl_int clEnqueueNDRangeKernel(
    cl_command_queue command_queue,
    cl_kernel kernel,
    cl_unit work_dim,
    const size_t* global_work_offset,
    const size_t* global_work_size,
    const size_t* local_work_size,
    cl_uint num_events_in_wait_list,
    const cl_event* event_wait_list,
    cl_event* event
    )
    我们着重关注一下后面三个参数:
    • num_events_in_wait_list:在执行这个命令之前需要等待几个事件。
    • event_wait_list:这是一个列表,里面是要等待的具体事件。
    • event:这个命令相关联的事件,如当前会将其赋值为CL_QUEUED,之后在执行的时候会赋值为CL_RUNNING等等。

    再看一下多个事件之间的联系的一个示例:

    1
    2
    3
    4
    5
    6
    cl_event k_events[2]; //定义两个事件
    clEnqueueNDRangeKernel(command1, .... , 0, NULL, &k_events[0]); //将第一个命令加入队列,会对k_events[0]赋值,指向之前不需要等待任何事件
    clEnqueueNDRangeKernel(command2, ...., 0, NULL, &k_events[0]); //同上
    clEnqueueNDRangeKernel(command3, ...., 2,&k_events, NULL) //执行这条命令时会等待前面的两个命令

    2.2用户自定义事件

      命令事件主要在命令队列中产生,影响同一个上下文的设备。如果我们需要与其他上下文进行同步,就需要使用到用户自定义事件:

    1
    2
    3
    4
    cl_event clCreateUserEvent(
    cl_context context, //指定上下文
    cl_uint* errcode_ret //该函数所关联的错误值
    )

    如果创建成功,errcode_ret会被赋值为CL_SUCCESS或者错误时,赋值为一下的值:

    • CL_INVALID_EVENT:上下文不合法
    • CL_OUT_OF_RESOURCE: 资源未就绪或分配资源失败
    • CL_OUT_OF_HOST_MEMORY:宿主机资源未就绪或分配资源失败

    之后我们就可以在各个处理函数中设置返回的事件的值:

    1
    2
    3
    4
    cl_int clSetUserEventStatus(
    cl_event event, //具体事件值
    cl_int execution_status //指向状态
    )

    3.事件管理

      上面已经说过了用户自定义事件的设置,那么命令事件的管理又是通过那些API的呢?

    1
    2
    3
    clGetEventStatus
    clRetainEvent //增加引用计数,即得到事件
    cl_ReleaseEvent //减少引用计数

    当然如果需要获取事件的更详细的信息,需要用到:

    1
    2
    3
    4
    5
    6
    7
    cl_int clGetEventInfo(
    cl_event event, //具体事件
    cl_event_info param_name, //查询的信息,如命令队列,或者上下文
    size_t param_value_size, //参数大小,
    void* param_value, //指向的结果的指针
    size_t param_value_size_ret //返回结果的大小
    )

    4.事件回调

      事件是OpenCL中为命令指定明确顺序约束的机制。不过事件不能跨上下文,跨上下文边界时,只有一种选择,就是让宿主机帮忙等待一个事件,然后使用用户事件触发另一个上下文命令的执行。总而言之,由于事件不能跨上下文,所以宿主机必须代表两个命令队列在两个上下文之间管理事件。

      同时,事件还可以使用OpenCL定义的回调机制与宿主机上的函数进行交互。回调就是应用程序异步调用的函数。

    我们可以使用下面这个函数设置回调:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    cl_int clSetEventCallback(
    cl_event event,
    cl_int command_exec_callback_type,
    void(CL_CALLBACK *pfn_event_notify)(
    cl_event event,
    cl_int event_command_exec_status,
    void *user_data),
    void *user_data
    )

    注意事项:

    • 撤销一个事件之前,与这个事件所关联的所有回调函数必须撤销,
    • 回调函数不能是代价高昂的的处理函数,或者调用OpenCL的API来创建上下文或命令队列,或者调用阻塞函数。
    • 为一个事件状态注册的多个回调函数,但不能保证按照注册的顺序执行。
    • 回调函数应保证是线程安全的,会被异步调用。

    5.内核事件

      上面的命令、事件都是要与命令队列相关联。可以同步命令,有助于命令与宿主机之间的交互提供细粒度的控制。

      那么内核中是否有相同的机制呢?其实事件还可以出现在内核内部,内核中的事件主要用来支持在全局与局部内存之间的异步数据复制。下面这些函数用以支持这些功能。

    1
    2
    3
    event_t async_work_group_copy()
    event_t async_work_group_strided_copy
    event_t wait_group_events

    会在后面的章节有所介绍。

  • 相关阅读:
    c语言命名规则 [转载]
    [转贴]C编译过程概述
    [转贴]漫谈C语言及如何学习C语言
    Semaphore源码分析
    如何快速转行大数据
    web前端到底怎么学?
    Code Review怎样做好
    SDK与API的理解
    分析消费者大数据
    程序员的搞笑段子
  • 原文地址:https://www.cnblogs.com/charleechan/p/12500570.html
Copyright © 2020-2023  润新知