インテル® Fortran コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス

非同期データ転送について (インテル® MIC アーキテクチャー)

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

CPU とターゲットデバイス間でデータを転送するには、すべて in 節またはすべて out 節の OFFLOAD_TRANSFER ディレクティブを使用します。signal 節が指定されていない場合、データ転送は同期され、それ以降の文はデータ転送が完了した後に実行されます。

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

ターゲットデバイスは、タグに関連付けられているすべてのデータの受信または共有が完了すると、後の wait 節が記述されたディレクティブで指定されている処理を開始します。データは、データ転送の開始時に指定された変数に格納されます。これらの変数はアクセス可能でなければなりません。

または、非ブロック API OFFLOAD_SIGNALED() を使用して、特定のターゲットデバイスでオフロードコードのセクションの実行が完了したかどうか判断することもできます。

注

インテル® AVX MIC アーキテクチャー上では、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 からターゲットへの非同期データ転送

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

ターゲットから CPU への非同期データ転送

ターゲットから CPU にデータを非同期で転送するには、2 つの異なるディレクティブで signal 節と wait 節を使用します。最初のディレクティブはデータ転送を開始し、次のディレクティブはデータ転送が完了するのを待機します。

CPU からターゲットへ転送する例

次の例では、浮動小数点配列 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 へ転送する例

次の例では、浮動小数点配列 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

関連情報