ひょっとして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