CEDEC 2009 での講演の準備中に、レイトレースの C のベンチマーク aobench を教えてもらったので、このベンチマークを Visual Studio 2010 の PPL(並列パターン ライブラリー)を使い、並列化してみました。
レンダリング ループを parallel_for を使って以下のように並列化しました。
void render(unsigned char *img, int w, int h, int nsubsamples) { int x, y; int u, v; … //for (y = 0; y < h; y++) { parallel_for( 0, h, [&](int y) { //for (x = 0; x < w; x++) { parallel_for( 0, w, [&](int x) { for (v = 0; v < nsubsamples; v++) { for (u = 0; u < nsubsamples; u++) {
…
} } //} }); //} });
この並列化によって、ベンチマークの結果は Core2 Quad で2.13秒(直列)から0.64秒(並列)へとそこそこの結果でしたが、結果の画像が次のようにおかしくなってしまいました。
2日ほど悩みましたが、理由がわからず US の Parallel Team に問い合わせると、10分で回答が返ってきました! 変数 u, v がループの外側で宣言され、並列な全タスクで共有されていたのが原因です。最終的に以下のようにループ内での宣言に直すと、正しい画像が得られるようになりました。並列化のワナですね...
void render(unsigned char *img, int w, int h, int nsubsamples) { … parallel_for( 0, h, [&](int y) { parallel_for( 0, w, [&](int x) { for (int v = 0; v < nsubsamples; v++) { for (int u = 0; u < nsubsamples; u++) {
} } }); });
PPLやTPLによる並列化は、スレッドを生成・管理するスレッド ベースの並列化手法に比べ、はるかに簡単に並列化でき、スケーラブルな性能が期待できるのが魅力的です。コードを添付しますので試してみてください。