OpenCL-2-OpenCL事件

本節介紹OpenCL的事件的相關知識。
  由上一節咱們已經清楚了宿主機經過命令隊列向計算設備傳遞命令。計算設備計算後返回。可是宿主機須要管理多個計算設備,多個命令隊列。那麼宿主機是如何管理、調度這些對象的呢。沒錯,就是事件(event)。安全

1.事件定義

  事件是與命令的狀態相關聯的對象。命令隊列中的命令會產生事件,其餘命令在執行以前須要等待某個事件。如咱們下面條以前須要查看水開了沒有,那麼水開了就是一個事件。異步

根據場景的不一樣,能夠分爲內核端事件和宿主機端事件:async

  • 內核端事件:主要負責異步執行命令的同步操做(多個處理單元的階段同步)和全局內核和本地內存的同步。(內核端事件相似於我的自掃門前雪的意味,由於人民內部矛盾內部解決嘛)。
  • 宿主機端事件:完成命令隊列之間的同步操做(統籌各個計算設備的操做)。

  同時事件還能夠劃分爲命令事件用戶自定義事件ide

2.事件分類

2.1命令事件

  事件在命令之間傳遞狀態信息。命令的狀態即事件的值能夠取如下:函數

  • CL_QUEUED:命令已經加入命令隊列。
  • CL_SUBMITTED:命令已經有宿主機提交給與所在命令隊列相關聯的設備。
  • CL_RUNNING:該命令正在執行。
  • CL_COMPLETE:命令已經完成
  • ERROR_CORE:負數,指代不一樣的錯誤狀況。

  建立事件的方法有不少,最多見的仍是命令在狀態發生變化時。以下面的命令是將內核加入隊列的API,那麼就會產生一個CL_QUEUED命令。ui

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等等。

再看一下多個事件之間的聯繫的一個示例:指針

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用戶自定義事件

  命令事件主要在命令隊列中產生,影響同一個上下文的設備。若是咱們須要與其餘上下文進行同步,就須要使用到用戶自定義事件:code

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:宿主機資源未就緒或分配資源失敗

以後咱們就能夠在各個處理函數中設置返回的事件的值:

cl_int clSetUserEventStatus(
  cl_event event,       //具體事件值
  cl_int execution_status //指向狀態
  )

3.事件管理

  上面已經說過了用戶自定義事件的設置,那麼命令事件的管理又是經過那些API的呢?

clGetEventStatus
clRetainEvent       //增長引用計數,即獲得事件
cl_ReleaseEvent     //減小引用計數

固然若是須要獲取事件的更詳細的信息,須要用到:

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定義的回調機制與宿主機上的函數進行交互。回調就是應用程序異步調用的函數。

咱們可使用下面這個函數設置回調:

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.內核事件

  上面的命令、事件都是要與命令隊列相關聯。能夠同步命令,有助於命令與宿主機之間的交互提供細粒度的控制。

  那麼內核中是否有相同的機制呢?其實事件還能夠出如今內核內部,內核中的事件主要用來支持在全局與局部內存之間的異步數據複製。下面這些函數用以支持這些功能。

event_t async_work_group_copy()
event_t async_work_group_strided_copy
event_t wait_group_events

會在後面的章節有所介紹。

版權聲明:本文爲博主原創文章,轉載需聲明爲轉載內容並添加原文地址。

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

相關文章
相關標籤/搜索