この記事は、The Parallel Universe Magazine 42 号に掲載されている「Vectorization and SIMD Optimization」の日本語参考訳です。
現代の 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) が使用された可能性が高いと考えられます。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。