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剖面圖 
ide

這款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是個集各類運算能力的大成者。這就如同一些公司的領導,他們可能在各個技術領域都作到比較精通。可是一個公司僅僅只有這樣的什麼均可以作的領導是不行的,由於領導的價值並不僅是體如今一線執行能力上,還包括調度能力。
spa


咱們以Intel和ARM的CPU爲例。好比我手上有一臺國產號稱8核心,每顆核心可達2GHz的手機,目前打開兩個應用則卡頓嚴重。而我這臺低等配置的兩核心,最高睿頻2.8GHz的筆記本,能夠輕輕鬆鬆運行多個應用。拋開系統和應用的區別,以及CPU支持的指令集來思考,究竟是什麼讓Intel的CPU使用起來愈來愈流暢?
.net


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


能夠見得CPU的主頻在2000年之前仍是符合摩爾定律的。可是在2005年左右,各大廠商都沒有投放更高主頻的CPU(理論上如今主頻應該達到10GHz了),有的反而進行了降頻。爲何?一是CPU的主頻發展在當前環境下已經接近極限,並且功耗也會隨着主頻增長而增長。可是咱們感受到電腦愈來愈慢了麼?
設計

也有人說是核心數。最近10來年,市面上桌面版intel系列CPU仍是集中在二、四、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

相關文章
相關標籤/搜索