葉毅嘉
摘要:近年來,圖形處理器(Graphic Process Unit,GPU)的快速發(fā)展使得其逐步用于通用計算。在性能各異的并行計算平臺中,英偉達(NVIDIA)公司推出的計算統(tǒng)一設(shè)備架構(gòu)(compute Unified Device Architecture,CUDA)因為充分利用GPU(Graphic Processing Unit)強大的計算能力實現(xiàn)了通用并行計算而受到研究者們的青睞。
關(guān)鍵詞:圖形處理器;CUDA;并行處理
0 引言
CUDA(Compute Unified Device Architecture)模型是由英偉達(NVIDIA)公司推出的一種基于GPU通用計算的編程模型和計算體系。該架構(gòu)不需要借助圖像學(xué)API,直接使用類C語言即可完成并行計算,使得使用GPU處理圖像中的復(fù)雜計算成為可能。
1 CUDA編程模型
CUDA將CPU串行處理和GPU并行處理完美的結(jié)合起來。一個完整的CUDA程序是由主機(CPU)程序和設(shè)備(GPU)程序共同組成,主機程序主要是為設(shè)備程序的運行做前期準備工作,主要包括數(shù)據(jù)初始化、數(shù)據(jù)拷貝、內(nèi)核函數(shù)間數(shù)據(jù)交換等。而設(shè)備程序主要就是完成并行計算的任務(wù)。CUDA編程模型分為兩個主要部分:CUDA軟件架構(gòu)和CUDA硬件架構(gòu)。其中CUDA軟件架構(gòu)又包括了軟件棧、通用編程模型和存儲模型三個方面。下面將從上述內(nèi)容對CUDA的編程模型進行介紹。
1.1 軟件模型
根據(jù)NVIDIA的官方文檔,CUDA的軟件體系共分3個方面:CUDA設(shè)備驅(qū)動程序、CUDA運行時庫和編程接口、CUDA官方函數(shù)庫。其中,設(shè)備驅(qū)動器是直接作用于GPU上的,開發(fā)者可以通過CUDA運行時庫和CUDA函數(shù)庫中的函數(shù)調(diào)用來使用設(shè)備。CUDA編程模型可以根據(jù)不同的需求提供不同的API,開發(fā)者可根據(jù)對GPU的控制程度來使用。并且為了很好的利用CUDA架構(gòu),CUDA還提供了一系列的輔助開發(fā)、調(diào)試的工具。
1.2 硬件模型
軟件程序的運行是建立在硬件的基礎(chǔ)上的,而GPU之所以能夠比CPU處理數(shù)據(jù)更加有效,在于GPU中有更多的晶體結(jié)構(gòu)可用于計算。而在CUDA的硬件架構(gòu)中,流處理器陣列是由多個線程處理器簇組成,而每個TPC又是由多個流處理器組成的。每個流處理器擁有一套完整的邏輯處理單元,就有一系列的功能,如取值、編碼、譯碼等。每個流處理器是由8個流處理單元和2組超級函數(shù)單元構(gòu)成。
2 線程模型
在CUDA編程模型中是通過大量的并行線程來實現(xiàn)計算的,因此CUDA架構(gòu)下最小的執(zhí)行單元線程(thread)。每個線程塊中是由多個可以通信的線程組成,每個線程和線程塊都有唯一的標示ID,則可以通過索引確切定位到每個線程。線程的索引和線程的ID是與線程塊的維度所確定的,一維線程索引和ID是相同的,二維維度為(m,n)的線程塊,線程索引(x,y)所對應(yīng)的線程ID為x+y*m;三維維度為(m,n,k)的線程塊,線程索引(x,y,z)所對應(yīng)的線程ID為x+y*m+z*m*n。CUDA線程的開辟是根據(jù)所需解決問題的數(shù)據(jù)大小來確定的,而每個線程塊內(nèi)的線程數(shù)由于其共享一個核心處理器的存儲器資源,則塊內(nèi)線程數(shù)量是有限制的,這個可以通過NVIDIA給出的資料查詢。一般為了使每個線程塊的調(diào)度達到最優(yōu)值,每個塊內(nèi)的線程數(shù)一般設(shè)為16的倍數(shù),但不能超過限定值。
3 存儲器模型
CUDA內(nèi)部存儲器的結(jié)構(gòu)是由寄存器、全局存儲器、共享內(nèi)存、本地寄存器、常量內(nèi)存和紋理內(nèi)存組成。下面是對這6個存儲器的介紹:
寄存器位于GPU晶體片中,在各種CUDA存儲結(jié)構(gòu)中,它的訪問速度快,因為它是線程所私有的,不允許其他線程訪問和使用。但由于GPU硬件的限制,寄存器不是無限的,每個線程塊中的寄存器是事先分配好的。但如果內(nèi)核函數(shù)中分配的寄存器數(shù)量超過了寄存器的總數(shù),編譯器會默認的將數(shù)據(jù)轉(zhuǎn)入設(shè)備端的本地內(nèi)存中,這樣就會大大降低程序數(shù)據(jù)訪問的效率。
全局寄存器也稱之為線性寄存器,占設(shè)備內(nèi)存的DRAM的大部分空間,在內(nèi)核函數(shù)運行時,所有的線程都可以讀寫其中的數(shù)據(jù)。正因如此,它的訪問速度較慢,耗時較多,線程訪問全局寄存器一般都要花費幾百個時間周期。全局寄存器一般在CPU中完成數(shù)據(jù)空間的開辟、數(shù)據(jù)的拷貝和傳輸、數(shù)據(jù)的釋放等操作。
常量存儲器位于顯存中,空間大小一般為64K,是一段只讀的地址空間,由于其具有緩存并且無訪問沖突的優(yōu)勢,常常用于常數(shù)的訪問。
本地存儲器是位于編譯器分配的全局存儲中,是歸每個線程所私有的數(shù)據(jù)空間,與全局存儲器相同,其在程序運行過程中不會緩存,所以其訪問速度也較慢。本地存儲器一般用來存放內(nèi)核函數(shù)所聲明的變量。
共享存儲器是可以被同一塊中的所有線程訪問的可讀寫存儲器,它的生存期就是塊的生命期。在沒有沖突的情況下,訪問共享存儲器幾乎與訪問寄存器一樣快,是實現(xiàn)線程間通信的最好方法。在同一個塊內(nèi),所有的線程都能夠讀共享存儲器中的數(shù)據(jù),相比于AMD的顯卡來說,共享存儲器是NVIDIA顯卡的一項特色。其和寄存器一樣位于GPU的晶體芯片中,所以其訪問速度較之全局內(nèi)存和本地內(nèi)存來說,其效率較高,并且可以減少線程塊中的線程通信的時間,一般只有2個時間周期。但由于其空間較小,一般每個SM有一個16K大小的共享寄存器,并且其數(shù)據(jù)只能在一個線程塊中共享。這就容易導(dǎo)致各線程塊中的數(shù)據(jù)不同步,容易引起數(shù)據(jù)混亂,為保證數(shù)據(jù)在程序執(zhí)行中的同步性,CUDA中使用syncthreads()函數(shù)來實現(xiàn)線程塊的同步。
紋理存儲器是GPU中專門用來渲染紋理的圖像處理單元,它是一塊只讀空間。在內(nèi)核函數(shù)運行的過程中,使用紋理寄存器首先需將數(shù)據(jù)與紋理綁定。紋理存儲器與常數(shù)存儲器一樣具有緩存機制。紋理存儲器相較于其它存儲器有兩大優(yōu)勢:一是紋理存儲器中的數(shù)據(jù)可以反復(fù)使用,避免了數(shù)據(jù)的重復(fù)讀取,提高了效率;二是可以拾取坐標對應(yīng)位置附近領(lǐng)域內(nèi)的像元數(shù)據(jù),該優(yōu)勢在對圖像進行處理中,可以提高局部性數(shù)據(jù)讀取效率。
4 結(jié)語
21世紀人類面臨的眾多重要科技課題,這些課題沒有萬億次以上的計算能力是無法解決的。GPU與生俱來就有強大的計算能力,NVIDIA公司推出了cuDA架構(gòu)使開發(fā)的難度大大降低,程序員可以很容易地利用GPU這個計算工具進行并行程序的開發(fā)?,F(xiàn)在GPU在非圖形領(lǐng)域得到了廣泛的應(yīng)用,基于GPU的通用計算研究也逐漸深入。