專利名稱:一種基于cuda實(shí)現(xiàn)多任務(wù)共享gpu的方法
技術(shù)領(lǐng)域:
本發(fā)明涉及一種多任務(wù)共享GPU的實(shí)現(xiàn)方法,具體涉及在NVIDA的CUDA架構(gòu)中合并多個(gè)任務(wù),實(shí)現(xiàn)任務(wù)并行的方法,屬于GPGPU計(jì)算領(lǐng)域。
背景技術(shù):
GPGPU (General-purpose computing on graphics processing units),是利用GPU來進(jìn)行大規(guī)模計(jì)算的技術(shù)。CUDA是NVIDA公司提供的GPGPU架構(gòu)。CUDA自從推出開始,就成為廣泛應(yīng)用的眾核并行計(jì)算形式。
GPU具有遠(yuǎn)遠(yuǎn)高于CPU的浮點(diǎn)運(yùn)算能力和內(nèi)存帶寬(附圖I),同時(shí)由于其高度的并行性,非常適合于大規(guī)模數(shù)據(jù)處理。然而,由于GPU的硬件設(shè)計(jì),GPU上的編程和CPU上的并行編程有所不同。一個(gè)顯著的區(qū)別就是,GPU不支持多任務(wù)共享每個(gè)任務(wù)在GPU上的運(yùn)行都是對GPU的硬件資源獨(dú)占的,不允許有其他的Kernel也在執(zhí)行。例如,當(dāng)多個(gè)任務(wù)都要使用GPU的時(shí)候,只能夠一個(gè)一個(gè)的順序地執(zhí)行,而不能一起同時(shí)在GPU上運(yùn)行。這一點(diǎn)和CPU上允許進(jìn)程之間進(jìn)行切換是有很大的不同。目前,尚未發(fā)現(xiàn)有專利或者文獻(xiàn)針對GPU上的多任務(wù)共享進(jìn)行討論。
發(fā)明內(nèi)容
本發(fā)明所使用的一些術(shù)語定義如下Kernel =CUDA架構(gòu)中,GPU 一次運(yùn)行所執(zhí)行的代碼。Thread, Block, Grid CUDA架構(gòu)中,一個(gè)大的Kernel被劃分為了很多小的基本單位,稱為線程(Thread)。所有Thread組織成為了兩級結(jié)構(gòu)。(附圖2)首先,這些Thread劃分為了若干個(gè)線程塊(Block),每個(gè)Block包含相同數(shù)目的Thread。Thread是以Block為單位分發(fā)到硬件資源上來執(zhí)行的。在Block內(nèi)部,線程的ID編號可以采用一維、二維或者三維,這稱為Block維數(shù)。在某一個(gè)確定的Kernel里面,每個(gè)Block都含有相同的維數(shù),以及每一維上相同的大小(這稱為維度)。維數(shù)和維度都是在GPU啟動(dòng)Kernel之前由程序員指定好的,執(zhí)行過程中是不能改變的。然后,所有的Block組成的整體(也就是所有的Thread)稱為線程網(wǎng)格(Grid)。和Block的維數(shù)定義類似,Block的ID編號,可以組織成一維、二維或者三維,稱為Grid的維數(shù),每一維上的大小稱為維度。SM (Streaming Multiprocessor) :GPU上的硬件單元,包括運(yùn)算單元、寄存器、片上存儲(chǔ)器。每個(gè)Block都會(huì)被分配到SM上進(jìn)行執(zhí)行。一個(gè)Block只能在一個(gè)SM上執(zhí)行,一個(gè)SM上可以同時(shí)執(zhí)行一個(gè)或者多個(gè)Block (取決于單個(gè)Block消耗的寄存器、片上存儲(chǔ)器資源的數(shù)目)。Global Memory :顯卡上的存儲(chǔ)器,屬于片外存儲(chǔ)器,GPU可以從中讀取,但是速度相對比較慢。Shared Memory GPU上的一種片上存儲(chǔ)器,每個(gè)SM中擁有一定數(shù)量的SharedMemory,通常為KB級大小,可以視作一種可供程序員維護(hù)的Cache,在CUDA架構(gòu)中有非常重要的意義。任務(wù)分塊單個(gè)任務(wù)劃分為多個(gè)子任務(wù),每個(gè)子任務(wù)稱為任務(wù)分塊。一個(gè)任務(wù)分塊將會(huì)對應(yīng)到一個(gè)Block中完成計(jì)算。本發(fā)明旨在提 供一種方法使得在CUDA架構(gòu)上實(shí)現(xiàn)多任務(wù)共享GPU,解決現(xiàn)有GT200架構(gòu)不支持多任務(wù)共享GPU的問題。本發(fā)明的原理包括三點(diǎn)I.對每個(gè)Block執(zhí)行的任務(wù)分塊,在GPU運(yùn)行之初由程序員通過對一個(gè)映射表的賦值來確定。通常,每個(gè)Block執(zhí)行的任務(wù)分塊,在算法設(shè)計(jì)的時(shí)候就已經(jīng)固定。本發(fā)明通過增加一個(gè)映射表,使得能夠在GPU啟動(dòng)之前,程序員可以對每個(gè)Block執(zhí)行的任務(wù)分塊進(jìn)行重排。2.利用GPU高并行度的特點(diǎn),把多個(gè)任務(wù)的Block合并到的一個(gè)Kernel中去。CUDA架構(gòu)中,可以同時(shí)啟動(dòng)成百上千的線程(Thread),進(jìn)行并行度非常高的計(jì)算任務(wù)。所有的Thread被按照一定數(shù)目組織成為若干的Block。本發(fā)明讓一個(gè)GPU在一個(gè)Kernel中同時(shí)啟動(dòng)大量的Block,執(zhí)行所有任務(wù)的任務(wù)分塊。3.考慮到任務(wù)之間可能具有約束性,利用GPU動(dòng)態(tài)調(diào)度Block到SM上的特性,處理約束關(guān)系。CPU上一種通常的做法是,如果有約束關(guān)系,那么在需要同步的地方,直接使用原子操作即可。雖然GPU也支持原子操作,但是原子操作的代價(jià)是非常大的,會(huì)帶來性能上的嚴(yán)重?fù)p失,并且極易造成死鎖。本發(fā)明充分考慮到了 GPU調(diào)度Block的規(guī)律性。GPU通常擁有數(shù)十到上百個(gè)SM。GPU上的Block在啟動(dòng)的時(shí)候并不會(huì)擁有硬件資源,而是在執(zhí)行的過程中,動(dòng)態(tài)地把Block分發(fā)給SM。但SM的數(shù)量一般相對于Block少很多,所以每個(gè)時(shí)刻,在SM上執(zhí)行的Block只是一部分,其他的Block只能等待。一旦有SM上Block的任務(wù)計(jì)算結(jié)束,GPU回收得到空閑資源的時(shí)候,就會(huì)從尚未執(zhí)行的Block中選取一定的Block分發(fā)到有空閑資源的SM上去。為Block分配資源的時(shí)候,是有一定的順序性的,這種順序性表現(xiàn)為I.總是優(yōu)先分發(fā)ID編號較小的Block到SM上去。例如ID編號為O的Block分發(fā)到SM上去的時(shí)間總是不晚于ID編號為I的Block被分發(fā)的時(shí)間。2.相對的,回收Block資源的時(shí)候,也是優(yōu)先回收ID編號較小的Block的空閑資源。例如ID編號為O的Block尚未結(jié)束,ID編號為10的Block執(zhí)行結(jié)束,但此時(shí)GPU不會(huì)回收編號為10的Block的資源,因?yàn)镮D編號更小,ID編號為O的Block的資源并未被回收。根據(jù)這種順序性,本發(fā)明先把需要優(yōu)先執(zhí)行的任務(wù),在映射表中適當(dāng)排序I.被其他任務(wù)依賴的任務(wù),使ID編號較小的Block來執(zhí)行它的任務(wù)分塊,這樣它會(huì)優(yōu)先獲得資源,被調(diào)度到SM上去進(jìn)行先執(zhí)行;2.依賴于其他任務(wù)的任務(wù),使ID編號較大的Block來執(zhí)行它的任務(wù)分塊,同時(shí),輔以適當(dāng)?shù)淖枞却僮?,保證其依賴的任務(wù)已經(jīng)完全執(zhí)行結(jié)束。完整的技術(shù)方案如下(流程參見圖4):一種基于CUDA實(shí)現(xiàn)多任務(wù)共享GPU的方法,包括如下步驟I)在Global Memory中建立映射表,確定合并后的Kernel中,每個(gè)Block執(zhí)行的任務(wù)編號和任務(wù)分塊編號;2) 一次用一個(gè)Kernel啟動(dòng)N個(gè)Block,N等于所有任務(wù)的任務(wù)分塊數(shù)目之和;3)用標(biāo)記和阻塞等待的方法,滿足原有任務(wù)之間的約束關(guān)系;
4)對于Shared Memory,采用預(yù)申請和靜態(tài)分配的方式進(jìn)行多任務(wù)共享。其中,步驟I)的優(yōu)選實(shí)現(xiàn)方法如下I. I)映射表要給出Block到任務(wù)和任務(wù)分塊的映射關(guān)系,即確定某個(gè)Block執(zhí)行哪個(gè)任務(wù)的哪個(gè)分塊;I. 2)任務(wù)在映射表中的排布要求滿足約束條件的拓?fù)漤樞蛉绻蝿?wù)A依賴于任務(wù)B,那么,執(zhí)行任務(wù)A的所有Block的ID編號應(yīng)該大于所有執(zhí)行任務(wù)B的Block的ID編號;I. 3)在滿足步驟I. 2)所述的約束條件的情況下,其他無約束關(guān)系任務(wù)在映射表中以任意的方式進(jìn)行排布。步驟2)的優(yōu)選實(shí)現(xiàn)方法如下2. I)將原有的任務(wù)的grid維數(shù)轉(zhuǎn)換為一維原有的任務(wù)可能是有不同的grid維數(shù)和維度,這里可以統(tǒng)一選取一維;如果原來的任務(wù)是多維的,只需要進(jìn)行一維到多維的換算即可;2. 2)若Block的維數(shù)不一致,則將之統(tǒng)一轉(zhuǎn)換為一維;若轉(zhuǎn)成一維之后Block的維度不一致,則統(tǒng)一選取一個(gè)最大的維度,讓其他較小的Block添加空線程補(bǔ)足,這樣所有的任務(wù)都采用了相同的Block維數(shù)和維度;2. 3)所有的Block在開始執(zhí)行計(jì)算之前,首先從映射表中獲取該Block需要執(zhí)行的任務(wù)編號和任務(wù)分塊編號;2. 4)根據(jù)步驟2. 3)中讀取的任務(wù)編號,選擇執(zhí)行不同的任務(wù)代碼;將步驟2. 3)中讀取的任務(wù)分塊編號,使用到具體的任務(wù)計(jì)算中去。步驟3)的優(yōu)選實(shí)現(xiàn)方法如下3. I)給每個(gè)任務(wù)設(shè)置標(biāo)志位mark,每個(gè)任務(wù)的每個(gè)任務(wù)分塊設(shè)置標(biāo)記數(shù)組tag □,用以標(biāo)記任務(wù)和任務(wù)分塊的執(zhí)行情況;3. 2)對于任務(wù)的每一個(gè)任務(wù)分塊,在該任務(wù)分塊完成之后,將對應(yīng)的標(biāo)記位tag置位,表明該任務(wù)分塊已經(jīng)執(zhí)行結(jié)束;3.3)用每個(gè)任務(wù)的最后一個(gè)Block,在計(jì)算返回前阻塞,循環(huán)檢查同一任務(wù)的其他任務(wù)分塊的對應(yīng)tag標(biāo)記位是否已經(jīng)被置位,一旦全部被置位,則對標(biāo)志位mark置位,表明該任務(wù)已經(jīng)結(jié)束;3. 4)如果任務(wù)A需要依賴于任務(wù)B,那么在任務(wù)A計(jì)算開始之前阻塞,循環(huán)檢測B的任務(wù)標(biāo)志位mark,直到其置位。步驟4)的優(yōu)選實(shí)現(xiàn)方法如下4. I)預(yù)先在Kernel開始的時(shí)候,申請一個(gè)足夠大的Shared Memory數(shù)組,其大小至少應(yīng)該等于每個(gè)任務(wù)所需要的Shared Memory用量的最大值;4. 2)每個(gè)任務(wù)單獨(dú)寫成一個(gè)函數(shù),將Shared Memory數(shù)組地址傳給這個(gè)函數(shù),函數(shù)中需要使用Shared Memory的時(shí)候,直接在這個(gè)數(shù)組中靜態(tài)分配使用。通過本發(fā)明,可以簡便地實(shí)現(xiàn)在現(xiàn)有GPU硬件架構(gòu)上實(shí)現(xiàn)多任務(wù)共享,可以簡化實(shí)際應(yīng)用中的編程工作,并在一定情況下取得良好的性能。
圖IGPU的浮點(diǎn)運(yùn)算能力存儲(chǔ)器帶寬同CPU的比較(圖片來源NVIDIA CUDAProgramming Guide Version 2. 3)
圖 2GPU 中的 Thread, Block, Grid 結(jié)構(gòu)(圖片來源NVIDIA CUDA ProgrammingGuide Version 2. 3)圖3兩種映射表的排布。圖3(a)實(shí)施方案中的3個(gè)任務(wù)使用圖形表示(約束關(guān)系用箭頭表不,任務(wù)I依賴于任務(wù)0);圖3(b) —種合法的映射表排布;圖3(c) —種不合法的映射表排布(任務(wù)I依賴于任務(wù)0,卻有Block排布到了任務(wù)O前面)。圖4本發(fā)明所述方法的流程圖。
具體實(shí)施例方式以下以一個(gè)具體的例子,對本發(fā)明做進(jìn)一步的說明。但是需要注意的是,公布實(shí)施例的目的在于幫助進(jìn)一步理解本發(fā)明,但是本領(lǐng)域的技術(shù)人員可以理解在不脫離本發(fā)明及所附的權(quán)利要求的精神和范圍內(nèi),各種替換和修改都是可能的。因此,本發(fā)明不應(yīng)局限于實(shí)施例所公開的內(nèi)容,本發(fā)明要求保護(hù)的范圍以權(quán)利要求書界定的范圍為準(zhǔn)。具體的例子是3個(gè)計(jì)算任務(wù)(具體任務(wù)內(nèi)容此處并無影響)。任務(wù)存在以下的約束關(guān)系任務(wù)I必須在任務(wù)O完成后才能進(jìn)行,因?yàn)槿蝿?wù)I需要使用任務(wù)O的結(jié)果,而任務(wù)2同任務(wù)O和任務(wù)I沒有任何約束關(guān)系。(附圖3 (a),圓圈代表任務(wù),箭頭代表依賴關(guān)系)使用技術(shù)方案中所述的方法實(shí)現(xiàn)任務(wù)并行。為了方便敘述,定義以下device函數(shù)分別完成3個(gè)計(jì)算任務(wù),分別稱為任務(wù)0,I和2。
任務(wù) O device void computeO (...);
任務(wù) I device void computel (...);
任務(wù) 2 device void compute2(...);同時(shí)假設(shè)每個(gè)任務(wù)都進(jìn)行了相同大小的任務(wù)分塊,各自的計(jì)算任務(wù)劃分為了 N個(gè)任務(wù)分塊。實(shí)施過程分為以下步驟A.建立映射表開辟兩個(gè)一維的數(shù)組,長度等于所有任務(wù)的任務(wù)分塊數(shù)之和,此例中為3*N。兩個(gè)數(shù)組的具體含義如下I. task_id□,取值為0、1或者2。這個(gè)數(shù)組給出了 Kernel中的Block需要執(zhí)行的任務(wù)。例如,圖3(b),task_id
到task_id[N_l]的值都為0,代表了 Block ID從O到N-I的Block都要執(zhí)行任務(wù)O ;其他值為I和2的元素,意義類似。2. block_id□,取值為O到N-I。這個(gè)數(shù)組給出了 Kernel中Block需要執(zhí)行的分塊編號。例如,圖3 (b),block_id[N]等于0,代表了編號為N的Block需要執(zhí)行編號為O的任務(wù)分塊(任務(wù)編號由I中的task_id指定)。編號的順序需要滿足具體問題所要求的任務(wù)之間的約束關(guān)系。任務(wù)I依賴于任務(wù)0,所以執(zhí)行任務(wù)I的分塊的那些Block, ID編號應(yīng)該大于執(zhí)行任務(wù)O的Block ID編號。例如簡單地做法,把任務(wù)O和任務(wù)2的block排布到前端,任務(wù)I的block排布到后端,如圖3(b)所不。而圖3 (C)的排布是不滿足約束關(guān)系的拓?fù)湫虻?,任?wù)I的分塊被排布到了任務(wù)O前面,在GPU的調(diào)度過程中會(huì)首先執(zhí)行,造成錯(cuò)誤,所以是是不合法的。確定好順序之后,可以在Kernel啟動(dòng)之前直接對task_id[]和block_id[]進(jìn)行賦值即可。B.啟動(dòng) Kernel定義一個(gè)合并后的Kernel, Block的數(shù)目等于原有所有任務(wù)的任務(wù)分塊數(shù)之和,此例中為3*N。這個(gè)Kernel的參數(shù)列表應(yīng)該傳入三個(gè)任務(wù)需要的所有參數(shù)。合并的Kernel應(yīng)該先獲取自身的Block ID號bidx
權(quán)利要求
1.一種基于CUDA實(shí)現(xiàn)多任務(wù)共享GPU的方法,包括如下步驟 1)在GlobalMemory中建立映射表,確定合并后的Kernel中,每個(gè)Block執(zhí)行的任務(wù)編號和任務(wù)分塊編號; 2)一次用一個(gè)Kernel啟動(dòng)N個(gè)Block,N等于所有任務(wù)的任務(wù)分塊數(shù)目之和; 3)用標(biāo)記和阻塞等待的方法,滿足原有任務(wù)之間的約束關(guān)系; 4)對于SharedMemory,采用預(yù)申請和靜態(tài)分配的方式進(jìn)行多任務(wù)共享。
2.如權(quán)利要求I所述的方法,其特征是,步驟I)的實(shí)現(xiàn)方法如下 I. D映射表要給出Block到任務(wù)和任務(wù)分塊的映射關(guān)系,即確定某個(gè)Block執(zhí)行哪個(gè)任務(wù)的哪個(gè)分塊; I. 2)任務(wù)在映射表中的排布要求滿足約束條件的拓?fù)漤樞蛉绻蝿?wù)A依賴于任務(wù)B,那么,執(zhí)行任務(wù)A的所有Block的ID編號應(yīng)該大于所有執(zhí)行任務(wù)B的Block的ID編號; 1.3)在滿足步驟I. 2)所述的約束條件的情況下,其他無約束關(guān)系任務(wù)在映射表中以任意的方式進(jìn)行排布。
3.如權(quán)利要求I所述的方法,其特征是,步驟2)的實(shí)現(xiàn)方法如下 2.I)將原有的任務(wù)的grid維數(shù)轉(zhuǎn)換為一維; 2. 2)若Block的維數(shù)不一致,則將之統(tǒng)一轉(zhuǎn)換為一維;若轉(zhuǎn)成一維之后Block的維度不一致,則統(tǒng)一選取一個(gè)最大的維度,讓其他較小的Block添加空線程補(bǔ)足,這樣所有的任務(wù)都采用了相同的Block維數(shù)和維度; 2. 3)所有的Block在開始執(zhí)行計(jì)算之前,首先從映射表中獲取該Block需要執(zhí)行的任務(wù)編號和任務(wù)分塊編號; 2.4)根據(jù)步驟2. 3)中讀取的任務(wù)編號,選擇執(zhí)行不同的任務(wù)代碼;將步驟2. 3)中讀取的任務(wù)分塊編號,使用到具體的任務(wù)計(jì)算中去。
4.如權(quán)利要求I所述的方法,其特征是,步驟3)的實(shí)現(xiàn)方法如下 3.I)給每個(gè)任務(wù)設(shè)置標(biāo)志位mark,每個(gè)任務(wù)的每個(gè)任務(wù)分塊設(shè)置標(biāo)記數(shù)組tag□,用以標(biāo)記任務(wù)和任務(wù)分塊的執(zhí)行情況; 3. 2)對于任務(wù)的每一個(gè)任務(wù)分塊,在該任務(wù)分塊完成之后,將對應(yīng)的標(biāo)記位tag置位,表明該任務(wù)分塊已經(jīng)執(zhí)行結(jié)束; 3.3)用每個(gè)任務(wù)的最后一個(gè)Block,在計(jì)算返回前阻塞,循環(huán)檢查同一任務(wù)的其他任務(wù)分塊的對應(yīng)tag標(biāo)記位是否已經(jīng)被置位,一旦全部被置位,則對標(biāo)志位mark置位,表明該任務(wù)已經(jīng)結(jié)束; 、 3.4)如果任務(wù)A需要依賴于任務(wù)B,那么在任務(wù)A計(jì)算開始之前阻塞,循環(huán)檢測B的任務(wù)標(biāo)志位mark,直到其置位。
5.如權(quán)利要求I所述的方法,其特征是,步驟4)的實(shí)現(xiàn)方法如下 、4.I)預(yù)先在Kernel開始的時(shí)候,申請一個(gè)足夠大的Shared Memory數(shù)組,其大小至少應(yīng)該等于每個(gè)任務(wù)所需要的Shared Memory用量的最大值; 、 4.2)每個(gè)任務(wù)單獨(dú)寫成一個(gè)函數(shù),將Shared Memory數(shù)組地址傳給這個(gè)函數(shù),函數(shù)中需要使用Shared Memory的時(shí)候,直接在這個(gè)數(shù)組中靜態(tài)分配使用。
全文摘要
本發(fā)明公布了一種基于CUDA實(shí)現(xiàn)多任務(wù)共享GPU的方法。包括在Global Memory中建立映射表,確定合并后的Kernel中,每個(gè)Block執(zhí)行的任務(wù)編號和任務(wù)分塊編號;一次用一個(gè)Kernel啟動(dòng)N個(gè)Block,N等于所有任務(wù)的任務(wù)分塊數(shù)目之和;用標(biāo)記和阻塞等待的方法,滿足原有任務(wù)之間的約束關(guān)系;對于Shared Memory,采用預(yù)申請和靜態(tài)分配的方式進(jìn)行多任務(wù)共享。通過本發(fā)明,可以簡便地實(shí)現(xiàn)在現(xiàn)有GPU硬件架構(gòu)上實(shí)現(xiàn)多任務(wù)共享,可以簡化實(shí)際應(yīng)用中的編程工作,并在一定情況下取得良好的性能。
文檔編號G06F9/50GK102708009SQ201210115719
公開日2012年10月3日 申請日期2012年4月19日 優(yōu)先權(quán)日2012年4月19日
發(fā)明者蔣吳軍, 陳一峯, 黃錕 申請人:北京大學(xué), 華為技術(shù)有限公司