OpenMP (オープンエムピー)は、並列計算機環境 において共有メモリ・マルチスレッド 型の並列アプリケーションソフトウェア 開発をサポートするために標準化されたAPIである[ 3] 。「OpenMP」は「open multiprocessing」の略である[ 3] 。
同様に並列コンピューティングに利用されるMPI では、メッセージの交換をプログラム 中に明示的に記述しなければならないが、OpenMPではディレクティブ (指令)を挿入することによって並列化を行う。OpenMPが使用できない環境では、このディレクティブは無視されるため、並列環境と非並列環境でほぼ同一のソースコード を使用できるという利点がある。また、プラットフォーム固有のスレッド API を使わず、コンパイラ によって暗黙的に生成されたスレッド[ 注釈 1] を利用してタスクを振り分けることになるため、並列プログラムを簡潔に記述できるだけでなく、複数の環境に移植しやすくなる。
MPIとの比較では、OpenMPは異なるスレッド が同一のデータを同じアドレスで参照できるのに対して、MPIでは明示的にメッセージ交換を行わなければならない。そのため、OpenMPは、SMP 環境においては大きなデータの移動を行なわずにすむので高い効率が期待できる。ただし並列化の効率はコンパイラ に依存するので、チューニングによる性能改善がMPIほど高くならないという問題がある。また、OpenMPはMPIに比べてメモリアクセスのローカリティが低くなる傾向があるので、頻繁なメモリアクセスがあるプログラムでは、MPIの方が高速な場合が多い [要出典 ] 。
OpenMPは、並列プログラミングにおいて最も広く利用されているAPIであるが、共有メモリに対してUniform Memory Access (英語版 ) に近いアクセスができるハードウェアシステムアーキテクチャでは、スケーラビリティに限界がある[ 3] 。そのため、現在のほとんどのスーパーコンピューターでは、OpenMP単独ではなく、分散メモリ環境で高いスケーラビリティを発揮するMPIと組み合わせた、ハイブリッドMPI+OpenMPが利用されている[ 3] [ 6] 。
2013年にリリースされたOpenMP 4.0では、多数の先進的な機能が追加された[ 7] 。SIMD 命令を使った自動ベクトル化 機能(omp simd
)や、GPU などのアクセラレータに並列処理を委譲する分散メモリ型のオフロード機能などがサポートされている[ 8] [ 9] 。
2023年現在、FORTRAN とC /C++ について標準化が行われている。
OpenMPを用いたコード例
以下はC言語 における for ループを並列処理させる例である。
int main ( int argc , char * argv [])
{
int i ;
#pragma omp parallel for
for ( i = 0 ; i < 10000 ; ++ i )
{
/* (並列処理させたいプログラム) */
}
return 0 ;
}
OpenMPはループの反復処理を自動的に複数のスレッドに分割して並行処理できるようにする。例えば4つのスレッドを用いて処理を分割する場合、上記例ではインデックス[0, 2499], [2500, 4999], [5000, 7499], [7500, 9999]の各範囲をそれぞれのスレッドに分担させる、といった具合である。実際にいくつのスレッドを起動するのか、また各スレッドに対してどのように処理を振り分けるのかはOpenMP処理系(コンパイラ)およびプログラム実行環境などの条件に依存する[ 10] 。
以下は区分求積法 を用いた円周率 πの数値計算を、OpenMP並列リダクションを用いて行うC++のコード例である。一部にC++11 の機能が使われているが、OpenMPのディレクティブ自体は言語バージョンとは無関係であり、C++98/C++03でも利用できる。
#include <iostream>
#include <chrono>
#include <cmath>
#include <iomanip>
#include <omp.h>
const double D_PI = 3.1415926535897932384626433832795 ;
// 区分求積法で π の近似値を求める。
// 1 / (x^2 + 1) を区間 [0, 1] で積分すると π/4 になるという定積分を利用する。
int main ()
{
const int DivNum = 1000 * 1000 * 1000 ;
const double delta = 1.0 / DivNum ;
std :: cout << "OpenMP max threads count = " << omp_get_max_threads () << std :: endl ;
const auto startTime = std :: chrono :: system_clock :: now ();
double sum = 0 ;
#pragma omp parallel for reduction(+ : sum)
for ( int i = 0 ; i < DivNum ; ++ i )
{
const double x = ( delta * i );
const double area = delta * 1.0 / ( x * x + 1.0 );
sum += area ;
}
const double pi = sum * 4.0 ;
const auto endTime = std :: chrono :: system_clock :: now ();
std :: cout << std :: setprecision ( 15 ) << "PI ~= " << pi << std :: endl ;
std :: cout << "Error [%] = " << ( 100.0 * std :: fabs ( D_PI - pi ) / D_PI ) << std :: endl ;
std :: cout << "Elapsed time [ms] = " << std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( endTime - startTime ). count () << std :: endl ;
return 0 ;
}
#pragma omp parallel for
は並列ループのディレクティブである。直後に続くreduction
はclause [ 注釈 2] と呼ばれ、並列処理の動作を調整することができる。ここでは総和を格納するスレッド共有変数sum
に対する更新操作の演算子(加算)を指定している。異なるスレッドから共有変数にアクセスするときは排他制御 やアトミック操作 が必要となるが、OpenMPのclauseを使用することでそのような煩雑なコードを記述する必要がなくなり、詳細を処理系に任せて隠蔽することができる。
OpenMPコンパイルオプションの有無を切り替えるか、OpenMPディレクティブをコメントアウト/コメント解除してからコンパイル・実行することで、マルチスレッド版およびシングルスレッド版の速度性能比較を簡単に行なうことができるのがOpenMPプログラムの特徴である。
対応コンパイラ
GCC :バージョン4.9でC/C++用のOpenMP 4.0を、バージョン4.9.1でFortran用のOpenMP 4.0をサポートした[ 15] 。GCC 5ではオフロード 機能のサポートが追加された。GCC 6以降でC/C++用のOpenMP 4.5を、GCC 7以降でFortran用のOpenMP 4.5をサポートしている。GCC 9以降でOpenMP 5.0の初期サポートが始まっている。
Clang :バージョン3.7でOpenMP 3.1に対応した[ 16] 。Clang 3.7以前は派生プロジェクトが存在した[ 17] 。Clang 3.9でオフロード以外のOpenMP 4.5機能をすべてサポートした[ 18] 。
Microsoft Visual C++ :Visual C++ 2017時点でOpenMP 2.0をサポートしている[ 19] 。Visual C++ 2019ではSIMD ベクトル化機能を実験的にサポートする[ 20] [ 21] 。
Intel C++ Compiler :バージョン12.1においてOpenMP 3.1をサポートしている。また、バージョン14.0においてOpenMP 4.0の機能を一部サポートしている[ 22] 。
Intel Fortran Compiler (英語版 ) : バージョン18.0以降でOpenMP 5.0の機能の大部分をサポートしている[ 23] 。
脚注
注釈
^ 実装によっては、スレッドを毎回起動・終了するのではなくスレッドプールが使われる[ 4] [ 5] 。
^ 日本語の各種ドキュメントでは、clauseは「指示節」[ 11] 、「文節」[ 12] 、「節」[ 13] 、「句」[ 14] などと訳されているが、いずれも同じ概念を指す。
出典
より詳しく知るための本など(For further learning)
洋書:
Rohit Chandra, Ramesh Menon, Leo Dagum, David Kohr, Dror Maydan and Jeff McDonald: Parallel Programming in OpenMP , Morgan Kaufmann, ISBN 978-1558606715 (2000年10月).
Barbara Chapman, Gabriele Jost and Ruud Van der Pas: Using OpenMP: Portable Shared Memory Parallel Programming , MIT Press, ISBN 978-0-262-53302-7 (2007年10月).
Ruud van der Pas, Eric Stotzer and Christian Terboven: Using OpenMP -- The Next Step: Affinity, Accelerators, Tasking, and SIMD , The MIT Press, ISBN 978-0262344005 (2017年10月27日). ※ OpenMP 4.5 の仕様を記述。
Timothy G. Mattson, Yun (Helen) He, and Alice Evelyn Konigs: The OpenMP Common Core: Making OpenMP Simple Again , The MIT Press, ISBN 978-0262538862 (2019年11月19日).
Tom Deakin and Timothy G. Mattson: Programming Your GPU with OpenMP: Performance Portability for GPUs , The MIT Press, ISBN 978-0-262547536 (2023年11月7日).
和書等:
関連項目
外部リンク