Cyanのパフォーマンスを計ってみる

たびたびCyanですみません、またこの実装で実験です。
cyan-1.0.2 - takuto_hの日記

Cyanのソースハックを試みる 2倍速達成 - なんたらノート 第二期 の延長で、継続使ったときのコピー負荷とかを根本的に変えなくても、ちょっと工夫するだけで妥当なパフォーマンスが得られないかがんばってみましたが、あまり芳しい成果がありませんでした。

で、どのぐらい遅いのかを確認してみようと、等価なコードを別の言語で書いてみると、以下のコードがだいたい同じ速度でした。きちんと計測していません、だいたいです。でも、だからって…

Cyan

iota(1000).filter^(x){ x * x == 1 }

Ruby

(0 ... 650000).to_a.select {|x| x * x == 1}
(0 ... 650000).select {|x| x * x == 1}

Scheme (Gauche) あまり上手くないです

(define (iota x) (begin
    (define (sub xx)
         (if (= xx x)
             '()
             (cons xx (sub (+ xx 1)))
         )
    )
    (sub 0)
))
(define (filter proc xs)
    (if (null? xs)
        '()
        (if (proc (car xs))
            (cons (car xs) (filter proc (cdr xs)))
            (filter proc (cdr xs))
        )
    )
)
(filter (lambda (x) (= (* x x) 1)) (iota 2000000))

Python

filter(lambda x: x * x == 1, list(xrange(6500000)))
filter(lambda x: x * x == 1, xrange(6500000))

Scala

//(0 until 26000000).toList().filter((x)=>{ x * x == 1}) =>OutOfMemoryException
(0 until 26000000).filter((x)=>{ x * x == 1})

なんじゃこりゃー。

Cyanは、Rubyに対して1/650、Schemeに対して1/2000、Pythonに対して1/6500のパフォーマンスってことになりました。Scalaに至っては1/26000! ScalaJITコンパイラでネイティブになるJavaバイトコードと考えて、ここでやめときます。

うーん、倍速にしても375/1000/3750倍、そして13000倍か…。うーん、インストラクションの動的生成とすべてを継続でやろうとしてるせい? それともネイティブコードの恩恵をすべて捨ててるせい? でもそれで3桁もの速度差になるもんかなぁ。Schemeでiotaとfilterを独自に定義しても1000倍差ってことは、ネイティブの恩恵ってだけじゃなさそうだけど、だとしたら前者、言語ランタイムの本質的問題ってことに?! でもそれなくしたら、単に書きやすいLispだよなぁ。