目次 >> OpenMP

OpenMP

OpenMPは複数のCPU(複数コアを含む)を持った計算機上での並列化に威力を発揮する。
OpenMPを使う最大の利点は、OpenMPに対応したコンパイラであれば、非常に簡単に並列化できる点である。
現在、gcc、Visual C++、およびIntelコンパイラなど主要なコンパイラはOpenMPに対応している。
習得も他の並列か技法に比べて比較的容易である。
なお、速度を最優先にする場合、単一コンピュータ上で動かした場合でも、OpenMPよりMPIの方が効率のよいことが多い。

なお、インテルがOpenMP初心者向けに非常にわかりやすい文書を公開している。

OpenMPプログラムのコンパイル

OpenMPの各種関数を使わない場合、#pragma ompで始まる指示をソースコード内に書き込み、下記のコンパイルスイッチをつけてコンパイルするだけで、並列化される。

インテルコンパイラ

インテルコンパイラ(icpc)の場合は、Linux用では-openmpを、Windows用では、/Qopenmpをつけてコンパイルする。なお、インテルコンパイラは、バージョン9よりAMDのプロセッサにも対応するようになったが、バージョン9とAMDプロセッサの組み合わせでのOpenMPはなぜが実行効率が非常に悪い。これはバージョン10にすることにより解決される。

Visual C++

Visual C++(cl)の場合は、/openmpをつけてコンパイルする。
Visual C++は2005よりOpenMPがサポートされている。なお、無料のExpressバージョンには含まれていないが、Windows SDK for Windows Server 2008 and .NET Framework 3.5を導入することによって、使えるようになる。詳細はこちら

GCC

gcc(g++)の場合は、-fopenmpをつけてコンパイルする。GCCはバージョン4.2から正式にサポートされるようになった。

OpenMPを使った並列計算

ここではOpenMPを使った並列計算について解説する。

OpenMPを使ってコンパイルしているかをプログラム中で知るには

OpenMPを使ってコンパイルしているかをプログラム中で知るには、_OPENMPが定義されているかで判別します。具体的には、

#ifdef _OPENMP
    //OpenMPを使ったコード
#else
    //OpenMPを使わない場合のコード
#endif

forループを並列化するには?

#pragma omp parallel forを使います。

#ifdef _OPENMP
#pragma omp parallel for
#endif
for(int i=0;i<N;i++)
{
    //ここの処理を書く
}

複数のforループが連続する場合は?

下記のように書くと毎回forループに入るたびにスレッドの生成コストが発生する。

    #ifdef _OPENMP
    #pragma omp parallel for
    #endif
    for(int i=0;i<N;i++)
    {
        //ここの処理を書く
    }
    #ifdef _OPENMP
    #pragma omp parallel for
    #endif
    for(int i=0;i<N;i++)
    {
        //ここの処理を書く
    }
    #ifdef _OPENMP
    #pragma omp parallel for
    #endif
    for(int i=0;i<N;i++)
    {
        //ここの処理を書く
    }

下記のようにすると、スレッド生成は一回ですむ。

#ifdef _OPENMP
#pragma omp parallel
#endif
{
    #ifdef _OPENMP
    #pragma omp for
    #endif
    for(int i=0;i<N;i++)
    {
        //ここの処理を書く
    }
    #ifdef _OPENMP
    #pragma omp for
    #endif
    for(int i=0;i<N;i++)
    {
        //ここの処理を書く
    }
    #ifdef _OPENMP
    #pragma omp for
    #endif
    for(int i=0;i<N;i++)
    {
        //ここの処理を書く
    }
}

ブロックごとに並列化するには?

#pragma omp parallel および#pragma omp sectionsを使います。

#pragma omp parallel
#pragma omp sections
{
    #pragma omp section
    {
        //並列させたい処理1
    }
    #pragma omp section
    {
        //並列させたい処理2
    }
    #pragma omp section
    {
        //並列させたい処理3
    }
}

並列数を変更するには?

通常は、環境変数OMP_NUM_THREADSから取得して並列数が決まる。omp_set_num_threads関数を使うと、プログラム中で指定できる。

#ifdef _OPENMP
omp_set_num_threads(4);
#endif

スレッド数を取得するには?

omp_get_max_threads()関数を使う。

#ifdef _OPENMP
cout<<"OpenMP : Enabled (Max # of threads = "<<omp_get_max_threads()<<")"<<endl;
#endif

本文中のFC4はFedora ProjectのFedora Core 4を、FC5はFedora Core 5を、FC6はFedora Core 6をopenSUSEはNovellのSUSE Linux OSSを表します。Fedora7以降は、単にFedora7、Fedora8、Fedora9、Fedora10、Fedora11と表示しています。Ubuntuは、必要に応じて7.10、8.04のようにバージョン番号をつけて区別しています。MandrivaはMandriva Linuxを表します。

ここに登場するドメイン名やIPアドレスなどはフィクションです。実在の人物・団体等とは一切関係がありません。
実際に使用する際は、各自の環境に合わせて書き換えてください。
もし何か間違いなどありましたらこちらからご連絡ください
リンクに許可は不要です。
Copyright (C) 2009 Chikuma Engineering Co., Ltd. All Rights Reserved.