はじめに
IT業界はよく日進月歩だと言われます。確かに我々開発者を取り巻く環境は日々変化し、新しいテクノロジーが毎月のように発表されています。しかし、ある程度経験を積んだ開発者は、そのような変化は表面上のものだと考えます。
プログラミング言語は進化し、どんどん新しい機能が追加されてゆき、それに伴い新しい開発環境が登場します。ですが、冷静に考えてみればそう慌てることはありません。昨今騒がれている言語の新しい機能も大半が古くからあるものですし、開発環境もそれ程やり方は変わっていません。開発ツールが進化しても、開発工程そのものはほとんど変わっていませんので、ちょっと新しいことを覚える程度で済みます。何も慌てることはありません。
しかしここ数年の間に大きな変化がありました。それはCPUのマルチコア化です。2006年にPentium 4シングルコアの製造が中止され、Intel Core 2が発売され始めた時、筆者は非常に衝撃を受けました。なぜならば、それは従来の開発技法が通用しないことを意味するからです。
今まではムーアの法則が示す通りに、CPUの性能はどんどん向上していき、開発者が特別なことをしなくてもCPUさえ買い換えれば開発したシステムの処理スピードが上がりました。ですが、もう単一CPUの時代は終わり、CPUのマルチコア化が進んで行きますので、開発者もそれに伴って並列プログラミングをする必要性が生じました。
あまりなじみのない方もいると思いますので簡潔に説明します。「並列プログラミング」とは、複数の処理を同時に行うようにアルゴリズムやオブジェクトデザインを考え、それに基づきコーディングすることです。CPUがマルチコアになれば、システムの性能を上げるためには、その複数のCPUを有効に使用せねばなりません。CPUがシングルコアに戻ることはないのですから、これからの時代は並列プログラミングが当たり前のものとなるのです。
並列プログラミング
今までシングルコアのCPUが主流だったからといって、並列プログラミングがまったくなかったわけではありません。今までもマルチスレッドプログラミングを行っていた人も多いと思います。この手法でもコア数が2ならば十分に対応可能でしょう。
しかし、コア数が4・8・16・32・64・……と増えるにつれてこの方法では対処できなくなります。また、コア数を固定したプログラミング方法では、エンドユーザーがCPUを買い換えた時パフォーマンスがアップしません。エンドユーザーは新しいCPUを買えばシステムの性能がよくなると考えていますので、これではシステム不備だと看做されてしまうでしょう。今後コア数が増加することは目に見えていますので、新しい技術が必要なのは明白です。
幸い並列プログラミングを助け、マルチコアを有効に利用するための技術があります。いろいろありますが、筆者が知っているのはOpenMPとTBB(インテル・スレッディング・ビルディング・ブロック)です。これからこの2つの技術を簡潔に説明します。
OpenMP
OpenMPはコンパイラを拡張し、プログラマーがプログラムを並列なものとして記述する手助けを行い、コンパイラに並列環境に適したコードを生成させるための規格です。この規格は1997年に制定され、FortranとC言語の拡張機能として広く普及しています。この技術の特徴は、独自のプリプロセッサディレクティブを使用することにより、並列環境とそうでない環境のコードを同一にできることです。効果も高く非常に有用な技術だと言えます。
TBB
TBBは標準C++を使用してスケーラブルな並列プログラミングをサポートするライブラリです。この技術の特徴は、スケーラブルでよりコア数が多いプロセッサーに変えてもパフォーマンスを向上できること、ライブラリなのでOpenMPなどの他の技術と併用できることです。C++の並列プログラミングにおいて、筆者の知る限り最良の技術です。
この2つの技術を有効利用すればマルチコア対応の並列プログラミングが効率よくできます。ただ一つだけ憂慮するべき点があります。それは開発環境です。実務では優れた開発環境を使用して開発効率を上げます。もし開発環境がなければ、どれだけ優れた技術でも開発効率が落ちては意味がありませんので、実務では採用できないでしょう。そこで筆者はこの2つの技術に対応した開発環境を求めていました。そして見つけたのが「インテル Parallel Studio」(以下、Parallel Studio)です。
Parallel Studioについて
私がParallel Studioを気に入った理由は3点あります。
第1に、OpenMPとTBBをサポートしていることです。
第2に、使い慣れたMicrosoft Visual Studioに統合されていることです。これは非常に重要な点です。たとえ優れた機能を持っていても、もし独自の操作法を要求する開発ソフトならば、習得するためのコストがかかり実務での採用は難しいものとなります。
第3に、プロファイル機能、デバッグを助ける機能、といった実務的なツールがセットになっていることです。並列プログラミングで一番難しい所はデバッグであり、並列化することのパフォーマンス測定も必要なので、この2つのツールも付属している点が気に入りました。
ここからは実際にParallel Studioを使用して説明しますので、Parallel Studioのインストールの方法について説明します。
- Parallel Studioをインストールする前に、Microsoft Visual Studioが正しくインストールされているかよく確認してください(2005または2008のStandard Edtion以上が必要)。
- Parallel Studioはフルインストールすると3GB程度必要になります。インストール前に十分なハードディスクの容量があることを確認してください。
インストール前の準備
評価版のダウンロードページにアクセスして、必要事項を記入の上申し込み登録をします。
![販売代理店のエクセルソフトのWebページから、評価版を入手する。](http://cz-cdn.shoeisha.jp/static/images/article/3946/fig01_s.gif)
その後表示されるホームページの指示に従って、Parallel Studioの登録申請を完了させてください。
登録が完了すると「シリアル番号」が表示されます。この番号は重要なものなので必ずメモしてください。またこのページでParallel Studio評価版がダウンロードができますのでparallel_studio_setup.exeをクリックしてダウンロードしてください。
登録完了後にインテル社から登録完了を知らせるメールが届きます。このメールの内容をよく読み、添付されている「ライセンスファイル」を大切に保存してください。
parallel_studio_setup.exeのダウンロード、シリアル番号のメモ、ライセンスファイルの保存の3つが終わったら準備完了です。
インストール
ダウンロードした「parallel_studio_setup.exe」は圧縮されているので任意の場所へ解凍します。解凍後、自動的にスタートアッププログラムが起動しますが、起動しない場合は解凍したファイルの「Setup.exe」をダブルクリックしてください。
Welcome画面で[次へ]ボタンを押下すると、ライセンスの使用許諾書が表示されるのでよく読んで、ラジオボタンの上[I accept...]を選択して[次へ]ボタンをクリックしてください。
Activation Options画面では、ラジオボタンの上から2つ目[Activate...]を選択して先ほどメモしたシリアル番号を入力するか、一番下のラジオボタン[Choose...]を選択して[次へ]ボタンを押してください。
上の手順で[Choose...]を選択した場合は、選択を促す画面が表示されますので上から2番目の「Use a license file」を選択して「次へ」ボタンを押してください。続いて、インストール前の準備で保存しておいたライセンスファイルを選択して[次へ]ボタンを押します。
Installation Options画面が表示されたら、[Full...]を選択して[次へ]ボタンを押下すると、インストールが始まります。
インストール完了を知らせる画面が表示されたら、完了です。次項では実際にParallel Studioを使用してみます。
サンプルコードの説明と実行
まずは、この記事のサンプルコードをダウンロードしてください。このコードの内容は、教師が生徒の5科目の採点をし平均点を求めるというものです。なお、このサンプルコードは実務を意識したものではないので、あくまでもParallel Studioを使用するためのものだと考えてください。
ダウンロードが終わったら、「ParallelComputation.sln」をダブルクックしてMicrosoft Visual Studioを起動します。
起動後、ソリューションエクスプローラのプロジェクト名[ParallelComputation]を右クリックし、[Intel Parallel Composer]-[Using Intel C++]を選択してください。選択するとメッセージボックスが表示されますので[Yes]を押下します。
次に、ソリューションエクスプローラのプロジェクト名[ParallelComputation]を右クリックし、[Build Component Selection]を選択すると、ダイアログボックスが表示されますので、[Use TBB]をチェックしてください。
![ソリューション名を右クリックして[Build Component Selection]を選択します。](http://cz-cdn.shoeisha.jp/static/images/article/3946/project_name.gif)
最後にこのプロジェクトではラムダ式を使っていますので、[プロジェクトのプロパティ]-[C++]-[Language]を選択すると表示されるプロパティページで、[Enable C++0x Support]をYesにしてください。
以上で準備完了です。デバッグなしで開始してください。すると、直列(シングルコア)での処理時間と並列(マルチコア)での処理時間が表示されます。
筆者の環境Aでは…
- CPU:Intel Core2 Duo E7400
- メモリ:4G
- OS:WindowsXP(32ビット、最新パッチ適用済み)
![実行結果。](http://cz-cdn.shoeisha.jp/static/images/article/3946/results.gif)
計測結果は、直列計算は0.0131596秒、並列計算は0.00733408秒でした。処理に必要な時間がおよそ55.7%(処理スピード約1.79倍)になっていますので、効率的に2つのCPUが使われていることが分かります。さらに、より多いコア数であればさらなる処理能力の向上が見込めます。
次に既存のシステムを改良することも考えて、古い環境でも試してみました。
筆者の環境Bでは…
- CPU:Intel Pentium4 530j
- メモリ:4G
- OS:WindowsXP(32ビット、最新パッチ適用済み)
計測結果は、直列計算は0.0262007秒、並列計算は0.0225461秒でした。処理に必要な時間がおよそ86%(処理スピード約1.16倍)になっていますので、ハイパースレッディング・テクノロジー対応の古いCPUですら処理効率が上がることが分かります。
しかも、パフォーマンスを向上させるために必要な作業量は少量です。
パフォーマンスチューニングで行う作業
必要な作業は大まかに言うと3つだけです。
1つ目に、TBBを使用するのに当たって必要なヘッダファイルをインクルードします。
2つ目に、main
関数内にtask_scheduler_init init;
のプログラムを追加します。
最後に、一番処理時間がかかっている場所を並列用に変えます。このサンプルでは、採点&平均点を求める場所が一番多くの処理時間を費やしているので、その部分を改良します。
void ComputationAverage() { Student* tmp = this->students; for( int i = 0; i < Count; i++) { tmp[ i ].set_score_j( ( int )( rand() % 100 ) ); tmp[ i ].set_score_n( ( int )( rand() % 100 ) ); tmp[ i ].set_score_sc( ( int )( rand() % 100 ) ); tmp[ i ].set_score_so( ( int )( rand() % 100 ) ); tmp[ i ].set_score_e( ( int )( rand() % 100 ) ); tmp[ i ].set_agerage ( ( tmp[ i ].get_score_j() + tmp[ i ].get_score_n() + tmp[ i ].get_score_so() + tmp[ i ].get_score_sc() + tmp[ i ].get_score_e() ) / 5 ); } };
void ParallelComputationAverage() { parallel_for( blocked_range( 0, Count, 10000 ), [](const blocked_range& range) { Student* tmp = this->students; for( int i = range.begin(); i < range.end(); i++) { tmp[ i ].set_score_j( ( int )( rand() % 100 ) ); tmp[ i ].set_score_n( ( int )( rand() % 100 ) ); tmp[ i ].set_score_sc( ( int )( rand() % 100 ) ); tmp[ i ].set_score_so( ( int )( rand() % 100 ) ); tmp[ i ].set_score_e( ( int )( rand() % 100 ) ); tmp[ i ].set_agerage ( ( tmp[ i ].get_score_j() + tmp[ i ].get_score_n() + tmp[ i ].get_score_so() + tmp[ i ].get_score_sc() + tmp[ i ].get_score_e() ) / 5 ); } }); };
今回は紙面の都合上コードの詳しい説明はできませんが、自分の手でマルチスレッドプログラミングをするよりも容易に、パフォーマンス向上が実現できることが実感できると思います。
Parallel Studioが備える並列処理システム開発補助機能
実際のシステム開発で並列処理を適用する場合、大まかに言うと開発ソフトに2つの機能が必須です。
1つ目はプロファイル機能です。システムは並列が向く処理と向かない処理がありますので、すべてを闇雲に並列化してはなりません。ですから、どの処理を並列化すればよいのかや、どこがボトルネックになっているのかを判断するためにプロファイル機能が必要となります。また、既存の資産を改良する場合にも役立ちます。
2つ目は並列処理専用のデバッグ機能です。実際のシステムが正常に動作するには、デバッグを何回も行わなくてはなりません。しかし、並列処理は一度に複数のプログラムが同時に作動しますので、シングルコアのプロセッサ用プログラムよりも処理が複雑化しデバッグが難しくなります。そこで、開発ソフトには並列処理に特化したデバッグ支援機能が必要となるのです。
幸いParallel Studioにはこの2つの機能が備わっています。Parallel Studioは、インテル Parallel Composer、インテル Parallel Inspector、インテル Parallel Amplifierの3つで構成されています。先ほど紹介したサンプルは、「インテル Parallel Composer」を使用して作りました。後の2つの機能がプロファイラ機能と、並列処理のデバッグ支援機能を持っています。今回は詳しくは説明できませんが、簡潔にこれらの機能を解説します。
「インテル Parallel Inspector」は並列処理のデバッグ支援に関する複数の機能を持っています。具体的には、マルチコアが同時にメモリーに読み書きすることにより起こる厄介なエラーを解決するために「スレッド化エラーチェック機能」があります。他にもマルチスレッドで発生するエラーを解決するために、スレッドが競合している部分を特定する機能などがあります。これらの機能は、並列処理で起こる数々の問題を解決するに非常に役立ちます。
「インテル Parallel Amplifier」は、プロファイルに関する複数の機能を持っています。具体的には、ロックによるパフォーマンス劣化/問題を検出するための「ロック/待ち分析機能」、並列処理によるパフォーマンスを詳細にチェックする「コンカレンシー分析機能」などがあります。これらの機能は、システムのパフォーマンスを効率よく向上させるのに非常に役立ちます。
説明を文章で読むと複雑そうに感じるでしょう。ですが、これらの機能はすべてグラフィカルに表示され、マウスで簡単に操作できますので、並列処理についてのパフォーマンスチューニング、およびデバッグについて熟練していない方でも比較的容易にできます。また、熟練者の方でもより一層効率よく作業できるでしょう。
まとめ
この記事では、始めにシステム開発において並列処理を考慮することが必須であることを述べ、それをサポートするテクノロジーがあることを解説しました。そして、Parallel Studioが並列処理で開発を行うのに適した機能を持っていることを紹介しました。
今回は駆け足での紹介となりましたので、Parallel Studioの機能をほんの一部しか紹介できませんでした。ですから、皆様は実際に評価版をダウンロードして、使ってみるとよいでしょう。我々を取り巻く環境は激変し、並列処理が当たり前のものとなる日は近いと思いますので、今から近い将来に向けて準備をしておくことをお勧めします。
参考資料
- 『インテルスレッディング・ビルディング・ブロック』 James Reinders 著、菅原清文 監修、エクセルソフト株式会社 訳、オライリー・ジャパン、2008年2月
- XLsoft Home