たらい回し関数の速度比較

aviutl拡張編集がLuaを使っているから、というだけで何となくLuaに手を出してみた。意外と簡単だし、実行速度も速いと感じたので、xyzzy lispと比較してみる。


せっかくなので、c++とも比較してみたいと思い、ベンチマーク用に適当なたらい回し関数を利用する。

; lisp
(defun tak (x y z)
  (if (< y x)
      (tak (tak (1- x) y z) (tak (1- y) z x) (tak (1- z) x y))
    z))
-- lua
function tak (x, y, z)
  if y < x then
    return tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y))
  else return z
  end
end
// c++
int tak(int x, int y, int z) {
  if (y<x) 
    return tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y));
  else return z;
}

三者とも書き方が微妙に違う。いやらしい。


これらについて、適当に(tak 18 9 0)を実行するメイン関数を書いて、xyzzyから呼び出し、結果が返ってくる時間を10回測定し、平均を取った。外部呼び出しのluac++は呼び出しコストが大きいので、何もしないプログラムを呼び出す時間を差し引いた。

処理系 時間(ms) xyzzy gcc
xyzzy 0.2.2.236 33470 1000 293.6
Lua 5.1.4 3139 94 27.54
LuaJIT 1.1.7 756 23 6.632
gcc (tdm-1) 4.5.0 (-O2) 114 3 1.000


xyzzyと比較するとLuaは11倍速い。差がありすぎる。LuaJITの方が速いらしいので、これも比較したら、さらに4倍くらい速い。c++と比較すると、LuaJITでも6.6倍くらい遅いのだが、スクリプト言語としては相当速いだろう。xyzzyc++に対して300倍近く遅い・・・。


もっとも、これは主に関数呼び出しの速度を計測するベンチマークである。c++でメモリ管理をしっかり行い、ハッシュテーブル等を導入すれば処理は遅くなる。また、スクリプト側もc++のライブラリ関数を使えば、その分だけc++との差が小さくなる。そう考えると、LuaJITでは、少ない労力でc++に近いパフォーマンスが期待できるのではないだろうか。