這部分主要以Integrated GPU為例子,介紹一下它們的儲存系統。目前我能找到的公開資料包括Intel Iris系列的Integrated GPU,以及ARM的Mali GPU。

正如上一篇文章所介紹的,在Integrated GPU中,GPU一般和CPU共享相同的物理儲存。GPU自己的local memory實際上是從CPU的main memory中分配出來一塊物理連續的空間來模擬的,即所謂的Unified Memory Architecture模型。注意即使在Unified Memory Architecture,Address也並非是Unified的,GPU和CPU用的地址也不一定位於一個地址空間內。

以下是Intel Gen9的SOC結構示意圖:

GPU儲存體系-Integrated GPU

Intel i7 6700K SOC結構示意圖,來源Intel公開資料,版權歸Intel所有

從這幅圖可以看出,Intel的GPU和CPU core之間透過一個叫SoC Ring Interconnect的匯流排進行互聯,並且連線到System Agent上。System Agent負責儲存訪問等。所以很明顯的一個事實就是,GPU實質上是和CPU共享相同的儲存訪問介面的。GPU和CPU共享儲存為硬體設計帶來了很多便利,然而付出的代價卻十分昂貴。接下來我們會用一個非常粗糙的例子來看看,到底是什麼導致了“核顯效能不強”這個常識的。

假如我們外接兩個2400MHz的DDR4 DRAM組成雙通道,每個DDR4頻寬是64b,那麼這個儲存系統所能提供的最大資料頻寬就是2400MHz * 64b * 2 ,峰值頻寬大概是38。4GB/s。這麼多的頻寬需要在CPU和GPU之間進行共享的。Intel的文件描述其GPU的計算能力是384 FLOP/clock@32b, 如果這個GPU工作於400MHz,那麼餵飽這個GPU的資料頻寬就是384*4*400MHz,大概是614。4GB/s,剛好是我們上邊那個DDR4儲存系統能提供最大頻寬的16倍。從這個簡單的計算可以看出,制約Integrated GPU效能的從來不是其本身的計算能力,而是memory bandwidth。當然,這個計算是非常粗糙的,核顯效能不強,頻寬提供不夠是一方面,此外還有包括散熱(和CPU處於一個Die中),功耗,以及片內匯流排所能提供的資料頻寬的限制。經網友提示,這裡特意要說明一點,這裡的計算只是未考慮快取系統的情況下,一個非常粗略簡單的峰值頻寬估計,旨在用簡單明瞭的計算方法來澄清gpu運算峰值頻寬與儲存系統之間的巨大鴻溝。在實際應用中,除了極端情況,譬如做壓力測試,很少會有gpu頻寬佔滿的情況。快取系統的引入也有效地填補了這一鴻溝。本系列文章在後續會增加關於gpu快取系統的介紹,以期有所助益。網友的提示詳情可以參考評論區,歡迎大家相互交流。

上邊這個計算,其實隱含著一個非常重要的假設,就是CPU和GPU之間只能透過外部的DRAM共享資料。在這個假設的前提下,GPU需要使用資料,就只能辛辛苦苦從外部DRAM中搬到SOC上了。然而對於Integrated GPU而言,其本身和CPU處於一個die上,天然就可以做到資料在chip上的共享,沒有必要非要用那麼慢的外部DRAM的。這就涉及到GPU儲存體系中另外一個概念,Snoop。

我們首先回顧一下從GPU角度的儲存。對於GPU而言,它能用的儲存包括自己的local memory(實際上就是遠在DRAM地方分出來的一部分),以及一部分透過GART可以訪問的system memory(直接訪問CPU的物理地址空間)。對於local memory而言,其可以完全對映到CPU的地址空間,因此,CPU要透過local memory往GPU share資料是非常簡單的事情。然而local memory是global的,CPU上各自執行的process想要使用local memory來快速傳遞資料基本上是不可能的,畢竟這種global的resource應該由核心來管理。CPU上各自的process想要往GPU上upload資料,還得依靠GART才行。

GART的原理非常簡單,就是將GPU自己的地址空間的一個地址對映到CPU的地址空間。假設GPU的local有128MB,那麼可以建立一個簡單的對映表,當GPU訪問128M-256M的時候,將之對映到CPU地址空間內,一般是不連續的4kB或者64kB的page。這樣,CPU上的程序將資料填寫到自己分配的地址空間內,然後核心透過GART,將GPU的一段地址空間對映到之前CPU上程序寫的地址空間,這樣,GPU就可以用另一套地址空間來訪問相同的資料了。

透過GART來進行資料之間的互動,資料的終點仍然在DRAM裡,這樣無法充分發揮Integrated GPU與CPU處於一個DIE的事實的。我們在review一下如果一個程序想要向GPU upload資料的過程:CPU上的程序寫資料到物理頁面,並

通知CPU將對應物理頁面的快取清空

,然後CPU上的核心態分配GPU地址空間,填寫GART,並且build DMA buffer來啟動GPU。所以,如果GPU可以直接訪問CPU的快取體系的話,資料就不用去DRAM中繞一圈,直接在chip上就可以共享了。這種做法,就是Snoop機制。

以Intel的這個為例,當CPU寫資料的時候,將資料flush到LLC,因為從結構設計上,LLC在CPU和GPU之間是共享的,因此,GPU訪問資料就可以直接hit到CPU之前寫入的資料了,這個還不是Snoop機制。如果資料此時還沒有更新到LLC,非Snoop的訪問就無能為力了,此時,Snoop機制允許GPU的資料訪問去檢查CPU內部那些非共享的cache,來獲取最新的資料。

因此,在Integrated GPU訪問system memory的時候,可以選擇指定Snoop屬性,以決定是否去CPU的cache中查詢相關的資料。SNOOP雖然保證了資料的一致性(單向一致性),卻並非free,其最大的代價就是增加了設計的複雜性。對於Integrated GPU而言,需要協調匯流排,CPU核的設計,擁有這些能力的公司也為數不多。除了Intel以外,ARM也算是個中翹楚了。其他Integrated GPU的技術細節不甚瞭解,因此在此不敢妄議。

ARM體系透過CCI匯流排保證core之間的資料一致性,對於Mali GPU,則提供一個ACP(

Accelerator Coherency Port)

介面,實現了GPU觀測CPU的Snoop path。 從G71開始,新的Bifrost架構的GPU全部實現了ACE匯流排,這也就意味著ARM已經實現了CPU-GPU之間雙向的資料一致性。

GPU儲存體系-Integrated GPU

ARM最新架構Bifrost已經可以實現雙向一致性,圖來自網路,版權歸原作者所有

彙總一下,對於Integrated GPU而言,其local memory和CPU共享相同的儲存實體,是為UMA結構。CPU有能力直接訪問GPU全部的local memory。GPU透過GART能夠訪問到CPU地址空間的資料,並且可以透過Snoop屬性,來做到單向一致性(GPU觀測CPU資料)。Snoop並非毫無代價,其實現頗具複雜度。