aobench の並列化
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による並列化は、スレッドを生成・管理するスレッド ベースの並列化手法に比べ、はるかに簡単に並列化でき、スケーラブルな性能が期待できるのが魅力的です。コードを添付しますので試してみてください。