C/C++ または Fortran と OpenMP* オフロード・プログラミング・モデル

インテル® oneAPI DPC++/C++ コンパイラーおよび、インテル® Fortran コンパイラーを使用すると、OpenMP* ディレクティブを使用してワークをインテルのアクセラレーター・デバイスにオフロードし、アプリケーションのパフォーマンスを向上できます。

このセクションでは、OpenMP* ディレクティブを使用して計算をアクセラレーター・デバイスにオフロードする方法について説明します。OpenMP* ディレクティブに慣れていない開発者は、インテル® oneAPI DPC++/C++ コンパイラー・デベロッパー・ガイドおよびリファレンス (英語) や インテル® Fortran コンパイラー・デベロッパー・ガイドおよびリファレンス (英語) の OpenMP* サポートのセクションで基本的な使い方をご覧いただけます。

OpenMP* は、FPGA デバイスではサポートされません。

基本的な OpenMP* target 構造

OpenMP* target 構造は、ホストからターゲットデバイスへ制御を移行するために使用されます。変数はホストとターゲットデバイスでマッピングされます。ホストスレッドは、オフロードされた計算が完了するまで待機します。ほかの OpenMP* タスクは、ホストで非同期に実行できます。それには、nowait 節を使用して、スレッドがターゲット領域の完了を待機しないようにします。

C/C++

次の C++ のコードは、SAXPY 計算をアクセラレーターにオフロードします。

#pragma omp target map(tofrom:fa), map(to:fb,a) 
#pragma omp parallel for firstprivate(a) 
for(k=0; k<FLOPS_ARRAY_SIZE; k++) 
    fa[k] = a * fa[k] + fb[k]

配列 fa は、計算の入力と出力の両方で使用されるため、アクセラレーターの to と from にマップされます。配列 fb と変数 a は計算の入力であり変更されることがないため、その出力をコピーする必要はありません。 変数 FLOPS_ARRAY_SIZE はアクセラレーターに暗黙にマップされます。ループ・インデックス k は、OpenMP* に従って暗黙的にプライベートです。

Fortran

この Fortran のコードのコードスニペットは、行列乗算をアクセラレーターにオフロードします。

!$omp target map(to: a, b ) map(tofrom: c ) 
!$omp parallel do private(j,i,k) 
    do j=1,n 
        do i=1,n 
            do k=1,n 
                c(i,j) = c(i,j) + a(i,k) * b(k,j) 
            enddo 
        enddo 
    enddo 
!$omp end parallel do 
!$omp end target

配列 ab はアクセラレーターの入力にマップされ、配列 c はアクセラレーターの入力と出力にマップされます。変数 n はアクセラレーターに暗黙にマップされます。ループ・インデックスは OpenMP* 仕様に従って自動的に private となるため、private 節はオプションです。

map 変数

ホストとアクセラレーター間のデータ共有を最適化するため、target data ディレクティブは変数をアクセラレーターにマップし、変数はその領域の範囲内でターゲットのデータ領域に維持されます。この機能は、複数のターゲット領域にまたがって変数をマップするのに役立ちます。

C/C++

#pragma omp target data [clause[[,] clause],...] 
  構造化ブロック

Fortran

!$omp target data [clause[[,] clause],...] 
  構造化ブロック
!$omp end target data

節の使用例

節には次の 1 つ以上を指定できます。詳細は、TARGET DATA (英語)を参照してください。

  • DEVICE (整数式)

  • IF ([TARGETDATA :] スカラー論理式)

  • MAP ([[マップタイプ修飾子 [,]] マップタイプ: ] リスト)

    マップタイプには以下を複数指定できます:

    • alloc

    • to

    • from

    • tofrom

    • delete

    • release

  • SUBDEVICE ([整数定数,] 整数式[ : 整数式[ : 整数式]])

  • USE_DEVICE_ADDR (リスト) // ifx でのみ利用可能

  • USE_DEVICE_PTR (ポインターリスト)

    この SUBDEVICE 節は、以下のような場合に無視されます:

    • ZE_FLAT_DEVICE_HIERARCHY が FLAT または COMBINED に設定されている場合

    • env LIBOMPTARGET_DEVICES が SUBDEVICE/SUBSUBDEVICE に設定されている場合

    • env ONEAPI_DEVICE_SELECTOR を使用してデバイスが選択されている場合

    DEVICE (integer-expression) 
    IF ([TARGET DATA:] scalar-logical-expression) 
    MAP ([[map-type-modifier[,]] map-type: alloc | to | from | tofrom | delete | release] list) 
    SUBDEVICE ([integer-constant ,] integer-expression [ : integer-expression [ : integer-expression]]) 
    USE_DEVICE_ADDR (list) // ifx でのみ利用可能 
    USE_DEVICE_PTR (ptr-list)

ホストの元の変数をデバイスの対応する変数と同期するには、target update ディレクティブ、または map 句内の always マップタイプ修飾子使用します。

OpenMP* TARGET を使用するコンパイル

次のコマンドは、OpenMP* target を使用するアプリケーションをコンパイルする例を示します。

C/C++

  • Linux*:

    icx -fiopenmp -fopenmp-targets=spir64 code.c
  • Windows* (icx または icpx を使用):

    icx /Qiopenmp /Qopenmp-targets=spir64 code.c

Fortran

  • Linux*:

    ifx -fiopenmp -fopenmp-targets=spir64 code.f90
  • Windows*:

    ifx /Qiopenmp /Qopenmp-targets=spir64 code.f90

OpenMP* オフロードの追加のリソース

インテルは、OpenMP* ディレクティブを使用してアクセラレーターをターゲットとする方法を示すサンプルコードを https://github.com/oneapi-src/oneAPI-samples/tree/master/DirectProgramming で提供しています。具体的なサンプルには以下があります。