読者です 読者をやめる 読者になる 読者になる

レガシーコード生産ガイド

私に教えられることなら

VFX ForthとSwiftForthめっちゃ速い

Forthでハノイの塔 - sileのブログ を見てやたら速いので「ホントに??」と思って調べてみた、ら、VFX Forth - common featuresのコード生成見てビックリした。こんな最適化できるんだ。

で、NASM / Linux x86-64でForth開発日誌3 ベンチマーク - レガシーコード生産ガイドのフィボナッチのコード試して見たら……

: fib ( n -- x ) dup 2 < if exit then 1- dup recurse swap 1- recurse + ;
: time ( p -- ) ticks >r execute ticks r> - ." elapsed " . ." ms" cr ;
39 ' fib time

結果は elapsed 320 ms

320ms?!

10回やって平均320ms。

同じようなコードでSwiftForthも計ってみると、平均368msだった。こっちも速い!

計測結果に加えると

C (-O2) 0.22
VFX Forth 0.32
Swift Forth 0.37
C 0.45
CommonLisp(SBCL, typed) 0.57
JavaScript(V8) 0.73
Squeak(method) 0.99
CommonLisp(SBCL) 1.50
forth 1.66
Squeak(block) 2.27
Gauche 6.52

なんと普通にコンパイルしたCと最適化したCの間という結果に。

VFXdis fibの結果を見ると

( 080C0850    83FB02 )                CMP       EBX, 02
( 080C0853    0F8D01000000 )          JNL/GE    080C085A
( 080C0859    C3 )                    NEXT,
( 080C085A    4B )                    DEC       EBX
( 080C085B    8D6DFC )                LEA       EBP, [EBP+-04]
( 080C085E    895D00 )                MOV       [EBP], EBX
( 080C0861    E8EAFFFFFF )            CALL      080C0850        FIB
( 080C0866    8B5500 )                MOV       EDX, [EBP]
( 080C0869    4A )                    DEC       EDX
( 080C086A    895D00 )                MOV       [EBP], EBX
( 080C086D    8BDA )                  MOV       EBX, EDX
( 080C086F    E8DCFFFFFF )            CALL      080C0850        FIB
( 080C0874    035D00 )                ADD       EBX, [EBP]
( 080C0877    8D6D04 )                LEA       EBP, [EBP+04]
( 080C087A    C3 )                    NEXT,

スタック操作をレジスタに、インライン展開、というカンジ。結構アグレッシブっぽいけどそんなに魔術ってわけでもない?NEXTはNEXTルーチンと違うのかな?Swiftも似たようなコードだけど、NEXTじゃなくてRETだった。

というわけでparsingワードでシンタックスとして扱う設計じゃないと最適化しにくいんじゃ……と思ってたけど、見事に覆される結果になった。

Defining Wordは作りにくかったりするんだろうか?そこらへんはちょっと謎だけど、とりあえず道はあるのだな、というだけでやる気が出てきた。

広告を非表示にする