Skip to content

Instantly share code, notes, and snippets.

@kokudori
Last active August 29, 2015 14:01
Show Gist options
  • Save kokudori/0cb1c68a1396fe5f9441 to your computer and use it in GitHub Desktop.
Save kokudori/0cb1c68a1396fe5f9441 to your computer and use it in GitHub Desktop.
レジスタベースVMの簡易実装雑感

概要

簡単なレジスタベースVMを作り、fib(38)を実行した時のマイクロベンチ結果

実装

Rustで下位3bit tagged-poinetr

アドレスのアラインメントを利用した埋め込みを実装した処理系
オブジェクトは環境非依存で64bit固定
ポインタをmodifyする必要がある

Rustで上位16bit tagged-poinetr

多くの環境で64bitアドレスの上位16bitが使用可能であることを利用した埋め込みを実装した処理系
オブジェクトは環境非依存で64bit固定
ポインタはmodifyしなくて良い(上位16bitを見れば良いだけなので)

RustでNaN boxing

IEEE754のNaNの冗長性を利用した埋め込みを実装した処理系
64bitアドレスの埋め込みは上記の上位16bitが使用されていない事を利用している
そのためポインタはmodifyしなくて良い
また、上記の実装に加え、倍精度浮動小数が即値で扱える

C++でNaN boxing

上記のC++バージョン
Rustにunionが無いのと、transmuteがやたらコストかかるので比較のためのC++実装

環境

Rust

Rustはver 0.10現在、Windows向けにx64対応がされていない
なので、x86はWindows、x64はUbuntuで各々比較

C++

x86もx64もVC++(VS2013)で行った

備考

基本演算はオペランドの符号情報を動的に扱うものとコンパイル時に決め打つものの2種類を用意
つまり、動的型付けバージョンと静的型付けバージョンのどちらも対応

結果

Rustで下位3bit tagged-poinetr in x86

オペランドの符号情報を動的に取得: 約8.1秒
オペランドの符号情報を静的に決定: 約5.6秒

Rustで下位3bit tagged-poinetr in x64

オペランドの符号情報を動的に取得: 約5.0秒
オペランドの符号情報を静的に決定: 約3.5秒

Rustで上位16bit tagged-poinetr in x86

オペランドの符号情報を動的に取得: 約9.11秒
オペランドの符号情報を静的に決定: 約5.5秒

Rustで上位16bit tagged-poinetr in x64

オペランドの符号情報を動的に取得: 約5.1秒
オペランドの符号情報を静的に決定: 約3.6秒

RustでNaN boxing

どの環境でもめちゃくちゃ時間かかった
30秒とか平気にかかるレベル

C++でNaN boxing in x86

オペランドの符号情報を動的に取得: 約3.1秒
オペランドの符号情報を静的に決定: 約3.1秒

C++でNaN boxing in x64

オペランドの符号情報を動的に取得: 約4.8秒
オペランドの符号情報を静的に決定: 約4.7秒

結論

  1. RustでNaN boxing遅すぎる
    Rustのtransmuteがかなり重いっぽい
    Rustにはunionが無いのでビットレベルでの操作をどうしていいのかよくわからなくてとりあえずtransmuteつかいまくったらこのざま
    何かしらのベストプラクティスがあるのかもしれない

  2. RustとC++でそこまでの速度は無いっぽい?
    これならRustでVM書けそう
    正直テンション上がる

  3. NaN boxing in C++で32bit環境の方が速くなった

    いや、本気で謎
    あとC++でオペランドの符号情報の動的/静的取得に差が無いのも謎

  4. C#(VS2013)でfib(38)試したら0.2秒だった
    正直JITかけたらこのあたりの差なんて誤差レベルになるんじゃ?とか思わなくもない

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment