GPU是協(xié)處理器,CPU才是主人,GPU并不是一個(gè)獨(dú)立運(yùn)行的計(jì)算平臺(tái),而需要與CPU協(xié)同工作,可以看成是CPU的協(xié)處理器,因此GPU并行計(jì)算,是指CPU+GPU的異構(gòu)計(jì)算架構(gòu)。在異構(gòu)計(jì)算架構(gòu)中,GPU與CPU一般通過PCI-E總線連接在一起來協(xié)同工作,CPU所在的位置稱為主機(jī)端(host),而GPU所在的位置稱為設(shè)備端(device)。
早期的CPU都是針對(duì)整數(shù)運(yùn)算的,也有的CPU有少量的浮點(diǎn)運(yùn)算處理,處理低像素還湊合。隨著像素?cái)?shù)越來越高,需要大量的浮點(diǎn)運(yùn)算處理器,GPU就出現(xiàn)了。所以標(biāo)準(zhǔn)意義的GPU其性能參數(shù)為FLOPS,F(xiàn)loating-pointOperations Per Second。最常用來測(cè)量FLOPS的基準(zhǔn)程式(benchmark)之一,就是Linpack。一個(gè)GFLOPS(gigaFLOPS)等于每秒十億(=10^9)次的浮點(diǎn)運(yùn)算,一個(gè)TFLOPS(teraFLOPS)等于每秒一萬億(=10^12)次的浮點(diǎn)運(yùn)算。而CPU的性能單位一般是DMIPS,DhrystoneMillion Instructions executed Per Second,每秒百萬次整數(shù)運(yùn)算指令執(zhí)行數(shù)。AI的性能單位則是TOPS,TeraOperations Per Second,1TOPS代表處理器每秒鐘可進(jìn)行一萬億次(10^12)操作,不區(qū)分整數(shù)還是浮點(diǎn),也不是指令而是operation。通常只有CPU才能做任務(wù)調(diào)度,是host,AI處理器和GPU都是需要CPU配合,是協(xié)處理器device。
典型GPU架構(gòu)圖
圖片來源:互聯(lián)網(wǎng)
典型GPU架構(gòu),從2010年的Fermi開始NVIDIA使用類似的原理架構(gòu),使用一個(gè)Giga Thread Engine來管理所有正在進(jìn)行的工作,GPU被劃分成多個(gè)GPCs (Graphics Processing Cluster),每個(gè)GPC擁有多個(gè)SM(SMX、SMM,Streaming Multiprocessor流多處理器)和一個(gè)光柵化引擎(Raster Engine),它們其中有很多的連接,最顯著的是Crossbar,它可以連接GPCs和其它功能性模塊(例如ROP或其他子系統(tǒng))。 GPU制造廠商經(jīng)常宣傳說他們擁有“240”個(gè)“core”,但他們所有的core其實(shí)是指 “ALUs/FPUs”,與CPU中提到的core還是有區(qū)別的,一般NVIDIA或ATI稱core為SP (streamingprocessor)或者SC (shadercore)或者TP (Threadcore),都是一個(gè)東西,一個(gè)SM中包含多個(gè)SP,但這些SP并不是完全獨(dú)立的執(zhí)行單元,每個(gè)SP雖然有單獨(dú)的register file,獨(dú)立的指令指針,但SP并沒有完整的獨(dú)立front-end比如取指和指令派發(fā),因此SP更像是CPU中執(zhí)行部分。
Fermi的SM處理器內(nèi)部框架
圖片來源:互聯(lián)網(wǎng)
Fermi是英偉達(dá)2010年發(fā)布的GPU架構(gòu),從此英偉達(dá)的GPU架構(gòu)開始都以科學(xué)家的名字做代號(hào),其前端結(jié)構(gòu)差別不大。
Warp Scheduler管理一組32個(gè)線程作為Warp(線程束,可以想象是紡紗機(jī)器把多條線紡織在一起)并將要執(zhí)行的指令移交給Dispatch(派遣,發(fā)送)Units。英偉達(dá)升級(jí)GPU一般都是升級(jí)Core內(nèi)核,別的都與Fermi高度一致。Fermi有32768個(gè)32-bit寄存器,F(xiàn)ermi有512個(gè)SM,也就是每個(gè)SM(每個(gè)線程束)分到64個(gè)寄存器,每個(gè)線程兩個(gè)。
Fermi的Core包含一個(gè)整數(shù)運(yùn)算單元,一個(gè)浮點(diǎn)運(yùn)算單元。每個(gè)SM還有SFU (SpecialFunction Units,特殊數(shù)學(xué)運(yùn)算單元),它們用于進(jìn)行三角函數(shù)和指對(duì)數(shù)等特殊運(yùn)算。每一個(gè)核都相當(dāng)于GPU中的ALU,一個(gè)CPU內(nèi)核最多有8個(gè)ALU,GPU則可以輕易達(dá)到數(shù)千個(gè)。但GPU通常只能應(yīng)對(duì)一種算法,CPU中的可以勝任非常多算法,ALU像一個(gè)教授,從加減乘除到微積分無所不能,GPU像幾千個(gè)小學(xué)生的集合,通常只做乘法。FP后來在GPGPU時(shí)代變?yōu)镕MA或FFMA (Fusedmultiply-and-accumulate),基本上所有所謂人工智能算法拆解到最底層都是乘積累加計(jì)算,也特指乘積累加指令集。
英偉達(dá)用于AI的采用Ampere架構(gòu)的A100GPU物理架構(gòu)
圖片來源:互聯(lián)網(wǎng)
2019年推出的Ampere架構(gòu)與Fermi架構(gòu)整體一致。
英偉達(dá)安培架構(gòu)中的SM內(nèi)部框架
圖片來源:互聯(lián)網(wǎng)
英偉達(dá)安培架構(gòu)中的SM內(nèi)部框架中,將ALU分得更細(xì),INT32即整數(shù)32位,F(xiàn)P32為浮點(diǎn)32位,F(xiàn)P64為浮點(diǎn)64位。專門針對(duì)矩陣運(yùn)算則有Tensor核。
實(shí)際CPU與GPU最大的區(qū)別是帶寬,CPU像法拉利,跑的很快,但要是拉貨,就不如重卡。GPU像重卡,跑的不快,但一次拉貨多。有些貨可以全部打包裝車運(yùn)輸,如這些貨都來自一個(gè)地方,大小相同,需要運(yùn)輸?shù)揭粋€(gè)地方,這就是計(jì)算密集型任務(wù)。有些貨不行,比如這些貨要去不同地方,體積大小不一,不能多個(gè)打包,只能多次運(yùn)輸,這就是控制密集型任務(wù)。CPU在緩存、分支預(yù)測(cè)、亂序執(zhí)行方面花了很多精力,用大量寄存器實(shí)現(xiàn)這些功能,保證了高速度,頻率一般都遠(yuǎn)高于GPU,每次速度很快,但大量寄存器占用大量空間,考慮到成本以及半導(dǎo)體的基本定律(單顆die面積不超過800平方毫米,否則良率會(huì)急速下降),CPU的核心數(shù)非常有限,每次能帶的貨很少。GPU相反,不考慮分支預(yù)測(cè)與亂序執(zhí)行,用最快的寄存器代替緩存,結(jié)構(gòu)簡(jiǎn)單,晶體管數(shù)量少,可以輕易做到幾千核心,每次能帶的貨很多,但速度不快。
深度學(xué)習(xí)或者說人工智能都是計(jì)算密集型任務(wù),數(shù)據(jù)一般占用大塊連續(xù)的內(nèi)存空間,GPU可以提供最佳的內(nèi)存帶寬,并且線程并行帶來的延遲幾乎不會(huì)造成影響。
除此之外,GPU的并行計(jì)算架構(gòu),通常來說與執(zhí)行單元(指的是CPU的核心或者GPU的流處理器)的距離越近,則訪問速度越快,其中寄存器和L1緩存與CPU距離最近。GPU的優(yōu)勢(shì)在于:GPU為每個(gè)處理單元(流處理器或者SM)均配備了一些寄存器,而GPU成百上千個(gè)處理單元就使得寄存器總的數(shù)量非常多(為CPU的30倍,高達(dá)14MB)且速度達(dá)到80TB/s。
相比之下,CPU的寄存器大小通常為64-128KB,運(yùn)行速度為10-20TB/s。當(dāng)然以上的比較在數(shù)值上會(huì)不太精確,并且CPU寄存器和GPU寄存器并不相同。兩者的大小和速度的差異是主要關(guān)鍵點(diǎn)。最后一點(diǎn)GPU的優(yōu)勢(shì)在于:大量且快速的寄存器和L1緩存的易于編程性,使得GPU非常適合用于深度學(xué)習(xí)。
英偉達(dá)Volta V100 GPU的存儲(chǔ)架構(gòu)圖
圖片來源:互聯(lián)網(wǎng)
上圖可以看出每個(gè)處理block都有高達(dá)64KiB的寄存器,寄存器是速度最快的,只要一個(gè)周期,緩存或者說SRAM還是要通過總線訪問的,速度遠(yuǎn)遠(yuǎn)不及寄存器。
早期GPU
早期的GPU和目前的GPGPU差別還是不小的,早期的GPU主要是圖形生成與渲染,第一步就是畫三角形,三角形光柵器一次要處理一堆東西:跟蹤三角形的形狀,插值出坐標(biāo)u和v (對(duì)于透視矯正映射,是u/z,v/z和1/z),執(zhí)行Z緩沖測(cè)試(對(duì)于透視矯正映射,可以用1/z緩沖替代),然后處理實(shí)際的紋理(還有著色)。這些都是浮點(diǎn)運(yùn)算,早期的CPU都是針對(duì)整數(shù)運(yùn)算的,也有的CPU有少量的浮點(diǎn)運(yùn)算處理,處理低像素還湊合,隨著像素?cái)?shù)越來越高,GPU就出現(xiàn)了。
GPU的圖形處理邏輯管線
圖片來源:互聯(lián)網(wǎng)
通常把圖形邏輯管線叫渲染管線,渲染流水線是在顯存中開啟的。CPU將網(wǎng)格、材質(zhì)、貼圖、著色器等注入顯存后,GPU開始渲染流水線。渲染流水線分為幾何階段和光柵化階段(也被稱為像素階段),并最終將運(yùn)算結(jié)果送到顯示器的緩沖區(qū)中。幾何階段分為頂點(diǎn)著色器->曲面細(xì)分著色器(DirectX11和OpenGL4.x以上可編程)->幾何著色器->裁剪->屏幕映射五個(gè)步驟。
光柵(ROP)化階段分為三角形設(shè)置->三角形遍歷->片元著色器->逐片元操作四個(gè)步驟。渲染流水線重點(diǎn)強(qiáng)調(diào)的和CPU的指令流水線并不同。它實(shí)際不是流水線,不同階段運(yùn)行的是同一次Draw Call(Draw Call指令是由CPU發(fā)出的),但一次Draw Call中先提交的數(shù)據(jù)可以不等待它之后的數(shù)據(jù)就進(jìn)入下一個(gè)流水線階段。
頂點(diǎn)渲染單元(也叫頂點(diǎn)著色或頂點(diǎn)著色引擎),主要負(fù)責(zé)描繪圖形,也就是建立模型。一個(gè)就是像素渲染管線(也叫像素渲染管道),主要負(fù)責(zé)把頂點(diǎn)繪出的圖形填上顏色。然后再加上紋理貼圖單元貼上紋理,一個(gè)精美的圖形就出來了。在微軟的DIRECTX10出來后,頂點(diǎn)渲染和像素渲染將淡出我們的視線,因?yàn)樗鼘⒉捎媒y(tǒng)一架構(gòu)。也就是一個(gè)核心中是由一組專門的通道既負(fù)責(zé)頂點(diǎn)渲染又負(fù)責(zé)像素渲染的。不過道理還是一樣的。
這就引出了GPU的兩個(gè)關(guān)鍵參數(shù)像素填充率和紋理填充率。當(dāng)然是越高越好,這樣顯示圖像幀率高且更細(xì)膩,分辨率更高。 像素填充率=顯卡的顯示核心頻率乘以像素渲染管線(即光柵單元)數(shù)量。單位是GB Pixel/s
紋理填充率=核心頻率乘以像素渲染管線數(shù)量再乘以紋理貼圖單元數(shù)量。單位是GB texture/s
GPU的CPU開銷即Draw Call驅(qū)動(dòng)開銷
長(zhǎng)久以來人們都覺得ARM的GPU即MALI效果不如高通的Adreno,實(shí)際單論像素填充率和紋理填充率,MALI更強(qiáng),但ARM的缺點(diǎn)就是Draw Call驅(qū)動(dòng)開銷太高。調(diào)用一次圖像編程接口(圖形API),以命令GPU進(jìn)行渲染的過程就稱為一次Draw Call,圖像編程接口(圖形API),是對(duì)GPU硬件的抽象,其地位類似C語言,屬于GPU編程的中低層。幾乎所有GPU都既可以和OpenGL合作也可以和DirectX合作。OpenGL是純粹的圖形API;DirectX是多種API的集合體,其中DirectX包含圖形API——Direct3D和Direct2D。DirectX支持Windows和Xbox;OpenGL支持Windows、MacOS、Linux等更多平臺(tái),在Android、iOS上允許使用OpenGL的簡(jiǎn)化版本OpenGL ES。OpenGL相對(duì)來說易上手,門檻低;DirectX難上手,門檻高。OpenGL渲染效率相對(duì)低,特性少;DirectX相對(duì)效率高,特性多。如DirectX12提供了底層API,允許用戶一定程度上繞過顯卡驅(qū)動(dòng)之間操縱底層硬件。
對(duì)于圖像生成的應(yīng)用,第一步,CPU把一個(gè)網(wǎng)格的頂點(diǎn)數(shù)據(jù)從硬盤中加載到內(nèi)存中(存在這一步的原因是大規(guī)模3D渲染中內(nèi)存可能不足)。
第二步,CPU對(duì)這個(gè)網(wǎng)格設(shè)置渲染狀態(tài)(每個(gè)網(wǎng)格不等于每個(gè)模型/圖片,因?yàn)榇嬖谂幚?。所謂渲染狀態(tài)包括紋理貼圖、材質(zhì)屬性和被編譯為二進(jìn)制文件的著色器。隨著渲染狀態(tài)一起被傳遞到GPU的還有光照和攝像機(jī)相關(guān)的信息。圖形API可以更深層次的定義渲染狀態(tài)需要的數(shù)據(jù)。
第三步,CPU將網(wǎng)格頂點(diǎn)數(shù)據(jù)與渲染狀態(tài)打包,將數(shù)據(jù)包按照指定格式交給DMA,由DMA將數(shù)據(jù)包傳入顯卡。DMA (Direct Memory Access,內(nèi)存直接訪問)。 指令到達(dá)GPU驅(qū)動(dòng)程序后,驅(qū)動(dòng)會(huì)首先檢查指令的合法性,如果指令非法,驅(qū)動(dòng)會(huì)通過DMA向CPU發(fā)送錯(cuò)誤信息。如果指令合法,驅(qū)動(dòng)通過DMA確認(rèn)Draw Call接收,然后將指令放入GPU緩沖。 一段時(shí)間后當(dāng)顯卡中存在空閑流水線,或者CPU顯式發(fā)送flush命令后,驅(qū)動(dòng)程序把緩沖區(qū)中的一份指令發(fā)送給GPU,GPU通過主機(jī)接口接受命令,并開始處理命令。
GPU將所有頂點(diǎn)存入頂點(diǎn)緩沖區(qū)(Vertex Buffer),GPU中的“圖元分配器(Primitive Distributer)”開始通過頂點(diǎn)生成三角形,并將他們分成批次(batch),發(fā)送給一個(gè)或多個(gè)GPCs,如果顯卡不存在GPCs,則直接分發(fā)給SMs。SM獲得數(shù)據(jù)后,束管理器安排多邊形引擎將三角形數(shù)據(jù)提取出來存入SM的L1緩存,隨后開始頂點(diǎn)著色器階段。
GPU會(huì)依次處理緩存中的每一個(gè)網(wǎng)格,網(wǎng)格的處理順序與CPU的提交順序有關(guān)。正因如此,CPU總是最后提交透明物體。等一幀中的所有Draw Call處理完畢后,顯示器才會(huì)將圖像打印在屏幕上。
Draw Call的性能瓶頸是CPU而非GPU。CPU每進(jìn)行一次Draw Call,都要調(diào)用一次DMA將數(shù)據(jù)輸入顯存。在每次調(diào)用時(shí),對(duì)顯存的映射尋址、DMA控制塊的注入、等待DMA響應(yīng)等系統(tǒng)消耗都會(huì)浪費(fèi)時(shí)間周期,多次進(jìn)行Draw Call就會(huì)有多次消耗。同時(shí),DMA擅長(zhǎng)一次傳輸大量數(shù)據(jù),而不擅長(zhǎng)多次傳輸少量數(shù)據(jù)。這使得降低Draw Call對(duì)于優(yōu)化顯示性能很有必要。
ARM MALI系列GPU
ARM的GPU設(shè)計(jì)項(xiàng)目最早從上個(gè)世紀(jì)90年代末期開始,由挪威科技大學(xué)開始開展,隨后在2001年,這個(gè)項(xiàng)目的Mali小組成員從研究中脫離出來,成立了一個(gè)名為Falanx Microsystems的公司。Falanx公司的人員剛開始瞄準(zhǔn)的是PC圖形市場(chǎng),但當(dāng)時(shí)已是后3DFX時(shí)代,群雄并起,包括S3、Rendition、Revolution以及Imagination等公司最后都失敗了,最終Falanx無法籌集到足夠的資金,被迫放棄了PC圖形市場(chǎng)。
在那個(gè)“緊迫期”,由于資金有限和PC圖形硬件極高的研發(fā)成本,F(xiàn)alanx最終決定轉(zhuǎn)向移動(dòng)SoC GPU設(shè)計(jì)。因?yàn)橐苿?dòng)GPU設(shè)計(jì)更簡(jiǎn)單且較容易成功。Falanx的產(chǎn)品Mali GPU也迎來了他們的第一個(gè)客戶—美國(guó)Zoran公司,使用了Mali-55作為他們Approach 5C SoC芯片的GPU,這顆芯片還被用在LG's Viewty這樣廣受歡迎的手機(jī)產(chǎn)品中。即使如此,F(xiàn)alanx還不滿足,最終在2006年迎來了他們的“大魚”。鑒于SoC市場(chǎng)持續(xù)增長(zhǎng)以及將帶來的移動(dòng)計(jì)算大潮,ARM公司終于決定買下Falanx,組建自己的GPU事業(yè)部,并聯(lián)合ARM的CPU一起推動(dòng)整個(gè)產(chǎn)業(yè)的增長(zhǎng)。ARM作為一個(gè)處于上升期、資金充裕的公司,完全有能力給Falanx充足的資金和研發(fā)資源來實(shí)現(xiàn)夢(mèng)想。
ARM第一代微架構(gòu)Utgard(北歐神話人物:烏特加德)。這一代架構(gòu)出來的比較早,主要是圖形加速IP??梢宰匪莸?007年的Mali-200。不過最讓人驚訝的是Mali-4xx系列,現(xiàn)在很多電視芯片都還在用這個(gè)IP。比如小米的智能電視,還有很多是Mali-4xx系列的。第二代微架構(gòu)Midgard(北歐神話人物:米德加德)。Midgard這一代GPU開始屬于同一著色器的架構(gòu),也就是上面說的vertex shader和fragment shader已經(jīng)統(tǒng)一在一起了,相當(dāng)于同一個(gè)shader計(jì)算單元可以處理多種著色器。當(dāng)然也開始支持通用計(jì)算。特別是對(duì)OpenCL的支持。第三代微架構(gòu)Bifrost(北歐神話中連接天宮和大地的:彩虹橋)。第四代微架構(gòu)Valhall(北歐神話中的瓦爾哈拉神殿,是戰(zhàn)死的勇士死后進(jìn)入奧丁神的神殿)是2019年第二季度推出來的。該系列是基于超標(biāo)量實(shí)現(xiàn)的。
常見高通與ARM MALI GPU參數(shù)對(duì)比
資料來源:互聯(lián)網(wǎng)
ARM MALI-G710
目前ARM最新的GPU為G710,ARM的架構(gòu)變動(dòng)比較頻繁。G710可能是ARM最成功的GPU架構(gòu),采用4納米制造工藝。 與英偉達(dá)桌面級(jí)GPU比,ARM的架構(gòu)差異比較大,ARM采用大核設(shè)計(jì),一般寫為MALI G710 MPX或MCX,X代表核心數(shù),MALI的核心就是渲染核即Shader Core,可以近似于英偉達(dá)的SM流多處理器。渲染核里有執(zhí)行引擎,可以算是CPU領(lǐng)域的ALU。
MALIG710渲染核
圖片來源:互聯(lián)網(wǎng)
早期ARM是SIMD設(shè)計(jì),近期變?yōu)镚PU常用的SIMT。G710的執(zhí)行引擎比G77翻倍,有兩個(gè)執(zhí)行引擎,每個(gè)執(zhí)行引擎包含兩個(gè)簇,執(zhí)行16位寬的線程,等于是64個(gè)ALU,G710支持7-16核設(shè)計(jì),也就是最高1024個(gè)ALU。
MALIG710執(zhí)行引擎
圖片來源:互聯(lián)網(wǎng)
G710的執(zhí)行核,前端沒有透露具體信息,應(yīng)該與G77一樣,是64個(gè)warp或1024個(gè)線程。每個(gè)處理單元都有三個(gè)ALU:FMA(混合的乘積累加計(jì)算)和CVT(Convert)單元是16-wide,而SFU(特殊功能單元)是4-wide。每個(gè)FMA每周期可以做16次運(yùn)算,運(yùn)算數(shù)據(jù)精度為FP32,換成FP16就是32次,8位整數(shù)INT8就是64次,像英偉達(dá)的桌面級(jí)GPU,F(xiàn)P16和FP32是分開計(jì)算的,也就是說可以同時(shí)計(jì)算,但移動(dòng)級(jí)的MALI不需要這樣設(shè)計(jì)。Convert單元處理基本整數(shù)操作和自然類型轉(zhuǎn)換操作,并充當(dāng)分支端口。
MALI-G77的渲染核
圖片來源:互聯(lián)網(wǎng)
圖片來源:互聯(lián)網(wǎng)
ARM MALI GPUCSF
G710最大的變化,添加了CSF。G710首次將Mali的Job Manager換成了所謂的Command Stream Frontend。這個(gè)CSF負(fù)責(zé)處理調(diào)度和draw call,CSF這個(gè)模塊由CPU、HW和固件構(gòu)成。ARM表示,HW本身是全新設(shè)計(jì)的;而固件層的引入,能夠針對(duì)一些比較復(fù)雜的圖形負(fù)載提供更具彈性的性能,而且能夠減少驅(qū)動(dòng)開銷、提升效率;對(duì)諸如Vulkan等API提供更簡(jiǎn)捷的支持等。固件處理來自host的請(qǐng)求和通知,負(fù)責(zé)硬件資源調(diào)度,減少諸如protected mode進(jìn)出的開銷,還能通過指令模擬來提供硬件原本不具備的特性。