自動並行化と自動ベクター化

自動並行化と自動ベクター化は、コード内のループのパフォーマンスが自動的に向上するように設計されています。

自動並行化

/Qpar コンパイラ スイッチは、コード内のループの "自動並行化" を有効にします。 既存のコードを変更せずにこのフラグを指定すると、並行化の利点を達成できる可能性があるループを見つける観点で、コンパイラがコードを評価します。 つまり、処理量がそれほど多くなく、したがって並行化の利点が多くないループを見つける可能性があります。また、不必要な並行化はいずれも、パフォーマンスの向上ではなく低下につながる可能性のあるスレッド プール、余分な同期、または他のプロセスの発生源になる可能性があります。したがって、コンパイラは並行化するループを保守的な基準で選択します。 たとえば、コンパイル時にループの上限が不明である次の例について考えてみましょう。

void loop_test(int u) {
   for (int i=0; i<u; ++i)
      A[i] = B[i] * C[i];
}

小さな値になる可能性があるため u 、コンパイラはこのループを自動的に並列化しません。 ただし、u が必ず大きいことを把握している場合は、開発者が並行化を希望することもあります。 自動並行化を有効にするには、#pragma loop(hint_parallel(n)) を指定します。n は並行化するスレッドの数です。 次の例では、コンパイラは 8 つのスレッドにまたがるループの並行化を試みます。

void loop_test(int u) {
#pragma loop(hint_parallel(8))
   for (int i=0; i<u; ++i)
      A[i] = B[i] * C[i];
}

すべての pragma ディレクティブと同様に、代替 pragma 構文 __pragma(loop(hint_parallel(n))) もサポートされています。

必要に応じて、コンパイラが並列化できないループがいくつかあります。 次に例を示します。

#pragma loop(hint_parallel(8))
for (int i=0; i<upper_bound(); ++i)
    A[i] = B[i] * C[i];

関数の upper_bound() が、呼び出されるたびに変化する可能性がある場合。 上限を認識できないため、コンパイラは、このループを並列化できない理由を説明する診断メッセージを出力できます。 次の例では、並行化できるループ、並行化できないループ、コマンド プロンプトで使用するためのコンパイラの構文、および各コマンド ライン オプションに対応するコンパイラ出力を示します。

int A[1000];
void test() {
#pragma loop(hint_parallel(0))
    for (int i=0; i<1000; ++i) {
        A[i] = A[i] + 1;
    }

    for (int i=1000; i<2000; ++i) {
        A[i] = A[i] + 1;
    }
}

次のコマンドを使用してコンパイル:

cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:1

生成される出力:

--- Analyzing function: void __cdecl test(void)
d:\myproject\mytest.cpp(4) : loop parallelized

次のコマンドを使用してコンパイル:

cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:2

生成される出力:

--- Analyzing function: void __cdecl test(void)
d:\myproject\mytest.cpp(4) : loop parallelized
d:\myproject\mytest.cpp(4) : loop not parallelized due to reason '1008'

2 つの異なる /Qpar-report (自動並行化レポート レベル) オプション間の出力の違いに注意してください。 /Qpar-report:1 を指定した場合は、正常に並行化されたループのみに関する並行化メッセージが出力されます。 /Qpar-report:2 を指定した場合は、並行化したループと並行化しなかったループの両方に関する並行化メッセージが出力されます。

理由コードとメッセージの詳細については、「ベクター化と並列化のメッセージ」を参照してください。

自動ベクター化

自動ベクター化機能は、コード内のループを分析し、可能な場合は、ターゲット コンピューター上のベクター レジスタとベクター命令を使用してそれらのループを実行します。 この方法により、コードのパフォーマンスが向上する可能性があります。 コンパイラは、/arch スイッチに従って、Intel または AMD プロセッサの SSE2、AVX、AVX2 の各命令、あるいは ARM プロセッサの NEON 命令を対象とします。

自動ベクター化機能は、/arch スイッチで指定されていない命令を生成することもあります。 これらの命令は、実行時チェックによって保護され、引き続きコードが正しく実行されることが確認されます。 たとえば、/arch:SSE2 のコンパイル時に SSE4.2 命令が送出されることがあります。 実行時チェックによって、ターゲット プロセッサで SSE4.2 を使用できるかが確認され、プロセッサがそれらの命令をサポートしていない場合は SSE4.2 でないバージョンのループにジャンプします。

既定では、自動ベクター化が有効になります。 ベクター化対象のコードのパフォーマンスを比較する場合は、#pragma loop(no_vector) を使用して、特定のループのベクター化を無効にすることができます。

#pragma loop(no_vector)
for (int i = 0; i < 1000; ++i)
   A[i] = B[i] + C[i];

すべての pragma ディレクティブと同様に、代替 pragma 構文 __pragma(loop(no_vector)) もサポートされています。

自動並行化と同様に、/Qvec-report (自動ベクター化レポート レベル) コマンド ライン オプションを指定することで、正常にベクター化されたループのみを報告する (/Qvec-report:1) ことも、正常にベクター化されたループとベクター化が失敗したループの両方を報告する (/Qvec-report:2) こともできます。

理由コードとメッセージの詳細については、「ベクター化と並列化のメッセージ」を参照してください。

ベクター化の実際の動作を示す例については、「オースティン プロジェクト パート 2/6: ページ カーリング」を参照してください。

関連項目

loop
ネイティブ コードでの並行プログラミング
/Qpar (自動並行化)
/Qpar-report (自動並行化レポート作成レベル)
/Qvec-report (自動ベクター化レポート作成レベル)
ベクター化と並列化のメッセージ