OpenCL學習筆記(11)--OpenCL設備模型

1.Opencl設備模型:__global被稱爲地址空間修飾符,這是因爲它所修飾的任何指針都會被保存在全局地址空間之中,而這個地址空間也被稱爲全局內存。每個引用內存的內核參數都必須有一個地址空間修飾符。

2.OpenCL設備模型提供了四種地址空間:
(1)全局內存–保存整個設備的數據,既可讀,也可寫;
(2)常數內存–和全局內存相似,但是隻可讀;
(3)局部內存–保存工作組中工作項的數據;
(4)私有內存–保存各個工作項的數據。
有些設備爲常數提供了專門的內存,但多數情況下,常數內存是和全局內存一樣的內存區域,因此,這兩種內存也是經常被放在一起討論。
工作項和工作組的數量是沒有限制的,但如果一個設備只含有M個計算單元,N個工作項/工作組,那麼任何時候,最多只能有MN個工作項來執行內核。

3.通過設置參數CL_DEVICE_GLOBAL_MEM_SIZE,CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE,或CL_DEVICE_LOCAL_MEM_SIZE,調用函數clGetDeviceInfo的方式來確定設備的地址空間。
(1)__global–參數的數據被保存在全局內存中;
(2)__constant–參數的數據被保存在全局、只讀內存(如果有的話)中;
(3)local–參數的數據被保存在局部內存中;
(4)__private__參數的數據被保存在私有內存(默認的)中。
例如,如果兩個指針指向的不同地址空間中的數據,就不可以在他們之間進行內存轉換。

4.(__global)__global char16或者__global uchar16.__global限定符可以用於所有的內核參數,並不僅僅是指針參數。除了參數之外,__global還可以限定內核之中所聲明的指針變量,在一個內核中,__global限定符只能用於修飾指針變量。

(__constant)內核參數以及內核中聲明的變量都可以被冠以__constant限定符。字符串常量以常數的形式保存,而任何修改常數的行爲都會報錯。__constant限定符讓數據對每個執行內核的工作項都可用。常數數據對整個程序,(而不僅僅只是爲單個內核)是全局可見的。所以在使用前必須要先初始化。

(__local)如果數據只需要在同一個工作組的不同工作項之間進行共享,就應該使用__local限定符來聲明。這種類型的數據只會針對處理內核的各個工作組分配一次,然後在工作組處理結束之後釋放內存。__local限定符也可以用內核參數以及內核中聲明的變量,但是不管是主機還是設備,都不能直接初始化內核中的局部變量。例如,下面一行內核函數中的代碼就會編譯報錯:
__local float x = 4.0;
解決方法如下:
__local float x ;
x = 4.0 ;

(__private)如果內核參數或聲明變量沒有任何地址空間限定符來修飾,它將會被保存在私有內存中。這其中包括所有非內核函數的參數和變量。私有數據是面向執行內核的每個工作項進行分配的。如果指針變量沒有限定符,他就會被設置指向私有內存,但image2d_t和image3d_t型指針會一直指向全局內存。

5.內存對齊;如果float3型量包含12個字節,這個向量會按16字節來對齊保存,因爲16是大於或等於12 的2的最小冪數,你也可以通過aligned屬性來控制數據對齊,但只能是在數據聲明時使用。aligned關鍵字之前要冠以__attribute__,例子:
short x attribute((align(4)));
這行代碼表示的是一般 按2字節對齊的 x,會改爲按4字節對齊。對齊因子必須是2的冪數。

6.局部和私有內核參數:一般內核參數是用__global限定符,然後以內存對象的形式從主機上輸出。但是並不一定需要用內存對象來構建內核函數。通過正確配置clSetKernelArg函數,來配置設備的局部和私有空間中的參數,
clSetKernelArg(cl_kernel kernel, cl_uint index, size_t size, const void*value)
最後一個參數指向的是數據,這些數據會被以內核參數的形式傳輸給設備。一般代碼都是指針指向內存對象,而與此同時的內核參數也被聲明爲__global或__constant.全局和常數空間中的數據都很容易使用,但是和局部或私有內存的數據相比,內存寬帶會更小一些。

7.局部參數:爲了編程配置整個過程,需要將clSetKernelArg函數的最後一個參數設爲NULL,
最好是先將數據從全局內存讀到局部內存中,然後在局部內存中進行處理。在工作項處理完數據之後,就可以將結果寫到全局內存中,然後再將結果傳輸回主機。可以有多個工作項處理相同的數據,以此來提升運算性能。

8.私有參數:私有參數只能被單個工作項訪問,它的內存訪問比局部內存訪問還要快,但是私有內存的空間也比局部和全局內存空間要小。和局部數據不同,內核的私有數據可以由主機應用程序來初始化。爲了編程配置私有數據,主機需要將clSetKernelArg函數的最後一個參數設爲基本數據類型,例如int*,float*,char*.

9.OpenCL的各種數據類型總結:
(1)假設你需要每個工作項都能夠訪問int型變量num_iterationg所在的地址空間,並且希望其初始值爲4,對應的主機應用程序中的操作如下:
int num_iterationg = 4;
clSetKernelArg(kernel, 0, sizeof(num_interation), &num_iterations);
內核函數:
__kernel void proc_data(int num_iters, …){
}
注意。其一,它並沒有像__global或__local那樣的地址空間限定符,換言之,Num_iters將會被保存在設備的私有地址空間中,每個工作項都會有各自不同的變量副本。其二,和其他我們所見到過的內核參數不同,num_iters並不是一個指針。私有內核參數並不是引用—他們必須是像int和float那樣的基本數據類型。
(2)私有數據是值傳遞的方式。
私有內核參數必須是基本數據類型,但不一定需要是標量類型。
float nums[4] = {0.0f, 1.0f, 2.0f, 3.0f };
clSetKernelArg{kernel, 0, sizeof(nums), nums};
內核不能以4元素數組的形式訪問私有數據,因爲私有參數不能是指針,但是數據可以以float4型向量的形式來訪問:
__kernel void proc_data(float4 values, …){
}

(3)OpenCL,每個內核都必須被冠以__kernel標識符,函數必須返回void.其次,OpenCL並不支持所有的C數據類型,而且還提供了一些新的數據類型。最後OpenCL的設備模型讓你可以控制內核數據的地址分配。

(4)OpenCL的標量數據類型並沒有多少不同,你還是可以用char,short,int, float和long等數據類型來編程。

(5)OpenCL的向量類型是最容易使用的。存有四個float型量的數據類型就被稱爲float4.初始化向量就跟初始化數組一樣,而且訪問向量的各個分量也很簡單–你可以使用數字(.so, .s1, .s2… .sF),字符(x,y,z,和w)以及使用返回一半向量分量的後綴名(.hi, .lo , .even, 和 .odd)等不同方式來訪問。

(6)全局地址空間保存的是整個設備的數據,常數地址空間保存的是隻讀數據,局部地址空間保存的是特定工作組的數據,私有地址空間保存的值特定工作項的數據,OpenCL提供了不同的限定符,來修飾變量和函數參數,指明其所在的內存位置。

(7)如果在調用clSetKernelArg函數時,指針指向內存對象,那麼,對應的內核函數參數必須是聲明爲__global或__constant類型的指針。如果調用clSetKernelArg函數時,指針被設爲NULL,對應的內核參數就必須聲明爲__local類型的指針。如果調用clSetKernelArg函數時,指針指向的是基本類型的數據,內核參數就不會是一個指針,也不需要有任何地址修飾符。

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