OpenHMPP (HMPP [1]ハイブリッドマルチコア並列プログラミング) -異種コンピューティングのプログラミング標準。一連のコンパイラディレクティブに基づいて、GPUプログラミングに関連する複雑さなしでハードウェアアクセラレータを処理するように設計されたプログラミングモデルです。ディレクティブに基づくこのアプローチは、アプリケーションコードとハードウェアアクセラレータ (HWA) の使用との間に緩やかな関係を可能にするために実装されました。
導入
OpenHMPP ディレクティブベースのプログラミング モデルは、ハードウェア アクセラレータ上で計算をオフロードし、ハードウェア メモリとの間のデータ移動を最適化する構文を提供します。
このモデルは、 INRIA、CNRS、レンヌ第1大学、レンヌ国立情報学研究所 の共同プロジェクトである CAPS (組み込みおよびスーパースカラー プロセッサ用のコンパイラとアーキテクチャ) によって開始された作業に基づいています。
OpenHMPPのコンセプト
OpenHMPP は、HWA 上でリモートで実行できる関数であるコードレットの概念に基づいています。
OpenHMPPコードレットのコンセプト
コードレットには次のプロパティがあります。
- それは純粋な関数です。
- 値は返しません ( Cの void 関数またはFortranのサブルーチン)。
- 引数の数は固定である必要があります (つまり、 C のstdarg.hのように可変引数関数にすることはできません)。
- 再帰的ではありません。
- そのパラメータはエイリアス化されていないものとみなされます (エイリアス化 (コンピューティング)およびポインター エイリアス化 を参照)。
- 呼び出しサイト ディレクティブ (別のコードレットへの RPC など) やその他の HMPP ディレクティブは含まれません。
これらのプロパティにより、コードレットRPC をHWA でリモートで実行できるようになります。この RPC とそれに関連するデータ転送は非同期に行うことができます。
コードレット RPC
HMPP は同期および非同期 RPC を提供します。非同期操作の実装はハードウェアに依存します。

HMPP メモリ モデル
HMPP は、ホスト プロセッサと HWA メモリの 2 つのアドレス空間を考慮します。

指令の概念
OpenHMPP ディレクティブは、アプリケーションのソース コードに追加された「メタ情報」と見なすことができます。これらは安全なメタ情報であり、元のコードの動作を変更しません。これらは、関数のリモート実行 (RPC) と HWA メモリとの間のデータ転送に対応します。
以下の表は、OpenHMPP ディレクティブを紹介しています。OpenHMPP ディレクティブはさまざまなニーズに対応しており、宣言専用のものもあれば、実行の管理専用のものもあります。
指令セットの概念
HMPP アプローチの基本的なポイントの 1 つは、ディレクティブとそれに関連付けられたラベルの概念であり、これにより、アプリケーションで配布されるディレクティブのセット全体に一貫した構造を公開できるようになります。
ラベルには 2 種類あります。
- コードレットに関連付けられたもの。一般に、この種類のラベルを持つディレクティブは、1 つのコードレット (コードレットのグループと区別するために、ドキュメントの残りの部分ではスタンドアロン コードレットと呼ばれます) の管理のみに制限されます。
- コードレットのグループに関連付けられたラベル。これらのラベルは次のように表記されます: “<LabelOfGroup>“。ここで、“LabelOfGroup” はユーザーが指定した名前です。一般に、このタイプのラベルを持つディレクティブはグループ全体に関連します。グループの概念は、パフォーマンスを得るためにアプリケーション全体のデータの特定の管理を必要とする問題のクラスに限定されています。
OpenHMPP ディレクティブ構文
表記を簡略化するために、HMPP ディレクティブの構文を記述するために 正規表現が使用されます。
構文ディレクティブの説明には、以下の色規則が使用されます。
- 予約済みの HMPP キーワードは緑色で表示されます。
- HMPP キーワードで省略可能な文法要素は赤で表示されます。
- ユーザーの変数は黒のままです。
一般的な構文
OpenHMPP ディレクティブの一般的な構文は次のとおりです。
- C言語の場合:
#pragma hmpp < grp_label > [codelet_label]?ディレクティブタイプ[ ,ディレクティブパラメータ]* [ & ]
- FORTRAN言語の場合:
!$hmpp < grp_label > [codelet_label]?ディレクティブタイプ[ ,ディレクティブパラメータ]* [ & ]
どこ:
<grp_label>: は、コードレットのグループに名前を付ける一意の識別子です。アプリケーションでグループが定義されていない場合、このラベルは単に省略できます。有効なラベル名は、次の文法に従う必要があります:[a-zA-Z_][a-zA-Z0-9_]*。「< >」文字は構文に属し、この種のラベルでは必須であることに注意してください。codelet_label: はコードレットに名前を付ける一意の識別子です。有効なラベル名は次の文法に従う必要があります:[a-zA-Z_][a-zA-Z0-9_]*directive: はディレクティブの名前です。directive_parameters: ディレクティブに関連付けられたいくつかのパラメータを指定します。これらのパラメータはさまざまな種類があり、ディレクティブに渡されるいくつかの引数または実行モード (たとえば、非同期と同期) を指定します。[&]: は、次の行にディレクティブを継続するために使用される文字です (C および FORTRAN で同じ)。
ディレクティブパラメータ
ディレクティブに関連付けられたパラメータは、さまざまなタイプにすることができます。以下は、OpenHMPP で定義されているディレクティブ パラメータです。
version = major.minor[.micro]: プリプロセッサが考慮する HMPP ディレクティブのバージョンを指定します。args[arg_items].size={dimsize[,dimsize]*}: 非スカラーパラメータ (配列) のサイズを指定します。args[arg_items].io=[in|out|inout]: 指定された関数の引数が入力、出力、またはその両方であることを示します。デフォルトでは、修飾されていない引数は入力になります。cond = "expr": グループまたはコードレットの実行を開始するために真である必要がある実行条件をブール C または Fortran 式として指定します。target=target_name[:target_name]*: 指定された順序で使用しようとするターゲットを指定します。asynchronous: コードレットの実行がブロックされないことを指定します (デフォルトは同期です)。args[<arg_items>].advancedload=true: 指定されたパラメータがプリロードされていることを示します。プリロードできるのは in または inout パラメータのみです。args[arg_items].noupdate=true: このプロパティは、データがすでにHWA上で利用可能であり、転送が不要であることを指定します。このプロパティが設定されている場合、考慮される引数に対して転送は行われません。args[<arg_items>].addr="<expr>":<expr>アップロードするデータのアドレスを指定する式です。args[<arg_items>].const=true: 引数が 1 回だけアップロードされることを示します。
OpenHMPP ディレクティブ
コードレットを宣言および実行するためのディレクティブ
ディレクティブcodeletは、ハードウェア アクセラレータ上でリモートで実行される計算を宣言します。codeletディレクティブの場合:
- コードレットラベルは必須であり、アプリケーション内で一意である必要があります。
- グループが定義されていない場合は、グループ ラベルは必要ありません。
- コードレット ディレクティブは関数宣言の直前に挿入されます。
ディレクティブの構文は次のとおりです。
#pragma hmpp < grp_label > codelet_labelコードレット [ 、バージョン= Major.minor[.micro]?]? [ , args[ arg_items ].io= [[ in | out | inout ]]* [ , args[ arg_items ].size={ dimsize[,dimsize]* } ]* [ , args[ arg_items ].const=true ]* [ , 条件 = "式"] [ , target=ターゲット名[:ターゲット名]*]
異なる用途や異なる実行コンテキストを指定するために、関数に複数のコードレット ディレクティブを追加できます。ただし、特定の呼び出しサイト ラベルに対しては、コードレット ディレクティブは 1 つしか存在できません。
ディレクティブcallsiteは、プログラム内の特定の時点でコードレットを使用する方法を指定します。
ディレクティブの構文は次のとおりです。
#pragma hmpp < grp_label > codelet_label呼び出し元 [ 、非同期]? [ , args[ arg_items ].size={ dimsize[,dimsize]* } ]* [ , args[ arg_items ].advancedload= [[ true | false ]]* [ , args[ arg_items ].addr=" expr " ]* [ , args[ arg_items ].noupdate=true ]*
以下に例を示します。
/* コードレットの宣言 */
#pragma hmpp simple1 codelet, args[outv].io=inout, target=CUDA static void matvec ( int sn , int sm , float 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 ; ...... /* コードレットの使用 */ #pragma hmpp simple1 callsite, args[outv].size={n} matvec ( n , m , myinc , inm , myoutv ); ...... }
場合によっては、アプリケーション全体にわたるデータの特定の管理が必要になります (CPU/GPU データ移動の最適化、共有変数など)。
ディレクティブgroupを使用すると、コードレットのグループを宣言できます。このディレクティブで定義されたパラメータは、グループに属するすべてのコードレットに適用されます。ディレクティブの構文は次のとおりです。
#pragma hmpp < grp_label > グループ [ 、バージョン = <メジャー>.<マイナー>[.<マイクロ>]?]? [ 、ターゲット = target_name [: target_name ]*]]? [ 、条件 = “ expr ” ]?
通信オーバーヘッドを最適化するためのデータ転送指示
HWA を使用する場合、主なボトルネックとなるのは、多くの場合、HWA とメイン プロセッサ間のデータ転送です。
通信オーバーヘッドを制限するために、HWA の非同期プロパティを使用して、同じコードレットの連続実行とデータ転送を重ねることができます。
- 割り当てディレクティブ
ディレクティブallocateは HWA をロックし、必要な量のメモリを割り当てます。
#pragma hmpp < grp_label > 割り当て[ ,args[ arg_items ].size={ dimsize[,dimsize]* } ]*
- リリース指令
ディレクティブreleaseは、グループまたはスタンドアロン コードレットの HWA をいつリリースするかを指定します。
#pragma hmpp <グループラベル>リリース
- advancedload ディレクティブ
ディレクティブadvancedloadは、コードレットのリモート実行の前にデータをプリフェッチします。
#pragma hmpp < grp_label > [codelet_label]? advancedload ,args[ arg_items ] [ ,args[ arg_items ].size={ dimsize[,dimsize]* } ]* [ ,args[ arg_items ].addr="式" ]* [ ,args[ arg_items ].section={ [添字トリプレット, ]+ } ]* [ 、非同期]
- delegatedstore ディレクティブ
このdelegatedstoreディレクティブは、非同期コードレットの実行が完了するまで待機し、結果をダウンロードするための同期バリアです。
#pragma hmpp < grp_label > [codelet_label]? delegatedstore ,args[ arg_items ] [ ,args[ arg_items ].addr=" expr " ]* [ ,args[ arg_items ].section={ [添字トリプレット, ]+ } ]*
- 非同期計算
ディレクティブsynchronizeは、非同期呼び出しサイトの実行が完了するまで待機することを指定します。同期ディレクティブの場合、コードレット ラベルは常に必須であり、コードレットがグループに属している場合はグループ ラベルが必要です。
#pragma hmpp < grp_label > codelet_label同期
- 例
次の例では、デバイスの初期化、メモリの割り当て、および入力データのアップロードは、ループの各反復ではなく、ループの外で 1 回だけ実行されます。
このsynchronizeディレクティブにより、コードレットの非同期実行が完了するまで待機してから、別の反復を開始できます。最後に、delegatedstoreループ外のディレクティブが sgemm の結果をアップロードします。
int main ( int argc 、char ** argv ) { #pragma hmpp sgemm allocate、 args[vin1;vin2;vout].size={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、synchronous、 args[vin1;vin2;vout].advancedload=true、 args[m、n、k、alpha、beta].advancedload=true sgemm ( size 、size 、size 、alpha 、vin1 、vin2 、beta 、vout ); #pragma hmpp sgemm synchronize } #pragma hmpp sgemm delegatedstore, args[vout] #pragma hmpp sgemm release
コードレット間でデータを共有する
これらのディレクティブは、グループ全体で指定された名前を共有するすべての引数をマップします。
すべてのマップされた引数の型と次元は同一である必要があります。
ディレクティブmapはデバイス上のいくつかの引数をマップします。
#pragma hmpp < grp_label > マップ、args[ arg_items ]
mapこのディレクティブは、マップされる引数が名前で直接指定されることを除いて、 ディレクティブと非常によく似ています。mapbynameディレクティブは、複数のディレクティブと同等ですmap。
#pragma hmpp <グループラベル> mapbyname [ ,変数名]+
グローバル変数
このresidentディレクティブは、グループ内のいくつかの変数をグローバルとして宣言します。これらの変数は、グループに属する任意のコードレットから直接アクセスできます。このディレクティブは、ソース コード内で直後の宣言ステートメントに適用されます。
このディレクティブの構文は次のとおりです。
#pragma hmpp < grp_label > resident [ , args[:: var_name ].io= [[ in | out | inout ]]* [ , args[:: var_name ].size={ dimsize[,dimsize]* } ]* [ , 引数[:: var_name ].addr="式" ]* [ , 引数[:: var_name ].const=true ]*
::var_name プレフィックス , が付いた表記は::、アプリケーションの変数が常駐として宣言されていることを示します。
地域の加速
リージョンは、コードレット/呼び出しサイト ディレクティブのマージです。目標は、コードレットを構築するためのコードの再構築を回避することです。したがって、codeletまたはcallsiteディレクティブで使用可能なすべての属性をディレクティブで使用できますregions。
C言語の場合:
#pragma hmpp [< MyGroup >] [ label ] region [ , args[ arg_items ].io= [[ in | out | inout ]]* [ , 条件 = "式"] < [ , args[ arg_items ].const=true ]* [ , target=ターゲット名[ :ターゲット名]*] [ , args[ arg_items ].size={ dimsize[ , dimsize]* } ]* [ , args[ arg_items ].advancedload= [[ true | false ]]* [ , args[ arg_items ].addr=" expr " ]* [ , args[ arg_items ].noupdate=true ]* [ 、非同期]? [ , プライベート=[ arg_items ] ]* { C ブロックステートメント }
実装
OpenHMPP オープン スタンダードは、HMPP バージョン 2.3 (2009 年 5 月、CAPS entreprise) に基づいています。
OpenHMPP ディレクティブベースのプログラミング モデルは、次のものに実装されています。
- CAPS コンパイラ、ハイブリッド コンピューティング向け CAPS エンタープライズ コンパイラ
- PathScale ENZO コンパイラ スイート (NVIDIA GPU をサポート)
OpenHMPP は、石油・ガス、[引用が必要]エネルギー、[引用が必要]製造、[引用が必要]金融、[引用が必要]教育・研究のHPC関係者[誰? ]によって使用されています。[引用が必要]
参照
参考文献
- ^ Dolbeau, Romain; Bihan, Stéphane; Bodin, François (2007 年 10 月 4 日). HMPP: ハイブリッド マルチコア並列プログラミング環境(PDF) . グラフィックス プロセッシング ユニットでの汎用処理に関するワークショップ。2014年 1 月 16 日時点のオリジナル(PDF)からアーカイブ。2014年1 月 14 日閲覧。
