Think Parallelで行こう!

第1回 並列処理を体感してみよう

株式会社フィックスターズ
浅原 明広

2009/7/8

共有メモリ型並列処理システムにおける並列化

 共有メモリ型並列処理システムとは、すべての演算器が共通のメモリ空間にアクセスできるシステムで、Symmetric Multiprocessing(SMP)システムと呼ばれることもあります。

 Quad Coreプロセッサを2ソケット搭載したサーバ製品はSMPシステムであり、この場合OSからは共通のメモリ空間に接続された演算器が8個見えることになります。大規模なスーパーコンピュータなどでは、CPUの数が64個や128個になるものもありますが、ハードウェアの構成上、それ以上の数のCPUを接続し、共通のメモリ空間にアクセスさせるのは難しいようです。

 現在はSMPシステムのPCが一般的ですので、実際上は、分散メモリ型が複数の計算機間の並列化なのに対して、共有メモリ型は計算機内部のCPU間の並列化であると考えておけばよいでしょう。

 MPIがデファクトスタンダードといえる分散型システムとは異なり、共有メモリ型では、並列化するためのツールやフレームワークはさまざまです。代表的なものをいくつか挙げてみましょう。

 このほか、前節で示したように通常分散メモリ型で使われるMPIを、1つの計算機内部の共有メモリ型の並列化にも使うことも可能です。

 以下では、このうち、並列化を比較的簡単に実装でき、一般的にも広まっているOpenMPを紹介します。

OpenMP

 OpenMPとは、共有メモリ型システムにおける並列化を効率よく行うことができるフレームワークです。1997年にOpenMP Version 1.0の仕様が策定されてから、徐々に進化を続け、最新の仕様書は2008年5月に公開されたVersion 3.0になります。

 現在では、GCC、Intel C/C++、IBM XLC、Microsoft Visual C++など、主要なコンパイラによってOpenMPがサポートされています。MPIのように、別途ライブラリなどをインストールする必要はありません。

 OpenMPでは、オリジナルのコードに対してプログラマが#pragmaで始まる指示文(Directive)を挿入し、コンパイラに対して並列化部分を明示的に指示します。コンパイラは指示文の指示どおりに並列化部分をスレッド分割し、並列処理を行うコードに変換してコンパイルします。本来、並列スレッドプログラミングを自分でやる場合は、スレッドの生成・消滅やデータの分割は自分で管理する必要がありましたが、OpenMPがその負担を削減します。

 ただし、OpenMPは並列化部分のロジックやデータの依存関係を分析しているわけではありません。あくまでも、指示文のとおりにスレッド分割するだけです。よって、プログラマが間違った指示文を使っている場合は、結果も意図しないものになります。

 OpenMPの特徴の1つに、通常の逐次処理コードと並列化されたコードを同一のコードで管理できることがあります。例えば、MPIを使ってオリジナルの逐次処理コードを並列化する場合、逐次処理コードを大幅に書き換えて、並列処理用のソースを別途書くことになりますが、OpenMPの場合、並列用と逐次用という2つのソースコードを書く必要はなく、コンパイラスイッチのオン・オフで出力の実行形式ファイルを逐次処理と並列処理に切り替えることができます。

 つまり、コンパイルオプションでOpenMPのサポートをオフにした場合は、単に#pragma文が無視されて通常の逐次処理を行う実行形式を生成し、OpenMPのサポートをオンにした場合は、並列化された高速な実行形式を生成します。

 では、リスト1のサンプルプログラムを、今度はOpenMPで並列化してみましょう(リスト3)。

●リスト3 配列の各要素を1インクリメントするサンプルコード(OpenMP)
001: /*
002:  * Array のインクリメント(OpenMP版)
003:  */
004: 
005: #include<stdio.h>
006: #include<stdlib.h>
007: #include<omp.h>
008: #define N 16
009: 
010: int main (int argc, char *argv[])
011: {
012:   int i;
013:   int *rootBuf;
014:   int num_of_threads;
015: 
016:   if(argc!=2){
017:     printf("usage: a.out <number of threads>\n");
018:     return(1);
019:   }
020: 
021:   num_of_threads = atoi(argv[1]);
022:   omp_set_num_threads(num_of_threads);
023:   
024:   rootBuf = (int *)malloc(N * sizeof(int));
025: 
026:   /* 配列Initialize */
027:   for(i=0;i<N;i++){
028:     rootBuf[i] = i;
029:   }
030: 
031:   /* 並列処理の開始 */
032: #pragma omp parallel
033:   printf("Exec by thread 0 (total 0 threads)\n",omp_get_thread_num(), omp_get_num_threads());
034: #pragma omp for
035:   /* Incriment */
036:   for (i = 0; i < N; i++) {
037:     rootBuf[i] = rootBuf[i] + 1;
038:   }
039: 
040:   /* 演算結果の出力 */
041:   printf("\n");	 
042:   for (i = 0; i < N; i++) printf("rootbuf[%d] = %d\n",i,rootBuf[i]);
043:   
044:   /* 終了処理 */
045:   free(rootBuf);
046: 
047:   return(0);
048: }

 OpenMPに関しても、今後の連載で1記事設けて詳しく説明したいと思っていますので、ここでは簡単なコメントのみ挙げます。

007行目:
"omp実行時ライブラリ関数"を使うために必要なインクルードファイルです
022行目:
この関数の呼び出し以降の並列領域におけるスレッド数を規定します。この関数は、コードの逐次実行部分から呼び出された場合にのみ有効です
032行目:
このpragma文以降が並列化されます
033行目:
各スレッドで、総スレッド数と各スレッドのスレッド番号をprintfします
034行目:
このpragma文直後のforループが適切なループサイズで並列実行されます

 MPIと比べると修正量は大幅に少なく、直観的にも分かりやすいかと思います。OpenMPオフィシャルサイトで、日本語に翻訳された仕様書が手に入りますので、詳しくはそちらを参照下さい。

 また、より本格的に勉強したい方には、『Using OpenMP: Portable Shared Memory Parallel Programming』(Barbara Chapmanほか著)をお勧めします。こちらは洋書になってしまいますが、OpenMPのチューニングにフォーカスした秀逸な教科書です。リスト3の処理の概念図を図5に示します。あわせて参考にして下さい。

●リスト3(OpenMP)の処理の概念図

 実際にコンパイルして実行するには、リスト3のソースコードファイルをlist3.cとして、以下のようにします。

●GCCの場合
gcc -fopenmp list3.c
●Intel Cの場合
icc -openmp list3.c

 適宜、最適化オプションなども併用してください。021行目を見ていただければ分かるように、コマンドライン引数として生成するスレッド数を取ります。実際にスレッド数を変えたり、Nを大きくしてみたりしながら、実行時間が変化することを確認してみてください。

 

 以上、「Think Parallelで行こう」の第1回、いかがだったでしょうか。今回の記事は、「並列化とは」からスタートして、分散型並列処理システム、共有型並列処理システム、それぞれで代表的な並列化フレームワークであるMPIとOpenMPを紹介しました。

 詳細な説明は省きましたが、両フレームワークの違いについては理解いただけたかと思います。しかしながら、実験されると分かるのですが、MPI版もOpenMP版も、今回の課題では演算処理が軽すぎて、並列実行しても実行速度はほとんど改善できません。

 もし余力のある方は、ループ内部の処理をより複雑な処理に変えてみてください。十分な計算負荷がある場合は、スレッド数に従って計算速度が改善されていく様子が分かると思います。MPIとOpenMPのより具体的な高速化手法については、本連載の今後の記事をお待ちください。

 次回は「マルチプロセッサ概説」と題して、最新のマルチコアプロセッサの特徴について、解説します。では、また次回までごきげんよう!

prev
3/3
 

Index
並列処理を体感してみよう
  Page1
いまだからこそ“Think Parallel”
並列処理手法とは何か
  Page2
分散メモリ型並列処理システムにおける並列化
Message Passing Interface
Page3
共有メモリ型並列処理システムにおける並列化
OpenMP

index Think Parallelで行こう!


Coding Edge フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

>

Coding Edge 記事ランキング

本日 月間