非同期データ転送について

このトピックは、インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャーにのみ適用されます。

CPU とコプロセッサー間でデータを転送するには、すべて in 節またはすべて out 節の OFFLOAD_TRANSFER 宣言子を使用します。 signal 節が指定されていない場合、データ転送は同期され、その次の文はデータ転送が完了した後に実行されます。

OFFLOAD_TRANSFERsignal 節が指定されると、データ転送は非同期になります。 signal 節で指定されるタグは、そのデータセットに関連付けられているアドレス式です。 データ転送が開始され、CPU は その宣言子以降の文を続行します。

コプロセッサーはタグに関連付けられているデータをすべて受信すると、後の wait 節が記述された宣言子で指定されている処理を開始します。 データは、データ転送の開始時に指定された変数に格納されます。これらの変数はアクセス可能でなければなりません。

CPU からコプロセッサーへの非同期データ転送

CPU からコプロセッサーにデータを非同期で転送するには、OFFLOAD_TRANSFER 宣言子in 節で signal 節を使用します。 in 節にリストされる変数によりデータセットが形成されます。 宣言子は、CPU からコプロセッサーへこれらの変数のデータ転送を開始します。 wait 節を含む以降の OFFLOAD 宣言子 (signal 節で使用されたタグと同じ値を使用) で制御された文は、データ転送が完了した後にコプロセッサーで実行されます。

非同期オフロード中に 1 つのスレッド (スレッド A) でシグナルが作成され、別のスレッドが (スレッド B) そのシグナルを待機する場合、スレッド A が非同期オフロードを開始しシグナルを設定する前にスレッド B がそのシグナルを照会しないようにしなければなりません。スレッド A が非同期オフロードを開始しシグナルを設定する前にスレッド B がそのシグナルを照会すると、未定義の動作を引き起こし、ランタイムでアプリケーションがアボートします。

例: CPU からコプロセッサー

次の例では、浮動小数点配列 f1 のデータ転送が 10 行目、f2 のデータ転送が 12 行目で開始されます。 オフロードは計算を開始しません。 f1f2 をコプロセッサーへ転送するだけです。 14 行目で、CPU はコプロセッサーで関数 foo の計算を開始します。 この関数は、直前に転送が開始されたデータ f1f2 を使用します。 コプロセッサーのオフロード領域の実行は、f1f2 の転送が完了した後に開始されます。 変数 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 プラグマを使用して、f1f2 を別々にコプロセッサーに送信しています (10 行目で f113 行目で 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 への非同期データ転送

コプロセッサーから CPU にデータを非同期で転送するには、2 つの異なるプラグマ/宣言子で signal 節と wait 節を使用します。 最初のプラグマはデータ転送を開始し、次のプラグマはデータ転送が完了するのを待機します。

例: コプロセッサーから CPU

次の例では、浮動小数点配列 in1in2 のデータ転送が 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

このヘルプトピックについてのフィードバックを送信