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

スレッド・アフィニティー・インターフェイス (Linux* および Windows*)

インテルのランタイム・ライブラリーには、OpenMP* スレッドを物理処理ユニットにバインドする機能があります。このインターフェイスは、KMP_AFFINITY 環境変数により制御されます。システム (マシン) のトポロジー、アプリケーション、オペレーティング・システムによってスレッド・アフィニティーはアプリケーションの速度に大きく影響します。

スレッド・アフィニティーは、特定のスレッド (仮想実行ユニット) をマルチプロセッサー・コンピューターの物理処理ユニットのサブセットに限定します。マシンのトポロジーにより、スレッド・アフィニティーはプログラムの実行速度に大きな影響を与えます。

スレッド・アフィニティーは、Windows* システムとスレッド・アフィニティー対応カーネルを持つ Linux* システムのバージョンでサポートされていますが、macOS* ではサポートされていません。

インテルの OpenMP* ランタイム・ライブラリーには、OpenMP* スレッドを物理処理ユニットにバインドする機能があります。このバインド機能は、3 種類のインターフェイスで使用できます。これらのインターフェイスは総称して、インテルの OpenMP* スレッド・アフィニティー・インターフェイスと呼ばれます。

次の用語がこのセクションで使用されています。

一部の環境変数はインテル製マイクロプロセッサーおよび互換マイクロプロセッサーで利用可能ですが、インテル製マイクロプロセッサーにおいてより多くの最適化が行われる場合があります。

KMP_AFFINITY 環境変数

KMP_AFFINITY 環境変数は、後述の「低レベルのアフィニティー API」で説明されているように、最初の並列領域の前、または omp_get_max_threads()omp_get_num_procs()、アフィニティー API 呼び出しを含む特定の API 呼び出しの前に設定する必要があります。

KMP_AFFINITY 環境変数には、次の一般的な構文が使用されます。

構文

KMP_AFFINITY=[<modifier>,...]<type>[,<permute>][,<offset>]

例えば、マシン・トポロジー・マップをリストするには、KMP_AFFINITY=verbose,none を指定し、modifierverbosetypenone を使用します。

次の表は、サポートされる引数のリストです。

引数

デフォルト

説明

modifier

noverbose

respect

granularity=core

オプション。キーワードと指定子から構成されます。

  • granularity=<specifier>
    設定可能な指定子は finethread、および core です。

  • norespect

  • noverbose

  • nowarnings

  • proclist={<proc-list>}

  • respect

  • verbose

  • warnings

<proc-list> の構文は、中レベルのアフィニティー・インターフェイスで説明されています。

type

none

必須です。使用するスレッド・アフィニティーを示します。

  • balanced

  • compact

  • disabled

  • explicit

  • none

  • scatter

  • logical (廃止予定。代わりに compact を指定します。ただし、permute 値は省略します。)

  • physical (廃止予定。代わりに scatter を指定します。場合により、offset 値も指定します。)

logicalphysical推奨されていないタイプですが、下位互換性のためにサポートされています。

permute

0

オプション。正の整数値です。type 値の explicitnonedisabled との使用は無効です。

offset

0

オプション。正の整数値です。type 値の explicitnonedisabled との使用は無効です。

アフィニティー・タイプ

"type" は、唯一必須の引数です。

type = none (デフォルト)

OpenMP* スレッドは特定のスレッド・コンテキストにバインドされません。ただし、オペレーティング・システムでアフィニティーがサポートされる場合は、コンパイラーは OpenMP* スレッド・アフィニティー・インターフェイスを使用してマシンのトポロジーを特定します。KMP_AFFINITY=verbose,none を指定して、マシンのトポロジーマップをリストします。

type = balanced

scatter と同様に、すべてのコアに少なくとも 1 つのスレッドが配置されるまで、別のコアにスレッドを配置します。ただし、ランタイムが同じコアで複数のハードウェア・スレッド・コンテキストを使用する際、balanced では OpenMP* スレッドの番号が互いに隣接していることが保証されるのに対して、scatter では保証されません。このアフィニティー・タイプは、インテル® MIC アーキテクチャーで特に役立ちます。シングルソケットのシステムの場合のみ CPU 上でサポートされます。

OpenMP* 環境変数 OMP_PROC_BIND=spread は、KMP_AFFINITY=balanced と似ており、マルチソケット CPU システムを含むすべてのプラットフォームで利用できます。

type = compact

compact を指定すると、フリー・スレッド・コンテキストの OpenMP* スレッド <n>+1 は、OpenMP* スレッド <n> が割り当てられたスレッド・コンテキストにできる限り近いスレッド・コンテキストに割り当てられます。例えば、トポロジーマップで、ルートにより近いノードほど、スレッドをソートしたときに上位になります。

type = disabled

disabled を指定すると、スレッド・アフィニティー・インターフェイスを完全に無効にします。これにより、OpenMP* ランタイム・ライブラリーはアフィニティー・インターフェイスがオペレーティング・システムでサポートされていないかのように動作します。これには、kmp_set_affinitykmp_get_affinity などのような、効果がなく、非ゼロのエラーコードが返される低レベル API インターフェイスが含まれます。

type = explicit

explicit を指定すると、proclist= modifier (このアフィニティー・タイプには必須) を使用して明示的に指定された OS proc ID のリストに OpenMP* スレッドが割り当てられます。「OS プロセッサー ID (GOMP_CPU_AFFINITY) を明示的に指定する」を参照してください。

type = scatter

scatter を指定すると、システム全体にわたってスレッドが均等に分配されます。scatter は、compact の逆です。そのため、マシンのトポロジーマップをソートするとノードリーフは最上位になります。

推奨されていないタイプ: logical と physical

logicalphysical は廃止予定で、将来のリリースではサポートされなくなります。両方とも、下位互換性のためにサポートされています。

logical および physical では、整数値が 1 つしかない場合は、permute 指定子ではなく、offset 指定子と解釈されます。これに対し、compactscatter では、整数値が 1 つのみの場合は permute 指定子と解釈されます。

compactscatter の例

次の図は、2 つのプロセッサーを搭載しているマシンを示しています。それぞれのプロセッサーには 2 つのコアがあります。各コアはインテル® ハイパースレッディング・テクノロジー (インテル® HT テクノロジー) 対応です。

また、次の図は、KMP_AFFINITY=granularity=fine,compact を指定したときに、OpenMP* スレッドがハードウェア・スレッド・コンテキストにバインドされる様子も示しています。



上図のシステムで scatter を指定すると、次の図のように、OpenMP* スレッドがスレッド・コンテキストに割り当てられます。これは、KMP_AFFINITY=granularity=fine,scatter を指定した結果です。



permute と offset の組み合わせ

compactscatter の両方とも permuteoffset が指定できます。ただし、1 つの整数だけを指定した場合は、コンパイラーは値を permute 指定子として解釈します。permuteoffset の両方ともデフォルトは 0 です。

permute 指定子はマシンのトポロジーマップをソートしたときに最上位にするレベルを制御します。permute の値により、指定された番号の最上位レベルは最下位にマッピングされ、順位が入れ替わります。ツリーのルートノードは、ソート操作では個別のレベルとは見なされません。

offset 指定子は、スレッド割り当ての開始地点を示します。

次の図は、KMP_AFFINITY=granularity=fine,compact,0,3 を指定した結果を示しています。



前述の例、連続したループ反復間でデータ共有を示す OpenMP* アプリケーションを実行するハードウェア構成について考えてみます。KMP_AFFINITY=compact を指定した際に行われるように、通信オーバーヘッド、キャッシュラインの無効オーバーヘッド、ページ・スラッシングが最小限になるように連続したスレッドを隣接してバインドさせます。ここで、利用可能な OpenMP* スレッドを活用していないアプリケーションに多くの並列領域があるとします。通常、スレッドは、同じコアにある別のアクティブなスレッドとの間にリソースの競合がない場合に実行速度が速くなるため、他のコアを使用せずに複数のスレッドを同じコアにバインドする状態は避けたほうが良いでしょう。通常、スレッドは、同じコアにある別のアクティブなスレッドとの間にリソースの競合がない場合に実行速度が速くなるため、他のコアを使用せずに複数のスレッドを同じコアにバインドする状態は避けたほうが良いでしょう。次の図は、KMP_AFFINITY=granularity=fine,compact,1,0 を設定してこの方法を示したものです。



OpenMP* スレッド n+1 は、別のコアの OpenMP* スレッド n にできるだけ近いスレッド・コンテキストにバインドされます。いったん、それぞれのコアに 1 つの OpenMP* スレッドが割り当てられると、後続の OpenMP* スレッドは利用可能なコアに同じ順番で異なるスレッド・コンテキストに割り当てられます。

アフィニティー・タイプの修飾子の値

タイプの前に付ける修飾子はオプションです。修飾子を指定しない場合は、noverboserespectgranularity=core が自動で使用されます。

修飾子は、左から右の順に解釈され、互いに無効にすることができます。例えば、KMP_AFFINITY=verbose,noverbose,scatter は、KMP_AFFINITY=noverbose,scatter または単に KMP_AFFINITY=scatter を指定するのと同じです。

modifier = noverbose (デフォルト)

詳細なメッセージは出力しません。

modifier = verbose

サポートされるアフィニティーに関するメッセージを出力します。メッセージには、パッケージ数、各パッケージにあるコア数、各コアにあるスレッド・コンテキスト数、物理スレッド・コンテキストにバインドされた OpenMP* スレッドについての情報が含まれます。

物理スレッド・コンテキストにバインドされた OpenMP* スレッドについての情報は、ハードウェア・スレッド・コンテキストとオペレーティング・システム (OS) プロセッサー (proc) ID 間のマッピングの形式で間接的に示されます。各 OpenMP* スレッドのアフィニティー・マスクは、OS プロセッサー ID セットとして出力されます。

例えば、インテル® ハイパースレッディング・テクノロジーを無効にした 2 つのプロセッサーを搭載したデュアルコア・システムで KMP_AFFINITY=verbose,scatter を指定すると、プログラムの実行時に次のようなメッセージが出力されます。

Verbose, scatter を指定した場合のメッセージ

... 
KMP_AFFINITY: Affinity capable, using global cpuid info 
KMP_AFFINITY: Initial OS proc set respected: 
{0,1,2,3} 
KMP_AFFINITY: 4 available OS procs - Uniform topology of 
KMP_AFFINITY: 2 packages x 2 cores/pkg x 1 threads/core (4 total cores) 
KMP_AFFINITY: OS proc to physical thread map ([] => level not in map): 
KMP_AFFINITY: OS proc 0 maps to package 0 core 0 [thread 0] 
KMP_AFFINITY: OS proc 2 maps to package 0 core 1 [thread 0] 
KMP_AFFINITY: OS proc 1 maps to package 3 core 0 [thread 0] 
KMP_AFFINITY: OS proc 3 maps to package 3 core 1 [thread 0] 
KMP_AFFINITY: Internal thread 0 bound to OS proc set {0} 
KMP_AFFINITY: Internal thread 2 bound to OS proc set {2} 
KMP_AFFINITY: Internal thread 3 bound to OS proc set {3} 
KMP_AFFINITY: Internal thread 1 bound to OS proc set {1}

verbose 修飾子を指定すると、いくつかの標準的、一般的なメッセージが生成されます。次の表は、メッセージの説明です。

メッセージ

説明

"affinity capable (アフィニティー可)"

すべてのコンポーネント (コンパイラー、オペレーティング・システム、ハードウェア) でスレッドのバインドが可能なようにアフィニティーがサポートされていることを示します。

"using global cpuid info (グローバル cpuid 情報使用)"

スレッドを各オペレーティング・システムのプロセッサーにバインドし、cpuid 命令の出力をデコードすることにより、マシントポロジーが特定されたことを示します。

"using local cpuid info (ローカル cpuid 情報使用)"

コンパイラーは初期スレッドのみから発行される cpuid 命令の出力をデコードし、マシントポロジーでオペレーティング・システムのプロセッサー数が使用されていることを想定しています。

"using /proc/cpuinfo (/proc/cpuinfo 使用)"

Linux* のみ。cpuinfo がマシントポロジーを特定するのに使用されることを示します。

"using flat (flat 使用)"

オペレーティング・システムのプロセッサー ID は、物理パッケージ ID と同じと見なされています。マシントポロジーを特定するこの方法は、その他の方法がどれも使用できず、また実際のマシントポロジーを正しく検出しない可能性がある場合に使用されます。

"uniform topology of (一様トポロジー)"

マシントポロジーのマップは、どの階層においてもリーフがそろった完全なツリーです。

次に、オペレーティング・システムのプロセッサーからスレッド・コンテキスト ID へのマッピングが出力されます。OpenMP* スレッドのスレッド・コンテキスト ID へのバインドは、アフィニティー・タイプが none でない限り、次に出力されます。スレッドレベルは、角括弧の中に示されます (上のリストを参照)。これは、マシントポロジーのマップにはそのスレッド・コンテキスト・レベルが示されないことを意味します。詳細は、「マシントポロジーの特定」を参照してください。

modifier = granularity

OpenMP* スレッドを特定のパッケージやコアにバインドすると、インテル® ハイパースレッディング・テクノロジー (インテル® HT テクノロジー) 対応のインテル® プロセッサーを搭載したシステムでパフォーマンス・ゲインを期待できます。しかし、一般的に各 OpenMP* スレッドを特定のコアにある特定のスレッド・コンテキストにバインドしても効果は期待できません。粒度は、トポロジーマップ内で OpenMP* スレッドのフロートが許可される最下位レベルを示します。

この修飾子は、次の指定子をサポートします。

指定子

説明

core

デフォルト。サポートされる最も荒い粒度レベルです。すべての OpenMP* スレッドが異なるスレッド・コンテキスト間でフロートするために、コアにバインドできます。

fine または thread

最も細かい粒度レベルです。各 OpenMP* スレッドが 1 つのスレッド・コンテキストにバインドされます。この 2 つの指定子は、機能的に同じです。

2 つのプロセッサーを搭載したデュアルコア・システムで、インテル® ハイパースレッディング・テクノロジー (インテル® HT テクノロジー) が有効な場合に、KMP_AFFINITY=verbose,granularity=core,compact を指定すると、プログラムの実行時に次のようなメッセージが出力されます。

Verbose, granularity=core,compact を指定した場合のメッセージ

KMP_AFFINITY: Affinity capable, using global cpuid info 
KMP_AFFINITY: Initial OS proc set respected: 
{0,1,2,3,4,5,6,7} 
KMP_AFFINITY: 8 available OS procs - Uniform topology of 
KMP_AFFINITY: 2 packages x 2 cores/pkg x 2 threads/core (4 total cores) 
KMP_AFFINITY: OS proc to physical thread map ([] => level not in map): 
KMP_AFFINITY: OS proc 0 maps to package 0 core 0 thread 0 
KMP_AFFINITY: OS proc 4 maps to package 0 core 0 thread 1 
KMP_AFFINITY: OS proc 2 maps to package 0 core 1 thread 0 
KMP_AFFINITY: OS proc 6 maps to package 0 core 1 thread 1 
KMP_AFFINITY: OS proc 1 maps to package 3 core 0 thread 0 
KMP_AFFINITY: OS proc 5 maps to package 3 core 0 thread 1 
KMP_AFFINITY: OS proc 3 maps to package 3 core 1 thread 0 
KMP_AFFINITY: OS proc 7 maps to package 3 core 1 thread 1 
KMP_AFFINITY: Internal thread 0 bound to OS proc set {0,4} 
KMP_AFFINITY: Internal thread 1 bound to OS proc set {0,4} 
KMP_AFFINITY: Internal thread 2 bound to OS proc set {2,6} 
KMP_AFFINITY: Internal thread 3 bound to OS proc set {2,6} 
KMP_AFFINITY: Internal thread 4 bound to OS proc set {1,5} 
KMP_AFFINITY: Internal thread 5 bound to OS proc set {1,5} 
KMP_AFFINITY: Internal thread 6 bound to OS proc set {3,7} 
KMP_AFFINITY: Internal thread 7 bound to OS proc set {3,7}

各 OpenMP* スレッドのアフィニティー・マスクは、OpenMP* スレッドがバインドされたオペレーティング・システムのプロセッサー・セットとしてリストされます (上を参照)。

次の図は、OpenMP* スレッドがバインドされた上記のリストのマシントポロジーを示しています。



これに対し、KMP_AFFINITY=verbose,granularity=fine,compact または KMP_AFFINITY=verbose,granularity=thread,compact を指定すると、プログラムの実行時に各 OpenMP* スレッドが 1 つのハードウェア・スレッド・コンテキストにバインドされます。

Verbose, granularity=fine,compact を指定した場合のメッセージ

KMP_AFFINITY: Affinity capable, using global cpuid info 
KMP_AFFINITY: Initial OS proc set respected: 
{0,1,2,3,4,5,6,7} 
KMP_AFFINITY: 8 available OS procs - Uniform topology of 
KMP_AFFINITY: 2 packages x 2 cores/pkg x 2 threads/core (4 total cores) 
KMP_AFFINITY: OS proc to physical thread map ([] => level not in map): 
KMP_AFFINITY: OS proc 0 maps to package 0 core 0 thread 0 
KMP_AFFINITY: OS proc 4 maps to package 0 core 0 thread 1 
KMP_AFFINITY: OS proc 2 maps to package 0 core 1 thread 0 
KMP_AFFINITY: OS proc 6 maps to package 0 core 1 thread 1 
KMP_AFFINITY: OS proc 1 maps to package 3 core 0 thread 0 
KMP_AFFINITY: OS proc 5 maps to package 3 core 0 thread 1 
KMP_AFFINITY: OS proc 3 maps to package 3 core 1 thread 0 
KMP_AFFINITY: OS proc 7 maps to package 3 core 1 thread 1 
KMP_AFFINITY: Internal thread 0 bound to OS proc set {0} 
KMP_AFFINITY: Internal thread 1 bound to OS proc set {4} 
KMP_AFFINITY: Internal thread 2 bound to OS proc set {2} 
KMP_AFFINITY: Internal thread 3 bound to OS proc set {6} 
KMP_AFFINITY: Internal thread 4 bound to OS proc set {1} 
KMP_AFFINITY: Internal thread 5 bound to OS proc set {5} 
KMP_AFFINITY: Internal thread 6 bound to OS proc set {3} 
KMP_AFFINITY: Internal thread 7 bound to OS proc set {7}

OpenMP* をハードウェア・コンテキストにバインドする例は、最初の例に示されています。

granularity=fine を指定すると、各 OpenMP* スレッドが 1 つの OS プロセッサーにバインドされます。これは、granularity=thread と等価で、現在、最も微細な粒度レベルです。

modifier = respect (デフォルト)

プロセスの元のアフィニティー・マスク、厳密には、OpenMP* ランタイム・ライブラリーを初期化するスレッドに指定されたアフィニティー・マスクが順守されます。動作は、Linux* と Windows* で異なります。

前の例と同じ、インテル® ハイパースレッディング・テクノロジー (インテル® HT テクノロジー) が有効なシステムで、KMP_AFFINITY=verbose,compact を指定して、最初のアフィニティー・マスク {4,5,6,7} (各コアでスレッド・コンテキストは 1) を起動すると、コンパイラーでは、インテル® ハイパースレッディング・テクノロジー (インテル® HT テクノロジー) が無効の 2 つのプロセッサーを搭載したデュアルコアのマシンであると判断されます。

Verbose,compact を指定した場合のメッセージ

KMP_AFFINITY: Affinity capable, using global cpuid info 
KMP_AFFINITY: Initial OS proc set respected: 
{4,5,6,7} 
KMP_AFFINITY: 4 available OS procs - Uniform topology of 
KMP_AFFINITY: 2 packages x 2 cores/pkg x 1 threads/core (4 total cores) 
KMP_AFFINITY: OS proc to physical thread map ([] => level not in map): 
KMP_AFFINITY: OS proc 4 maps to package 0 core 0 [thread 1] 
KMP_AFFINITY: OS proc 6 maps to package 0 core 1 [thread 1] 
KMP_AFFINITY: OS proc 5 maps to package 3 core 0 [thread 1] 
KMP_AFFINITY: OS proc 7 maps to package 3 core 1 [thread 1] 
KMP_AFFINITY: Internal thread 0 bound to OS proc set {4} 
KMP_AFFINITY: Internal thread 1 bound to OS proc set {6} 
KMP_AFFINITY: Internal thread 2 bound to OS proc set {5} 
KMP_AFFINITY: Internal thread 3 bound to OS proc set {7} 
KMP_AFFINITY: Internal thread 4 bound to OS proc set {4} 
KMP_AFFINITY: Internal thread 5 bound to OS proc set {6} 
KMP_AFFINITY: Internal thread 6 bound to OS proc set {5} 
KMP_AFFINITY: Internal thread 7 bound to OS proc set {7}

マシンには、8 個のスレッド・コンテキストがあるため、デフォルトではコンパイラーにより OpenMP* parallel 構造で 8 個のスレッドが作成されています。

"スレッド 1" の角括弧はスレッド・コンテキストのレベルが無視され、トポロジーマップには示されていないことを意味します。次の図は、対応するマシンのトポロジーマップです。



ローカルの cpuid 情報を使用してマシントポロジーを特定する場合、インテル® ハイパースレッディング・テクノロジー (インテル® HT テクノロジー) をサポートしていないマシンとサポートしているけれども無効になっているマシンとの区別がつきません。そのため、そのレベルの要素 (ノード) に兄弟がいない場合は、コンパイラーはそのレベルをマップに含めません (ただし、パッケージレベルは常に含まれます)。前述したように、パッケージレベルは、マシンに 1 つのパッケージしかない場合でも、常にトポロジーマップに表示されます。

modifier = norespect

プロセスのアフィニティー・マスクは順守されません。OpenMP* スレッドはすべてのオペレーティング・システムのプロセッサーにバインドされます。

physicallogical のみがアフィニティー・タイプとしてサポートされていた以前のバージョンの OpenMP* ランタイム・ライブラリーでは、norespect がデフォルトで、修飾子としては認識されませんでした。

compactscatter がアフィニティー・タイプに追加されてから、デフォルトは respect に変更されました。そのため、アプリケーションが不完全な初期スレッド・アフィニティー・マスクを指定した状態では、logicalphysical のスレッドのバインドは、新しいコンパイラー・バージョンで変更されることがあります。

modifier = nowarnings

アフィニティー・インターフェイスからの警告メッセージを出力しません。

modifier = warnings (デフォルト)

アフィニティー・インターフェイスからの警告メッセージを出力します (デフォルト)。

マシントポロジーの特定

IA-32 およびインテル® 64 アーキテクチャー・システムでは、パッケージに APIC (Advanced Programmable Interrupt Controller) がある場合、コンパイラーは cpuid 命令を使用して package idcore id、および thread context id を入手します。通常の状態では、システム上の各スレッド・コンテキストには起動時に固有の APIC ID が割り当てられます。コンパイラーは、OS スレッド・コンテキスト数 (マシン上のプロセシング要素の合計数) とともに cpuid 命令によって取得されるその他の情報を取得し、APIC ID から package IDcore IDthread context ID を識別する方法を特定します。

cpuid 命令で APIC ID を指定する方法は 2 つあります - リーフ 4 で指定する以前の方法とリーフ 11 で指定するより新しい方法。リーフ 4 で利用可能な一意の APIC ID は 256 のみです。リーフ 11 ではそのような制限はありません。

通常、パッケージ上のすべての core id とコア上のすべての thread context id は連続しています。ただし、上の図で示されるように、package id の番号付けでは連続していないことも一般的です。

コンパイラーがいずれの方法を使用してもトポロジーを特定できないが、アフィニティーがオペレーティング・システムでサポートされている場合は、警告メッセージが出力され、トポロジーは flat と想定されます。例えば、ある flat トポロジーでは、オペレーティング・システムがプロセス N をパッケージ N にマップし、1 コアにつき 1 スレッドのみ、そして各パッケージには 1 コアがあると想定されます。

マシントポロジーが上記のように特定できない場合は、手動で /proc/cpuinfo を一時ファイルにコピーして、エラーを修正し、「KMP_CPUINFO_FILE/proc/cpuinfo」のセクションで説明されているように、KMP_CPUINFO_FILE=<temp_filename> 環境変数を介して、マシントポロジーを OpenMP* ランタイム・ライブラリーに指定します。

マシントポロジーの特定に使用する方法にかかわらず、マシン上の各コアで 1 コアにつき 1 スレッドしかない場合は、スレッド・コンテキスト・レベルはトポロジーマップには表示されません。マシン上の各パッケージで 1 パッケージにつき 1 コアしかない場合は、コアレベルはトポロジーマップには表示されません。各パッケージには異なる数のコアが含まれている可能性があり、各コアは異なる数のスレッド・コンテキストをサポートしている可能性があるため、トポロジーマップは完全なツリー状とは限りません。

パッケージレベルは、マシンに 1 つのパッケージしかない場合でも、常にトポロジーマップに表示されます。

KMP_CPUINFO_FILE/proc/cpuinfo

インテル® C++ コンパイラーの OpenMP* ランタイム・ライブラリーが Linux* システム上のマシントポロジーを検出する方法の 1 つに、/proc/cpuinfo の内容を解析する方法があります。このファイル (または Linux* ファイルシステムにマップされているデバイス) の内容が不十分であったり、エラーを含む場合は、内容を書き込み可能な一時ファイル <temp_file> にコピーし、修正するか必要な情報を追加して、さらに KMP_CPUINFO_FILE=<temp_file> を設定します。

これを行うことにより、OpenMP* ランタイム・ライブラリーは、/proc/cpuinfo に含まれる情報を読み取る代わりに、また APIC ID をデコードしてマシントポロジーを検出する代わりに、KMP_CPUINFO_FILE が示す <temp_file> を読み取ります。つまり、<temp_file> に含まれる情報が、その他の方法よりも優先されます。/proc/cpuinfo を持たない Windows* システムでは、KMP_CPUINFO_FILE インターフェイスを使用することができます。

/proc/cpuinfo または <temp_file> にはマシン上の各プロセシング要素のエントリーのリストが含まれています。各プロセッサー要素にはエントリー (分かりやすい名前と各行の値) のリストが含まれています。空白行は各プロセッサー要素を区切ります。次のフィールドのみが、<temp_file> または /proc/cpuinfo にある各エントリーからマシントポロジーを特定するのに使用されます。

フィールド

説明

processor:

プロセシング要素の OS ID を指定します。OS ID は一意でなければなりません。processor フィールドと physical id フィールドは、このインターフェイスの使用に唯一必須のものです。

physical id:

物理チップ ID であるパッケージ ID を指定します。各パッケージには複数のコアが含まれています。パッケージレベルは常にインテル® コンパイラーの OpenMP* ランタイム・ライブラリーのマシン・トポロジー・モデルにあります。

core id:

コア ID を指定します。コア ID がない場合は、デフォルトの 0 に設定されます。マシン上の各パッケージがシングルコアしかない場合は、(コア ID フィールドのいくつかが非ゼロの場合でも) コアレベルはマシンのトポロジーマップにはありません。

thread id:

スレッド ID を指定します。コア ID がない場合は、デフォルトの 0 に設定されます。マシン上の各コアでシングルスレッドしかない場合は、(スレッド ID フィールドのいくつかが非ゼロの場合でも) スレッドレベルはマシンのトポロジーマップにはありません。

node_n id:

これは、/proc/cpuinfo の拡張です。不均等メモリーアクセス (NUMA: Non-Uniform Memory Access) システムにおける異なるレベルのメモリー相互接続でノードを指定するのに使用できます。任意のレベル n がサポートされています。node_0 レベルがパッケージレベルに最も近いレベルで、複数のパッケージがレベル 0 で 1 つのノードを構成します。レベル 0 の複数のノードは、レベル 1 で 1 つのノードを構成します。

各エントリーは、示されているとおりに正確に小文字で、オプションのスペース、コロン (:)、さらにオプションのスペース、そして整数 ID を記述します。これ以外のフィールドは無視されます。

多くの Linux* バリアントで thread id フィールドが /proc/cpuinfo に含まれておらず、siblings とラベル付けされたフィールドがノードごとのスレッド数またはパッケージごとのノード数を指定することはよくあることことです。ただし、インテルの OpenMP* ランタイム・ライブラリーは、siblings とラベルされたフィールドを無視するため、thread id フィールドと siblings フィールドを区別できます。このような状況が発生した場合は、警告メッセージの「物理ノード/パッケージ/コア/スレッド ID が一意ではありません。」が表示されます (指定されたタイプが nowarnings の場合を除く)。

Windows* プロセッサー・グループ

64 ビットの Windows* オペレーティング・システムでは、複数のプロセッサー・グループが 64 を超えるプロセッサーに対応できます。各グループのサイズは、64 プロセッサーの最大値までに制限されます。

複数のプロセッサー・グループが検出されると、デフォルトでは 2 レベルのツリー (レベル 0 はグループ内のプロセッサー、レベル 1 は異なるグループ) であると判断されます。そして、グループにバインドされた OpenMP* スレッド数がグループ内のプロセッサー数と等しくなるまで、スレッドがグループに割り当てられ、後続のスレッドは次のグループに割り当てられます。

デフォルトでは、スレッドはグループ内のすべてのプロセッサー間を移動することができ、粒度はグループの数と同じになります [granularity=group]。このバインドを無効にし、compact、scatter など、別のアフィニティー・タイプを明示的に使用することができます。その場合は、スレッドが異なるグループの複数のプロセッサーにバインドされないように、十分に細かい粒度を使用する必要があります。

特定のマシン・トポロジー・モデル・メソッドの使用 (KMP_TOPOLOGY_METHOD)

KMP_TOPOLOGY_METHOD 環境変数を設定して、特定のマシン・トポロジー・モデル・メソッドを OpenMP* で使用するように強制できます。

説明

cpuid_leaf11

cpuid 命令のリーフ 11 により指定された APIC ID をデコードします。

cpuid_leaf4

cpuid 命令のリーフ 4 により指定された APIC ID をデコードします。

cpuinfo

KMP_CPUINFO_FILE を指定しない場合は、/proc/cpuinfo を解析してトポロジーを特定するように強制できます (Linux* のみ)。

前述のように、KMP_CPUINFO_FILE を指定する場合は、それを使用します (Windows* または Linux*)。

group

2 レベルのマップ (レベル 0 はグループ内の異なるプロセッサーを指定、レベル 1 は異なるグループを指定) として判断します (64 ビットの Windows* のみ)。

flat

プロセッサーの flat (線形) リストとして判断します。

hwloc

Portable Hardware Locality (hwloc) ライブラリーと同様に判断します。最も詳細なモデルで、NUMA ノード、パッケージ、コア、ハードウェア・スレッド、キャッシュ、Windows* プロセッサー・グループなどを含みます。

OS プロセッサー ID (GOMP_CPU_AFFINITY) を明示的に指定する

GOMP_CPU_AFFINITY 環境変数は、後述の「低レベルのアフィニティー API」で説明されているように、最初の並列領域の前、または omp_get_max_threads()omp_get_num_procs()、アフィニティー API 呼び出しを含む特定の API 呼び出しの前に設定する必要があります。

ライブラリーにハードウェア・トポロジーを検出させて自動的に OpenMP* スレッドをプロセシング要素に割り当てる代わりに、オペレーティング・システム (OS) プロセッサー (proc) ID のリストを使用して、明示的に割り当てを指定することができます。ただし、これには OS proc ID がどのプロセシング要素を表現しているかについての知識が必要です。

このリストは、KMP_AFFINITY 環境変数に明示的なアフィニティー・タイプとともに proclist 修飾子で指定されるか、またはインテルの OpenMP* 互換ライブラリーの使用時に、GOMP_AFFINITY 環境変数 (gcc との互換用) で指定されるかのいずれかです。

-qopenmp-lib compat コンパイラー・オプションで有効にされたインテルの OpenMP* 互換ライブラリーを使用する際、Linux* システムでは GOMP_AFFINITY 環境変数を使用して OS プロセッサー ID を指定します。その構文は、libgomp のものと同じです (<proc_list> が GOMP_AFFINITY 環境文字列全体を生成すると想定)。

説明

<proc_list> :=

<entry> | <elem> , <list> | <elem> <whitespace> <list>

<elem> :=

<proc_spec> | <range>

<proc_spec> :=

<proc_id>

<range> :=

<proc_id> - <proc_id> | <proc_id> - <proc_id> : <int>

<proc_id> :=

<positive_int>

このリストに指定されている OS プロセッサーは、その後 OpenMP* グローバルスレッド ID の順に OpenMP* スレッドに割り当てられます。リストにある要素よりも多くの OpenMP* スレッドが作成された場合は、リストサイズを基にする割り当てが行われます。つまり、OpenMP* グローバルスレッド ID n は、リスト要素 n mod <list_size> にバインドされます。

前の図の例と同じように OS proc ID が割り当てられた前述のマシン、インテル® ハイパースレッディング・テクノロジー (インテル® HT テクノロジー) が有効になっていないデュアルコア、デュアルパッケージ・マシンについて考えてみましょう。アプリケーションが 4 (デフォルト) ではなく、マシンを超過してしまう 6 つの OpenMP* スレッドを生成するとします。GOMP_AFFINITY=3,0-2 の場合、次の図に示されているように、gcc でコンパイルして、libgomp でリンクしたときと同じように OpenMP* スレッドがバインドされます。



同じ構文が、OS proc ID リストを KMP_AFFINITY 環境変数文字列の proclist=[<proc_list>] 修飾子に指定するのに使用できます。若干の差異として、gcc の OpenMP* ランタイム・ライブラリー libgomp と全く同じセマンティクスを持つために、GOMP_AFFINITY 環境変数は granularity=fine を示唆します。KMP_AFFINITY 環境変数で granularity= 指定子を使用せずに OS proc リストを指定すると、デフォルトの granularity は変更されません。つまり、OpenMP* スレッドはシングルコアの異なるスレッド・コンテキスト間でフロートすることができます。このように、GOMP_AFFINITY=<proc_list> は、KMP_AFFINITY="granularity=fine,proclist=[<proc_list>],explicit" のエイリアスです。

KMP_AFFINITY 環境変数文字列では、構文はオペレーティング・システムのプロセッサー ID セットを処理するために拡張されます。ユーザーは OpenMP* スレッドが実行 ("フロート") できるオペレーティング・システムのプロセッサー ID セットを角括弧で指定できます。

説明

<proc_list> :=

<proc_id> | { <float_list> }

<float_list> :=

<proc_id> | <proc_id> , <float_list>

これにより、機能的には granularity= specifier と同様で、より柔軟性を発揮します。OpenMP* スレッドが実行される OS プロセッサーには、マシントポロジーで隣接している OS プロセッサーは除外されますが、その他の離れた OS プロセッサーは含まれます。次の図に示すように KMP_AFFINITY="granularity=fine,proclist=[3,0,{1,2},{1,2}],explicit" を使用して、OS プロセッサー 1 と OS プロセッサー 2 の間で OpenMP* スレッド 2 と 3 を "フロート" させることができます。



verbose も指定された場合、アプリケーションが実行された出力結果には以下が含まれます。

KMP_AFFINITY="granularity=verbose,fine,proclist=[3,0,{1,2},{1,2}],explicit"

KMP_AFFINITY: Affinity capable, using global cpuid info 
KMP_AFFINITY: Initial OS proc set respected: {0,1,2,3} 
KMP_AFFINITY: 4 available OS procs - Uniform topology of 
KMP_AFFINITY: 2 packages x 2 cores/pkg x 1 threads/core (4 total cores) 
KMP_AFFINITY: OS proc to physical thread map ([] => level not in map): 
KMP_AFFINITY: OS proc 0 maps to package 0 core 0 [thread 0] 
KMP_AFFINITY: OS proc 2 maps to package 0 core 1 [thread 0] 
KMP_AFFINITY: OS proc 1 maps to package 3 core 0 [thread 0] 
KMP_AFFINITY: OS proc 3 maps to package 3 core 1 [thread 0] 
KMP_AFFINITY: Internal thread 0 bound to OS proc set {3} 
KMP_AFFINITY: Internal thread 1 bound to OS proc set {0} 
KMP_AFFINITY: Internal thread 2 bound to OS proc set {1,2} 
KMP_AFFINITY: Internal thread 3 bound to OS proc set {1,2} 
KMP_AFFINITY: Internal thread 4 bound to OS proc set {3} 
KMP_AFFINITY: Internal thread 5 bound to OS proc set {0}}

低レベルのアフィニティー API

ユーザーがプログラムの実行開始前に環境変数を設定して (または並列領域に到達する前に kmp_settings インターフェイスを使用して) OpenMP* スレッドを OS proc にバインドさせなくても、それぞれの OpenMP* スレッドでは、実行し、kmp_set_affinity API 呼び出しでバインドさせる適切な OS proc セットを決定できます。

注意

このアフィニティー・インターフェイスを使用することで、スレッドを実行するハードウェア・リソースを完全に制御することができます。そのためには、論理 CPU (OS によって制御されるハードウェア・スレッドの列挙子) がどのように実行マシンの物理ハードウェアへマップされるかを詳しく理解する必要があります。マップ方法はマシンによって異なるため、マシン固有の情報をコードに記述すると、別のマシンで実行するときに不適切なアフィニティーを強制することになります。この詳細レベルで最適化を検討している場合、コードを別のマシンに移動する可能性が高いでしょう。

このインターフェイスを使用することで、MPI などのプログラムの起動メカニズムによって設定されるリソースの制約も無視できます。特に、同じノード上の複数の OpenMP* プロセスが同じハードウェア・スレッドを使用しないようにできます。これも、パフォーマンスの低下を引き起こすアフィニティーを強制する可能性があります。OpenMP* ランタイムはこの問題の発生を防ぐことも、問題が発生した際に警告を出力することもしません。このインターフェイスはエキスパート向けです。注意して使用してください。

移植性に優れ、低レベルの知識を必要としない、できるだけ高いレベルのアフィニティー設定を利用することを推奨します。

タイプ名 kmp_affinity_mask_tomp.h で定義される C/C++ API インターフェイス:

これらのインターフェイスの一部には、同等のオフロード・インターフェイスがあります。同等のオフロード・インターフェイスには、ターゲットの種類と番号を指定する 2 つの追加の引数があります。詳細は、「CPU の関数を呼び出してコプロセッサーの実行環境を変更する」を参照してください。

構文

説明

int kmp_set_affinity (kmp_affinity_mask_t *mask)

現在の OpenMP* スレッドのアフィニティー・マスクを *mask に設定します。ここで、*mask は以下にリストされた API 呼び出しで作成された OS proc ID のセットで、スレッドは、そのセットの OS proc でのみ実行します。成功した場合はゼロ (0)、エラーコードの場合は非ゼロを返します。

int kmp_get_affinity (kmp_affinity_mask_t *mask)

現在の OpenMP* スレッドのアフィニティー・マスクを取得し、kmp_create_affinity_mask() への呼び出しで前もって初期化されているはずの *mask に格納します。成功した場合はゼロ (0)、エラーコードの場合は非ゼロを返します。

int kmp_get_affinity_max_proc (void)

マシン上の最大 OS proc ID に 1 を足した値が返されます。すべての OS proc ID が 0 (包括的) と kmp_get_affinity_max_proc() (排他的) の間で保証されます。

void kmp_create_affinity_mask (kmp_affinity_mask_t *mask)

新しい OpenMP* スレッド・アフィニティー・マスクを割り当て、*mask を OS proc の空のセットに初期化します。セット自身として、実際のセットへのポインターとして、またはセットを示すテーブルへのインデックスとしてなど、kmp_affinity_mask_kind のオブジェクトの使用は自由です。実際の表現が何であるかといった仮定をしてはなりません。

void kmp_destroy_affinity_mask (kmp_affinity_mask_t *mask)

OpenMP* スレッド・アフィニティー・マスクの割り当てを解除するkmp_create_affinity_mask() への各呼び出しで、対応する kmp_destroy_affinity_mask() への呼び出しがなければなりません。

int kmp_set_affinity_mask_proc (int proc, kmp_affinity_mask_t *mask)

OS proc ID proc をセット *mask に追加します (追加されていない場合)。成功した場合はゼロ (0)、エラーコードの場合は非ゼロを返します。

int kmp_unset_affinity_mask_proc (int proc, kmp_affinity_mask_t *mask)

OS proc ID proc がセット *mask にある場合、それを削除します。成功した場合はゼロ (0)、エラーコードの場合は非ゼロを返します。

int kmp_get_affinity_mask_proc (int proc, kmp_affinity_mask_t *mask)

OS proc ID proc がセット *mask にある場合は 1 を返します。ない場合は、0 を返します。

OpenMP* スレッドが kmp_set_affinity() への呼び出しに成功して自身のアフィニティー・マスクを設定したら、後続の kmp_set_affinity() への呼び出しでリセットされない限り、少なくとも並列領域が終わるまでは、そのスレッドは対応する OS proc セットにバインドされたままです。

並列領域間では、アフィニティー・マスク (および OS proc バインド機能に対応する OpenMP* スレッド) はスレッド・プライベートのデータ・オブジェクトと見なされ、「OpenMP* アプリケーション・プログラム・インターフェイス」で説明されているように、同様の永続性を持ちます。詳細は、OpenMP* API 仕様 (http://www.openmp.org) を参照してください。該当部分の一部を以下に抜粋 (参考訳) します。

アフィニティー・マスクとスレッドバインド機能が 2 つの連続したアクティブな並列領域間で永続するには、次の 3 つの条件がすべて満たされなければなりません。

そのため、プログラムの実行が上記の OpenMP* 仕様の 3 つの規則に従っており、唯一の目的が各スレッドのアフィニティー・マスクを設定することであるプログラムの開始時点で並列領域を作成すると、低レベルのアフィニティー API 呼び出しにより、ユーザーは KMP_AFFINITY 環境変数の動作と同じことができます。

次に、低レベルのインターフェイスの使用例を示します。このコードは、実行スレッドを特定の論理 CPU にバインドします。

// 実行スレッドが論理 CPU i で実行するように強制します
// 成功したら 0 を、失敗したら 1 を返します
int forceAffinity(int i)
{
kmp_affinity_mask_t mask;

kmp_create_affinity_mask(&mask); 
kmp_set_affinity_mask_proc(i, &mask); 
    
return (kmp_set_affinity(&mask) == 0); 
}

このプログラムは、OS proc ID のターゲットマシンの物理プロセシング要素へのマッピングに関する知識に基づいて記述されたものです。別のマシンや異なる OS がインストールされている場合、プログラムは実行されますが、OpenMP* スレッドの物理プロセシング要素へのバインド動作は異なります。また、明示的に効率の悪い分配を強制してしまう可能性があります。

関連情報