実際に並列化を行ってみる
ブースで行われたデモンストレーションでは、Core 2 DuoのPCを使って、行列の積和演算(matmul)と20万のうちの素数の数を求める処理(prime)を並列化していく様子が実演された。
並列化の処理では、命令レベルで行う手法(ベクタライズ)と、スレッドの並列化がある。スレッドの並列化には、インテル コンパイラーを使った自動並列化、OpenMPを使うもの、Parallel Composerのライブラリ(TBBやIPP)を使ったもの、Win32APIを使うものなどあるが、今回のデモでは、並列化しない状態を基準に、ベクタライズや自動並列化を行い、さらにOpenMPを使う手法まで、段階的に実演していた。
まずは、基準値として、並列化をしていない状態、Microsoftのコンパイラを使った場合のアプリケーションをビルドした。
matmul 2.093sec prime 3.407sec 計 5.5sec
次に、インテル コンパイラーを使った場合。Visual Studioの画面上で、プロジェクトをParallel Composerのプロジェクトに変換してビルドする。
matmul 1.968sec prime 3.407sec 計 5.375sec
matmulについては少し早くなった。
続いて、Parallel Amplifierの機能を使ってhotspotを分析し、どの処理に時間がかかっているかを確認。当然ながら、matmulとprimeの演算に時間がかかっていることがわかった。ここから並列化を行うこととなる。ベクタライズと自動並列化のオプションを追加してビルド。コードの修正はなく、オプションを選択していくだけだ。結果、matmulに対しての並列化が行われ、約2倍のパフォーマンスとなった。
matmul 1.078sec prime 3.406sec 計 4.484sec
primeに対しては、コンパイラが判断した結果、自動並列化をしなかったため、OpenMPを使用して並列化処理を行っていく。primeでのfor文の前に次の1行を追加するとOpenMPでの並列化を行う。併せてOpenMPの命令を認識させるための設定も行う。
#pragma omp parallel for
実行結果は次のとおり。
matmul 1.046sec prime 2.563sec 計 3.609sec
primeに対しても並列化が行われ、いくぶん早くなった。しかし、肝心の演算結果が17984であったものが17983と間違ったものになってしまった。このバグを検出するためにParallel Inspectorを利用する。
まず作業効率を考え、デバッグ時は問題が発生しなかったmatmulは無視し、prime演算自体も20万から200に変更した。スレッドのダブりを確認するよう設定して結果を確認すると、2つの問題が検出された。factorに対して、複数のreadとwriteが発生していることがわかった。並列化のエラー特有のデータの競合である。Parallel Inspectorからソースの編集画面に戻り、スレッド単位でのfactorを設けるため、先ほど追加したOpenMPの命令を次のように修正した。
#pragma omp parallel for private(factor)
さらに、シングルスレッドで実行させたい部分について次の行も追加した。
#pragma omp critical
この状態でParallel Inspectorで検証し、問題が解消されたことを確認。コードを元に戻して実行した結果は次のとおり。
matmul 1.218sec prime 2.563sec 計 3.781sec
primeの演算結果は正しくなり、速度も向上した。ここでスレッドセーフなアプリケーションとなったが、Parallel AmplifierでConcurrencyをチェックし、さらにチューニングを施していく。
matmulは複数のスレッドで均等に動作しているが、primeのほうは一つのスレッドで動作している時間が長いことがわかった。primeの分析結果を詳しく見ると、処理のアンバランス性が見つかった。20万のうちの最初の10万を演算するスレッドと10万1~20万を演算するスレッドとを比較した場合、後半の方が処理が多くなるといった不公平性が出た結果だ。
これを均等に割り振るために、OpenMPのコードを次のように修正した。
#pragma omp parallel for private(factor) schedule(static,1)
これにより、各スレッドに対して順番にデータを割り振ることができるようになる。ここで実行し、Concurrencyを見ると、primeのほうも均等に処理されることが確認できた。チューニングしたアプリケーションを実行。
matmul 1.109sec prime 1.797sec 計 2.906sec
結果は、matmul、prime共に基準値のほぼ2倍となった。OpenMPによる並列化の場合、2コアの開発環境で作ったアプリケーションを、4コアや9コアといったサービス環境に納品した場合それに相応したスケーラビリティが得られるという。
Parallel Studioのリリースは5月27日だが、インテル社としては珍しくβ版を配布し、事前予約も受け付けていたという。SODECのブースでも興味を持ってベータ版のCDをもらう人が多かった。現状ではメニューやダイアログなどのインターフェイスは英語となっているが、重要と思われるマニュアルの一部は日本語化する予定だ。なお、現在購入しておけば、来年リリース予定のParallel Advisorもリリース後に利用できるようになる。