レイトレースベンチの並列テスト
プログラミングErlangの20章にlists:mapを置き換えるだけで並列化できますよ、
と書いてあったのでやってみた。
置き換えたのはこのレイを飛ばす部分。
% オーバーサンプリング(N x N倍サンプリングして平均する) sampling({PIXEL_X, PIXEL_Y}, Scene, N, GET_RAY)-> average_color( % lists:map(fun({X, Y})->ray_trace(GET_RAY(X, Y), Scene) end, % ↓並列版 lib_misc:pmap(fun({X, Y})->ray_trace(GET_RAY(X, Y), Scene) end, over_sampling({PIXEL_X, PIXEL_Y}, N)) ).
Core DUO(Windows XP)で計測してみました。
>erl -noshell -s renderer main tmp.bmp 200 3 {57046000,ok} >erl -noshell -s renderer main tmp.bmp 200 3 -smp +S 1 {102031000,ok} >erl -noshell -s renderer main tmp.bmp 200 3 -smp +S 2 {56812000,ok} >erl -noshell -s renderer main tmp.bmp 200 3 -smp +S 3 {58890000,ok}
通常のmapを使った版
>erl -noshell -s renderer main tmp.bmp 200 3 {88109000,ok}
並列無しと2並列とでは1.8倍くらい高速になった。
mapを並列版に差し替えた分のオーバーヘッドがあるので、
2並列程度ではうれしさが少なめな感じです。
4コアとかだったらよさそう。
ただ、レイトレースの書き方に問題があって
シーンの情報をいちいち全部渡していることでメッセージを最小化できていないことが性能に影響しているかもしれない。
(小さいシーンなので影響はないかもしれない)
次は分散版のmapを作ってどんな効果があるのか試してみたいと思う。
今回使ったマシン以外にOSX, Linux, Windowsを一台ずつ参加させて4台5コアで実験予定。
ちなみに、分散版のmapはプログラミングErlangには載って
いなかったので関連する章を読んで勉強する必要がありそうですw
コマンドライン実行用の追加コード。
引数がアトムのリストで渡ってくるので文字列に変換している。
必要な場合はさらに数値に変換している。
% コマンドライン用 main([F, Size, L])-> io:write(timer:tc(renderer, compatible, [ atom_to_list(F), list_to_integer(atom_to_list(Size)), list_to_integer(atom_to_list(L)) ])), init:stop().
プログラミングErlangより
並列版map。
-module(lib_misc). -export([pmap/2]). pmap(F, L)-> S=self(), Ref=erlang:make_ref(), Pids=lists:map(fun(I)-> spawn(fun()-> do_f(S, Ref, F, I) end) end, L), gather(Pids, Ref). do_f(Parent, Ref, F, I)-> Parent ! {self(), Ref, (catch F(I))}. gather([Pid|T], Ref)-> receive {Pid, Ref, Ret}->[Ret|gather(T, Ref)] end; gather([], _) -> [].
Erlangは最初からこの本ではじめるべきと思う。
7章が好き。