天天看點

OpenCL 學習step by step (9) 灰階圖Histogram計算(3)

     在OpenCL程式設計中,特别是基于GPU的opencl的程式設計,提高程式性能最主要的方法就是想法提高memory的使用率,它主要包括兩方面的優化:一方面是提高global memory的合并讀寫效率,另一方面就是減少local memory的bank conflict。下面我們分析一下教程7中的代碼,看看它的memory使用率如何?

    首先我們用amd的opencl profiler分析一下程式性能[最新的app sdk改用CodeXL進行性能分析]。

     下面我們來分析我們的kernel代碼中memory操作:

     首先是shared memory的的初始化,我們知道shared memory是local memory,被一個workgroup中的所有thread,或者說work item共享。在amd硬體系統中,local memory是LDS,它通常是為32k或更高,分為32個bank,dword位元組位址,每個bank 512個item,我們可以通過函數得到自己系統中的local memory數量:

cl_ulong DeviceLocalMemSize;

clGetDeviceInfo(device,

    CL_DEVICE_LOCAL_MEM_SIZE,

    sizeof(cl_ulong),

    &DeviceLocalMemSize,

    NULL);

LDS的示意圖如下,對于每個bank,同時隻能有一個讀寫請求,如果兩個thread都讀寫bank1,那個必須串行通路,這就稱作bank conflict。

OpenCL 學習step by step (9) 灰階圖Histogram計算(3)

kernel初始化local memory的代碼如下:

//初始化共享記憶體

for(int i = 0; i < BIN_SIZE; ++i)

    sharedArray[localId * BIN_SIZE + i] = 0;

     在同一時間,thread0通路位址0(bank1),thread1,通路位址256,也在bank1,…,這樣就有很多bank conflit,降低程式的性能。從profiler裡面可以看到,lds bank conflit為13.98,很高的比例,是以此時同時運作的thread就比較少,隻有總wave(每個wave 64個thread)的12%(我曾經預設lds記憶體配置設定是0,這樣我們就省去了這些代碼,但是實際上配置設定記憶體是一些随機的值…)。

OpenCL 學習step by step (9) 灰階圖Histogram計算(3)
OpenCL 學習step by step (9) 灰階圖Histogram計算(3)

第二段memory操作的代碼為:

    //計算thread直方圖

    for(int i = 0; i < BIN_SIZE; ++i)

    {

        uint value = (uint)data[groupId * groupSize * BIN_SIZE + i * groupSize + localId];

        sharedArray[localId * BIN_SIZE + value]++;

    }

其中有lds的操作,也有global memory的操作,對于全局memory的通路,在同一時刻,thread0通路i=0的memory

,thread1通路相鄰的memory單元…,這是對于global memory的通路會采用合并讀寫的方式(coalencing),就是一個memory請求傳回16個dword,也就是一個請求滿足16個thread,提高memory使用率。此時對lds的寫是随機的,根據value的值決定,不能控制…

OpenCL 學習step by step (9) 灰階圖Histogram計算(3)

最後一段memory讀寫的代碼:

//合并workgroup中所有線程的直方圖,産生workgroup直方圖

for(int i = 0; i < BIN_SIZE / groupSize; ++i)

{

     uint binCount = 0;

     for(int j = 0; j < groupSize; ++j)

         binCount += sharedArray[j * BIN_SIZE + i * groupSize + localId];

     binResult[groupId * BIN_SIZE + i * groupSize + localId] = binCount;

}

其中lds的讀寫如下圖,此時每個線程通路不同的bank,因為amd lds通路就是以32為機關,是以實際上,這段代碼不會有bank conflit。

OpenCL 學習step by step (9) 灰階圖Histogram計算(3)