このトピックは、インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャーにのみ適用されます。
CPU とコプロセッサー間でデータを転送するには、すべて in 節またはすべて out 節の OFFLOAD_TRANSFER 宣言子を使用します。 signal 節が指定されていない場合、データ転送は同期され、その次の文はデータ転送が完了した後に実行されます。
OFFLOAD_TRANSFER に signal 節が指定されると、データ転送は非同期になります。 signal 節で指定されるタグは、そのデータセットに関連付けられているアドレス式です。 データ転送が開始され、CPU は その宣言子以降の文を続行します。
コプロセッサーはタグに関連付けられているデータをすべて受信すると、後の wait 節が記述された宣言子で指定されている処理を開始します。 データは、データ転送の開始時に指定された変数に格納されます。これらの変数はアクセス可能でなければなりません。
CPU からコプロセッサーにデータを非同期で転送するには、OFFLOAD_TRANSFER 宣言子の in 節で signal 節を使用します。 in 節にリストされる変数によりデータセットが形成されます。 宣言子は、CPU からコプロセッサーへこれらの変数のデータ転送を開始します。 wait 節を含む以降の OFFLOAD 宣言子 (signal 節で使用されたタグと同じ値を使用) で制御された文は、データ転送が完了した後にコプロセッサーで実行されます。
非同期オフロード中に 1 つのスレッド (スレッド A) でシグナルが作成され、別のスレッドが (スレッド B) そのシグナルを待機する場合、スレッド A が非同期オフロードを開始しシグナルを設定する前にスレッド B がそのシグナルを照会しないようにしなければなりません。スレッド A が非同期オフロードを開始しシグナルを設定する前にスレッド B がそのシグナルを照会すると、未定義の動作を引き起こし、ランタイムでアプリケーションがアボートします。
次の例では、浮動小数点配列 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
コプロセッサーから CPU にデータを非同期で転送するには、2 つの異なるプラグマ/宣言子で signal 節と wait 節を使用します。 最初のプラグマはデータ転送を開始し、次のプラグマはデータ転送が完了するのを待機します。
次の例では、浮動小数点配列 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 !dec$ 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-1) 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-1) 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