王 欣 王 寧
[摘要]簡要介紹GPU的存儲結(jié)構(gòu),它是基于GPU的CUDA編程的前提和基礎(chǔ)。
[關(guān)鍵詞]GPGPUGPUCUDA
中圖分類號:TP3文獻(xiàn)標(biāo)識碼:A文章編號:1671-7597(2009)0820030-01
一、引言
現(xiàn)代的顯示芯片已經(jīng)具有高度的可程序化能力,由于顯示芯片通常具有相當(dāng)高的內(nèi)存帶寬,以及大量的執(zhí)行單元,因此開始有利用顯示芯片來幫助進(jìn)行一些計算工作的想法,即GPGPU(General-Purpose Compution on Graphics Processing Units)。CUDA即是NVIDIA的GPGPU模型。
二、GPU簡介
作為圖形處理芯片市場的領(lǐng)先者,NVIDIA公司在GPGPU領(lǐng)域投入大量研究力量,并于2006年底成功推出支持通用計算的G80架構(gòu)圖形處理器芯片[1],在市場上大獲成功。在此基礎(chǔ)上,NVIDIA公司于2007年和2008年陸續(xù)推出G92、GT200架構(gòu)。憑借CUDA并行編程平臺良好的用戶接受度,GT系列架構(gòu)的圖形處理器逐漸在高性能計算領(lǐng)域占有一席之地。
與Intel和AMD(ATI)不同,NVIDIA傾向于采用標(biāo)量處理單元來實現(xiàn)向量計算。在GT系列架構(gòu)的圖形處理器芯片中,多個簡單的標(biāo)量流處理器核心組合在一起形成流式多核處理器。多個流處理器核心執(zhí)行相同指令時構(gòu)成SIMD,從而較好支持向量計算。流處理器陣列由多個流式多核處理器組成,且多核處理器數(shù)目具有可擴(kuò)展性。
三、GPU的存儲結(jié)構(gòu)
所有目前支持CUDA的NVIDIA顯示芯片,其shader部份都是由多個multiprocessors組成。每個multiprocessor里包含了八個stream process
ors,其組成是四個一組,也就是說實際上可以看成是有兩組4D的SIMD處理器。此外,每個multiprocessor還具有8192個寄存器,16KB的share memory,以及texture cache和constant cache。
(一)GPU的執(zhí)行過程。在執(zhí)行CUDA程序的時候,每個stream processor對應(yīng)一個thread。每個multiprocessor則對應(yīng)一個block。但是thread卻可以遠(yuǎn)超sp的數(shù)目。
實際上,雖然一個mp只有八個sp,但是由于stream processor進(jìn)行各種運算都有l(wèi)atency,更不用提內(nèi)存存取的latency,因此CUDA在執(zhí)行程序的時候,是以warp為單位。目前的CUDA裝置,一個warp里面有32個threads,分成兩組16 threads 的 half-warp。由于stream processor的運算至少有4 cycles的latency,因此對一個4D的stream processors來說,一次至少執(zhí)行16個threads(即half-warp)才能有效隱藏各種運算的latency。
(二)Shared Memory。目前CUDA裝置中,每個multiprocessor有16KB的shared memory。Shared memory分成16個bank(存儲體)。如果同時每個thread是存取不同的bank,就不會產(chǎn)生任何問題,存取shared memory的速度和存取寄存器相同。不過,如果同時有兩個(或更多個)threads存取同一個bank的數(shù)據(jù),就會發(fā)生bank conflict[2],這些threads就必須照順序去存取,而無法同時存取shared memory了。
Shared memory是以4 bytes為單位分成banks。因此,假設(shè)以下的數(shù)據(jù):
那么,data[0]是bank 0、data[1]是bank 1、data[2]是bank 2、…、data[15]是bank 15,而data[16]又回到bank 0。由于warp在執(zhí)行時是以half-warp的方式執(zhí)行,因此分屬于不同的halfwarp的threads,不會造成bank conflict。
因此,如果程序在存取shared memory的時候,使用以下的方式:
int number=data[base+tid];
那就不會有任何bank conflict,可以達(dá)到最高的效率。但是,如果是以下的方式:
int number=data[base+4*tid];
那么,thread 0和thread 4就會存取到同一個bank,thread 1和thread 5也是同樣,這樣就會造成bank conflict。
(三)Global Memory。由于multiprocessor對global memory存取的latency非常的長,所以為了提高效率,global memory的存取,需要"coalesced"。所謂的coalesced,是表示讀取除了連續(xù)之外,而且它開始的地址,必須是每個thread所存取的大小的16倍。例如,如果每個thread都讀取32bits的數(shù)據(jù),那么第一個thread讀取的地址,必須是16*4=64bytes的倍數(shù)。
在目前的CUDA 2.0裝置中,每個thread一次讀取的內(nèi)存數(shù)據(jù)量,可以是32 bits、64 bits、或128 bits。不過,32 bits的效率是最好的。64 bits的效率會稍差,而一次讀取128 bits的效率則比一次讀取32 bits要顯著來得低(但仍比non-coalesced的存取要好)。
(四)Texture。CUDA支持texture。在CUDA的kernel程序中,可以利用顯示芯片的texture單元,讀取texture的數(shù)據(jù)。使用texture和global memory最大的差別在于texture只能讀取,不能寫入,而且顯示芯片上有一定大小的texture cache。因此,讀取texture的時候,不需要符合coalesced的規(guī)則,也可以達(dá)到不錯的效率。此外,讀取texture時,也可以利用顯示芯片中的texture filtering功能(例如bilinear filtering),也可以快速轉(zhuǎn)換數(shù)據(jù)型態(tài),例如可以直接將32 bits RGBA的數(shù)據(jù)轉(zhuǎn)換成四個32 bits浮點數(shù)。
顯示芯片上的texture cache是針對一般繪圖應(yīng)用所設(shè)計,因此它仍最適合有區(qū)塊性質(zhì)的存取動作,而非隨機(jī)的存取。因此,同一個warp中的各個thread最好是讀取地址相近的數(shù)據(jù),才能達(dá)到最高的效率。
對于已經(jīng)能符合coalesced規(guī)則的數(shù)據(jù),使用global memory通常會比使用texture要來得快。
四、總結(jié)
GPU是未來眾核技術(shù)發(fā)展的方向之一,在并行化計算領(lǐng)域具有廣闊的前景。本文總結(jié)了GPU的存儲結(jié)構(gòu),以及相關(guān)的注意事項,它是CUDA編程的基礎(chǔ),對理解GPU的硬件結(jié)構(gòu)也十分重要。
參考文獻(xiàn):
[1]Eric Lindholm,John Nickolls,etc.NVIDIA Tesla:A Unified Graphics And Computing Architecture,IEEE Micro,v.28 n.2,pp.39-55,Mar/Apr.2008.
[2]CUDA Programming Guide 2.0,NVIDI [C].2008.http://developer.
Download.nvidia.com/compute/cuda/2_0/docs/NVIDIA_CUDA_Programming_Guide_2.0.pdf.
作者簡介:
王欣(1975-),女,河北人,碩士,講師,研究方向:計算機(jī)網(wǎng)絡(luò)。