ベクトル化と SIMD 最適化

この記事は、The Parallel Universe Magazine 42 号に掲載されている「Vectorization and SIMD Optimization」の日本語参考訳です。


parallel_v42_05
[訳者注: 記事内のコンパイラー・メッセージは、日本語版のコンパイラーがインストールされている環境では日本語で表示されます。]

現代の CPU は複数のレベルで並列処理を行います。単一の CPU ノードにおける最大粒度の並列処理はマルチスレッド化です。命令レベルの並列処理を実現するため、CPU はパイプライン化を使用します[編集者注: パイプライン化の詳しい説明は、The Parallel Universe 32 号の「命令パイプラインに関する考察」を参照してください]。CPU における最小粒度の並列処理は、ベクトル化によるデータレベルの並列処理です。ベクトル化とは、同じ操作を一度に複数の要素に適用する CPU の機能です。

簡単に言えば、SIMD (Single Instruction, Multiple Data) 命令セットを使用してループを再構成して、ループの反復回数を減らします。例えば、インテル® Xeon® プロセッサーは、インテル® アドバンスト・ベクトル・エクステンション 512 (インテル® AVX-512) 命令セットをサポートしているため、32 ビットの float 型を処理する N 回の反復ループは、理想的なシナリオでは N/16 回実行され、16 倍のパフォーマンスを達成できます。

この記事では、インテル® C/C++ および Fortran コンパイラーのコンパイラー・レポートを使用して、アプリケーションをベクトル化する方法を紹介します。

コンパイラーによる最適化とレポート

可能な場合、インテル® C/C++ および Fortran コンパイラーは SIMD 命令を生成します。これは、コンパイラーの自動ベクトル化機能で、-O2 または -O3 コンパイラー・オプションを使用すると、デフォルトでベクトルコードが生成されます。しかし、ベクトルコードは常に生成できるわけではなく、生成できない場合、コンパイラーは最適化レポートにその理由を示します。Linux* および macOS* では -qopt-report[=n] オプションを、Windows* では /Qopt-report[:n] オプションを使用して最適化レポートを生成できます。n はオプションのレポートの詳細レベルです。有効な値は、0 (レポートなし) から 5 (詳細) です。n=1 から n=5 の各レベルでは、前のレベルのすべての情報と、レベルに応じた追加の情報が含まれます。

最適化レポート: ベクトル化 [vec]

リスト 1 は単純なベクトル加算コードで、図 1 はこのコードに関するコンパイラーの最適化レポートです。


リスト 1. 単純なベクトル加算コード

以下は、Windows* のコマンドラインです。

以下は、Linux* のコマンドラインです。


図 1. 単純なベクトル加算コードに関するコンパイラーの最適化レポート

レポートの最初のリマークは、vec01.cpp: line 20 にある外側のループに関するものです。コンパイラー・レポートは、外側のループはベクトル化されず、内側のループはベクトル長 4 でベクトル化されたこと (つまり、CPU は 1 つの命令で 4 つの整数要素を処理できること) を示しています。コンパイラーはまた、ベクトル実行とスカラー実行の潜在的なスピードアップも予測しています。

実際のスピードアップを確認するには、動的/ランタイム解析を行うインテル® Advisor を使用します。コンパイラーは、ベクトル化されたループの最大トリップカウントも予測しています。以下の式を使用して、おおよそのトリップカウントを計算できます。

このサンプルコードでは、1024/(4*4)=64 になります。この式は、ピールループとリマインダー・ループを考慮して調整する必要があります。ベクトル長が 4 であることから、SIMD 命令は 128 ビットのデータ (= 4 * 32 ビット整数) を処理したと推測でき、インテル® ストリーミング SIMD 拡張命令 (インテル® SSE) が使用された可能性が高いと考えられます。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事