Rubyの実行時間を計ってみる

項番 処理 時間 カラループを引いた実時間
1 カラループ 0.34 0
2 a=0 0.65 0.31
3 a=1+1 1.07 0.73
4 a=1*1 1.09 0.75
5 a=d 0.65 0.31
6 a=d*2 1.1 0.76
7 a=d+d 1.08 0.74
8 a=0.1+0.1 1.36 1.02
9 a=0.1*0.1 1.35 1.01
10 a=map[2][2] 1.41 1.07
11 a=map[2*2+2] 1.93 1.59

Celeron1.8GHzのPCを使っている。
HPCモジュールを使って、1000回実行した時間を計ってみた。単位はミリ秒。
誤差が大きいからさらに1000回ループして、1000で割った値だ。
3回実行して少ない値を取った。


計算については、基本的にはメソッド呼び出し数に依存している。
掛け算より足し算のほうが若干速いが、d*2をd+dに書き換えるほどの差でもない。
労力をかけるだけ無駄だ。
整数より実数のほうが遅い。
必要がない限りは整数にしたほうがいいだろうが、アルゴリズムを細工してまで整数にこだわるほどの差ではない。
10番のmapは2次元配列で、11番はそれを1次元配列にしたものだ。
2次元配列が遅く、それを1次元配列に平坦化したら速くならないかと思ったのだが、計算のメソッドが増えたせいで逆に遅くなった。
DXRubyExtensionで高速マップデータアクセス手段を提供する必要性は微妙なところだ。
でも、たとえば2次元配列は右や下にはみだした場合の処理が面倒で、それ用のクラスで「ループさせる」「範囲外は指定のデータに固定する」などを提供できれば、楽になるし速くなるということで需要はなきにしもあらず。
でもやっぱり微妙だ。


ループも試してみた。

項番 処理 時間 カラループを引いた実時間
1 for i in 0..9 do end 6.59 6.25
2 10.times do end 4.65 4.31
3 (0..9).each do end 5.59 5.25
4 0.upto(9) do end 4.77 4.43

2番と4番、イテレータブロックで値を受け取ると、1番とほぼ同じ時間になる。
はてな記法のテーブルで|をエスケープする方法がわからなかったので書いてないだけだ。
それぞれ10回ループした時間だから、1回の時間はかなり少ないことがわかる。
3番が一番遅いが、こんな書き方わざわざしないだろう。


マップチップをたくさん描画する場合に、こうしたら速い、みたいなやりかたが無いかと思ったのだが、特にそういったものは無いようだ。
そして、これを見る限りDXRubyExtensionという形で何かを提供してみても、根本的解決にはならないことが想像できる。
やはりRPGのようなゲームの描画周りで凝ったことをしようと思うと、現状のDXRubyでは厳しいのだ。
また、Rubyの特徴は実にわかりやすく「全般的に遅い」ということになる。
言い換えれば、ループによる大量処理といった負荷が集中する場合に弱い。
Rubyゲームプログラミングを改善していこうと思ったら、そういう部分にフォーカスしてくのがよさそうだ。
たとえば背景描画も、ループと描画登録をCの中だけで完結させれば、相当なパフォーマンス改善になるはずだ。
逆に言えば、Rubyは全体としてそれなりのパフォーマンスが出るから、大量のループ以外はRubyで書いても問題にはなりにくい。
従って、Cでフレームワークを作ってRubyで処理内容を書く、というアプローチは、覚えるのが面倒になるだけでパフォーマンス的には意味が無い。


DXRubyのスタンスは、基本的にはゲームのアルゴリズムはすべてRubyで書く。
だが、最低限のことすら遅すぎて無理な場合、そもそもそれはRubyでは作れないということになってしまい、そこがRubyゲームプログラミングの限界になる。
そういった部分を解決していけたらいいと思う。