2016. 3. 20.
石立 喬

OpenMPとVisual C++による並列処理(2A)

――― Win32アプリケーションで、グラフを用いてVisual C++、Qpara、OpenMPの使用効果を比較する -----

 「OpenMPとVisual C++による並列処理(4)」で、グラフを使って実行時間の測定結果を表示したところ、非常に分かり易い結果が得られたので、さかのぼって、「・・・並列処理(2)」もグラフで示すことにした。被測定ループについては、すでに説明してあるので、ここでは結果を中心に紹介する。

比較方法
 以下に示す全ての組み合わせ(24通り)について実行時間を調べる。
     ビルド較正 ------- Debug、Release
     forループ -------- 一重、二重
     処理内容 --------- 三角関数の積の配列代入、累加算代入
     並列化手法 ------- Visual C++デフォルト、Qpar使用、OpenMP使用
 累加算代入処理に関しては、演算結果を表示させ、誤計算が生じていないことを確認する。
 グラフは、ビルド後、最初の実行によるものを表示させる。

グラフ表示のための準備
 「・・・並列処理(3」、「・・・並列処理(4)」などで、すでに説明してある方法で、下記により準備する。
 1)Win32プロジェクトのテンプレートを生成する
 2)OpenMPのサポートを設定する
 3)Qparを有効にする
 4)omp.hとmath.h(三角関数用)をインクルードする
 5)UserProgram関数をプロトタイプ宣言する
 6)WM_PAINTからUserProgramを呼び出すようにする
 7)UserProgramを記述する

使用したプログラム
 図1は、Win32プロジェクトのWM_PAINTから呼び出されるUserProgram関数で、この内容については、「・・・並列処理(4)」に詳述してあるので参照されたい。図1のプログラムは、VC++デフォルト、Qpar、OpenMPを切り替えるようにしてあり、不必要な部分をコメントアウトして使用する。図1は、VC++デフォルトの場合を示す。
 これをDebug構成でビルドし、実行させた結果を図2に示す。VC++デフォルトの場合は、実行時間にバラツキがなく、ほぼ一定である。



図1 使用したUserProgram



図2 図1のプログラムの実行結果、累加算代入ではないので、sum = 0になっている


測定したループの種類
 「・・・並列処理(2)」で用いたのと同様に、表1の各ループ処理について実行時間を測定した。プログラムコードでは、VC++デフォルトで使用する場合を示してあるので、Qpar用とOpenMP用の各#pragma文はコメントアウトされている。

表1 測定に使用した一重および二重ループ

ループ処理種別 プログラムコード Debug構成 Release構成
一重ループ配列代入 図3 図4
一重ループ累加算代入 図5 図6
二重ループ配列代入 図7 図8
二重ループ累加算代入 図9 図10


一重ループで配列代入の場合
 Debug構成による結果を図3に、Release構成を図4に示す。OpenMPでは、実行1回目に時間が非常に大きくなることが多い。再ビルドなして何回かプログラムの実行を繰り返すと、このピークは消えたり、小さくなったりする。すべての並列化手法で、Debug構成に比べてRelease構成が高速であるが、OpenMPは高速化が十分でなく、Release構成では、結果としてVC++デフォルトよりOpenMPの方が遅くなっている。


図3 Debug構成では、VC++デフォルトとQpar使用は同じ、OpenMPは、平均で35%になった



図4 Release構成では、Qparで75%になり、OpenMPでは逆に増大した


一重ループで累加算代入の場合
 Debug構成による結果を図5に、Release構成を図6に示す。すべての並列化手法で、Release構成がDebug構成よりやや速い。Debug構成のOpenMP使用で、38回目までほぼ一定の実行時間が続き、その後少し短くなって一定の時間が続く理由はわからない。


図5 Debug構成では、配列代入と傾向は変わらず、OpenMPの効果はやや悪くなった



図6 Release構成では、配列代入に比べて、OpenMPを除き遅くなった


二重ループで配列代入の場合
 Debug構成による結果を図7に、Release構成を図8に示す。すべての並列化手法で、Release構成がDebug構成よりはるかに速い。



図7 Debug構成では、一重ループとほとんど変わらない 



図8 Release構成では、全般的に、一重ループより速くなった


二重ループで累加算代入の場合
 Debug構成による結果を図9に、Release構成を図10に示す。すべての並列化手法で、Release構成がDebug構成より速い。


図9 Debug構成の場合、Qpar付加は全く変わらない、OpenMPは平均的には有効、



図10 Release構成では、全体的に、一重ループの半分になった


結 論
 以上の測定結果を、平均値でまとめたのが表2である。

表2 実行速度測定結果のまとめ(単位:μsec)


 表2によれば、以下のことが分かる。
 1)Debug構成では、ループ処理種別によらず、VC++デフォルトとQparが、全て同じである。→Qparの効果なし
 2)Debug構成で、OpenMPを使用すると処理速度が平均40%程度に短縮される。→OpenMPの効果あり
 3)Release構成でも、VC++デフォルトとQparは同じである(一重の配列代入を除き)。→一部にQparの効果あり
 4)Release構成で、OpenMPは、配列代入でVC++デフォルトに劣る。→OpenMPは配列代入に不向き、累加算代入は効果あり
 OpenMPが、累加算代入に優れているのは、reduction(+ : sum)が使用できるからではないかと思われる。
 OpenMPは気まぐれである。原因が良く分からないし、実用時の性能を、今回求めた平均値で判断して良いのか、CPUの種類との相性まで考えて、判断しないといけないのか、多くの宿題が残っている。
 ここに示した全てのデータは、かなり変動するので、一例として、参考にしてほしい。
 さきに、「・・・並列処理(2)」で示したものを要約した、「Debug構成なら無条件でOpenMPを使い、Release構成の累加算代入ではOpenMPを使用すべきである。Qparを使用する理由は、特に見当たらない。 」の結論に変更の必要はない。




「Visual C++の勉強部屋」(目次)