インテル® Fortran コンパイラー 17.0 デベロッパー・ガイドおよびリファレンス
このトピックは、インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャーにのみ適用されます。
CPU とコプロセッサー間でデータを転送するには、すべて in 節またはすべて out 節の OFFLOAD_TRANSFER ディレクティブを使用します。 signal 節が指定されていない場合、データ転送は同期され、それ以降の文はデータ転送が完了した後に実行されます。
OFFLOAD_TRANSFER に signal 節が指定されると、データ転送は非同期になります。 signal 節で指定されるタグは、そのデータセットに関連付けられているアドレス式です。 データ転送が開始され、CPU はそのディレクティブ以降の文を続行します。
コプロセッサーはタグに関連付けられているデータをすべて受け取ると、後の wait 節が記述されたディレクティブで指定されている処理を開始します。
データは、データ転送の開始時に指定された変数に格納されます。これらの変数はアクセス可能でなければなりません。
または、非ブロック API OFFLOAD_SIGNALED() を使用して、特定のターゲットデバイスでオフロードコードのセクションの実行が完了したかどうか判断することもできます。
signal 節と wait 節、OFFLOAD_WAIT 構造、および OFFLOAD_SIGNALED() API は、特定のターゲットデバイスに関連するため、target() 節で target-number を指定する必要があります。
シグナルが開始される前にシグナルを照会すると、未定義の動作を引き起こし、アプリケーションはランタイムアボートします。 例えば、ターゲットデバイス 1 で開始されたシグナル (SIG1) をターゲットデバイス 0 で照会する場合について考えてみます。 シグナルはターゲットデバイス 1 で開始されているため、ターゲットデバイス 0 に関連付けられたシグナル (SIG1) はなく、アプリケーションはアボートします。
非同期オフロード中に 1 つのスレッド (スレッド A) でシグナルが作成され、別のスレッドが (スレッド B) そのシグナルを待機する場合、スレッド A が非同期オフロードを開始しシグナルを設定する前はスレッド B がそのシグナルを照会してはなりません。これを行うと、アプリケーションはランタイムアボートします。
signal (tag) 節を使用している場合、if-specifier が FALSE と評価されると、シグナルは未定義となり、このシグナルの待機は未定義の動作を引き起こします。
CPU からコプロセッサーにデータを非同期で転送するには、OFFLOAD_TRANSFER ディレクティブの in 節で signal 節を使用します。
in 節にリストされる変数によりデータセットが形成されます。
ディレクティブは、CPU からコプロセッサーへこれらの変数のデータ転送を開始します。
wait 節を含む以降の OFFLOAD ディレクティブ (signal 節で使用されたタグと同じ値を使用) で制御された文は、データ転送が完了した後にコプロセッサーで実行されます。
コプロセッサーから CPU にデータを非同期で転送するには、2 つの異なるディレクティブで signal 節と wait 節を使用します。 最初のディレクティブはデータ転送を開始し、次のディレクティブはデータ転送が完了するのを待機します。
次の例では、浮動小数点配列 f1 のデータ転送が 10 行目、f2 のデータ転送が 12 行目で開始されます。オフロードは計算を開始しません。f1 と f2 をコプロセッサーへ転送するだけです。 14 行目で、CPU はコプロセッサーで関数 foo の計算を開始します。 この関数は、直前に転送が開始されたデータ f1 と f2 を使用します。 コプロセッサーのオフロード領域の実行は、f1 と f2 の転送が完了した後に開始されます。 変数 result は、計算結果を返します。
01 integer, parameter:: n=4086 02 real, allocatable :: f1(:), f2(:), result 03 !dir$ attributes offload:mic :: f1, f2, foo 04 integer :: signal_1, signal_2 05 !dir$ attributes align : 64 :: f1 06 !dir$ attributes align : 64 :: f2 07 allocate(f1(n)) 08 allocate(f2(n)) 09 f1 = 1.0 10 !dir$ offload_transfer target (mic:0) in(f1) signal(signal_1) 11 f2 = 3.14 12 !dir$ offload_transfer target (mic:0) in(f2) signal(signal_2) 13 !dir$ offload begin target(mic:0) wait (signal_1, signal_2) 14 result = foo(n, f1, f2) 15 !dir$ end offload
複数の独立した非同期データ転送が発生する可能性があります。次の例では、offload_transfer プラグマを使用して、f1 と f2 を別々にコプロセッサーに送信しています (10 行目で f1、13 行目で f2)。
01 program main 02 integer, parameter:: n=4086 03 real, allocatable :: f1(:), f2(:), result 04 !dir$ attributes offload:mic :: f1, f2, foo 05 integer :: signal_1, signal_2 06 !dir$ attributes align : 64 :: f1 07 !dir$ attributes align : 64 :: f2 08 allocate(f1(n)) 09 allocate(f2(n)) 10 !dir$ offload begin target(mic:0) in (f1 ) nocopy (f2) signal(signal_1) 11 call foo(N, f1, f2) 12 !dir$ end offload 13 !dir$ offload_transfer target(mic:0) wait(signal_1) out (f2) 14 end program main
次の例では、浮動小数点配列 in1 と in2 のデータ転送が 15 行目で開始されます。 このプラグマは計算を開始しません。in1 をコプロセッサーへ転送するだけです。 do ループ内で in1 または in2 のいずれかはコプロセッサーに転送され、転送されたセットの計算が開始されます。 20 行目で CPU はコプロセッサーで関数 compute の計算を開始し、in1 を処理するように指示します。 24 行目で CPU はコプロセッサーで関数 compute の計算を開始し、23 行目で転送された in2 を処理するように指示します。
次の例は、オフロードの入力をダブルバッファーにしています。
01 module M 02 integer, parameter :: NNN = 100 03 integer, parameter :: count = 25000000 04 integer :: arr(NNN) 05 real :: dd 06 !dir$ attributes offload:mic::arr, dd 07 end module M 08 subroutine do_async_in() 09 !dir$ attributes offload:mic :: compute 10 use m 11 integer i, signal_1, signal_2, iter 12 real, allocatable :: in1(:), in2(:) 13 real, allocatable :: out1(:), out2(:) 14 iter = 10 15 !dir$ offload_transfer target(mic:0) in(in1 : length(count) alloc_if(.false.) free_if(.false.) ) signal(signal_1) 16 do i=1, iter 17 if (mod(i,2) == 0) then 18 !dir$ offload_transfer target(mic:0) if(i .ne. iter) in(in2 : length(count) alloc_if(.false.) free_if(.false.) ) signal(signal_2) 19 !dir$ offload target(mic:0) nocopy(in1) wait(signal_1) out(out1 : length(count) alloc_if(.false.) free_if(.false.) ) 20 call compute(in1, out1) 21 else 22 !dir$ offload_transfer target(mic:0) if(i .ne. iter) in(in1 : length(count) alloc_if(.false.) free_if(.false.) ) signal(signal_1) 23 !dir$ offload target(mic:0) nocopy(in2) wait(signal_2) out(out2 : length(count) alloc_if(.false.) free_if(.false.) ) 24 call compute(in2, out2) 25 endif 26 end do 27 end subroutine do_async_in