CUDA學習筆記(一):淺析GPU計算——CPU和GPU的選擇


 

轉載自CSDN:Never-Giveup

目前市面上介紹GPU編程的博文很多,其中很多都是照章宣科,讓人只能感受到冷冷的技術,而缺乏知識的溫度。所以我希望能寫出一篇可以體現技術脈絡感的文章,讓讀者可以比較容易理解該技術,並可以感悟到cuda編程設計及優化的原理。


談到計算,我們一般都會先想到CPU。CPU的全稱是Central Processing Unit,而GPU的全稱是Graphics Processing Unit。在命名上。這兩種器件相同點是它們都是Processing Unit——處理單元;不同點是CPU是“核心的”,而GPU是用於“圖像”處理的。在我們一般理解里,這些名稱的確非常符合大眾印象中它們的用途——一個是電腦的“大腦核心”,一個是圖像方面的“處理器件”。但是聰明的人類並不會被簡單的名稱所束縛,他們發現GPU在一些場景下可以提供優於CPU的計算能力。


於是有人會問:難道CPU不是更強大么?這是個非常好的問題。為了解釋這個疑問,我們需要從CPU的組織架構說起。由於Intel常見的較新架構如broadwell、skylake等在CPU中都包含了一顆GPU,所以它們不能作為經典的CPU架構去看待。我們看一款相對單純的CPU剖面圖 

這款CPU擁有8顆處理核心,其他組件有L3緩存和內存控制器等。可以見得該款CPU在物理空間上,“核心”並不是占絕大部分。就單顆Core而言(上圖CPU屬於Haswell-E架構,下面截圖則為Haswell的Core微架構。“Intel processors based on the Haswell-E microarchitecture comprises the same processor cores as described in the Haswell microarchitecture, but provides more advanced uncore and integrated I/O capabilities. ”——《64-ia-32-architectures-optimization-manual》) 

可以看到,其有20多種“執行單元”(Execution Units),如ALU、FMA、FP add和FP mul等。每個“執行單元”用於處理不同的指令

可以見得CPU是個集各種運算能力的大成者。這就如同一些公司的領導,他們可能在各個技術領域都做到比較精通。但是一個公司僅僅只有這樣的什么都可以做的領導是不行的,因為領導的價值並不只是體現在一線執行能力上,還包括調度能力。


我們以Intel和ARM的CPU為例。比如我手上有一台國產號稱8核心,每顆核心可達2GHz的手機,目前打開兩個應用則卡頓嚴重。而我這台低等配置的兩核心,最高睿頻2.8GHz的筆記本,可以輕輕松松運行多個應用。拋開系統和應用的區別,以及CPU支持的指令集來思考,到底是什么讓Intel的CPU使用起來越來越流暢?


有人可能說是主頻,我們看下CPU主頻的發展圖( 參考周斌老師課件 后續補上)


可以見得CPU的主頻在2000年以前還是符合摩爾定律的。但是在2005年左右,各大廠商都沒有投放更高主頻的CPU(理論上現在主頻應該達到10GHz了),有的反而進行了降頻。為什么?一是CPU的主頻發展在當前環境下已經接近極限,而且功耗也會隨着主頻增加而增加。但是我們感覺到電腦越來越慢了么?

也有人說是核心數。最近10來年,市面上桌面版intel系列CPU還是集中在2、4、8核心數上。以2005年的奔騰D系列雙核處理器和現在core i3 雙核處理器來對比,奔騰D應該難以順暢的運行Win10吧(它的執行效率連2006年發布的Core 2 Duo都不如)。

還有人會說是亂序執行(out of order)。一個比較經典的亂序執行例子是這樣的


class_name * p = NULL; 
……
p = new class_name;


我們一般理解這個過程可以分解為:1 分配空間;2 調用構造函數;3 空間地址賦值給p。然后CPU可能會將2,3兩個順序顛倒。

這樣做有什么好處呢?比如另外一個線程B要檢測p是否為NULL,如果不為NULL則調用相應方法。如果按照先構造再賦值的順序,線程B要等待上述流程結束后才能開始前進。而如果采用先賦值再構造,線程B在賦值結束后就開始前進了,而此時new操作所在的線程可能也同步完成了構造函數的調用。(當然這和我們理解不同,可能會引起bug)

然而ARM也有這樣的功能 

除了上述觀點外,還有緩存存取速率、緩存大小等影響因素。但是這些因素,ARM系列CPU也可以做到,但是為什么還是沒Intel快呢?

當然因素肯定是多樣的。接下來我只是羅列出個人認為比較重要的原因分支預測(Branch predictor)。再以一段代碼為例

int b = 3;

int c = 4;
bool a = memory_enough();
if (a) {
b *= c;
}
else {
b += c;
}


如果按照一般的想法,CPU執行的流程是:獲取a的值后選擇一個分支去執行。假如a的邏輯可能比較耗時(比如存在IO等待操作),CPU要一直等待下去么?現在CPU的做法則相對智能,它會預測a的值,執行預測對應的分支。然后等到a的值返回后再校驗是否猜測正確,如果正確,我們將節省一個分支執行的等待時間。如果猜測錯誤,則回退回去再執行正確的流程。

可能有人會懷疑分支在代碼邏輯中的比例那么高么?需要獨立設計這么一個功能來優化?據我對部分項目做得統計分析,很多業務代碼的分支占比在80%左右。


可能還有人會懷疑這種猜測靠譜么?據尚未考證的消息,intel號稱准確率超過90%。雖然ARM也有分支預測功能,但是其准確率有這么高么?我尚未找到相應數據。


說了這么多,我只想說明一個觀點:CPU是一個擁有多種功能的優秀領導者。它的強項在於“調度”而非純粹的計算。而GPU則可以被看成一個接受CPU調度的“擁有大量計算能力”的員工。


為什么說GPU擁有大量計算能力。我們看一張NV GPU的架構圖 

這款GPU擁有4個SM(streaming multiprocessor),每個SM有4*8個Core,一共有4*4*8=64個Core(此處的Core並不可以和CPU結構圖中的Core對等,它只能相當於CPU微架構中的一個“執行單元”。之后我們稱GPU的Core為cuda核)。


再對比一下CPU的微架構和架構圖,以FP mul“執行單元為例”,一個CPU的Core中有2個,六核心的CPU有12個。雖然我們不知道GPU cuda核的內部組成,但是可以認為這樣的計算單元至少等於cuda核數量——60。


60和12的對比還不強烈。我們看一張最新的NV顯卡的數據


5120這個和12已經不是一個數量級了!

如果說cuda核心數不能代表GPU的算力。那我們再回到上圖,可以發現這款GPU提供了640個Tensor核心,該核心提供了浮點運算能力。我並不太清楚CPU中有多少類似的核心,但是從NV公布的一幅圖可以看出兩者之間的差距——也差一個量級。

除了計算能力,還有一個比較重要的考量因素就是訪存的速率。當我們進行大量計算時,往往只是使用寄存器以及一二三級緩存是不夠的。


目前Intel的CPU在設計上有着三級緩存,它們的訪問速度關系是: L1>L2>L3 ,而它們的容積關系則相反: L1<L2<L3 。以圖中Intel Core i7 5960X為例,其L3緩存的大小只有20M。很明顯CPU自帶的緩存大小太小,不足以承載所有的系統。於是需要使用內存來補充。該款CPU的最大支持64G內存,其內存最大帶寬是68GB/s。


然而GPU對應的顯存帶寬則比CPU對應內存高出一個數量級! 

通過本文的講述,我們可以發現GPU具有如下特點:

  • 1 提供了多核並行計算的基礎結構,且核心數非常多,可以支撐大量並行計算

  • 2 擁有更高的訪存速度

  • 3 更高的浮點運算能力

    如果我們在使用CPU運行代碼時遇到上述瓶頸,則是考慮切換到GPU執行的時候了。


參考:

https://blog.csdn.net/breaksoftware/article/details/79275626

           

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM