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