Cog VM リリース記念: Squeak、Ruby、Python を恒例のフィボナッチベンチで戦わせてみる
Cog VM は、VisualWorks用の超高速 Smalltalk VM を手がけた Eliot Miranda 氏による Squeak Smalltalk 向けの新しい高性能 VM 。
Teleplace社(旧 Qwaq社)の製品である同名の仮想空間共有ソフトのベースである Croquet用に開発されたものですが、同社の厚意によりオープンソースとして公開され、Squeak のユーザーも利用可能になりました。
Win 向けのバイナリも公開されていたので、さっそく恒例のフィボナッチベンチ(39番目のフィボナッチ数 63245986 の再帰的な算出にかかる時間を計測。実装はナイーブなものにして、メモ化や遅延評価は使用しない)で人気のスクリプト言語(Ruby、Python)と戦わせてみました。結果はこんなかんじ(Core2 Duo 2.4GHz, Win Vista を使用)。
追記: Python3.1.2、Gauche0.9 の結果を追加。
追記: リクエストにおこたえして C と v8 の結果も追加。
| 処理系 | 速度[秒] |
| Ruby1.8 | 123 |
| Ruby1.9 | 20.8 |
| Python2.5 | 50.3 |
| Python3.1 | 66.2 |
| Gauche0.9 | 16.0 |
| Squeak4.1 normal VM | 15.6 (メソッド版), 63.5 (ブロック版) |
| Squeak4.1 Cog VM | 4.79 (メソッド版), 5.36 (ブロック版) |
| VisualWorks7.7 | 1.65 (メソッド版), 3.34 (ブロック版) |
| C | 1.76 |
| v8-2.1 | 1.88 |
商用で爆速の Smalltalk 処理系である VisualWorks には一歩及ばないものの、ノーマルVM で“よい勝負”どまりだった Ruby1.9 に対し、新しい Cog VM ではメソッド版(Integer>>#fib として定義。39 fib で呼び出し)のみならず、大きく水をあけられていたブロック版(Ruby風に言えば Proc版。fib value: 39 で呼び出し)でも圧勝しています。すばらしいですね。
使用したコードと出力などを以下に示します。
Ruby
$ cat fib.rb def fib(n) return n if n < 2 fib(n-2) + fib(n-1) end n = ARGV[0].to_i start = Time.now puts fib(n), (Time.now - start).to_s + " sec" $ ruby -v fib.rb 39 ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-cygwin] 63245986 123.01 sec $ ruby1.9 -v fib.rb 39 ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-cygwin] 63245986 20.767 sec
Python(2、3 共通)
$ cat fib.py
from sys import argv
from time import time
def fib(n):
if n < 2:
return n
else:
return fib(n-2) + fib(n-1)
n = int(argv[1])
start = time()
print(fib(n))
print(str(time() - start) + " sec")
$ python -V
Python 2.5.2
$ python fib.py 39
63245986
50.3140001297 sec
$ python3 -V
Python 3.1.2
$ python3 fib.py 39
63245986
66.2220001221 sec
Smalltalk(Squeak、VisualWorks 共通)
| fib mTime mRes bTime bRes | Integer compile: 'fib ^(self < 2) ifTrue: [self] ifFalse: [(self - 2) fib + (self - 1) fib]'. fib := nil. fib := [:n | n < 2 ifTrue: [n] ifFalse: [(fib value: n-2) + (fib value: n-1)] ]. mTime := Time millisecondsToRun: [mRes := 39 fib]. bTime := Time millisecondsToRun: [bRes := fib value: 39]. ^Array with: mTime -> mRes with: bTime -> bRes
"Squeak VM 4.0.2 => {15573 -> 63245986. 63477 -> 63245986} "
"Cog VM => { 4793 -> 63245986. 5364 -> 63245986} "
"VisualWorks 7.7 => { 1651 -> 63245986. 3335 -> 63245986} "
Scheme(Gauche)
$ cat fib.scm (define (fib n) (if (< n 2) n (+ (fib (- n 2)) (fib (- n 1))))) (display (time (fib (string->number (car *argv*))))) $ gosh -V fib.scm 10 Gauche scheme shell, version 0.9 [utf-8,pthreads], i686-pc-cygwin $ gosh fib.scm 39 ;(time (fib (string->number (car *argv*)))) ; real 16.020 ; user 15.054 ; sys 0.015 63245986
C
$ cat fib.c
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
long fib(int n){
if (n < 2) {
return n;
} else {
return fib(n-2) + fib(n-1);
}
}
int main(int argc, char *argv[]){
clock_t startTime, endTime;
long res;
startTime = clock();
res = fib(atoi(argv[1]));
endTime = clock();
printf("%ld, %f sec\n", res, (float)(endTime - startTime)/CLOCKS_PER_SEC);
return 0;
}
$ gcc -Wall -O2 -o fib fib.c
$ ./fib 39
63245986, 1.762000 sec
JavaScript (v8)
$ cat fib.js
function fib(n) {
if (n < 2) {
return n;
} else {
return fib(n-2) + fib(n-1);
}
}
var start = new Date();
print(fib(39));
print(new Date() - start + " msec");
$ v8-2.1/shell fib.js
63245986
1890 msec