第四篇:GPU 並行程式設計的儲存系統架構

穆晨發表於2017-01-18

前言

       在用 CUDA 對 GPU 進行並行程式設計的過程中,除了需要對執行緒架構要有深刻的認識外,也需要對儲存系統架構有深入的瞭解。

       這兩個部分是 GPU 程式設計中最為基礎,也是最為重要的部分,需要花時間去理解吸收,加深內功。 

瞭解 GPU 儲存系統架構的意義

       CUDA 程式設計架構的設計思路本身也就是讓程式設計師去使用快取,而不是讓快取像 CPU 程式設計結構那樣對程式設計師透明。

       通過對所使用儲存結構的優化,能夠讓程式的並行後的效果得到很大提高。

       因此,這個問題是需要我們在開發全程中考慮的。

第一層:暫存器

       每個流處理器中的暫存器數以千計,每個執行緒都能分配到其私有的暫存器,這樣做的好處是使得執行緒的切換幾乎是零開銷 (也許說是執行緒束的切換會更為準確)。

       應當在硬體條件允許的情況下,儘可能地使用暫存器 (注意是硬體條件的允許之下)。

       在核函式中定義的變數就是暫存器變數。

第二層:共享記憶體

       共享記憶體的本質是可受使用者控制的一級快取。每個 SM 中的一級快取與共享記憶體共享一個 64 KB的記憶體段。在費米架構中,可以為每個塊定義 16 KB的共享記憶體。靈活地使用共享記憶體,能夠大幅度提高視訊記憶體的頻寬。此外,共享記憶體也是實現塊內執行緒間通訊的有效工具。

       使用時需要注意的一個地方是,只有在確定需要重複利用此空間的資料,或者明確要使塊內執行緒進行通訊的前提下,才考慮使用共享記憶體。(原因不解釋)

       使用時需要注意的另一個地方是應當儘可能地避免儲存體衝突。這裡所謂的儲存體是指實現共享記憶體的硬體 - 一個費米架構的裝置上有 32 個儲存體。解決此問題的關鍵在於:順序訪問儲存體。

       實際開發中,常常將一個任務分解成多個部分(不論是任務分解還是資料分解),共享記憶體在其中扮演著任務塊工作任務彙總或者資料塊工作任務彙總的角色。

       核函式中定義的變數加上__shared__宣告後就會存放在共享記憶體中了。

第三層:常量記憶體

       常量記憶體其實只是全域性記憶體的一種虛擬地址形式,並沒有特殊保留的常量記憶體塊。

       使用起來非常方便,在主機端對需要放到常量記憶體區的變數新增 __constant__ 關鍵字宣告之即可。

       唯獨需要注意的是,如果一個常量僅僅是一個字面值,那麼將它宣告為巨集也行,例如 PI 這樣的常數就一般定義為巨集。

第四層:全域性記憶體

       全域性記憶體,也就是視訊記憶體。

       在主機端開闢的視訊記憶體空間均屬於全域性記憶體範疇。

       使用全域性記憶體的時候,需要注意的是應當學會對視訊記憶體採取合併的訪問方式。何謂合併的訪問方式呢?請參閱下篇文章。

相關文章