インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャーで OpenMP* を利用する最も一般的な手法
この記事は、インテル® デベロッパー・ゾーンに掲載されている「Best Known Methods for Using OpenMP* on Intel® Many Integrated Core (Intel® MIC) Architecture」の日本語参考訳です。
概要
この記事は、インテル® Composer XE Linux* 版のドキュメントの補足説明です。インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャー向けの C/C++ および Fortran オフロードプログラムとネイティブプログラムで、OpenMP* 拡張を利用する最も一般的な手法の概要を紹介します。
はじめに
最も一般的な手法 (BKM) とは、ユーザーがシステムを最大限に活用できるテクニック、説明、ヒントです。ここで説明する BKM は、インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャー上で実行するプログラムの実装と最適化に関するものと、多用途の並列プログラミング言語拡張である OpenMP* に関するものです。インテル® MIC アーキテクチャーのオフロード実行環境とネイティブ実行環境の両方で動作する OpenMP* 手法とヒントについて述べます。OpenMP* は、簡単なモデルと分かりやすい単純な構文を提供します。構文には豊富なオプションがあり、さまざまなケースできめ細やかなチューニングが可能です。ここでは、いくつかのオプションの最も効果的な適用方法も紹介します。ここで示すコード例は、インテル® Composer XE 2013 のコンパイラーで検証しました。
インテル® MIC アーキテクチャーで使用するための環境設定
BKM: MIC_ENV_PREFIX を使用して自動でターゲットに渡すホスト環境を制限
ターゲット・コプロセッサーに実行をオフロードする際、MIC_ENV_PREFIX 環境変数を使用して、ホスト環境で定義されている設定のうち選択したものだけをターゲットに渡すことができます。
対象: C/C++ および Fortran のオフロードコード
詳細: ホストでこの環境変数を設定すると (通常、「MIC」に設定する)、ホスト側のユーザー定義のシェル環境変数のうち、定義した文字列の先頭に「_」 (下線) が追加されたものだけがターゲット環境に送られます。ただし、ホストで特別な意味を持つ MIC_LD_LIBRARY_PATH (オフローダーによって検索されるホスト上のターゲット・ライブラリーの場所) は例外です。(オフロードプログラムのターゲット環境に LD_LIBRARY_PATH はありません。) MIC_ENV_PREFIX はこの記事の複数の例で使用していますが、現在の動作では、ターゲットへ送るホスト環境変数を検索する前に、必ず指定したプリフィックスに下線 (“_”) が追加されます。
ホストで MIC_ENV_PREFIX を設定しない場合、ほとんどのホスト環境がオフロードプロセス環境にコピーされます。これは紛らわしいため、注意が必要です。特に、ターゲットとホストの両方で OpenMP* を利用する場合、特定のアーキテクチャーに応じて、アフィニティーやスレッド数のような特性を変更することが考えられるため、注意してください。
オフロード指示句と併用する際の OpenMP* 指示句の基本的な使用法
BKM: オフロードの重要な詳細
簡単なオフロード宣言から開始し、オプションを追加してさまざまな処理を行うように変更できます。
対象: C/C++ および Fortran のオフロードコード
詳細: 最も単純で可搬性に優れたオフロード文を次に示します (C および Fortran)。
#pragma offload target (mic:0) ここに OpenMP for ループや関数呼び出しが記述されます... !$DIR OFFLOAD TARGET (mic:0) CALL offloadfunc(...)
このような「最小限」のコード例であっても、オプションのコンポーネント「:0」を含められます。これは、特定のカード番号 (この場合はカード 0) を指定します。カード番号が指定されていない場合 (つまり、「mic」だけの場合)、スケジューラーは常にカード 0 を使用します。その結果、より予測可能なパフォーマンスになります。複数のカードにわたって負荷のバランスをとる場合は、offload 指示句の target 節で「mic:n」と手動で指定しなければいけません。n はオフロード先のカード番号です。同期オフロードについて理解したら、次に行うことは、ホストからターゲットへデータをコピーしたり、ターゲットからホストへデータをコピーしたり、ターゲットでデータを割り当てたり、あるいはそれらの組み合わせです。オフロードデータを理解するには、IN、OUT、INOUT、および NOCOPY 指示句は通常のデータスコープを拡張するのではなく、限定するという点を認識することが重要です。利用可能なデータすべてが使用されていない場合、ホストとターゲット間でコピーされるデータを限定することで、パフォーマンスが大幅に向上する可能性があります。
ターゲットとの間で送受信されるデータをフィルターするメカニズムにより、データに関する詳細 (データの長さ、アライメント、動的割り当てなど) を指定することができます。次の例は、INOUT 指定子を用いて、データポインター名 (memp)、その長さ (200 要素。サイズは memp の型によって決定される)、そのデータ・アライメント (8 バイト) を指定します。INOUT 指定子は、対象となる識別子のオフロード動作は変更しませんが、オフロードデータの特性を指定できます。
#pragma offload target(mic:0), inout(memp : length(200) align(8))
4 つ目のキーワード NOCOPY は、ターゲット側だけにあるポインターを使うプログラムで、LENGTH、ALLOC_IF、および FREE_IF 指示句とよく一緒に使用されます。また、IN と LENGTH(0) 指示句を指定すると、オフロードするたびにデータをコピーしなくても、複数のオフロードにわたってターゲットでデータを保持することができます。(これらのキーワードに関する詳細は、『インテル® コンパイラー・ユーザー・リファレンス・ガイド』およびインテル® Xeon Phi™ コミュニティー・ポータルを参照してください。)
さらに、非同期オフロード機能を利用することもできます。非同期オフロードでは、SIGNAL および WAIT 指示子を指定してオフロードを同期し、OFFLOAD_TRANSFER および OFFLOAD_WAIT プラグマによりオフロード計算とは別にデータ転送だけを処理することで、ホストとオフロードターゲット間のオーバーラップしない厳密なシーケンシャル実行を緩和します。この機能についても、『インテル® コンパイラー・ユーザー・リファレンス・ガイド』で説明されています。
これらのトピックについては、使用例を含め、別の記事で詳しく取り上げる予定です。
BKM: –openmp-report オプションを利用してコンパイラーによる OpenMP* 領域とループの処理を確認する
-openmp-report コマンドライン・オプションは、C/C++ または Fortran ソースのコンパイル時に、コンパイラーによって行われる OpenMP* 構造の処理に関する診断メッセージを stderr に出力します。–openmp-report=1 に設定すると、コンパイル単位内の並列ループ、並列領域、並列セクションに関する診断が得られます。2 に設定すると、さまざまな同期構造に関する診断も出力されます。–vec-report も参照してください。
対象: C/C++ および Fortran のオフロードコードおよびネイティブコード
例: –openmp-report オプションは、–openmp と一緒に指定する必要があります。OpenMP* の並列領域とループ構造を使用するコードでは、以下のようなレポート、またはループや領域が並列化されなかったことを示す診断が出力されます。列番号から対象の OpenMP* 構造を追跡できます。
MICFtest.F90(104): (列 7) リマーク: OpenMP 定義領域が並列化されました。 MICFtest.F90(110): (列 7) リマーク: OpenMP 定義ループが並列化されました。 MICFtest.F90(172): (列 7) リマーク: OpenMP 定義領域が並列化されました。 MICFtest.F90(186): (列 7) リマーク: OpenMP 定義ループが並列化されました。 MICFtest.F90(199): (列 7) リマーク: OpenMP 定義ループが並列化されました。 MICtest.cpp(534): (列 5) リマーク: *MIC* OpenMP 定義領域が並列化されました。 MICtest.cpp(538): (列 5) リマーク: *MIC* OpenMP 定義ループが並列化されました。 MICtest.cpp(568): (列 5) リマーク: *MIC* OpenMP 定義領域が並列化されました。 MICtest.cpp(582): (列 5) リマーク: *MIC* OpenMP 定義ループが並列化されました。 MICtest.cpp(594): (列 2) リマーク: *MIC* OpenMP 定義ループが並列化されました。
BKM: オフロードセクションがターゲットまたはホストのどちらで実行されているかが不明な場合はスレッド数をカウントする
検証中のコードが実際にターゲットで実行されているかどうか不明な場合は、スレッドチーム内のスレッド数を返す簡単なコードを一時的に追加します。
対象: C/C++ および Fortran のオフロードコード
例: 以下のサンプルコードは、omp_get_num_threads() を使って、並列領域で実行中のスレッド数を取得する方法を示します。get_num_threads は並列セクション内で呼び出しますが、余分な作業を避けるため 1 つのスレッドのみが呼び出すようにします。
C/C++
using namespace std; #pragma offload_attribute(push,target(mic)) //{ #include <iostream> #include <omp.h> void testThreadCount() { int thread_count; #pragma omp parallel { #pragma omp single thread_count = omp_get_num_threads(); } cout << "Thread count: " << thread_count << endl; } #pragma offload_attribute(pop) //} int main (int argc, char **argv) { #pragma offload target(mic), if (argc > 1) testThreadCount(); }
Fortran
!DIR$ ATTRIBUTES OFFLOAD : mic ::testThreadCount subroutine testThreadCount() use omp_lib integer :: thread_count !$omp parallel !$omp single thread_count = OMP_GET_NUM_THREADS() !$omp end single !$omp end parallel WRITE (*, '(A,I4)') "The number of threads is ", thread_count end subroutine testThreadCount program threadcnt integer :: arg_num arg_num = COMMAND_ARGUMENT_COUNT () !DIR$ ATTRIBUTES OFFLOAD : mic ::testThreadCount !DIR$ OFFLOAD target(mic), if (arg_num .ge. 1) call testThreadCount() end program threadcnt
OMP_GET_NUM_THREADS() は、「最内の囲まれた並列領域」内のスレッド数を返しますが、このようなコンテキストが不要な OMP 呼び出しもあります。例えば、OMP_GET_MAX_THREADS() では、並列領域を指定せずにスレッド数の上限を取得できます。スレッド数には関心がなく、コードの実行場所のみを知りたい場合は、もっと簡単です! testThreadCount() の本体を次のコードに置換するだけです。このコードは、関数の 2 つのコピーでそれぞれのメッセージを出力します。
#ifdef __MIC__ //{ cout << “running on target” << endl; #else //}{ cout << “running on host” << endl; #endif //}
ネイティブ環境とオフロード環境における OpenMP* の違い
BKM: OpenMP* パラメーターのデフォルト値はオフロード実行とネイティブ実行では異なる
システムは自身の処理で使用するコアを予約するため、オフロード・コンパイラーにより呼び出されたプログラムを実行する場合と、クロスコンパイルされたプログラムをターゲットでネイティブ実行する場合では、OpenMP* のいくつかのパラメーターが異なります。
対象: C/C++ および Fortran のオフロードコードおよびネイティブコード
詳細: 上記のスレッド数を取得するサンプルコードを少し変更することで、この違いが分かります。オフロード実行する場合、次のような出力結果になります (これは、初期のコプロセッサーのプロトタイプで実行した結果です。最新の製品版ではもっと大きな数値になります)。
Thread count: 124 Threads_max: 124 Proc count: 124 Is dynamic: 0 Is nested: 0 Sched kind: 1 Sched modifier: 0 Thread limit: 2147483647 Max Active levels: 2147483647 Active Level: 1
同じマシンで、同じプログラムをネイティブ実行した場合、次のような出力結果になります。
Thread count: 128 Threads_max: 128 Proc count: 128 Is dynamic: 0 Is nested: 0 Sched kind: 1 Sched modifier: 0 Thread limit: 2147483647 Max Active levels: 2147483647 Active Level: 1
ネイティブ実行ではすべてのコアを利用できるため、このような違いが生じます。これは、カーネル・スレッド・テーブルで実装され、OpenMP* ランタイム環境で設定されるアフィニティー・マップにより模倣されます。オフロードプログラムを実行する前に環境変数 KMP_AFFINITY=verbose を設定すると、このアフィニティー・マップを確認できます。次のような出力が生成されます (ここでは一部のみ示します)。
OMP: Info #156: KMP_AFFINITY: 124 available OS procs OMP: Info #157: KMP_AFFINITY: Uniform topology OMP: Info #179: KMP_AFFINITY: 1 packages x 31 cores/pkg x 4 threads/core (31 total cores) ... OMP: Info #147: KMP_AFFINITY: Internal thread 0 bound to OS proc set {1} OMP: Info #147: KMP_AFFINITY: Internal thread 1 bound to OS proc set {5} OMP: Info #147: KMP_AFFINITY: Internal thread 2 bound to OS proc set {9} OMP: Info #147: KMP_AFFINITY: Internal thread 3 bound to OS proc set {13} OMP: Info #147: KMP_AFFINITY: Internal thread 4 bound to OS proc set {17} OMP: Info #147: KMP_AFFINITY: Internal thread 5 bound to OS proc set {21} ...
ここで、デフォルトのアフィニティーは「fine」であることが分かります。各スレッドは特定の論理 CPU に緊密にバインドされているため、OS はマシン内でスレッドを移動できません。上記の例では、利用可能なコア数は 31、スレッド数は 124 です。コードをネイティブ実行する前に、カードで KMP_AFFINITY=verbose を設定すると、利用可能なコア数が 1 つ増えます (論理 CPU は 4 つ増えます)。
OMP: Info #156: KMP_AFFINITY: 128 available OS procs OMP: Info #157: KMP_AFFINITY: Uniform topology OMP: Info #179: KMP_AFFINITY: 1 packages x 32 cores/pkg x 4 threads/core (32 total cores) ... OMP: Info #147: KMP_AFFINITY: Internal thread 0 bound to OS proc set {1} OMP: Info #147: KMP_AFFINITY: Internal thread 1 bound to OS proc set {5} OMP: Info #147: KMP_AFFINITY: Internal thread 2 bound to OS proc set {9} OMP: Info #147: KMP_AFFINITY: Internal thread 3 bound to OS proc set {13} OMP: Info #147: KMP_AFFINITY: Internal thread 4 bound to OS proc set {17} OMP: Info #147: KMP_AFFINITY: Internal thread 5 bound to OS proc set {21} ...
この場合、32 コアすべてを利用することができ、アフィニティー・マップに追加のハードウェア・スレッド (番号 0、125、126、および 127) が表示されます。ハードウェア・スレッド番号が飛んでいますが、これは、/proc/cpuinfo の内容 (関連ビット) のとおりに、APIC (Advanced Programmable Interrupt Controller) によって番号が付けられるためです。
processor : 0 apicid : 124 processor : 1 apicid : 0 processor : 2 apicid : 1 processor : 3 apicid : 2 ... processor : 123 apicid : 122 processor : 124 apicid : 123 processor : 125 apicid : 125 processor : 126 apicid : 126 processor : 127 apicid : 127
このハードウェア・スレッドのマッピング構造は、すべてのデバイスでコア数に関係なく使用されます。オフロード実行の場合、システムはアフィニティー・マップから 1 コアを除外します。除外されるコアのハードウェア・スレッド番号は連続していません。(常に、上位 3 つとスレッド 0 になります。) 除外されるコアは、インテル® Coprocessor Offload Infrastructure (インテル® COI) とほかのオフロード関連サービスによって使用されます。
オフロード実行とネイティブ実行では、OpenMP* プログラムの環境は大きく異なります。ネイティブ実行の場合、一般的な環境は単純です。environ テーブルダンプを使って、メインプロセスの環境を簡単に出力できます (ここでは、OpenMP* ランタイム・オブジェクトへのパスを指定するため LD_LIBRARY_PATH を追加しています)。
~ # /tmp/getmyenvnat ENV: "USER=root" ENV: "LD_LIBRARY_PATH=/tmp" ENV: "HOME=/" ENV: "SSH_TTY=/dev/pts/0" ENV: "LOGNAME=root" ENV: "TERM=ansi" ENV: "PATH=/usr/bin:/bin" ENV: "SHELL=/bin/sh" ENV: "PWD=/" ENV: "SSH_CONNECTION=192.168.1.99 48111 192.168.1.100 22"
ただし、ユーザーにより制限されない限り、ほとんどの場合、オフロード環境はホスト環境の完全なコピーになります。LD_LIBRARY_PATH がコピーされず、ホストの完全な PATH (「/usr/bin:/bin」が追加されたもの) が渡される場合、低レベルの通信ライブラリーであるインテル® COI とインテル® 対称コミュニケーション・インターフェイス (インテル® SCI) はそれぞれ識別子を挿入します。ホスト環境に関する情報はすべて、ホスト環境で MIC_ENV_PREFIX を定義することで簡単に除外できます。
$ export MIC_ENV_PREFIX=MIC $ ./getmyenv mic ENV: "COI_LOG_PORT=65535" ENV: "ENV_PREFIX=MIC" ENV: "PATH=/usr/bin:/bin" ENV: "SCIF_SOURCE_NODE=0" ENV: "__KMP_REGISTERED_LIB_1017=blahblahblahblah-libiomp5.so"
MIC_ENV_PREFIX を定義すると、ターゲット環境をホスト環境のさまざまな副作用から隔離しつつ、ホストの変数名にプリフィックスを追加して (ユーザー定義された MIC_ENV_PREFIX の値に「_」 (下線) を追加した変数名を持つ) 特定の変数を渡すことができます。ENV_PREFIX の定義からも明らかなように、これは問題なく動作します。MIC_ENV_PREFIX の値を変更すれば、以前の値の変数はオフロードされません。
このメカニズムを利用して、ホストとターゲット、それぞれの環境で実行する値を設定することが可能です。ただし、これは LD_LIBRARY_PATH には使用できません。コンパイラーの初期化スクリプトを実行すると、ホスト環境で LD_LIBRARY_PATH と MIC_LD_LIBRARY_PATH の両方が定義されます。前者はホストのライブラリー環境を示し、後者はオフロードコードのターゲット・ライブラリー・パスを示します。
インテル® MIC アーキテクチャーで OpenMP* を利用する際のアドバイス
BKM: OpenMP* のスタックサイズ (OMP_STACKSIZE) を変更する場合は、異なるオプション、デフォルト、スレッド数が大きい場合の影響を考慮する
注意深い読者の皆さんは、ホストおよびターゲットでスレッドを実行する際、スタックサイズを調整するさまざまなコントロールを利用できることにお気付きでしょう。これらのコントロールは相互に作用しますが、デフォルトは異なります。
対象: C/C++ および Fortran のオフロードコードおよびネイティブコード
詳細: 1 つ目は、KMP_STACKSIZE です。この値には、単位 (バイト、キロバイト、メガバイトなど) を示すサフィックス B/K/M/G/T を追加できます。
export KMP_STACKSIZE=4M
KMP_STACKSIZE の単位を省略した場合はバイトが仮定されます。KMP_STACKSIZE は OMP_STACKSIZE 設定よりも優先され、両方が指定された場合、ランタイムは警告を出力します。OMP_STACKSIZE もサフィックス B/K/M/G/T を使いますが、省略した場合はキロバイトが仮定されます。念のため、これらのパラメーターを使用する場合は、常に単位を示すサフィックスを指定してください。
MIC_ENV_PREFIX を定義せずにホストから計算をオフロードする場合、ターゲットプロセスをスポーンする際に、スタックサイズ環境変数が (残りの環境変数と一緒に) ホストからターゲットへコピーされます。MIC_ENV_PREFIX を定義してオフロードする場合、ホスト環境においてホストとターゲットで異なる設定を定義することができます。
export MIC_ENV_PREFIX=MIC export OMP_STACKSIZE=8M export MIC_OMP_STACKSIZE=2M
注意: 通常、インテル® Xeon Phi™ プロセッサーは、最大 60 コア (1 コアあたり 4 スレッド、合計 240 スレッド以上) を利用できます。デフォルトの OMP スタックサイズは 4MB なので、デフォルトでこのプラットフォームのスレッドは、すべてのスタックの割り当てだけに 1GB のローカルメモリーを必要とします。(上記の例では、ホスト側のデフォルト値を 2 倍にし、このリソース制限を半分にしています。)
これらの環境変数に加えて、ランタイム・ライブラリーもホスト環境の MIC_STACKSIZE 設定に対応します。これにより、オフロードコードを実行するターゲットプロセスのスタックサイズが制御されます (つまり、この制限はオフロードコードにのみ適用されます)。このスタックのデフォルトのサイズは 12MB ですが、スタックは 1 つだけです。同様に、ネイティブ・アプリケーションは、デフォルトのスタックサイズが 8MB のプロセスで実行します。
BKM: プロセッサー・アフィニティーはアルゴリズムのパフォーマンスに多大な影響を及ぼす可能性があるため、パフォーマンスを最大限に引き出すアフィニティーをターゲット・アーキテクチャーで採用する上で、利用可能なアフィニティー型とアルゴリズムの動作を理解することが重要
ハードウェア・スレッドはコアごとにグループ化され、グループ内でリソースを共有します。このリソースの共有は、アルゴリズムの動作次第では、特定のアルゴリズムにとってプラスにもマイナスにもなります。アルゴリズムの動作を理解することは、最適なアフィニティーを選択する上で重要です。アフィニティーは、環境変数 (KMP_AFFINITY) または関数呼び出し (kmp_set_affinity) により指定できます。
対象: C/C++ および Fortran のオフロードコードおよびネイティブコード
詳細: アフィニティーは、ターゲット上で OpenMP* のメインスレッドを実行するプロセスで開始します。オフロードプログラムは、オフロードシステム関数用の最後のコアを除いたアフィニティー・マップを継承します。ネイティブプログラムはすべてのコアを利用できるため、スレッド間のロードバランスに必要な計算はやや異なります。
あるアルゴリズムは、スレッド間でデータを共有し、共有キャッシュを活用することで計算をスピードアップします。別のアルゴリズムは、一度しかアクセスしないデータを多量に必要とするため、利用可能なバンド幅を最大限に活用できるようにスレッドを分散させます。そして、これらの中間に位置するアルゴリズムもあります。OMP_NUM_THREADS と KMP_AFFINITY (およびこれらに対応する関数) は、ユーザーとプログラマーが適切なスレッド数を設定することができます。
export MIC_ENV_PREFIX=MIC export MIC_OMP_NUM_THREADS=60 export MIC_KMP_AFFINITY=verbose,granularity=fine,scatter
31 コアのターゲット・プロセッサーでオフロード・アプリケーションを実行する場合、上記の一連のホスト環境設定は、ハードウェア・スレッドを利用可能な数の半分に制限し、コア全体にわたりできるだけ分散させます。この例では、MIC_ENV_PREFIX を定義し、続く行でスレッド数とターゲットでのみ分散するように指定しています。粒度が fine に設定されているため、各 OpenMP* スレッドは 1 ハードウェア・スレッドに制限されます。粒度を core に設定すると、それぞれのコアに割り当てられた 4 つの OpenMP* スレッドがグループ化され、そのコアの領域を自由に使用できます。
アフィニティー型 COMPACT は OpenMP* をできるだけ少数のコアに割り当て、SCATTER は隣接するスレッド番号が別々のコアに割り当てられるように分散させます。ただし、場合によっては、スレッド数を制限し、隣接するスレッド番号が同じコアに割り当てられるようにコア全体に分散することで利点が得られます。この場合、新しいアフィニティー型 BALANCED を使用します。前述の verbose 設定により、OpenMP* スレッド番号の分散方法を指定することができます。オフロード OpenMP* コンポーネントを含むプログラムを実行するだけで、アフィニティー・レポートが出力されます。いくつかのアフィニティー型を実行して、違いを見てみましょう。
KMP_AFFINITY=granularity=fine, compact
KMP_AFFINITY=granularity=fine, scatter
KMP_AFFINITY=granularity=fine, balanced
この例では、MIC_OMP_NUM_THREADS は 60 に設定されていますが、31 コアしかないため、最後のいくつかのコアには OpenMP* スレッドが 1 つしかありません。MIC_OMP_NUM_THREADS を 62 に設定すると、スレッド 59 がコア 29 に移動され、スレッド 60 とスレッド 61 がコア 30 に割り当てられます。
ネイティブ実行の場合も同じ規則が適用されますが、環境変数にサフィックス「MIC_」を追加して MIC_ENV_PREFIX を使用する必要はありません。balanced アフィニティー型では、最後のコアを利用し、すべてのコアに 2 スレッドが割り当てられるように、OMP_NUM_THREADS を 64 にすることができます。最後のコアにおけるハードウェア・スレッド番号の不規則性は、アフィニティー・マスクによって隠されます。
これらのアフィニティー型のほかに、低レベルのアフィニティー・インターフェイスを利用して非標準のマッピングを行うことができます。低レベルのアフィニティー API の利用には注意が必要です。すでに明示的なアフィニティー・マップを持つコードをインテル® MIC アーキテクチャーに移植する場合、新しいアーキテクチャーで正しくマップされることは非常にまれです。再度アフィニティーを最適化するまで、基本のマップにリセットしたほうが良いでしょう。
BKM: スケーリング・テストのおける KMP_PLACE_THREADS の使用
インテル® MIC アーキテクチャー固有の環境変数 KMP_PLACE_THREADS は、正しいアフィニティーを保持しつつ、スケーリング・テストにおいてインテル® Xeon Phi™ コプロセッサーのサブセットを簡単に割り当てます。KMP_PLACE_THREADS を設定することで、プログラムで使用されるマシンのスライスを制限し、そのスライス内で単純なアフィニティーを設定できます。
対象: C/C++ および Fortran のオフロードコードおよびネイティブコード
詳細: 例えば、コア数や 1 コアあたりのスレッド数を変更してプログラムのスケーリングの変化を検証するため、KMP_PLACE_THREADS=30c,2t に設定して、30 コア、1 コアあたり 2 スレッドを使用します。そして、KMP_AFFINITY=scatter または KMP_AFFINITY=compact に設定して、60 ハードウェア・スレッドを異なる方法で割り当てることができます。ランタイムはデフォルトで利用可能なすべてのハードウェア・スレッド (この場合は 60) を利用するため、別途 OMP_NUM_THREADS を設定する必要はありません。
OMP_NUM_THREADS と KMP_PLACE_THREADS を設定する場合は注意が必要です。OMP_NUM_THREADS の値が、KMP_PLACE_THREADS で指定される利用可能なハードウェア・スレッド数よりも大きいと、オーバーサブスクリプションが発生し、パフォーマンスが低下します。逆に小さいと、コアによって割り当てられるスレッド数が異なり、パフォーマンスの検証が困難になります。
著者紹介
Robert Reed は、インテルの開発製品部門内にあるテクニカル・コンピューティング、アナライザー、およびランタイム・チームのソフトウェア・パフォーマンス・エンジニアです。長年にわたって Tektronix でプログラミング・スキルを磨き、その後さまざまな企業の請負・コンサルティングを経て、インテルに入社しました。これまで、パフォーマンスの最適化とさまざまな解析 (アーキテクチャー固有の DGEMM 関数のシミュレーションから 3D エディターのよる流体と生地まで) に関する多数のプロジェクトに携わってきました。インテル® MIC アーキテクチャー・プログラムには、その名前が決まる前から参加しています。趣味は、歌を歌うことと、ポートランドで上演される演劇を鑑賞することです。
Intel、インテル、Intel ロゴは、アメリカ合衆国およびその他の国における Intel Corporation の商標です。
* その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。
© 2013 Intel Corporation. 無断での引用、転載を禁じます。
パフォーマンスに関する注意事項
* パフォーマンスおよびベンチマークの結果に関する詳細は、www.intel.com/benchmarks (英語) を参照してください。
性能に関するテストに使用されるソフトウェアとワークロードは、性能がインテル® マイクロプロセッサー用に最適化されていることがあります。SYSmark* や MobileMark* などの性能テストは、特定のコンピューター・システム、コンポーネント、ソフトウェア、操作、機能に基づいて行ったものです。結果はこれらの要因によって異なります。製品の購入を検討される場合は、他の製品と組み合わせた場合の本製品の性能など、ほかの情報や性能テストも参考にして、パフォーマンスを総合的に評価することをお勧めします。
* その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。