1. 程式人生 > 其它 >第3章-圖形處理單元-3.1-資料並行架構

第3章-圖形處理單元-3.1-資料並行架構

《實時渲染》第四版中翻:3.1-資料並行架構。

3.1 資料並行架構

不同的處理器架構使用各種策略來避免延遲。CPU經過優化,可以處理各種資料結構和大型程式碼庫。CPU可以有多個處理器,但每個處理器都以序列方式執行程式碼,有限的SIMD向量處理是次要的例外。為了儘量減少延遲的影響,CPU的大部分晶片都由快速本地快取組成,記憶體中充滿了接下來可能需要的資料。CPU還通過使用智慧的技術來避免延遲,例如分支預測、指令重新排序、暫存器重新命名和快取預取[715]。

GPU採取不同的方法。GPU的大部分晶片區域專用於大量處理器,稱為著色器核心,通常數量以千計。GPU是一個流處理器,依次處理有序的相似資料集。由於這種相似性——例如一組頂點或畫素——GPU可以以大規模並行的方式處理這些資料。另一個重要元素是這些調用盡可能獨立,這樣它們就不需要來自相鄰呼叫的資訊,也不共享可寫的記憶體位置。這條規則有時會被打破以允許新的和有用的功能,但這種例外是以潛在的延遲為代價的,因為一個處理器可能會等待另一個處理器完成它的工作。

GPU針對吞吐量進行了優化,吞吐量定義為可以處理資料的最大速率。然而,這種快速處理是有代價的。由於專用於快取記憶體和控制邏輯的芯片面積較少,每個著色器核心的延遲通常比CPU處理器遇到的延遲要高得多[462]。

假設一個網格被光柵化,存在兩千個畫素有要處理的片元;一個畫素著色器程式將被呼叫兩千次。想象一下,只有一個著色器處理器,這是世界上最弱的GPU。它開始為兩千個片段中的第一個片元執行著色器程式。著色器處理器對暫存器中的值執行一些算術運算。暫存器是本地的並且可以快速訪問,因此不會發生延遲。然後著色器處理器接受了一條比如紋理訪問的指令;一個例子是,對於給定的表面位置,程式需要知道應用於網格的影象的畫素顏色。紋理是一個完全獨立的資源,不是畫素程式本地記憶體的一部分,紋理訪問可能會在一定程度上非常耗時。一次記憶體獲取可能需要數百到數千個時鐘週期,在此期間GPU處理器什麼也不做。此時著色器處理器將停止,等待返回紋理的顏色值。

為了讓這個糟糕的GPU變得更好,給每個片元一個小的儲存空間來存放它的本地暫存器。現在,著色器處理器不再停留在紋理獲取上,而是允許切換並執行另一個片段,即2000箇中的第二個片段。這個切換非常快,第一個或第二個片段中的任何東西都不會受到影響,除了注意哪個指令在第一個上執行。現在執行第二個片段。與第一個相同,執行一些算術函式,然後再次遇到紋理提取。著色器核心現在切換到另一個片段,第三個。最終所有兩千個片段都以這種方式處理。此時,著色器處理器返回到第一個片段。此時紋理顏色已被獲取並可使用,因此著色器程式可以繼續執行。處理器以相同的方式繼續執行,直到遇到另一條已知會暫停執行的指令,或者程式完成。單個片段的執行時間比著色器處理器專注於它的時間長,但片段的總體執行時間為整體大幅減少。

在這種架構中,通過切換到另一個片元讓GPU保持忙碌,從而隱藏了延遲。GPU通過將指令執行邏輯與資料分離,使這種設計更進一步。這種設計方式被稱為單指令多資料(SIMD),能夠在固定數量的著色器程式上以鎖步方式執行相同的命令。SIMD的優勢在於,與使用單獨的邏輯和排程單元來執行每個程式相比,處理資料和交換所需的矽(和功率)要少得多。將我們的兩千個片元示例轉換為現代GPU術語,片元的每個畫素著色器呼叫稱為執行緒。這種型別的執行緒與CPU執行緒不同。它包含一些用於著色器輸入值的記憶體,以及著色器執行所需的任何暫存器空間。使用相同著色器程式的執行緒被捆綁成組,NVIDIA稱為warp,AMD稱為wavefront。一個warp/wavefront被安排由一些GPU著色器核心執行,數量從8到64都行,使用SIMD處理。每個執行緒都對映到一個SIMD通道。

假設我們有兩千個執行緒要執行。NVIDIA GPU上的warp包含32個執行緒。這產生了\(2000/32=62.5\)個warp,這意味著分配了63個warp,其中一個warp是半空的。warp的執行類似於我們的單GPU處理器示例。著色器程式在所有32個處理器上以鎖步方式執行。當進行記憶體讀取時,所有執行緒都會同時遇到它,因為對所有執行緒執行相同的指令。通常讀取操作意味著這個執行緒warp將停止,所有執行緒都在等待它們的(不同的)結果。但是在GPU中卻不會停頓,而是將warp交換為32個執行緒的不同warp,然後由32個核心執行。

這種交換與我們的單處理器系統一樣快,因為在換入或換出warp時不會觸及每個執行緒中的資料。每個執行緒都有自己的暫存器,每個warp都會跟蹤它正在執行的指令。交換新的warp只是將一組核心指向一組不同的執行緒來執行;沒有其他開銷。如此warp執行或換出,直到所有工作完成。見圖3.1。

圖3.1. 簡化的著色器執行示例。三角形的片元,稱為執行緒,組合成warp。每個warp顯示為四個執行緒,但實際上有32個執行緒。要執行的著色器程式有5條指令長。四個GPU著色器處理器的集合為第一個warp執行這些指令,直到在“txr”命令上檢測到停頓條件,這需要時間來獲取其資料。第二個warp被換入並應用著色器程式的前三個指令,直到再次檢測到停頓。在第三個warp被換入並停止後,通過交換第一個warp並繼續執行來繼續執行。如果此時其“txr”命令的資料尚未返回,則執行將真正停止,直到這些資料可用。每個warp依次完成。

在我們的簡單示例中,紋理的記憶體獲取延遲可能會導致warp被換出。實際上,遇到更短的延遲時都可以將warp換出,因為交換的成本非常低。還有其他幾種技術用於優化執行[945],但warp交換是所有GPU使用的主要延遲隱藏機制。這個過程的工作效率涉及幾個因素。例如,如果執行緒很少,則可以建立很少的warp,從而使延遲隱藏成為問題。

著色器程式的結構是影響效率的重要特徵。一個主要因素是每個執行緒的暫存器使用量。在我們的示例中,我們假設2000個執行緒可以同時駐留在GPU上。與每個執行緒相關聯的著色器程式所需的暫存器越多,GPU中的執行緒就越少,因此warp也就越少。warp不足可能意味著無法通過交換來緩解卡頓。常駐的warp被稱為“飛行中”,這個數字被稱為佔用率。高佔用率意味著有許多warp可用於處理,因此空閒處理器的可能性較小。低佔用率通常會導致效能不佳。記憶體獲取的頻率也會影響需要多少延遲隱藏。Lauritzen在文獻[993]中概述了佔用率如何受暫存器數量和著色器使用的共享記憶體的影響。Wronski在文獻[1911, 1914]中討論了理想的佔用率如何根據著色器執行的操作型別而變化。

另一個影響整體效率的因素是由“if”語句和迴圈引起的動態分支。假設在著色器程式中遇到“if”語句。如果所有執行緒都評估並採用相同的分支,則warp可以繼續而無需擔心其他分支。然而,如果一些執行緒,甚至一個執行緒,採用備用路徑,那麼warp必須執行兩個分支,丟棄每個特定執行緒不需要的結果[530, 945]。這個問題稱為執行緒發散,其中一些執行緒可能需要執行迴圈迭代或執行warp中的其他執行緒不需要的“if”路徑,從而使它們在此期間處於空閒狀態。

所有GPU都實現了這些架構理念,從而導致系統具有嚴格的限制,但每功率的計算能力卻非常龐大。瞭解該系統的執行方式將幫助你作為程式設計師更有效地利用它提供的功能。在接下來的部分中,我們將討論GPU如何實現渲染管道、可程式設計著色器如何操作以及每個GPU階段的演變和功能。