[譯]How GPU works

序言
首先,我想說明一下,雖然文章的標(biāo)題是 How GPU Works,但是我無意再去重復(fù)GPU工作的各個stage,流水線這些概念。本文會深入到更底層一點:GPU是如何執(zhí)行shader的。在本文中,我除了GPU執(zhí)行shader的方式之外,還有稍微涉及一些多核心,SIMD,超線程這些過去大家看上去貌似非常高大上的概念。
一個簡單shader

這就是一個非常簡單的diffuseshader(HLSL),是fragment(pixel) shader,每個片元著色器是獨立執(zhí)行的,并不需要特地的去執(zhí)行并行編程(像CPU多線程那樣),但是每個片元著色器確實有自己單獨的邏輯控制流。
代碼運行的方式
GPU和CPU運行shader的方式差不多,都是先編譯成匯編,然后單步執(zhí)行。


CPU和GPU架構(gòu)對比


兩者對比可以發(fā)現(xiàn),GPU core相比CPU core,去掉了亂序執(zhí)行,分支預(yù)測和內(nèi)存預(yù)取的功能,并去掉了大塊的緩存,使相同面積可以容納更多的核心。而且去除了分支預(yù)測,亂序等功能之后也能使程序順序執(zhí)行時更高效(代價是分支效率下降,后文會提)。



指令流共享
到此我們可以發(fā)現(xiàn)一個現(xiàn)象,就是每個片元執(zhí)行的代碼都是相同的,GPU cores完全可以復(fù)用一套指令。為此,GPU工程師們發(fā)明了一個極具想象力的設(shè)計。

將ALU和Context增加,使用一個指令來控制多個ALU進(jìn)行計算。這種技術(shù)在CPU那邊有個學(xué)名,叫 SIMD ,也就是通過一條匯編指令控制多個計算。

這樣,就實現(xiàn)了譯碼器和ALU一對多的映射。




分支運算
上文提到過GPU core相比CPU core,是簡化過的,簡化掉了分支分支預(yù)測的功能,那GPU是如何執(zhí)行分支語句的呢。了解shader的同學(xué)可能也了解,分支語句會讓shader的性能極劇下降,在此我也會一起解釋。


GPU在編譯時會找到分支語句的位置,然后在執(zhí)行時,對于分支語句,會將各分支分配給不同的ALU來執(zhí)行。

并不是每個ALU的計算結(jié)果都有效,而無效的結(jié)果Context會負(fù)責(zé)舍棄。也就是說在最壞情況下,分支語句相比無分支語句僅有1/8的的性能(取決于ALU數(shù))。期望值是1/2,也就是平常大家常說的分支語句會令shader性能折半。
Stalls
Stalls是一個硬件術(shù)語,指芯片因為上一條指令執(zhí)行過慢,而無事可做的情況。
回到之前的diffuseshader上。

采樣是GPU從顯存中讀取貼圖信息的過程,有大量延遲,一般在100到1000個時鐘周期。為了防止這個問題,CPU通常采用超大的緩存+超大帶寬的方式來減小io時的stalls。

這里又是CPU和GPU硬件設(shè)計上截然不同的地方,因為Cache不命中會使 Stall 發(fā)生(必須從主存儲器取值),所以GPU設(shè)計時索性去掉了big data cache和Memory pre-fetcher,取而代之的是一種非常巧妙的方法。

對于一個GPU core,所需擁有的Context數(shù)是ALU數(shù)目的數(shù)倍。這樣,當(dāng)其中一組Context遭遇采樣io時,迅速切換到下一組Context。等到IO結(jié)束之后,前一組Context余下的指令才繼續(xù)執(zhí)行。大家一般談?wù)摰?span id="s0sssss00s" class="color-pink-03">CPU超線程其實也是這個原理,兩個Context共享一個physics core。


圖像采樣需要數(shù)百時鐘周期,是通常指令執(zhí)行的數(shù)十到數(shù)百倍,因此一個GPU core上擁有的Context數(shù)也是ALU的數(shù)十倍。剛好符合了實際情況:屏幕像素數(shù)遠(yuǎn)遠(yuǎn)多于GPU流處理器個數(shù)。

實例:GTX480


NVIDIA管一個GPU core叫一組SM,一個ALU叫一個CUDA core,CUDA core可以在一個時鐘周期內(nèi)執(zhí)行一個乘法和一個加法(即一個MAD,Multiply & Add指令)。一組SM有兩個Fetch/Decode單元,個人猜測這樣就可以在執(zhí)行分支語句時一人一半。一組SM有48組Context,也就是說,一組SM,可以同時執(zhí)行 32 * 48 = 1536 個 CUDA 線程。

GTX480一共有15組SM,也就是說GTX480同時可以執(zhí)行多達(dá) 1536 * 15 = 23,040 個 CUDA 線程??梢哉f非常驚人了。
結(jié)語
本文介紹了一下DX10/openGL 3.x時代的顯卡,也就是SM4.0統(tǒng)一著色架構(gòu)下的顯卡設(shè)計。在tensorFlow和RTX相繼問世后,NVIDIA也發(fā)布了擁有tensor core的titan V和擁有RTX core的RTX2080/2080Ti,面對機器學(xué)習(xí)和光線追蹤這兩個if else遍地的情況,GPU的設(shè)計也作出了很大的變化,最直接的感受就是分支語句沒有性能損失了。相信GPU的設(shè)計也更接近CPU了。從當(dāng)年的Silicon Graphics RealityEngine的眾CPU開始,到RTX/tensor core,圖形硬件的發(fā)展,不也是毅種循環(huán)嗎。
引用:?
https://www.cs.cmu.edu/afs/cs/academic/class/15462-f11/www/lec_slides/lec19.pdf
http://www.cs.cmu.edu/afs/cs/academic/class/15462-f12/www/lec_slides/462_gpus.pdf