OpenMP は、マルチスレッド並列プログラミングのための API (Application Programming Interface)で、C++ や Fortran の言語規格に準拠しています。
実装の際は、プログラム内に OpenMP で規定された宣言子を挿入し、インテル® コンパイラーのようなOpenMP をサポートするコンパイラーでコンパイルを行います。インテル® コンパイラーではコンパイル時にコンパイル・オプションとして Windows の場合 /Qopenmp スイッチを、また Linux/Mac OS の場合は-openmp スイッチを指定します。
詳細は下記をご覧ください。
インテル® C/C++コンパイラー OpenMP 活用ガイド マルチコア対応アプリケーション開発 (2) (PDF)
インテル® Fortran コンパイラー OpenMP 活用ガイド マルチコア対応アプリケーション開発 (3)(PDF)
OpenMP はスケーラブルに性能が発揮できるよう設計されているので、コア数が増えた場合でもソースを変更することなく容易に対応ができます。以下のようなメリットが挙げられます。
- 並列化の際に、どこをどのように並列化するかのみ考えればよいので、ネイティブスレッドに比べて特別な関数やロジックを考える必要がない。
- ソースコードがそれほど増えないので保守が容易。
- スケーラブルに性能が向上するように設計されているため、将来マルチコア化が進んでも特別な対応が必要ない。
- OpenMP 用オプションの有無だけでシングルスレッドとマルチスレッドが切り替わるので簡単に性能差や結果を比較することができる。また、OpenMPを利用したコードはシングルスレッドでも動作する。
- 並列アプリケーションのプロトタイプを簡単に作成することができる。
OpenMP 宣言子は、コンパイラーに対して並列化のためのヒントを与えるのでなく、明示的に並列化を指示するという事に注意する必要があります。間違った宣言子を指定しても、コンパイラーはその指示に従って並列化を行います。また、データの依存性などがあっても、コンパイラーは警告メッセージやエラーメッセージを出し、その指示を無視することなく忠実に並列化を行いますので、依存性があるループなどを OpenMPで並列化した場合には、計算結果が不正になります。
変数がグローバルで Shared の場合、並列化特有の問題が発生する可能性があります。 インテル® スレッド・チェッカーでこれらの問題の有無を容易に判定できます。
OpenMP 用の再配布ライブラリーを配布する必要があります。
例) libguide.lib、libguide40.lib、libguide40.dll等
<インストールディレクトリ>/license フォルダーにある fredist.txt (または credist.txt) ファイルは、インテル® コンパイラーの再配布可能なライブラリーをリストしています。このファイルにリストされていう限り、ロイヤルティーフリーで自由に配布可能です。
OpenMP 適用のためのステップは次のようになります。
- インテル® VTune パフォーマンス・アナライザーを使いプログラムの動作の詳細な解析を行い、ホットスポットを検出します。
- ホットスポットに対してOpenMP 宣言子の適用などを検討します。データの依存関係などのために並列化できない部分などについては、依存関係の解消のために行うプログラムの変更を行います。この時、他のハイレベルの最適化手法(ソフトウェア・パイプラインやベクトル化)などに影響を与えるときがあります。この並列化による他のハイレベルの最適化の阻害は避ける必要があります。そのためには、並列化の適用時と非適用時の性能を比較検討する必要もあります。
バージョン 10.0 以降に新しく追加された KMP_AFFINITY 環境変数を使用することで指定できます。
詳細はバージョン10.1 のリリースノート "OpenMP アプリケーション用の KMP_AFFINITY 環境変数 " を参照してください。
インテル固有の OpenMP 拡張実装を利用することができます。たとえば、KMP_AFFINITY環境変数を利用すると、OpenMPで生成されるスレッドのアフィニティーを制御することができます。詳細についてはコンパイラーのマニュアルを参照してください。
ベクトル化とは、命令レベルでのデータ並列の処理になります (ILP:Instruction Level Parallelism と呼ばれます)。ベクトル化は通常 1 命令で 1つのデータ要素しか使用できないところを、1 命令で複数のデータ要素を処理することにより、1 命令辺りの処理データ数を増やすことで高速化します。対して、並列化とは同時に複数の演算を行うことにより処理速度を高めることで高速化を行う手法です。
ベクトル化の実装についてはいくつか方法があります。SSE命令によるアセンブラー記述、組み込み関数の利用、ベクトル化をサポートするコンパイラーで自動的にベクトル化を行うという方法があります。 一番手軽に行えるのは、やはりコンパイラーの自動ベクトル化機能を使用することです。詳細はコンパイラー最適化ガイド(PDF) をご覧ください。
依存関係を排除できないループを並列化することはできますが、アクセス同期を行わなければならず、シングルスレッドよりもパフォーマンスが低下することもあります。パフォーマンス志向の並列化を実現するには、データ構造や関連を設計しなおす必要があります。また、並列化にはデータの並列化とタスクの並列化と二種類あります。上記内容はデータの並列化といって、同内容の計算を複数のスレッドに分割する並列化手法です。
もう一つの手法である、タスクの並列化を検討してみてください。 タスクの並列化とは全く処理内容が異なる関数を同時に並列化することで並列化を実現するという手法です。
タスクの並列化に関しては、ソニーデジタルネットワークアプリケーションズ株式会社様の事例をご覧ください。
|