OpenCL全局同步案例分析


openCL作爲GPU編程的一種工具庫,編程方式 與CPU上不同,尤其是 線程同步。

GPU編程,爲了充分利用硬件特性,會開啓大量的計算線程,幾千甚至幾萬個邏輯線程。

對於一些複雜的計算過程,往往需要分步驟執行,即存在同步點。例如:A步驟1000個線程執行完畢後(同步點),再B步驟500個線程執行,執行完畢後(同步點),再執行C....等。

 

本人對不同的 同步方法進行了性能測試。

這裏假設讀者有一定的 OpenCL編程基礎。

 

測試任務爲:將兩個數組簡單計算後存儲。數組 a,b; 初始值全部 a=2,b=3;  計算 b=b+a*a; b=b*b; 正確結果爲全部 b=49;

這裏人爲的設定了一個 同步點。在步驟1: b=b+a*a 完成後同步一次,再執行步驟2: b=b*b;,並且步驟1 的執行,按數組順序執行由前往後。2的執行,按數組倒序執行,由後往前。

如果同步點,沒能正確的全局同步,那麼會出現,1,2同時執行,造成計算結果錯誤。

 

編程方式一:使用OpenCL的 barrier()同步。如下代碼:

max = 數組的長度 =500萬。也就是說測試中 opencl至少開啓 500萬個邏輯線程。


__kernel void Test01(
    __global  float* a
    , __global  float* b, int max)
{
    int i = get_global_id(0);
    if (i > max)
        return;

    b[i] = b[i] + a[i] * a[i];      //數組順序計算
    barrier(CLK_GLOBAL_MEM_FENCE);    //同步點

    i = max - 1 - get_global_id(0) ;  //數組倒序計算

    b[i] = b[i] * b[i];
}


barrier 的特點:並不是全局同步。僅僅 group 內同步。一個500萬線程的任務,往往會分成 數千個 group。類似 線程,進程的關係。

而GPU硬件,真正同時執行的線程,並沒有500萬,可能也就 1024個 或者 2048個線程,同時執行。具體看GPU設備的規格。那麼實際執行過程,是一批一批的線程進行執行。具體執行流程這裏不作展開。總結的講,便是 barrier 同步 會出現,步驟1,2順序混亂,不能達到全局同步的效果。造成計算結果 錯誤

 

編程方式二:拆分計算過程爲多個kernel。


__kernel void Test02(
    __global  float* a
    , __global  float* b, int max)
{
    int i = get_global_id(0);
    if (i > max)
        return;
    b[i] = b[i] + a[i] * a[i];    //順序計算
}

__kernel void Test03(
    __global  float* a
    , __global  float* b, int max)
{
    int i = get_global_id(0);
    if (i > max)
        return;

    i = max - 1 - get_global_id(0);  //倒序計算

    b[i] = b[i] * b[i];
}


在CPU端  創建2個opencl kernel :Test02,Test03,分別由 clEnqueueNDRangeKernel先後執行。通過設置 clEnqueueNDRangeKernel,或隊列執行順序,或用事件方式,便可以實現全局同步。保證步驟1,2的計算結果 正確

 

要正確實現 opencl 全局同步,應適當拆分計算過程 爲多個 kernel 來分別執行。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章