サンプルコードの説明と実行
まずは、この記事のサンプルコードをダウンロードしてください。このコードの内容は、教師が生徒の5科目の採点をし平均点を求めるというものです。なお、このサンプルコードは実務を意識したものではないので、あくまでもParallel Studioを使用するためのものだと考えてください。
ダウンロードが終わったら、「ParallelComputation.sln」をダブルクックしてMicrosoft Visual Studioを起動します。
起動後、ソリューションエクスプローラのプロジェクト名[ParallelComputation]を右クリックし、[Intel Parallel Composer]-[Using Intel C++]を選択してください。選択するとメッセージボックスが表示されますので[Yes]を押下します。
次に、ソリューションエクスプローラのプロジェクト名[ParallelComputation]を右クリックし、[Build Component Selection]を選択すると、ダイアログボックスが表示されますので、[Use TBB]をチェックしてください。
最後にこのプロジェクトではラムダ式を使っていますので、[プロジェクトのプロパティ]-[C++]-[Language]を選択すると表示されるプロパティページで、[Enable C++0x Support]をYesにしてください。
以上で準備完了です。デバッグなしで開始してください。すると、直列(シングルコア)での処理時間と並列(マルチコア)での処理時間が表示されます。
筆者の環境Aでは…
- CPU:Intel Core2 Duo E7400
- メモリ:4G
- OS:WindowsXP(32ビット、最新パッチ適用済み)
計測結果は、直列計算は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 ); } }); };
今回は紙面の都合上コードの詳しい説明はできませんが、自分の手でマルチスレッドプログラミングをするよりも容易に、パフォーマンス向上が実現できることが実感できると思います。