歡迎您光臨本站 註冊首頁

GPU計算

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  關於brookgpu的簡要介紹看下面的鏈接:
http://tech.sina.com.cn/c/2003-12-30/26206.html
本文翻譯了斯坦福大學網站上的關於brookgpu語言的一篇文章,原文在:
http://graphics.stanford.edu/projects/brookgpu/lang.html
關於brookgpu的用法在公社中有介紹,請看下面的網址:
http://www.linuxfans.org/nuke/modules.php?name=Site_Downloads&op=geninfo&did=2171
想使用brookgpu需要nvidia的顯卡和cg的驅動。
ftp://download.nvidia.com/developer/cg/Cg_1.2.1/Linux/Cg-1.2.1-Linux.tar.gz
CG介面完成對nvidia_drv.o或fglrx_drv.o或via_drv.o的控制。所以對於能用以上3個.o的GPU都是可的

歡迎大家增加測試的數據和你對brookgpu的理解,初次翻譯一個新的技術,錯誤在所難免,請大家多多批評指正!
我的mail:zhangyu9587@sina.com,歡迎你與我聯繫!

顯卡代替CPU的語言-BrookGpu簡介
Brook是標準ANSI C語言的擴展,它是一種為人們所熟悉的高效的語言,它集成了數據并行計算和算術計算集中這兩個特點。
通用的計算模型,也就是所謂的流(Stream),同傳統的常規語言相比,有以下兩個主要的優點:
1.數據并行:允許編程者指定如何在不同的數據上并行地執行相同的操作。
2.算術計算集中:鼓勵編程者指定數據上的操作,以達到全局的通信最小而局部的計算最大!
更多的關於Brook的內容可以在Merrimac web site 找到,裡面包括了這種語言的完整的說明。Brookgpu為了在GPU上使用,它實現了Brook規範的一個子集。一個Brook 程序中包含合法的C代碼和聲明流(streams)的句法擴展以及叫做kernels的函數。

流(Streams)
流是一個新的數據類型的擴展,代表了一系列能夠被并行處理的數據。Streams的聲明規則和數組很像,都是使用尖括弧進行聲明的。聲明一個流的例子如下所示:
float s <10, 10>;
上面聲明了一個2維的浮點類型的流。每個流都是由流元素組成的。在上面的例子中,s是一個包含了100個浮點類型流元素的流。流的形狀就是指流的維數。在這個例子中,流的形狀是10×10。流是用列優先的方式來進行描述的,同C語言中的數組類似。因此,形狀為<100>的流與形狀為<1,100>和<1,1,100>的流是等同的。
儘管同C數組很類似,但Brookgpu中的流同C語言中的數組有以下的區別:
1. 在kernels函數外不允許通過下標來獲得流元素(例如 s[3][2])。
2. 不允許對流進行靜態的初始化,例如:
float s<100>={1.0f,2.0f,....}是不允許的。
3. 流必須是局部變數(堆棧)。
4. 流只能在核心(kernel)函數中被讀寫或者是通過特殊的運算符從普通的指針和versa 獲得數據。
streamRead(s,data_s);
/*用*data_s處的數據對流stream s<>進行賦值*/
streamWrite(s,data_s);
/*用流s<>的數據對*data_s進行賦值*/
儘管這個操作還可能通過編譯器進行進一步的優化,但是它向流中進行拷貝已經是十分高效了。
對於GPU編譯過的代碼,流對應於組織內存(texture memory)的區域。編譯器能進行代碼流分析來更好地決定什麼時候什麼地點來分配組織內存(texture memory),或者完全消除流變數需要暫時存儲的需要。為了方便起見,brook也擴展C來包括float2,float3和float4作為基本的數據類型。這些類型同C語言中用typedef 的結構(structs)是等價的。例如:
typedef stuct {
float x;
float y;
float z;
float w;
} float4;
另外,這些數據類型能夠通過使用構造函數的語法來構造:
float4 a (0.2f,1.0f,3.2f,1.0f); // x=0.2f,y=1.0f ......
核心(kernels)
核心是在流上操作的特殊函數,是應用到每個輸入流元素的一種并行函數。在一系列的輸入流上調用一個核心函數就在每個流元素上實施了隱含的循環,即對每一個流元素調用核心體。通過GPU帶有的核心函數,流被輸入進視頻存儲器,核心函數被編譯成由其「渲染」的分段程序。除了在聲明核心時,它的前面要加上關鍵字kernel,核心的定義和函數的定義非常的相似,返回類型通常都是void,並且其中的一個流參數要標記類型限定語\'out\'。全局內存空間和靜態變數在kernels里無法被訪問。一個kernel聲明的例子如下所示:
kernel void k (float s<>,float3 f, float3 f, float a[10][10], out float o<>)
在這個例子中,輸入流s的每一個元素都要調用kernel k的核心體。變數s在kernel體的內部的類型是float,為了每次隱含的調用,s被初始化為一個不同的元素。變數f是kernel中的一個常數,它在每次迭代中保持同一個值。在kernels內部,對輸入流或是常數參數進行寫操作都是不允許的。
變數a是一個二維數組,它可以通過標準C語言訪問數組的方法來訪問。a的維數並不需要被指定,然而如果指定了數組的維數,編譯器可以更快地產生代碼。每一個流都會以數組形式輸入到一個核心(kernel)裡面。
變數o是一個輸出流。輸出流是一個只寫的參數,它的值由kernel函數體來進行賦值。在kernel體的內部,變數o的類型也是float。s的每一個元素都隱含地執行kernel體,產生輸出流o的元素。注意到kernel的原型和函數體都受限於C和C++支持的cg/HLSL的子集。它們包括向量流類型,矩陣類型和標準的庫函數。
想獲得更多的信息,請參照CG語言規範,網址是:
http://developer.nvidia.com/object/linux_cg_toolkit.html
http://developer.nvidia.com/attach/3722
也可以參照HLSL文檔,網址是:
http://msdn.microsoft.com/library/default.asp?url=/library/en- us/directx9_c/directx/graphics/reference/Shaders/HighLevelShaderLanguage.asp
調用一個kernel函數同調用任何C函數類似。
kernel void k(float s<>, float3 f, float a[10][10], out float o<>);
float a<100>;
float b<100>;
float c<10,10>;
streamRead(a, data1);
streamRead(b, data2);
streamRead(c, data3);
// 調用 kernel \"k\"
k (a, 3.2f, c, b);
streamWrite(b, result);

Reductions(約簡)
Brook 提供對流進行并行約簡的支持。約簡是指將一個流轉化為維數更小的流或一個單獨的值的操作。這個操作可以由一個單獨的,兩輸入的運算符來定義的,這個運算符必須是可結合的和可交換的。考慮到這個性質,流元素可以被看成是無序的集合,在運算過程中,那些元素可以以任意順序結合直到產生出約簡的結果。
約簡函數只支持那些既能結合又能交換的約簡。編譯器必須能夠以任意的順序來計算約簡。例如,計算一個流的和既是可結合的又是可交換的:
a+b+c+d =(a+b)+(c+d)=a+b+c+d
合法約簡的例子是求和、相乘、求最大值或最小值、相或、相與、異或等位操作。不合法約簡的例子包括減法和相除。我們必須注意的是編譯器並不驗證約簡函數的合法性。所以編程者必須保證約簡操作是合法的。聲明一個不合法的約簡將會導致進入未定義的執行狀態。
約簡函數的聲明同kernel函數的聲明類似,都有一些額外的限制。下面是一個約簡函數的例子,它計算了一個浮點流的所有元素的和。
void reduce sum (float a<>,reduce float result<>) {
result = result + a;
}
約簡函數只能帶有兩個流參數,一個輸入流和一個輸出流,輸出流前有關鍵字reduce,其餘的參數都不能是流。另外,兩個流的類型必須相吻合。為了計算兩個值的約簡,kernel要允許對約簡參數同時進行讀和寫。
傳遞到約簡kernel的約簡參數可以是標量值或是流。如果約簡參數是一個標量,所有的流元素都將調用約簡函數來產生一個單獨的值,這個值被存放在約簡變數中。約簡的初始值被定義成輸入流的第一個值。

多維約簡
如果約簡的參數是一個流,那麼如何進行約簡操作將是由輸入流的維數和約簡輸出流維數之間的關係來決定的。
float s<100,200>;

float t;
sum(s, t); // 求s中所有元素的和,結果放在t中
float t<100, 1>;
sum(s, t);

float t<1, 200>;
sum(s, t);
調用約簡kernel來約簡元素就可以將輸入流轉換成不同維數的輸出流。例如:
float s<100,200>;
float t<50, 20>;
sum(s, t);
在這個例子中,y方向上可以被2整除而x方向上可以被10整除。每生成t的一個元素,s的2×10個元素都要調用執行約簡kernel。
如果維數不互相匹配,或是約簡的維數比輸入流的維數更大,或是輸入流的維數不是偶數,都會產生編譯的錯誤。
使用流的形狀
為了生成在當今圖形硬體上能有效運行的代碼,brook for GPUS並沒有實現在官方Brook規範說明中大多數流的運算符
(http://merrimac.stanford.edu/brookspec-v0.2.pdf)。但是,當調用kernels和隱式執行流操作時,Brook這種語言利用了輸入流和輸出流的相對形狀。
基於流的形狀,運算符streamStride和streamRepeat結合在一起並被隱式地調用。例如:

kernel void foo (float a<>, out float b<>);

float a<10,20>;
float b<50,10>;

foo(a,b);
在這個例子中,輸出流b的y方向上比輸入流a大5倍,然而輸出流b的x方向上只有輸入流a的一半大。對於b中的每一個流元素,kernel foo只被調用一次。流a隱式地改變大小來匹配輸出流的大小。在這個例子中,在y方向上通過重複元素的方式(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3....)來使維數增加,而通過在x方向上每隔一個去掉一個元素的方法(1,3,5,7,9....)來使維數減少。每個輸入流都重複上面的操作。數組參數不受影響。

重複流
重複流是一種特殊類型的流,它預先就被初始化為一系列順序的值(1,2,3,4,...)。創建一個重複流使用iter關鍵字和運算符:
iter float s<100> = iter(0.0f, 100.0f);
// s被初始化成0.0, 1.0, 2.0, ..., 99.0
iter操作符的第一個參數通常是流的初始值。第二個操作符是流的數值的上限,產生完全相同的形式【初始值,上限】。流元素之間的步長等於(初始值-上限)/流中元素的個數。
iter float s<100> = iter(0.0, 1.0f);
// s: 0.00, 0.01, 0.02, 0.03, ..., 0.99

iter float s<10> = iter(2.0f, 7.0f);
// s: 2.0, 2.5, 3.0, 3.5, ..., 6.5
一維重複流也同時與float2,float3,float4類型一起使用。每一個元素都被單獨的插值。

iter float2 s<10> = iter(float2(0, 0), float2(10, 5));
// s: (0,0), (1,0.5), (2,1), ..., (9,4.5)。
目前的編譯器只支持一維和二維的重複流。如果流是二維的,流元素的類型必須是float2。在二維的情況下,插值稍稍有些不同。

iter float2 s<4, 4> = iter (float2(0,0), float2(4, 10))
s:
(0, 0) (1, 0) (2, 0) (3, 0)
(0, 2.5) (1, 2.5) (2, 2.5) (3, 2.5)
(0, 5) (1, 5) (2, 5) (3, 5)
(0, 7.5) (1, 7.5) (2, 7.5) (3, 7.5)
流元素的每一個部分都會根據相應維數的最大和最小值進行插值。
目前Brookgpu編譯器和運行不支持二維以上的重複流,更進一步地說,如果一個重複流傳遞進入一個kernel,它的維數必須和輸出流的維數相匹配。這些限制可能會在將來發行的版本中取消,目前重複流和數據流並不相同,因此,重複流的參數中必須包含iter這個關鍵字,而且將重複流做為一個輸出結果傳進kernel也是不允許的。這些限制可能會在將來發行的版本中改變。
ScatterOp
streamScatterOp(s, index_stream, array,STREAM_SCATTER_ASSIGN);

StreamScatterop運算符執行一個間接的寫操作,流s中包含傳遞給Scatter的數據,索引流(index Stream)中包含在數組中要寫入數據的偏移量。第四個參數是執行如下的操作:將新來的數據同已經保存在數組中的數據結合起來,這個參數可以是一個約簡函數,或是枚舉函數的一個組成部分,例如STREAM_SCATTER_ASSIGN執行一個將流數據直接寫入數組的寫操作。

GatherOp
streamGatherOp(t, index_stream, array, STREAM_GATHER_FETCH);

streamGatherOp執行一個數組上間接的讀操作。它通過使用索引流來生成一個取值的流(t)。如果數組是多維的,索引流提供一個在數組內的線性偏移(基於C語言數組的列優先排列)。
第四個參數可以是任何kernel函數,這個函數包含一個單獨的輸出流或是一個預定義的操作符。STREAM_GATHER_FETCH參數指出Gather操作僅僅讀取值並將這個值放入流中就行了。

原帖地址在:
請在這個地址進行討論:
http://www.linuxfans.org/nuke/modules.php?name=Forums&file=viewtopic&t=73651\'


閱讀:4659次

責任編輯:wheel

來源:GPU計算
網友評論
大名
評論標題:
wheel
 無標題
詳細內容:(2004-07-02 09:18:31)其實就是用CG介面完成對nvidia_drv.o或fglrx_drv.o或via_drv.o的控制。所以對於能用以上3個.o的GPU都是可的。 象素遮掩是用DX9的介面要的.CG是可以用 OpenGL的介面的.這和DX9不同.


[火星人 ] GPU計算已經有445次圍觀

http://coctec.com/docs/program/show-post-71915.html