CUDA儲存器組織

yyfn風辰發表於2010-02-07
Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONECUDA的儲存器由一系列不同的地址空間組成。其中,shared memoryregister位於GPU片內,Texture memoryConstant memory可以由GPU片內快取加速對片外視訊記憶體的訪問,而Local memoryDevice memory位於GPU片外的視訊記憶體中。 Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE

最靠近流處理器的是暫存器檔案(register file),每個暫存器檔案是32bit。對執行緒來說,暫存器都是私有的,不允許其它執行緒染指。由於更靠近流處理器,暫存器具有最快的速度,GT200的每個SM擁有64KB的暫存器檔案(Register Files),故一個塊內最多可分配16K個暫存器,而G80中每個SM只有32KB,故一個塊最多可分配8K個暫存器。最新加入的64bit資料型別(雙精度浮點和64位整數型)將佔用兩個相鄰的暫存器單元。CUDA的執行環境能夠動態的為執行緒塊分配暫存器,而每個執行緒塊中的執行緒佔用的暫存器大小則是靜態分配的,線上程塊壽命期間都不會更改,因此一個執行緒佔用的暫存器數目是它在執行時佔用的最大數目。如果暫存器被消耗完,資料將被儲存在本地儲存器(local memory)。對每個執行緒來說,本地儲存器也是私有的,但是本地儲存器是視訊記憶體中的一個分割槽,速度很慢,而且使用本地儲存器過多的話,程式也會終止,因此,程式設計時要儘量保證不能將資料放到本地儲存器中,這可以通過修改塊大小,使用共享儲存器等方法來解決。

共享儲存器是可以被同一塊中的所有執行緒訪問的可讀寫儲存器,它的生存期就是塊的生命期。在沒有衝突的情況下,訪問共享儲存器幾乎與訪問暫存器一樣快,是實現執行緒間通訊的最好方法。共享儲存器可以實現許多不同的功能,如用於儲存共用的計數器或者塊內的公用結果(例如reduction)。在同一個塊內,所有的執行緒都能夠讀寫共享儲存器中的資料,相比於AMD的顯示卡來說,共享儲存器是NVIDIA顯示卡的一項特色。一般而言,在kernel執行時,要先將資料從全域性儲存器寫入共享儲存器;計算完成後要將共享儲存器中的結果轉存入全域性儲存器。

Tesla的每個SM擁有16KB共享儲存器,用於同一個執行緒塊內的執行緒間通訊。為了使一個half-warp內的執行緒能夠在一個核心週期中並行訪問,共享儲存器被組織成16bank,每個bank擁有32bit的寬度,故每個bank可儲存256個整形或單精度浮點數,或者說目前的bank組織成了25616列的矩陣。如果一個half-warp中有一部分執行緒訪問屬於同一bank的資料,則會產生bank conflict,降低訪存效率,在衝突最嚴重的情況下,速度會比全域性視訊記憶體還慢,但是如果half-warp的執行緒訪問同一地址的時候,會產生一次廣播,其速度反而沒有下降。在不發生bank conflict時,訪問共享儲存器的速度與暫存器相同。在不同的塊之間,共享儲存器是毫不相關的。 Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE

在實現中,GPU要把視訊記憶體中的資料寫到共享儲存器中,必須先把資料寫到暫存器裡,再轉移到共享儲存器中,在程式設計時,這是隱式實現的。所以如果沒有塊內的資料共享千萬不能用共享儲存器,否則會降低速度。但是如果由於暫存器使用過量,那麼我們可以使用共享儲存器來當暫存器使用,此時比純使用暫存器慢一點,但是是值得的。

Tesla能夠在共享儲存器內進行高速的原子操作。這裡的原子操作是指保證每個執行緒能夠獨佔的訪問儲存器,即只有當一個執行緒完成對儲存器的某個位置的操作以後,其他執行緒才能訪問這一位置。G80只支援對global memory的原子操作。訪問global memory需要很長的訪存延遲(長達數百個時鐘週期),效能很低。在GT200及以後的GPU上,可以支援對shared memory中的原子操作指令(其中包括CAS指令,並且支援64位)。但是,CUDA並不提供對浮點數的原子操作(只有一個賦值的浮點原子指令),而在科學計算中,浮點數的使用遠比整數要多,而且在Fermi的特性列表中,也沒有看到加入浮點原子指令的資訊,這不能不說是一個遺憾。 Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE

除此以外,多處理器上,還有兩種只讀的儲存器:常數儲存器(constant memory)和紋理儲存器(texture memory),它們是利用GPU用於圖形計算的專用單元實現的。常數儲存器空間較小(只有64KB),屬於片外儲存器,其速度比shared要慢,但是它具有快取,並且無須考慮衝突問題,主要用來加速對常數的訪問。

從物理上說,紋理儲存器不是儲存器,它只是利用了紋理快取而已。紋理快取與CPU的快取有很大的不同。首先,CPU的快取往往是一維的,因為大多數的架構中的儲存器地址是線性的。當訪問一個只有4-8Byte的資料字時,會取出一個快取單元中所有的64B資料。根據區域性性原理,CPU處理的資料往往有很強的時空相關性,因此多取出的相鄰的資料極有可能會被用到。CPU處理的資料只有一維,因而其快取也只是在一個維度上是連續的;GPU需要處理的紋理則是連續的二維影像,因此紋理快取也必須是在兩個維度上連續分佈的。典型的儲存器控制器會將二維的紋理儲存器空間對映為一維。其次,紋理快取是隻讀的,也不滿足資料一致性。當紋理被修改以後,必須更新整個紋理快取,而不是紋理快取中被修改的一小部分。第三,紋理快取的主要功能是為了節省頻寬和功耗,而CPU的快取則是為了實現較低的延遲。第四,紋理可以實現對資料的特殊處理,比如怎樣處理越界資料,自動實現插值等。

最後是全域性儲存器(global memory),使用的是普通的視訊記憶體。整個網格中的任意執行緒都能讀寫全域性儲存器的任意位置。目前對Global memory的訪問沒有快取,因此視訊記憶體的效能對GPU至關重要。為了能夠高效的訪問視訊記憶體,讀取和儲存必須對齊,寬度為4Byte。如果沒有正確的對齊,讀寫將被編譯器拆分為多次操作,極大的影響效率。此外,多個half-warp的讀寫操作如果能夠滿足合併訪問(coalesced access),那麼多次訪存操作會被合併成一次完成,從而提高訪問效率。

G80的合併訪存條件十分嚴格。首先,訪存的開始地址必須對齊:16x32bit的合併必須對齊到64Byte(即訪存起始地址必須是64Byte的整數倍);16x64bit的合併訪存起始必須對齊到128Byte16x128bit合併訪存的起始地址必須對齊到128Byte,但是必須橫跨連續的兩個128Byte區域。其次,只有當第K個執行緒訪問的就是第K個資料字時,才能實現合併訪問,否則half warp中的16個訪存指令就會被髮射成16次單獨的訪存。

GT200不僅放寬了合併訪問條件,而且還能支援對8bit16bit資料字的合併訪問(分別使用32Byte64Byte傳輸)。在一次合併傳輸的資料中,並不要求執行緒編號和訪問的資料字編號相同。其次,當訪問128Byte資料時如果地址沒有對齊到128Byte,在G80中會產生16次訪存指令發射,而在GT200中只會產生兩次合併訪存。而且,這兩次合併訪存並不是兩次128Byte的。例如,一次128Byte訪存中有32Byte在一個區域中,另外一個區域中有96Byte,那麼只會產生一次32Byte合併訪存(對有32Byte資料的區域)和一次128Byte(對有96Byte資料的區域)。 Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE

除了device端儲存器外,還有存在於host端的儲存器,即記憶體。在CUDA中,主機端記憶體分為兩種:Pageable host memoryPage-locked host memory,其中Page-locked host memory保證位在於實體記憶體中,並且能夠通過DMA加速與顯示卡的通訊,提高資料傳輸速度,但是如果主機的記憶體不夠用的話,會減弱系統的效能,但是一般不會出現這種情況。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23057064/viewspace-626987/,如需轉載,請註明出處,否則將追究法律責任。

相關文章