Let's start Scheme

2010-06-03

ベンチマーク

CPS変換の勉強中にANF(A-normal form)との共通点を見つけて、
ひょっとしてCPS変換しなくてもA正規化すればいいのでは?
という誘惑にかられたことから、ちょっとベンチマークとってみた。
(どっちが速度が出るか比較したかった。速い方がいいじゃん!)

使用したコードは以下
(define tarai-org
  (lambda (x y z)
    (if (<= x y)
 y
 (tarai-org (tarai-org (- x 1) y z)
     (tarai-org (- y 1) z x)
     (tarai-org (- z 1) x y)))))
(time (tarai-org 10 5 0))

(define (<=/cps x y k) (k (<= x y)))
(define (-/cps x y k) (k (- x y)))
(define tarai-cps  
  (lambda (x y z k)
    (<=/cps 
     x y
     (lambda (b)
       (if b
    y
    (-/cps
     x 1 
     (lambda (x2)
       (tarai-cps 
        x2 y z
        (lambda (t1)
   (-/cps
    y 1 
    (lambda (y2)
      (tarai-cps
       y2 z x
       (lambda (t2)
         (-/cps
   z 1
   (lambda (z2)
     (tarai-cps
      z2 x y
      (lambda (t3)
        (k (tarai-cps t1 t2 t3)))))))))))))))))))
(time (tarai-cps 10 5 0 (lambda (x) x)))

(define tarai-anf
  (lambda (x y z)
    (let ((G139 (<= x y)))
      (if G139
   y
       (let ((G140 (- x 1)))
  (let ((G141 (tarai-anf G140 y z)))
    (let ((G142 (- y 1)))
      (let ((G143 (tarai-anf G142 z x)))
        (let ((G144 (- z 1)))
   (let ((G145 (tarai-anf G144 x y)))
     (tarai-anf G141 G143 G145)))))))))))
(time (tarai-anf 10 5 0))

(define tarai-lambda
 (lambda (x y z)
  ((lambda (G143)
     (if G143
  y
  ((lambda (G144)
     ((lambda (G145)
        ((lambda (G146)
    ((lambda (G147)
       ((lambda (G148)
   ((lambda (G149)
      (tarai-lambda G145 G147 G149))
    (tarai-lambda G148 x y)))
        (- z 1)))
     (tarai-lambda G146 z x)))
  (- y 1)))
      (tarai-lambda G144 y z)))
   (- x 1))))
   (<= x y))))
(time (tarai-lambda 10 5 0))
tarai-orgが元のたらいまわし関数。以下、-cps、-anf、-lambdaと続くが、順に元の関数のお手製CPS変換、A正規化、A正規化後letをlambdaに変換したものとなっている。 っで、以下がベンチマーク結果
Petite Chez Scheme 7.9.4
(time (tarai-org 10 ...))
    no collections
    16 ms elapsed cpu time
    0 ms elapsed real time
    0 bytes allocated
(time (tarai-cps 10 ...))
    no collections
    0 ms elapsed cpu time
    0 ms elapsed real time
    840 bytes allocated
(time (tarai-anf 10 ...))
    7 collections
    78 ms elapsed cpu time, including 0 ms collecting
    0 ms elapsed real time, including 0 ms collecting
    29505472 bytes allocated, including 29469704 bytes reclaimed
(time (tarai-lambda 10 ...))
    7 collections
    78 ms elapsed cpu time, including 0 ms collecting
    0 ms elapsed real time, including 0 ms collecting
    29505120 bytes allocated, including 29489216 bytes reclaimed

Gauche 0.9
;(time (tarai-org 10 5 0))
; real   0.016
; user   0.016
; sys    0.000
;(time (tarai-cps 10 5 0 (lambda (x) x)))
; real   0.000
; user   0.000
; sys    0.000
;(time (tarai-anf 10 5 0))
; real   0.031
; user   0.031
; sys    0.000
;(time (tarai-lambda 10 5 0))
; real   0.437
; user   0.359
; sys    0.078
個人的には超意外にもCPSが一番早かった!!
Gaucheのdisasm関数でコンパイル結果を見てみたが、末尾最適化が効いてるのかな?
Chez Schemeの結果からアロケーションが結構発生するみたいだけど、それを踏まえてもありと思わせる結果である。

でも、これってこれらのVMがCPS変換されたコードを速く走らせるのであって、CPS変換されたコードが無条件で速くなるわけではないんだよなぁ・・・
う~ん・・・

No comments:

Post a Comment