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