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

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

發佈了11 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章