現代のCPUではCall Threaded Codeは意外と速い?
自前のForth処理系で試して結構びっくりした
Speed of various interpreter dispatch techniques V2ではそれぞれのスレッデッドコードの速度を多数のCPUで比較してあるが、情報としては古く現代の最新CPUのものは載っていないのと自分でForth処理系を作っていたので軽く実験してみた
ベンチマークとしてはtimeコマンドで測っていたり(処理系の動作に必要なファイルのコンパイルの時間が含まれている)単純なfibonacci(38)だったりで雑ではあるがCall Threaded Codeが結構速く感じたので記しておく
code:indirect-threading
$ cat mikoforth.fth examples/fib.fth | time ./mikoforth.exe
39088169
Command exited with non-zero status 5
0.00user 0.00system 0:01.20elapsed 0%CPU (0avgtext+0avgdata 232maxresident)k
0inputs+0outputs (0major+72minor)pagefaults 0swaps
code:call-threading
$ cat mikoforth.fth examples/fib.fth | time ./mikoforth.exe
39088169
Command exited with non-zero status 5
0.00user 0.00system 0:01.05elapsed 0%CPU (0avgtext+0avgdata 236maxresident)k
0inputs+0outputs (0major+73minor)pagefaults 0swaps
環境はRyzen 1800Xのメモリ8GBx2で測っている
もちろん単純な比較はできない
64bitを前提に処理系作っている
なので、愚直なindirect threaded codeだとコードサイズが膨らむ
64bitのアドレスを並べているので
call threaded codeではcall rel32で並べている
Indirect Threaded Codeだと8バイトに対し、Call Threaded Codeは5バイトで済む
処理系のサイズも違う
Indirect Threaded Code: 12KB
Call Threaded Code: 7KB
Call Threaded Codeは現代のCPU(特に64bit環境)ではむしろ結構速いしバイナリのサイズ小さくなるし最適化の余地が残されている(レジスタ割り付けとかやろうと思えばできる)ので結構アリなのではないかと思った
まぁ結局最適化するForth処理系はネイティブコード生成してるし
あとCPUメーカーはもちろんネイティブコードの動作を速くする方向で最適化するので、結果時代が進むにつれてこっちが社会的な仕組みとして有利というのはありそう
分岐予測とか
いずれARMでも試してみたい