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

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

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

スレッド・アフィニティーは、Windows OS システムとスレッド・アフィニティー対応カーネルを持つ Linux OS システムのバージョンでサポートされていますが、Mac OS* X ではサポートされていません。スレッド・アフィニティー・インターフェイスはインテル® プロセッサーでのみサポートされています。

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

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

KMP_AFFINITY 環境変数

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

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

  • 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 = 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

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

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

compact 型と scatter 型の例

次の図は、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: アフィニティー可、グローバル cpuid 情報使用

KMP_AFFINITY: 初期 OS proc セット順守:

{0,1,2,3}

KMP_AFFINITY: 4 利用可能な OS proc 数 - 一様トポロジー

KMP_AFFINITY: 2 pkg 数 x 2 コア数/pkg x 1 スレッド数/コア (4 合計コア数)

KMP_AFFINITY: OS proc から物理スレッドマップ ([] => マップにないレベル):

KMP_AFFINITY: OS proc 0 をパッケージ 0 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 2 をパッケージ 0 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 1 をパッケージ 3 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 3 をパッケージ 3 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: 内部スレッド 0 を OS proc セット {0} にバインドします。

KMP_AFFINITY: 内部スレッド 2 を OS proc セット {2} にバインドします。

KMP_AFFINITY: 内部スレッド 3 を OS proc セット {3} にバインドします。

KMP_AFFINITY: 内部スレッド 1 を OS proc セット {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: アフィニティー可、グローバル cpuid 情報使用

KMP_AFFINITY: 初期 OS proc セット順守:

{0,1,2,3,4,5,6,7}

KMP_AFFINITY: 8 利用可能な OS proc 数

KMP_AFFINITY: 2 pkg 数 x 2 コア数/pkg x 2 スレッド数/コア (4 合計コア数)

KMP_AFFINITY: OS proc から物理スレッドマップ ([] => マップにないレベル):

KMP_AFFINITY: OS proc 0 をパッケージ 0 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 4 をパッケージ 0 [コア 0] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 2 をパッケージ 0 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 6 をパッケージ 0 [コア 1] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 1 をパッケージ 3 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 5 をパッケージ 3 [コア 0] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 3 をパッケージ 3 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 7 をパッケージ 3 [コア 1] [スレッド 1] にマップします。

KMP_AFFINITY: 内部スレッド 0 を OS proc セット {0,4} にバインドします。

KMP_AFFINITY: 内部スレッド 1 を OS proc セット {0,4} にバインドします。

KMP_AFFINITY: 内部スレッド 2 を OS proc セット {2,6} にバインドします。

KMP_AFFINITY: 内部スレッド 3 を OS proc セット {2,6} にバインドします。

KMP_AFFINITY: 内部スレッド 4 を OS proc セット {1,5} にバインドします。

KMP_AFFINITY: 内部スレッド 5 を OS proc セット {1,5} にバインドします。

KMP_AFFINITY: 内部スレッド 6 を OS proc セット {3,7} にバインドします。

KMP_AFFINITY: 内部スレッド 7 を OS proc セット {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: アフィニティー可、グローバル cpuid 情報使用

KMP_AFFINITY: 初期 OS proc セット順守:

{0,1,2,3,4,5,6,7}

KMP_AFFINITY: 8 利用可能な OS proc 数

KMP_AFFINITY: 2 pkg 数 x 2 コア数/pkg x 2 スレッド数/コア (4 合計コア数)

KMP_AFFINITY: OS proc から物理スレッドマップ ([] => マップにないレベル):

KMP_AFFINITY: OS proc 0 をパッケージ 0 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 4 をパッケージ 0 [コア 0] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 2 をパッケージ 0 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 6 をパッケージ 0 [コア 1] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 1 をパッケージ 3 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 5 をパッケージ 3 [コア 0] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 3 をパッケージ 3 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 7 をパッケージ 3 [コア 1] [スレッド 1] にマップします。

KMP_AFFINITY: 内部スレッド 0 を OS proc セット {0} にバインドします。

KMP_AFFINITY: 内部スレッド 1 を OS proc セット {4} にバインドします。

KMP_AFFINITY: 内部スレッド 2 を OS proc セット {2} にバインドします。

KMP_AFFINITY: 内部スレッド 3 を OS proc セット {6} にバインドします。

KMP_AFFINITY: 内部スレッド 4 を OS proc セット {1} にバインドします。

KMP_AFFINITY: 内部スレッド 5 を OS proc セット {5} にバインドします。

KMP_AFFINITY: 内部スレッド 6 を OS proc セット {3} にバインドします。

KMP_AFFINITY: 内部スレッド 7 を OS proc セット {7} にバインドします。

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

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

modifier = respect (デフォルト)

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

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

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

KMP_AFFINITY: アフィニティー可、グローバル cpuid 情報使用

KMP_AFFINITY: 初期 OS proc セット順守:

{4,5,6,7}

KMP_AFFINITY: 4 利用可能な OS proc 数 - 一様トポロジー

KMP_AFFINITY: 2 pkg 数 x 2 コア数/pkg x 1 スレッド数/コア (4 合計コア数)

KMP_AFFINITY: OS proc から物理スレッドマップ ([] => マップにないレベル):

KMP_AFFINITY: OS proc 4 をパッケージ 0 [コア 0] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 6 をパッケージ 0 [コア 1] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 5 をパッケージ 3 [コア 0] [スレッド 1] にマップします。

KMP_AFFINITY: OS proc 7 をパッケージ 3 [コア 1] [スレッド 1] にマップします。

KMP_AFFINITY: 内部スレッド 4 を OS proc セット {0} にバインドします。

KMP_AFFINITY: 内部スレッド 1 を OS proc セット {6} にバインドします。

KMP_AFFINITY: 内部スレッド 2 を OS proc セット {5} にバインドします。

KMP_AFFINITY: 内部スレッド 3 を OS proc セット {7} にバインドします。

KMP_AFFINITY: 内部スレッド 4 を OS proc セット {4} にバインドします。

KMP_AFFINITY: 内部スレッド 5 を OS proc セット {6} にバインドします。

KMP_AFFINITY: 内部スレッド 6 を OS proc セット {5} にバインドします。

KMP_AFFINITY: 内部スレッド 7 を OS proc セット {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 を識別する方法を特定します。

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

Linux オペレーティング・システムの IA-64 アーキテクチャー・システムでは、コンパイラーはこの情報を /proc/cpuinfo から取得します。package idcore idthread context id は、/proc/cpuinfophysical idcore idthread id フィールドから取得されます。core idthread context id のデフォルトは 0 です。physical id フィールドはマシントポロジーを特定するために呈示されなければなりませんが、必ずしも呈示されているとは限りません。/proc/cpuinfo に含まれる情報が不十分であったり、エラーを含む場合は、KMP_CPUINFO_FILE 環境変数 (「KMP_CPUINFO と /proc/cpuinfo」で説明) を使用して、代替指定ファイルを作成し、OpenMP ランタイム・ライブラリーに渡します。

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

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

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

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

KMP_CPUINFO と /proc/cpuinfo

インテル® コンパイラーの 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 を記述します。これ以外のフィールドは無視されます。

Note icon

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

次のサンプルは、異なるレベルのメモリー相互接続モデルに拡張された IA-64 アーキテクチャー・システムのサンプル・エントリーです。

/proc/cpuinfo または <temp-file> のサンプル

processor : 23

vendor : GenuineIntel

arch : IA-64

family : 32

model : 0

revision : 7

archrev : 0

features : branchlong, 16-byte atomic ops

cpu number : 0

cpu regs : 4

cpu MHz : 1594.000007

itc MHz : 399.000000

BogoMIPS : 3186.68

siblings : 2

node_3 id : 0

node_2 id : 1

node_1 id : 0

node_0 id : 1

physical id : 2563

core id: 1

thread id: 0

この例には、インテル® コンパイラーの OpenMP アフィニティー・インターフェイスの機能に影響する /proc/cpuinfo のフィールド、processorpysical idcore idthread id が含まれています。/proc/cpuinfo のその他のフィールド (vendorarch、...、siblings) は無視されます。4 つのフィールド node_n は拡張です。

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

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

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

-openmp-lib compat コンパイラー・オプションで有効にされたインテル® OpenMP 互換ライブラリーを使用する際、Linux システムでは GOMP_CPU_AFFINITY 環境変数を使用して OS プロセッサー ID を指定します。その構文は、libgomp のものと同じです (<proc_list> が GOMP_CPU_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_CPU_AFFINITY=3,0-2, の場合、次の図に示されているように、gcc でコンパイルして、libgomp でリンクしたときと同じように OpenMP スレッドがバインドされます。


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

KMP_AFFINITY: 初期 OS proc セット順守: {0,1,2,3}

KMP_AFFINITY: 4 利用可能な OS proc 数 - 一様トポロジー

KMP_AFFINITY: 2 pkg 数 x 2 コア数/pkg x 1 スレッド数/コア (4 合計コア数)

KMP_AFFINITY: OS proc から物理スレッドマップ ([] => マップにないレベル):

KMP_AFFINITY: OS proc 0 をパッケージ 0 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 2 をパッケージ 0 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 1 をパッケージ 3 [コア 0] [スレッド 0] にマップします。

KMP_AFFINITY: OS proc 3 をパッケージ 3 [コア 1] [スレッド 0] にマップします。

KMP_AFFINITY: 内部スレッド 0 を OS proc セット {3} にバインドします。

KMP_AFFINITY: 内部スレッド 1 を OS proc セット {0} にバインドします。

KMP_AFFINITY: 内部スレッド 2 を OS proc セット {1,2} にバインドします。

KMP_AFFINITY: 内部スレッド 3 を OS proc セット {1,2} にバインドします。

KMP_AFFINITY: 内部スレッド 4 を OS proc セット {3} にバインドします。

KMP_AFFINITY: 内部スレッド 5 を OS proc セット {0} にバインドします。

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

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

型名 kmp_affinity_mask_tomp.h または omp.mod で定義される Fortran API インターフェイス:

構文

説明

integer function kmp_set_affinity(mask)
integer (kind=kmp_affinity_mask_kind) mask

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

integer kmp_get_affinity(mask)
integer (kind=kmp_affinity_mask_kind) mask

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

integer function kmp_get_affinity_max_proc()

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

subroutine kmp_create_affinity_mask(mask)
integer (kind=kmp_affinity_mask_kind) mask

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

subroutine kmp_destroy_affinity_mask(mask)
integer (kind=kmp_affinity_mask_kind) mask

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

integer function kmp_set_affinity_mask_proc(proc, mask)
integer proc
integer (kind=kmp_affinity_mask_kind) mask

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

integer function kmp_unset_affinity_mask_proc(proc, mask)
integer proc
integer (kind=kmp_affinity_mask_kind) mask

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

integer function kmp_get_affinity_mask_proc(proc, mask)integer proc
integer (kind=kmp_affinity_mask_kind) mask

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

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

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

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

そのため、プログラムの実行が上記の OpenMP 仕様の 3 つの規則に従っており、唯一の目的が各スレッドのアフィニティー・マスクを設定することであるプログラムの開始時点で並列領域を作成すると、低レベルのアフィニティー API 呼び出しにより、ユーザーは KMP_AFFINITY 環境変数の動作と同じことができます。前の図に示されている例をもう一度考えてみます。KMP_AFFINITY=compact を模倣するには、グローバルスレッド ID n の各 OpenMP スレッドにおいて、OS proc ID n modulo cn modulo c + c、... (c はコア数) を含むアフィニティー・マスクを作成する必要があります。これは、次の C コードをプログラムの開始時に実行されるアプリケーションに挿入することにより作成できます。

int main() {

#pragma omp parallel

{

int tmax = omp_get_max_threads();

int tnum = omp_get_thread_num();

int nproc = omp_get_num_procs();

int ncores = nproc / 2;

int i;

kmp_affinity_mask_t mask;

kmp_create_affinity_mask(&mask);

for (i = tnum % ncores; i < tmax; i += ncores) {

kmp_set_affinity_mask_proc(i, &mask);

}

if (kmp_set_affinity(&mask) != 0) <error>;

}

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