🌟

OpenMPの基本-OpenMPでHello World-

2024/04/20に公開

はじめに

OpenMPに関する記述が少ないので書いてみることにしました。

OpenMPとは

OpenMP(Open MultiProcessing)とは、共有メモリ型計算機用に考え出された並列計算をする為の仕様の名称で、各計算機ベンダーやコンパイラ開発をしている人がこの仕様を元に実装しています。ターゲットとしてはC/C++/FORTRANとなっています。
有名なところではGCC(GNU Compiler Collection)がありこのコンパイラではOpenMPの仕様に沿って実装されています。

以下がOpenMPの仕様が載っている大元のサイトです。

https://www.openmp.org

共有メモリ計算機とは

共有メモリ型計算機とはその名の通り、メモリを共有している計算機を指しています。昔は超高級計算機だったのですが、今や普通のパソコンでも共有メモリ計算機となっています。
つまり、コアが複数あったとき、メモリ領域を共有して物事を実行しています。
これの対義的なものとして「分散メモリ型計算機」と言うものがありこれにはこれでデファクトスタンダードな仕様があります。

OpenMPの特徴

OpenMPはコンパイラディレクティブである#pragma ompから始まるOpenMP指示子と呼ばれるものを用いて並列化を指示する事ができます。これには色々な利点があります。

  1. 可搬性がある:コンパイラディレクティブの形で記述できるのでどこへ持っていってもこの記述が理解できるコンパイラがあればコンパイル可能になります。
  2. ソースコードの一元化を実現できる:逆にこの指示子を理解できないコンパイラがあったとしてもOpenMPはコンパイラディレクティブで書かれていますので、無視することができます。
  3. 可読性の維持:コンパイラディレクティブ一行で指示ができますので比較的可読性を維持しやすくなっています。

OpenMPでHello World

では早速並列化してみましょう。
まずは一般的なHello WorldをC言語で書いてみましょう。

hello.c
#include<stdio.h>

int main(int argc,char *argv[])
{
    printf("Hello World!\n");
}

コンパイルして実行します。

$ gcc -o hello hello.c
$ ./hello
Hello World!

では、これにOpenMPを用いて並列化をしていきます。

omp_hello.c
#include<stdio.h>
#include<omp.h>

int main(int argc,char *argv[])
{
#pragma omp parallel
    printf("Hello World!!\n");
}

違いはヘッダファイルが1行追加され、#pragma omp parallelというコンパイラディレクティブがあるかないところだけと言うことが確認できます。
ではコンパイルして実行します。

$ gcc -fopenmp -o omp_hello omp_hello.c
$ ./omp_hello
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!

コンパイル時にOpenMPを解釈してコンパイルするための指示オプション-fopenmpを含めてコンパイルしただけでHello World!!がたくさん出てきました。
私のマシンはPコア6・Eコア8の計20スレッドで動いていますので20行のHelloWorld!!が出ました。

スレッド数の制御

OpenMPはスレッドの数(コアの数:HyperThreadningTechnologyを使っていたら増える場合があります)だけ並列化します。
では、これをもう少し少ない数で動かしたいと思ったときはどうすれば良いか。
そこはきちんと制御できます。
環境変数OMP_NUM_THREADSで変更します。たとえば5スレッドで動かしたいときは次のようにします。

$ OMP_NUM_THREADS=5 ./omp_hello
Hello World!!
Hello World!!
Hello World!!
Hello World!!
Hello World!!

勿論環境変数ですのでexport OMP_NUM_THREADS~/.bashrcに記述してもOKです。
ただ、Pコアだけで動かしたいという欲望は私の腕ではまだ実現できていません。

ソースコードの一元化に関する手法

特徴における利点として「ソースコードの一元化の実現」を挙げました。本当なのかここで実験してみます。
OpenMPプログラムを-fopenmpオプションなしでコンパイルしてみます。

$ cat ./omp_hello.c
#include<stdio.h>
#include<omp.h>

int main(int argc,char *argv[])
{
#pragma omp parallel
    printf("Hello World!!\n");
}
$ gcc -o omp_hello_single omp_hello.c
$ ./omp_hello_single
Hello World!!

きっちり1行しかHello world!!が出てきませんでした。

おわりに

これはほんの序章に過ぎません、ここから色々な制御をおこないプログラムを高速化していくことができます。それについては今後記載していきます。

Discussion