インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
同期データ転送を開始して完了します。signal 節と一緒に使用すると、非同期データ転送を開始します。このプラグマは、インテル® MIC アーキテクチャーにのみ適用されます。
#pragma offload_transfer clause[clause...] |
必須の指示節
offload-parameter
target ( target-name [ :target-number ] )
オプション指示節
if-clause
mandatory
optional
signal ( tag )
status ( statusvarname )
stream ( handle )
wait ( tag[, tag, ...])
必須の指示節
ホストとターゲット間でコピーされるプログラム変数とデータの量を制御します。clause (節) は次のいずれかです。
in |
ターゲット領域への入力に使用する変数。この値はターゲット領域が完了した後にターゲットからホストにコピーされません。 構文: in ( variable-ref [, variable-ref …] [ modifier[ , modifier… ] ] ) |
out |
ターゲット領域の出力に使用する変数。ホストはこの変数をターゲットにコピーしません。 構文: out ( variable-ref [, variable-ref …] [ modifier[ , modifier… ] ] ) |
nocopy |
以前のターゲットの実行から再利用される値、またはオフロードされたコードセクション内で使用される値を含む変数は、コピーを防ぐために nocopy 節にリストします。 構文: nocopy ( variable-ref [, variable-ref …] [ modifier[ , modifier… ] ] ) |
in または out 式 (後述の modifier の説明を参照) は、式が記述される文または節の前で評価されます。
宣言からサイズが分かる配列変数は全体でコピーされます。配列のサブセットを処理する場合、サブセットの開始要素へのポインターと element-count-expr を使用して配列のサブセットを転送します。
この引数の変数は次のとおりです。
variable-ref |
次のいずれかです。
|
||||||||||||||||||||
modifier |
次のいずれかです。
|
||||||||||||||||||||
target-name はターゲットを表します。インテル® Xeon Phi™ 製品の場合は mic を使用します。
target-number は signal 節と wait 節に必須です。target-number は整数式です。値は次のように解釈されます。
次の式に応じて、文を特定のターゲット上で実行します。
target = target-number % number_of_targets
例えば、4 つのターゲットを搭載したシステムの場合:
2 または 6 を指定すると、ランタイムシステムはターゲット 2 でコードを実行します (2 % 4 と 6 % 4 はどちらも 2 になるため)。
1000 を指定すると、ランタイムシステムはターゲット 0 でコードを実行します (1000 % 4 = 0 になるため)。
文をランタイムシステムによって選択されたターゲット上で実行します。
予約済み。
target-number は signal 節と wait 節に必須です。
ターゲットが利用できない場合、optional 節を一緒に指定しない限り、プログラムは実行に失敗してエラーメッセージを出力します。optional 節は、ターゲットが利用できないときに文をホストで実行します。
オプション指示節
ブール式。
式の評価結果 |
動作 |
---|---|
true |
文はターゲットで実行されます。 |
false |
文はホストで実行されます。if-clause と signal 節あるいは wait 節を一緒に使用した場合の動作は不定です。 |
この節を使用してオフロードを有効にするかどうかを制御します。関連するオフロード文がすべて有効または無効になるように、関連するプラグマでこの節を適切に使用してください。
ターゲットで実行する必要がある場合に指定します。ホストで実行することはできません。
ターゲット・ハードウェアが利用できない場合にプログラムの実行を継続するには、statusvarname 変数を初期化して、このプラグマで status ( statusvarname ) 節を指定します。後述の「説明」セクションでステータス変数の初期化方法と設定可能な値について説明します。
optional 節を指定しないと、この節を指定した場合と同じになります。この節を明示的に指定することで、暗黙のデフォルトを明確にすることができます。
ターゲットでの実行を要求しますが、必須ではありません。ターゲットが利用できない場合にホストで実行するように指定します。
ターゲットではなく、ホストで文が実行された理由を確認するには、statusvarname 変数を初期化して、このプラグマで status ( statusvarname ) 節を指定します。後述の「説明」セクションでステータス変数の初期化方法と設定可能な値について説明します。
mandatory 節はこの節の逆です。そのため、同じプラグマでこの節と一緒に使用しないでください。
非同期データ転送または計算処理のハンドルとなります。演算はオフロードで処理され、ホストでプラグマ以降のコードを実行中に out 節によりオフロードから結果が返されます。この節がない場合、オフロード全体と関連するデータ転送は同期して実行されます。ホストは、プラグマが完了するまでそれ以降のコードを実行しません。
tag は、ポインターのサイズ値をベースライン言語で表現したもので、非同期データ転送または計算処理のハンドルとして使用されます。
この節を使用する場合、target 節で 0 以上の target-number を指定します。
オフロード構造の実行状態を特定します。statusvarname 変数には、実行状態を示す値が含まれます。後述の「説明」セクションでステータス変数の初期化方法と設定可能な値について説明します。
optional 節と一緒に使用し、ターゲットが利用できない場合、ターゲットで実行される文は代わりにホストで実行されます。
mandatory 節と一緒に使用し、ターゲットが利用できない場合、ターゲットで実行される文は無視され、プログラムは実行を継続します。文が無視されたり、ホストで実行された理由を確認するには、この変数の値を調べます。
handle で指定した stream へオフロードします。handle は、ストリームを作成するインテル® MIC アーキテクチャー・ベースのデバイスを指定する _Offload_create_stream 関数から取得されます。オフロードは、ストリームが作成されたデバイスに対して実行されます。詳細は、「ストリームを使用したオフロード」を参照します。
開始した非同期データ転送または非同期計算を待つ場合に指定します。
tag は、ポインターのサイズ値をベースライン言語で表現したものです。signal 節と同じ表現の値が使用され、開始した非同期処理のハンドルとして使用されます。ここで言う非同期処理は、非同期データ転送または非同期計算です。
この節を使用する場合、target 節で 0 以上の target-number を指定します。
シグナルが開始される前にシグナルを照会すると、未定義の動作を引き起こし、アプリケーションはランタイムアボートします。例えば、target:1 で開始されたシグナルを target:0 で照会すると、シグナルは target:1 で開始されているため、target:0 に関連付けられたシグナルはなく、アプリケーションはランタイムアボートします。
このプラグマは、非同期データ転送を開始し、同期データ転送を開始して完了します。
プラグマに続く文は、ターゲットが利用可能な場合、ターゲットで実行されます。ターゲットが利用できない場合、optional、mandatory、および status (statusvarname) 節により文の実行方法が決定されます。
指定する節 |
動作 |
---|---|
optional |
文はホストで実行されます。 |
optional および status (statusvarname) |
文はホストで実行され、statusvarname にターゲットを利用できない理由が格納されます。 |
mandatory |
文は無視され、プログラムは終了します。 |
mandatory および status (statusvarname) |
文は無視され、プログラムは実行を継続します。statusvarname にターゲットを利用できない理由が格納されます。 |
statusvarname ステータス変数を初期化するには、OFFLOAD_STATUS_INIT(statusvarname) マクロを使用します。ステータス変数の値は offload.h で定義されています。設定可能な値は次のとおりです。
値 |
説明 |
---|---|
OFFLOAD_SUCCESS = 0 |
文はターゲットで実行されました。 |
OFFLOAD_DISABLED |
文はターゲットで実行されませんでした。if-clause を指定し、その値が false の場合、文はホストで実行されました。 |
OFFLOAD_UNAVAILABLE |
ターゲットが利用できないため、文はターゲットで実行されませんでした。 |
OFFLOAD_OUT_OF_MEMORY |
offload-parameter 用のメモリーが不足していたため、文はターゲットで実行されませんでした。 |
OFFLOAD_PROCESS_DIED |
ターゲットでランタイムエラーが発生し、ターゲットのプロセスが終了したため、文はターゲットで実行されませんでした。 |
OFFLOAD_ERROR |
エラーが発生したため、文はターゲットで実行されませんでした。 |
2 つの異なるプラグマを使用してターゲットとホストからデータを非同期に受け取る例 |
---|
01 const int N = 4086; 02 float *f1, *f2; 03 f1 = (float *)memalign(64, N*sizeof(float)); 04 f2 = (float *)memalign(64, N*sizeof(float)); ... 10 // ホストは入力同期として f1 を送信 11 // 出力は f2 にあるが直ちに必要ではない 12 #pragma offload target (mic:0) signal(f2) \ 13 in( f1 : length(N) ) \ 14 nocopy( f2 : length(N) ) signal(f2) 15 { 16 foo(N, f1, f2); 17 } .. 20 #pragma offload_transfer (mic:0) wait(f2) \ out( f2 : length(N) alloc_if(0) free_if(1)) 21 22 // ホストは f2 の結果を使用可能 |
offload_target プラグマはデータ転送を開始し、offload_transfer プラグマはデータ転送が完了するのを待機します。
オフロードの入力をダブルバッファーにする例 |
---|
#pragma offload_attribute(push, target(mic)) int count = 25000000; int iter = 10; float *in1, *out1; float *in2, *out2; #pragma offload_attribute(pop) void do_async_in() { int i; #pragma offload_transfer target(mic:0) in(in1 : length(count) alloc_if(0) free_if(0) ) signal(in1) for (i=0; i<iter; i++) { if (i%2 == 0) { #pragma offload_transfer target(mic:0) if(i!=iter-1) in(in2 : length(count) alloc_if(0) free_if(0) ) signal(in2) #pragma offload target(mic:0) nocopy(in1) wait(in1) out(out1 : length(count) alloc_if(0) free_if(0) ) compute(in1, out1); } else { #pragma offload_transfer target(mic:0) if(i!=iter-1) in(in1 : length(count) alloc_if(0) free_if(0) ) signal(in1) #pragma offload target(mic:0) nocopy(in2) wait(in2) out(out2 : length(count) alloc_if(0) free_if(0) ) compute(in2, out2); } } } |
ターゲットでアライメントを指定するポインター配列の例 |
---|
#define ARRAY_SIZE 4 #define DATA_ELEMS 100 __declspec(target(mic)) int start[ARRAY_SIZE]; __declspec(target(mic)) int len[ARRAY_SIZE]; __declspec(target(mic)) int align[ARRAY_SIZE]; __declspec(target(mic)) float *p[ARRAY_SIZE]; float *q[ARRAY_SIZE]; int main() { int i, j; bool failed = false; bool align_failed = false; for (i=0; i<ARRAY_SIZE; i++) { // ポインター配列要素の割り当て。利用可能なメモリーがあると仮定。 p[i] = (float *)malloc(sizeof(float)*DATA_ELEMS); q[i] = (float *)malloc(sizeof(float)*DATA_ELEMS); p[i][0:DATA_ELEMS] = i; q[i][0:DATA_ELEMS] = p[i][0:DATA_ELEMS]; } start[0] = 0; start[1] = 1; start[2] = 1; start[3] = 0; len[0] = DATA_ELEMS; len[1] = DATA_ELEMS - 2; len[2] = DATA_ELEMS - 2; len[3] = DATA_ELEMS; align[0] = 2048; align[1] = 4096; align[2] = 8192; align[3] = 8; // start と length はセクション // alloc_if と free_if のデフォルト値 // アライメントを指定する // 配列の割り当ては element 0 から開始するが、転送はそうではない // いくつかの要素を更新して MIC から取得する // UUUUUUUUUUUUUU // .UUUUUUUUUUUU. // .UUUUUUUUUUUU. // UUUUUUUUUUUUUU #pragma offload target(mic) \ inout( p[0:ARRAY_SIZE] : \ extent(start[0:ARRAY_SIZE]:len[0:ARRAY_SIZE]) \ align(align[0:ARRAY_SIZE]) ) { for (i=0; i<ARRAY_SIZE; i++) { if (((long long)&p[i][0] & (align[i]-1)) != 0) { align_failed = true; printf("p[%d] failed alignment\n", i); fflush(0); } p[i][start[i]:len[i]] += 1.0; } } ... return 0; } |
ポインター配列と部分配列を使用する alloc_if と free_if の例 |
---|
#define ARRAY_SIZE 4 #define DATA_ELEMS 100 __declspec(target(mic)) int start[ARRAY_SIZE]; __declspec(target(mic)) int len[ARRAY_SIZE]; __declspec(target(mic)) int allocif[ARRAY_SIZE]; __declspec(target(mic)) int freeif[ARRAY_SIZE]; __declspec(target(mic)) int *p[ARRAY_SIZE]; int main() { int i, j; bool failed = false; for (i=0; i<ARRAY_SIZE; i++) { // ポインター配列要素の割り当て。利用可能なメモリーがあると仮定。 p[i] = (int *)malloc(sizeof(int)*DATA_ELEMS); p[i][0:DATA_ELEMS] = i; } start[:] = 1; len[:] = 98; // start と length はセクション // free_if と align のデフォルト値 // alloc_if はベクトルを使用し、free_if はスカラー拡張を使用する // 割り当てのみ allocif[:] = 1; #pragma offload_transfer target(mic) \ nocopy( p[0:ARRAY_SIZE] : \ extent(start[0:ARRAY_SIZE]:len[0:ARRAY_SIZE]) \ alloc_if(allocif[0:ARRAY_SIZE]) \ free_if(0) ) // メモリーを再利用してオフロードを行う #pragma offload target(mic) \ inout( p[0:ARRAY_SIZE] : \ extent(start[0:ARRAY_SIZE]:len[0:ARRAY_SIZE]) \ alloc_if(0) \ free_if(0) ) { for (i=0; i<ARRAY_SIZE; i++) { p[i][start[i]:len[i]] += 1; } } // メモリーを解放する // alloc_if はスカラー、free_if はベクトル freeif[:] = 1; #pragma offload_transfer target(mic) \ nocopy( p[0:ARRAY_SIZE] : \ extent(start[0:ARRAY_SIZE]:len[0:ARRAY_SIZE]) \ alloc_if(0) \ free_if(freeif[0:ARRAY_SIZE]) ) ... return 0; } |
into、into_extent、alloc_extent を使用するポインター配列の例 |
---|
#define ARRAY_SIZE 4 #define DATA_ELEMS 100 #define SEND_ROWS 2 #define SEND_COLS 50 #define P_OFFSET_IN 2 #define P_OFFSET_OUT 0 #define Q_OFFSET 0 #define COL_OFFSET 50 __declspec(target(mic)) int len[ARRAY_SIZE]; __declspec(target(mic)) short int *p[ARRAY_SIZE]; __declspec(target(mic)) short int *q[ARRAY_SIZE*2]; #ifdef RUN_ON_CPU bool run_on_cpu = true; #else __declspec(target(mic)) bool run_on_cpu = false; #endif int main() { int i, j; bool failed = false; for (i=0; i<ARRAY_SIZE; i++) { // ポインター配列要素の割り当て。利用可能なメモリーがあると仮定。 p[i] = (short int *)malloc(sizeof(short int)*DATA_ELEMS); q[i] = (short int *)malloc(sizeof(short int)*DATA_ELEMS); q[i+ARRAY_SIZE] = (short int *)malloc(sizeof(short int)*DATA_ELEMS); p[i][0:DATA_ELEMS] = i; } len[:] = SEND_COLS; // start と length の拡張にスカラーを使用 // alloc_if、free_if、align のデフォルト値 // MIC に転送されるデータと MIC から転送されるデータ // p[2][50:50] -> q[0][50:50] は指定された 50 要素のみ割り当てる // p[3][50:50] -> q[1][50:50] は指定された 50 要素のみ割り当てる // 計算を実行する // p[0][50:50] <- q[0][50:50] // p[1][50:50] <- q[1][50:50] #pragma offload target(mic) \ in (p[P_OFFSET_IN:SEND_ROWS] : extent(COL_OFFSET:SEND_COLS) \ into(q[Q_OFFSET:SEND_ROWS]) into_extent(COL_OFFSET:SEND_COLS) \ alloc_extent(COL_OFFSET:len[0:SEND_ROWS]) ) \ out(q[Q_OFFSET:SEND_ROWS] : extent(COL_OFFSET:SEND_COLS) \ into(p[P_OFFSET_OUT:SEND_ROWS]) into_extent(COL_OFFSET:SEND_COLS) ) { for (i=0; i<SEND_ROWS; i++) { // CPU で実行する場合は "in into" を模倣する if (run_on_cpu) { q[Q_OFFSET+i][COL_OFFSET:SEND_COLS] = p[P_OFFSET_IN+i][COL_OFFSET:SEND_COLS]; } q[Q_OFFSET+i][COL_OFFSET:SEND_COLS] += i*2; // CPU で実行する場合は "out into" を模倣する if (run_on_cpu) { p[P_OFFSET_OUT+i][COL_OFFSET:SEND_COLS] = q[Q_OFFSET+i][COL_OFFSET:SEND_COLS]; } } } ... return 0; } |