AO Bench on MacRuby 0.5, ruby-trunk, 1.9.2-preview1, 1.8.7-p160

下のほうに日本語版があります。

[En]
AO Bench is a small ambient occlusion renderer for benchmarking floating point performance by Syoyo Fujita. AO Bench was ported to various languages. See http://lucille.atso-net.jp/aobench/

A Ruby version of AO Bench is ported by id:miura1729
The result on yarv2llvm and ruby 1.9 is shown in http://d.hatena.ne.jp/miura1729/20090208/1234084920

I have done benchmarch on MacRuby 0.5, ruby-trunk, ruby-1.9.2-preview1, ruby-1.8.7-p160.

Note

Result
Best score of 3 times calculation is shown.

macruby          252.49 real       282.69 user         3.24 sys
trunk            201.78 real       201.52 user         0.21 sys
1.9.2-preview1   491.76 real       491.33 user         0.45 sys
1.8.7-p160       902.46 real       901.28 user         0.39 sys

ruby-trunk is faster than 1.9.2-preview1 about 60% !

Screen shot

Ruby 1.8.7-160

Ruby 1.9.2-preview1

Ruby trunk

MacRuby 0.5

!!?

[edit]
This buggy result seems caused by quality of random numbers generated by MacRuby rand().
When I re-define simple rand method as below, results of MacRuby and ruby-trunk are same.

$seed = 0
RANDMAX = (2 ** 32)
def rand
  $seed = ($seed * 1103515245 + 12345) % RANDMAX
  $seed.to_f / RANDMAX
end

[/edit]

I also made a little work on miura san's script to work in Multi Thread to illuminate MacRuby's major advantage : free from GIL (Global Interpreter Lock) and real concurrency.

The result is as follows...

$ time ruby-trunk ao-render-parallel.rb ao-trunk-parallel.ppm
start 2009-11-15 20:49:11 +0900
thread 1 finished 2009-11-15 20:49:53 +0900
thread 2 finished 2009-11-15 20:52:36 +0900
ruby-trunk ao-render-parallel.rb ao-trunk-parallel.ppm  205.01s user 0.31s system 99% cpu 3:25.42 total

$ time macruby ao-render-parallel.rb ao-macruby-parallel.ppm
start 2009-11-15 20:52:57 +0900
zsh: segmentation fault  macruby ao-render-parallel.rb ao-macruby-parallel.ppm
macruby ao-render-parallel.rb ao-macruby-parallel.ppm  0.30s user 0.03s system 51% cpu 0.625 total

[Ja]
MacRuby の話題なんでちょっと頑張って英語で書いてみました。変なところがあったら容赦なくつっこんでやってください。

syoyo さんの AO Bench (http://lucille.atso-net.jp/aobench/) は 3D レンダリングを実行する現実的な浮動小数点数演算のベンチマークで、とても多くの言語に移植されています。

Ruby 版は yarv2llvm の作者である id:miura1729 さんによって移植されています。
http://d.hatena.ne.jp/miura1729/20090208/1234084920

miura1729 さんの移植されたスクリプトに、ファイルへの出力をサポートするように少しだけ手をいれて、MacRuby 0.5(r3010), ruby(MRI) の trunk(r25770), 1.9.2-preview1, 1.8.7-p160 でベンチマークを取ってみました。
実行環境や結果は上の英語版の通りです。

まず、1.9.2-preview1 と trunk の間で 60% もの速度改善があったことに驚きました。もしや Float の即値化がもう入ってたっけ、と思って ruby.h をみましたがそうではないようです。 ChangeLog を眺めてみると rand にいくつか修正がありますが速度にはあまり関係なさそうです。進捗をチェックしてみると全般的に後半に速度の低減がみられたので、メモリ管理絡みの改善が効いているのかもしれません。

また期待していた MacRuby ですが、1.9.2-preview1 に対して約50%の速度ですが、trunk には負けています。さらに出力結果の画像が壊れています。MacRuby では Float の埋め込みをしているかわりに、少し精度を犠牲にしているので、もしかしたら結果の品質に影響があるかもしれないと予想はしていましたが。この壊れかたはもっと根本的におかしいです。出力は PPM(Portable PixMap) なので画素数に対してファイルサイズは固定(256x256x3 bytes)のはずなのですが、結果が 3〜4KB 程(サイズは実行毎に不定でした)大きくなってしまっていましたので、prinf("%c") の動作に問題があるのかもしれません。できたら追試してみたいと思います。
ええやはり printf("%c") がまずかったようで、pack("C") で代替したら画像サイズがおかしくなるのは直りました。それでもまだなんだか変です。3bit 程度の精度のせいではないとは思いますが、よくわかりません。

[追記]
英語版のほうに書いたように rand メソッドを線形合同法で自前で実装すると、MacRuby と trunk の結果は完全に一致したので、原因は乱数の品質にあるようです。MacRuby にパッチ書くチャンスです! 報告して修正を取り込んでもらいました。
[/追記]

あと細かいことで、実行進捗を出力ファイルサイズでチェックしていて気がついたのですが、MRI はファイル出力がだいたい 4KB 単位で buffering されていることが見て取れましたが、MacRuby はどうやら一切出力の buffering はないようでした。system 時間が若干多いのはそのせいではないかと思われます。

それから、スクリプトに少し手を加えて 2 Thread 実行するように(単に画面を上下に分割して別々の Thread で出力してから、最後にくっつけるだけ)してみました。Core 2 Duo なので GIL のない MacRuby はこれで CPU をフルに使うことができて trunk に対する advantage を示せるかな、と思っていたのですが、結果は上の通りです。安定性はまだまだですかねぇ。