Udacity cs344Unit 3-Introduction to Parallel Programming筆記(超詳細,CUDA,並行,GPU)
1.課程目標
如何分析GPU演算法的速度和效率(speed and efficiency)
三個新的基本演算法:歸約,掃描和直方圖(reduce,scan and histogram)
2.
3.再看之前講的例子
考慮兩件事
介紹幾個概念
a.步驟(step):指的是 單人!完成某特定計算(比如挖洞)所需時間
b.工作總量(total amount of work):所有參與員工完成計算量的總值
也就是,人數 * 步數 = 工作總量
4.談論演算法時,將討論兩個成本
a.step complexity(步驟複雜度):一共分成幾個步驟得到了最終結果,那個步驟數量
b.work complexity(工作複雜度):一共進行了多少次計算?
我們會用step complexity 或者work complexity來衡量一個演算法,而這兩個指標通常與input的大小是有關聯的
5.
從數學定義開始
有兩個輸入(一個數組和一個運算子)運算子要具有兩個性質:二元性和可結合性
6.
先看序列的歸約(每一個操作都依賴前一個操作)
操作次數為4次,共計4 steps
這意味著工作複雜度(與節點數目一致)和步驟複雜度(操作總次數)都是和input成正比的
7.並行歸約(就是想辦法給他湊成可以一同運算的,互相不依賴的——改變運算次序)結合性保證了次序改變,結果不受影響
如果只有p個處理器,需要多少步,才能處理n個輸入
8.試著編寫一下這個程式碼
9.
舉一個現實中用到scan的例子:收支平衡(計算餘額)
你輸入一個,我得一個結果
9.數學描述
介紹一個概念:某個運算子的標識元素(identify element):比如“+”的identify element 是0
10.序列的for迴圈,n是幾就進行了多少次操作,就是多少個步驟,並行怎麼計算?
a.我們怎麼計算掃描和並行(的步驟和操作次數)
b.我們怎麼能儘量降低工作和步驟複雜度?
在這兩個小問題之前
先來看一個大問題:
在並行有這麼多種操作的前提下,我們為啥偏偏先關注掃描的並行化?
當每次只能進行一次計算的時候,是沒辦法並行的(都要依賴前面一次的結果)
但是像這類的計算,通常可以轉化成掃描的形式
當可以用掃描的方式來刻畫計算的時候,就有用啦!
因為:我們可以使掃描並行化!並且在GPU上飛快執行!
我們要做的是:找到能轉化成scan的運算模型!把問題從不適合GPU的轉化成適合GPU的
11.當找到模型後,怎麼實現掃描呢?
有兩種方法
a.不包含掃描(exclusive scan):計算結果中不包含當前元素
b.包含掃描(include scan)
把包含掃描轉化成不包含
12.測驗:scan的複雜度
步驟複雜度:就看最複雜的那個需要多少步驟就行了
工作複雜度:每一次運算都加起來的總和【0+1+2+...+(n-1)】
由於工作複雜度太高,所以聰明的人們又想出了兩種演算法!
12.Hill + Steele VS Blelloch
a.
先看步驟複雜度,是logn(一般採用了分治思想的,複雜度都會是logn,因為砍掉了一些資料沒有切實的計算,而這裡的底數也不必在意,就像是若複雜度為n的平方,也不必在意前面的係數一樣)
工作複雜度:是這個矩形的面積,用長n乘上寬logn
b. 三角矩形法(想著傳手畫圖)【這個很像郭老師講的歸約和回溯啊,第一階段進行歸約,得出最後想要的結果,第二階段再去找湊成這個結果的路徑是什麼】
測試 max操作
看複雜度
工作量是不是也是2倍的?比logn要小嘛?
13.給你一點直覺,在兩個演算法分別在工作複雜度和步驟複雜度上各佔優勢時候,要怎麼選擇
a.工作多於處理器:可以犧牲步驟,換取工作量
b.處理器多於工作:願意犧牲工作量來換取更少的步驟(選擇步驟複雜度低的)
在並行演算法裡有很多的沙漏模型(比如剛剛的三角矩形演算法就是這樣):那麼我們可以在不同的階段採用不同的演算法,來保證總體執行通常,效率最高
14.直方圖
(就是統計介於某個段值內的實體個數)
如果我知道我的身高,想知道比我矮的有多少個,就用exclusive scan
15.實現過程
16.程式碼實現
線上性程式中
看並行的為啥會出錯:有兩個執行緒同時執行的風險
所以暴力簡單法不可行
17.看仨有效的法子
a.改成原子操作就可以啦
這種方法在bin(也就是各個段盛放的容器)個數很大是時候,會很好用。因為原子操作會限制並行度的大小
推出b
b.分本地記憶體,再歸約
不需要原子操作
c.先排序再歸約
18最終思想:由於這三種方法(沒有最好,各有利弊),所以把這三個方法分別用於不同的階段就好啦
a.大多數執行緒試圖訪問bin儲存器時候,原子操作不適用,因為會有大量執行緒處於等待之中(bin是直方圖下面的段數)
所以就先分block,因為在共享記憶體裡是不需要進行原子操作的,只有當最後合併時候,才需要進行原子操作
19.