這一篇我們一起學習一下如何使用cuda實現並行歸約演算法。
首先我們要知道什麼是並行歸約。並行歸約(reduction)是一種很基礎的並行演算法,簡單來說,我們有n個輸入資料,使用乙個符合結合律的二元操作符作用其上,最終生成1個結果。這個二元操作符可以是求和、取最大、取最小、平方、邏輯與或等等。
我們以求和為例,假設輸入如下:
int array[8] = [3, 1, 7, 0, 4, 1, 6, 3]
在序列的情況下,演算法很容易實現,一般我們會使用下面這樣的**。
int
但當我們試圖進行平行計算時,問題就會變得複雜。
由於加法的交換律和結合律,陣列可以以任意順序求和。所以我們會自然而然產生這樣的思路:首先把輸入陣列劃分為更小的資料塊,之後用乙個執行緒計算乙個資料塊的部分和,最後把所有部分和再求和得出最終結果。
依照以上的思路,我們可以按下圖這樣計算。就上面的輸入例子而言,首先需要我們開闢乙個8個int的儲存空間,圖中一行的資料代表我們開闢的儲存空間。計算時首先將相鄰的兩數相加(也稱相鄰配對),結果寫入第乙個數的儲存空間內。第二輪迭代時我們再將第一次的結果兩兩相加得出下一級結果,一直重複這個過程最後直到我們得到最終的結果,空白方框裡面儲存的內容是我們不需要的。這個過程相當於,每一輪迭代後,選取被加數的跨度翻倍,後面我們核函式就是這樣實現的。
相鄰配對實現並行歸約
相比與序列計算,我們只用了3輪迭代就得出了8個數的和,時間複雜度由o(n)變為o(logn)。
當然使用歸約演算法時我們不會只有這麼小的輸入陣列,這時候就要用到執行緒塊了,我們可以把輸入陣列先劃分成很多包含8個int型值的陣列,每乙個小陣列分配給乙個執行緒塊,最後再將所有的結果傳回主機序列求和。
主函式如下,與我們上乙個例程結構類似,先初始化,分配記憶體,然後執行核函式,最後和cpu對照組對比,檢驗結果是否正確。我們重點關注分配執行緒網格和執行緒塊的主幹部分。與上面例子裡講的8元素陣列不同,實際使用時為了達到高加速比,我們會把輸入陣列分成更大的塊。
int
__global__
最後我們看看執行結果,cpu花費89.3ms,而gpu花費2.5ms,運算結果一致。
終端截圖
完整**和編譯生成的可執行檔案放在這裡:
總結一下,這一篇我們使用cuda完成了乙個基礎的並行歸約演算法,不過這演算法還有很大的優化空間,接下來我們一起對這個演算法進行優化,看看能再加快多少。
cuda程式設計入門 HelloWorld
為了提高並行運算速度,開始接觸cuda程式設計,cuda 在安裝的時候提供了很多示例,一般位於home目錄下,可以作為學習的參考,同時官網提供的入門教程,就是很好的學習資料。cuda程式設計首先要轉換與cpu 下程式設計的思想,在cpu 下,我們一般都是按照順序進行執行,或者開幾個執行緒處理幾個任務...
CUDA程式設計
cuda目前支援linux和windows作業系統。進行cuda開發需要依次安裝驅動 toolkit sdk三個軟體。在 安裝目錄 c src目錄下有很多的例程可以進行學習。cuda 的核心有三個重要抽象概念 執行緒組層次結構 共享儲存器 遮蔽同步 barrier synchronization 可...
cuda程式設計
參照 一 gpu與cpu的聯絡與區別 gpu上可以進行資料結構統一的運算,gpu上整合大量相對cpu邏輯計算單元簡單的計算部件,利於序列。cpu上可以邏輯計算 流程控制等複雜的過程,利於並行。總而言之,gpu是乙個 人多力量大 的部件,而cpu是乙個 單兵作戰力強 的部件。基於cpu gpu的異構計...