2012-12-30

たまにはベンチとかして遊んでみる

年末でおうちにいるので、ちょっと遊んでみることにしましょう。
satosystemsさんによる、こんなブログエントリ「フィボナッチで各種言語をベンチマーク」をみつけました。ほんとに沢山の言語で同じアルゴリズムのプログラムを記述して実行に必要な時間を計測してます。で、結果は記事を見ていただくとして、

Python(CPython) 53.651
Lisp (GNU CLisp) 211.802

とか書いてあるわけです。んー、よりによってCLispですか。この処理系はちょっと遅いしなぁ。他の言語はNative Code Compilerとか使ってるし、ワシが日頃使っているCommon Lisp処理系であるところのSBCLで計測してみました。コードは全く同じで以下の通り。
  1. (defun fib (n)  
  2.   (if (< n 2) n  
  3.       (+ (fib (- n 2)) (fib (- n 1)))))  
SBCL 1.0.55のコンパイラによるNative Codeの出力は以下のとおり。
  1. ; disassembly for FIB  
  2. 0784808D:       488B55F0         MOV RDX, [RBP-16]  
  3. ;      091:       BF04000000       MOV EDI, 4  
  4. ;      096:       488D0C2530040020 LEA RCX, [#x20000430]      ; GENERIC-<  
  5. ;      09E:       FFD1             CALL RCX  
  6. ;      0A0:       0F8C94000000     JL L1  
  7. ;      0A6:       488B55F0         MOV RDX, [RBP-16]  
  8. ;      0AA:       BF04000000       MOV EDI, 4  
  9. ;      0AF:       4C8D1C255B020020 LEA R11, [#x2000025B]      ; GENERIC--  
  10. ;      0B7:       41FFD3           CALL R11  
  11. ;      0BA:       480F42E3         CMOVB RSP, RBX  
  12. ;      0BE:       488D5C24F0       LEA RBX, [RSP-16]  
  13. ;      0C3:       4883EC18         SUB RSP, 24  
  14. ;      0C7:       488B0562FFFFFF   MOV RAX, [RIP-158]  
  15. ;      0CE:       B902000000       MOV ECX, 2  
  16. ;      0D3:       48892B           MOV [RBX], RBP  
  17. ;      0D6:       488BEB           MOV RBP, RBX  
  18. ;      0D9:       FF5009           CALL QWORD PTR [RAX+9]  
  19. ;      0DC:       480F42E3         CMOVB RSP, RBX  
  20. ;      0E0:       488955F8         MOV [RBP-8], RDX  
  21. ;      0E4:       488B55F0         MOV RDX, [RBP-16]  
  22. ;      0E8:       BF02000000       MOV EDI, 2  
  23. ;      0ED:       4C8D1C255B020020 LEA R11, [#x2000025B]      ; GENERIC--  
  24. ;      0F5:       41FFD3           CALL R11  
  25. ;      0F8:       480F42E3         CMOVB RSP, RBX  
  26. ;      0FC:       488D5C24F0       LEA RBX, [RSP-16]  
  27. ;      101:       4883EC18         SUB RSP, 24  
  28. ;      105:       488B0524FFFFFF   MOV RAX, [RIP-220]  
  29. ;      10C:       B902000000       MOV ECX, 2  
  30. ;      111:       48892B           MOV [RBX], RBP  
  31. ;      114:       488BEB           MOV RBP, RBX  
  32. ;      117:       FF5009           CALL QWORD PTR [RAX+9]  
  33. ;      11A:       480F42E3         CMOVB RSP, RBX  
  34. ;      11E:       488BFA           MOV RDI, RDX  
  35. ;      121:       488B55F8         MOV RDX, [RBP-8]  
  36. ;      125:       4C8D1C25E0010020 LEA R11, [#x200001E0]      ; GENERIC-+  
  37. ;      12D:       41FFD3           CALL R11  
  38. ;      130:       480F42E3         CMOVB RSP, RBX  
  39. ;      134: L0:   488BE5           MOV RSP, RBP  
  40. ;      137:       F8               CLC  
  41. ;      138:       5D               POP RBP  
  42. ;      139:       C3               RET  
  43. ;      13A: L1:   488B55F0         MOV RDX, [RBP-16]  
  44. ;      13E:       EBF4             JMP L0  
  45. ;      140:       CC0A             BREAK 10                   ; error trap  
  46. ;      142:       02               BYTE #X02  
  47. ;      143:       18               BYTE #X18  
  48. ;      144:       54               BYTE #X54                  ; RCX  
型宣言とかしてないので、GENERIC-+とかCallしていてイマイチな感じだけれども、実行してみます。マシンはCore2Quad Q9550 2.8GHz, Memory 4GiB、Gentoo GNU/Linux Kernel 3.6.6です。
  1. CL-USER> (time (print (fib 38)))  
  2.   
  3. 39088169   
  4. Evaluation took:  
  5.   1.630 seconds of real time  
  6.   1.704106 seconds of total run time (1.704106 user, 0.000000 system)  
  7.   104.54% CPU  
  8.   4,617,572,036 processor cycles  
  9.   0 bytes consed  
  10.     
  11. 39088169  
元記事のsatosystemsさんの実行環境は
すべての言語と処理系の実行環境は Ubuntu 10.04 が搭載された Let's Note Y4(Pentium M 778MHz、メモリ 1GB)です。
とのことなので、直接値の比較はできません。自分のマシン上でのCPythonの結果は22.84秒でしたので、satosystemsさんのマシンより (53.65 / 22.84 =) 2.35倍速いと仮定すると、SBCLでの推定実行時間は (1.63 * 2.35 =) 3.83秒ということになります。
これがどのへんの位置になるかというと、

Scala1.90
Fortran (gfortran)1.92
Go (run)1.96
Haskell (ghci)1.99
Scheme (ikarus)2.07
JavaScript (node.js)2.62
Boo (compile)2.67
Java (gcj)2.88
Boo (interpret)3.56
Common Lisp (SBCL)3.83
Scheme (Gambit: gcs -O2)4.52
Scheme (Gambit: gcs)7.13
Forth (gforth-fast)7.39
OCaml (ocaml)7.53
OCaml (ocamlc)7.53
Forth (gforth)8.39
Python (CPython)58.65
Lisp (GNU CLisp)211.80
Ruby (CRuby)213.18

と、まぁ、妥当な線に落ち着いたかと。ちなみに、目一杯(declare (optimize (speed 3) (safety 0)) (type fixnum n)) とかしてみたり、色々と弄り回しても、生成コードも実行時間もほとんど変化しませんでした。元記事の結果を見れば分かるのですが、同じ言語でも処理系によって全然結果が違います。つまりは、「言語というより処理系のベンチマーク」ってことなわけですね。

注:コンパイル時に評価しちゃうとか色々と反則技はありますが、こういうのは普通にやってこそ意味があるっぽいので、モヒカンな方々は野暮なツッコミしないでね!

0 件のコメント:

コメントを投稿