2009年4月30日 星期四

一點關於 brook+ 的筆記...

這張圖是個人對 brook+ 的感想... -_-

1.記憶體要用 new ::brook::Stream 去產生 CAL 對應裝置 (不一定是 CPU or GPU) 裡的記憶體空間, 如宣告一個 vector, 一維陣列, 內容物是 float, 要 x 個大小:

unsigned int dim[1] = { x };
::brook::Stream<float> = new ::brook::Stream<float>(1, dim);

如果是二維, 假設是 x * y 大小的話:

unsigned int dim[2] = { x, y };
::brook::Stream<float> = new ::brook::Stream<float>(2, dim);

new 後面接的 1 跟 2 就是 dim 指標的最大深度, 也就是需要幾維, 後面會講到的 domain 也會用到這個概念.

##如果陣列內元素是 float4 或 int4 的話, 它一個元素就是 128bit 寬大小而非 32bit. 雖然這算常識但還是要提一下.
##我不確定最大可以到幾維, 好像是 4.

2."<>" 標記, 指的是一個值, 但是這個值是一個 vector 裡的一個元素, 而是哪一個則看它所屬的thread 是第幾個.

3.kernel function 內可以使用 instance() 取得現在是上述 vector 裡的第幾個元素, 如果是一維的話可以使用
int x=instance().x; 
取得座標點, 二維可以使用:
int2 p = instance().xy;
int x = p.x; //取出 x 座標的範例. 
int y = p.y; //取出 y 座標的範例.

因為 int 裡最大的就是 int4, 內值分別為 int4.x, int4.y, int4.z, int4.w 四個, 所以我猜記憶體最大可用維度應該是四維....

4.盡可能使用 <> 去跑, brook+ 裡會拆成好幾個 thread 去跑 (未證實. 據說這就是 scatter 機能..) 例如以下的 kernel function code:
kernel void copy(float input<>, out float output<>)
{
    output = input;
}
假設 input output 兩個 vector 長度都是 x 的話, 就會拆 x 個 thread 各別去做 data copy 的動作..

5.盡可能使用 <> 另一個理由是因為, array output 在目前的 brook+ 裡只能允許有一個.

6.brook+ 內每個 kernel function 不允許擁有自己的 local memory..

7.kernel function 內索引變數可以活用 int4 來做, 例如:

int4 nIDX = { 0, 0, 0, 0 };
int4 nSTP = { 1, 256, 1, 256 };

fOut = pfSrc[nIDX.x] + pfSrc[nIDX.y] + pfSrc[nIDX.z] + pfSrc[nIDX.w];
nIDX += nSTP;
......

int4 也可以改 float4, brook+ 內允許使用浮點數當索引值..

8.brook+ 內 kernel function 不允許呼叫其它的 kernel function..

9.output <> 的值無法拿來給 kernel function 程式做讀取之用, 要讀取再寫入 (a+=b 的場合) 的話要用 reduce 的寫法:
reduce void reduceGPU(float input<>, reduce float output<>)
{
    output += input;
}
但是 reduce 的限制很多, 只能有兩個參數, 就是這一進一出..
output [] 這種 array 型態的話就可以, 只是當你程式要讀取時, 通常該被更新的值都沒被更新.

10.kernel function 不可以做指標型態轉換, 也不支援 int <=> float 值的轉換.

11.外面要呼叫像第四個那種 copy function, 但只需要 copy 某一個範圍時, 可以下 domain 參數, 例如:
::brook::Stream<float> a[10];
::brook::Stream<float> b[10];
copy(a.domain(2, 6), b.domain(2, 6));
這樣就可以 copy a[2] ~ a[5] 給 b[2] ~ b[5].
附帶說明一點, 在這種寫法下, kernel function 內 instance().x 抓到的起始值是 0, 不會是 2.

brook+  一來它是 data parallel 而不像 nvcc 是 thread parallel 導向的做法, 而因為不管計算 float32 x1 或 float32 x4 (float4) ATi GPU 內部都是以 float32 x 4 在演算, 所以使用 float4 會比只用 float 有效率, 所以在這前提之下, 能夠把資料的平行化處理拆散到多少, 會關係效能以外, 甚至影響計算結果是否正確.

真是難寫死了... 特別是資料平行的演算法 -_-

沒有留言: