基本介紹
- 中文名:異構多核並行編程
- 外文名:HMPP
- 標準是否開放:是
- CPU:支持
- GPU:支持
- 優點:同一編碼能套用於多種結構
簡介,OpenHMPP標準概念,OpenHMPP Codelet 概念,Codelet RPCs,HMPP 存儲器模型,指令概念,指令集的概念,OpenHMPP指令語法,一般語法,指令參數,OpenHMPP 指令,聲明和執行一個codelet的指令,數據傳輸指令可以最佳化通信開銷,Codelets之間共享數據,全局變數,加速區,實現,
簡介
OpenHMPP基於指令的編程模型提供了一種語法,有效地減輕硬體加速器上的計算,最佳化數據向/從硬體存儲器移動。模型基於 CAPS (編譯器和超標量體系結構以及嵌入式處理器) 的初始化工作, 以及來自INRIA, CNRS, 雷恩第一大學和雷恩INSA的共同項目。
OpenHMPP標準概念
OpenHMPP標準基於codelets的概念, 可以在硬體上遠程執行。
OpenHMPP Codelet 概念
codelet具有以下屬性:
1. 它是一個純函式。
- 它不包含靜態或不穩定的變數聲明,也不涉及任何全局變數,除非這些已經由HMPP “resident”指令所聲明
- 它不包含任何具有無形體(不能內聯)的函式調用。這包含庫和系統函式的使用, 例如 malloc, printf, ...
- 每個函式必須引用靜態純函式(沒有函式指針)。
2. 它不返回任何值(C中的void函式或FORTRAN子程式)。
3. 參數的數量應該是固定的(即沒有像C中的vararg那樣可變數量的參數)。
4. 它不是遞歸的。
5. 它的參數設定為non-aliased。
6. 它不包含callsite指令(即RPC至另一個codelet)或其他HMPP指令。
這些屬性確保codelet RPC可以通過硬體遠程執行。此RPC及其相關的數據傳輸可以是異步的。
Codelet RPCs
HMPP提供同步和異步的RPC。異步操作的執行依賴於硬體。
HMPP 存儲器模型
HMPP考慮到兩個地址空間: 一個主機處理器和硬體存儲器。
指令概念
OpenHMPP指令可能被視為“元信息” 添加到應用程式原始碼。它們是安全的元信息,即不會改變原始代碼的行為。它們處理函式的遠程執行(RPC),以及數據向/從硬體存儲器傳輸。下表介紹了OpenHMPP指令。OpenHMPP指令滿足不同需求: 其中一些專門用於聲明,其他用於執行的管理。
指令集的概念
HMPP方法的基本點之一是指令的概念及其關聯的標籤,使它能夠在分布於應用程式中的整個指令集上公開一個相干結構。有兩種類型的標籤:
- 一類關聯到codelet。攜帶這種標籤的指令一般僅限於管理一個(在文檔 的其餘部分稱為stand-alone,以便從一組codelet中區分開)。
- 一類關聯到一組codelets。這些標籤說明如下: “<LabelOfGroup>“, 其中“LabelOfGroup” 是由用戶指定一個名稱。 具有這種標籤的指令一般涉及到整個組。組的概念是保留給這樣一類問題,即要求對整個應用程式的數據做具體管理以獲取性能。
OpenHMPP指令語法
為了簡化符號, 正則表達式 將用於描述HMPP指令的語法。 下面的顏色通常用於描述指令的語法:
- 保留的HMPP關鍵字是藍色;
- 在HMPP關鍵字中可以被減少的基本語法是紅色;
- 用戶變數仍然為黑色。
一般語法
OpenHMPP指令的一般語法如下:
- C語言:
#pragmahmpp<grp_label>[codelet_label]?directive_type[,directive_parameters]*[&] - FORTRAN語言:
!$hmpp<grp_label>[codelet_label]?directive_type[,directive_parameters]*[&
其中:
- <grp_label>: 是命名一組 codelets 的獨一標識符。在應用程式中沒有組被定義的情況下, 這個標籤可以簡單地略過。Legal標籤必須遵循此語法: [a-z,A-Z,_][a-z,A-Z,0-9,_]*。請注意 “< >” 字元屬於語法,且對這類標籤是強制性的。
- codelet_label: 是命名一個codelet的獨一標識符。Legal 標籤必須遵循此語法: [a-z,A-Z,_][a-z,A-Z,0-9,_]*
- directive: 是指令的名稱;
- directive_parameters: 指定一些指令相關聯的參數。這些參數可能是不同類型並指定 給指令的某些參數或執行的一種模式(例如同步與異步);
- [&]: 是用於在下一行繼續該指令的字元 (C和FORTRAN都是相同的)。
指令參數
關聯到一個指令的參數可能是不同類型。以下是 在HMPP中定義的指令參數:
- version = major.minor[.micro]: 由預處理器指定HMPP指令的版本。
- args[arg_items].size={dimsize[,dimsize]*}: 指定一個非標量參數 (數組)的大小。
- args[arg_items].io=[in|out|inout]: 表示指定函式參數是輸入, 輸出或兩者兼而有之。默認情況下, 非限定參數為輸入。
- cond = "expr": 指定組或codelets開始執行的一個條件C或Fortran布爾表達式的值為是 C或Fortran布爾表達式的值為true。
- target=target_name[:target_name]*: 指定是哪個target以嘗試使用給定的順序。
- asynchronous: 指定不阻止codelet的 執行 (默認是同步的)。
- args[<arg_items>].advancedload=true: 表明指定的參數是預載入的。只有in或inout參數可以被預載入。
- args[arg_items].noupdate=true: 此屬性指定 硬體上的數據已經可用,因此不需要轉換。 當設定了此屬性時, 所考慮的參數沒有任何傳遞。
- args[<arg_items>].addr="<expr>": <expr>是一個表達式,給出了數據上載的地址。
- args[<arg_items>].const=true: 表示參數只要上載一次。
OpenHMPP 指令
聲明和執行一個codelet的指令
codelet指令聲明在硬體加速器上遠程執行計算。
codelet 指令:
- codelet標籤是強制性的並且在應用程式中是獨一的
- 如果沒有組被定義則不需要組標籤。
- Codelet指令在函式聲明之前插入。
該指令的語法是:
#pragma hmpp <grp_label> codelet_label codelet[, version = major.minor[.micro]?]?[, args[arg_items].io=[[in|out|inout]]*[, args[arg_items].size={dimsize[,dimsize]*}]*[, args[arg_items].const=true]*[, cond = "expr"][, target=target_name[:target_name]*]
可以在一個函式中加入多個codelet指令,以便指定不同用途或不同執行文本。但是, 一個給定調用站點標籤只能有一個codelet指令。 Callsite指令指定程式內的給定點如何使用一個codelet。該指令的語法是:
#pragma hmpp <grp_label> codelet_label callsite[, asynchronous]?[, args[arg_items].size={dimsize[,dimsize]*}]*[, args[arg_items].advancedload=[[true|false]]*[, args[arg_items].addr="expr"]*[, args[arg_items].noupdate=true]*
這裡有一個例子:
/* declaration of the codelet */#pragma hmpp simple1 codelet, args[outv].io=inout, target=CUDAstatic void matvec(int sn, int sm, loat inv[sm], float inm[sn][sm], float *outv){int i, j;for (i = 0 ; i < sm ; i++) {float temp = outv[i];for (j = 0 ; j < sn ; j++) {temp += inv[j] * inm[i][ j];}outv[i] = temp;}int main(int argc, char **argv) {int n;......./* codelet use */#pragma hmpp simple1 callsite, args[outv].size={n}matvec(n, m, myinc, inm, myoutv);........}
某些情況下, 需要具體管理整個應用程式的數據(CPU/GPU 數據移動最佳化, 共享變數...)。group指令允許聲明一組codelets。 指令中定義的參數套用於所有屬於該組的 codelets。該指令的語法是:
#pragma hmpp <grp_label> group[, version = <major>.<minor>[.<micro>]?]?[, target = target_name[:target_name]*]]?[, cond = “expr”]?
數據傳輸指令可以最佳化通信開銷
硬體使用時的主要瓶頸通常是硬體和住處理器之間的數據傳輸。要限制通信開銷,可以通過使用硬體的異步屬性,連續執行相同的codelet以重疊數據傳輸。
- allocate指令
allocate指令鎖定硬體,並分配所需的記憶體量。 #pragma hmpp <grp_label> allocate [,args[arg_items].size={dimsize[,dimsize]*}]*
- release指令
release指令指定何時為一組或一個獨立codelet釋放硬體。
#pragma hmpp <grp_label> release
- advancedload 指令
advancedload指令在codelet遠程執行之前預取數據。
#pragma hmpp <grp_label> [codelet_label]? advancedload,args[arg_items][,args[arg_items].size={dimsize[,dimsize]*}]*[,args[arg_items].addr="expr"]*[,args[arg_items].section={[subscript_triplet,]+}]*[,asynchronous]
- delegatedstore 指令
delegatedstore指令是一個同步障,以等待一個異步codelet執行完成,然後下載結果。
#pragma hmpp <grp_label> [codelet_label]? delegatedstore,args[arg_items][,args[arg_items].addr="expr"]*[,args[arg_items].section={[subscript_triplet,]+}]*
- 異步計算
同步指令指定等待,直到一個異步callsite執行完成。對於同步指令, codelet 標籤始終是強制性的,並且若是codelet屬於一個組,需要有組標籤。 #pragma hmpp <grp_label> codelet_label synchronize
- 示例
在下面的例子中,完成設備初始化,記憶體分配和輸入數據的上載在循環外只有一次,而不是每次循環疊代。同步指令允許在啟動另一個疊代之前等待codelet的異步執行的完成。最後在循環外delegatedstore指令將上載sgemm結果。
int main(int argc, char **argv) {#pragma hmpp sgemm allocate, args[vin1;vin2;vout].siez={size,size}#pragma hmpp sgemm advancedload, args[vin1;vin2;vout], args[m,n,k,alpha,beta]for ( j = 0 ; j < 2 ; j ++) {#pragma hmpp sgemm callsite, asynchronous, args[vin1;vin2;vout].advancedload=true, args[m,n,k,alpha,beta].advancedload=truesgemm (size, size, size, alpha, vin1, vin2, beta, vout);#pragma hmpp sgemm synchronize}#pragma hmpp sgemm delegatedstore, args[vout]#pragma hmpp sgemm release
Codelets之間共享數據
這些指令共同映射所有參數共享所有組的給定名稱。所有映射參數的類型和尺寸必須是相同的。 map指令映射設備上的幾個參數。 #pragma hmpp <grp_label> map, args[arg_items]此指令除了參數按其名稱直接指定映射之外,與map指令很類似。 mapbyname 指令相當於多映射指令。
#pragma hmpp <grp_label> mapbyname [,variableName]+
全局變數
Resident指令聲明某些變數在一個組內為全局變數。 然後可以從任何屬於組的codelet中直接訪問這些變數。此指令套用於原始碼中在其之後的聲明語句。
此指令的語法是:
#pragma hmpp <grp_label> resident[, args[::var_name].io=[[in|out|inout]]*[, args[::var_name].size={dimsize[,dimsize]*}]*[, args[::var_name].addr="expr"]*[, args[::var_name].const=true]*
符號::var_name 以::為前綴, 表示一個應用程式的變數聲明為resident。
加速區
codelet/callsite指令合併為一個區域。目的是避免代碼重構中構建codelet。 因此,所有codelet或callsite指令可用屬性都可以用於regions指令。 在C語言中:
#pragma hmpp [<MyGroup>] [label] region[, args[arg_items].io=[[in|out|inout]]*[, cond = "expr"]<[, args[arg_items].const=true]*[, target=target_name[:target_name]*][, args[arg_items].size={dimsize[,dimsize]*}]*[, args[arg_items].advancedload=[[true|false]]*[, args[arg_items].addr="expr"]*[, args[arg_items].noupdate=true]*[, asynchronous]?[, private=[arg_items]]*{C BLOCK STATEMENTS}
實現
HMPP開放標準基於HMPP 2.3版本(2009年5月, CAPS 公司)。HMPP基於指令的編程模型已經實現如下:
- HMPP 工作檯, 用於混合計算的CAPS企業編譯器
- PathScale ENZO 編譯器套件(支持NVIDIA GPUs)
此外,HMPP開放標準用於石油和天然氣,能源,製造業,金融,教育及研究領域的高性能計算,讓開發人員使用大部分多核處理器,同時保留其遺留資源。