FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

自作Binary Translation型RISC-VエミュレータのTCG最適化解析

前回の続き。自作Binary Translation型RISC-Vエミュレータの最適化作業をしている。TCGの最適化やRefCellへの書き換えをしてもあまり変わらなかったので、もう何が原因なのか良く分からなくなってきた。とりあえず実行時に発生してしまう細かなメモリコピーを削減するしかあるまい。

現状の実装ではメモリを確保してコピーをしたり、transmute()を何度も繰り返してしまう(transmute()自体は問題ないと思うけれども)部分があるのでそれを徹底的に最適化していった。Rustのメモリ制約の中でうまく最適化をしていくのはなかなか慣れない作業だが、可能な限り不要なコピーを消していく。

f:id:msyksphinz:20201210010711p:plain

さて、残りのrun_loop()でいったい何が行われているのかさっぱりわからん。変なHashMapは全く使っていないし、それ以外でいったい何が行われているのか...

実際、生成されるTCGおよびx86命令自体はQEMUが生成する物自体とそれほど大差ない気がしている。それなのにいったい何が違うのだろう?

生成ルーチンに問題があるのか、ループ実行時に問題があるのかを判別するためには、1度バイナリを実行した後、環境を初期化せずにもう一度バイナリを実行して、TCGがすべてヒットする環境を作り出したうえで実行時間の差分が見て解析するが簡単だと思いついた。

そこで以下のように2回同じバイナリを実行してみる。

    let mut emu = EmuEnv::new(arg_config);
    emu.clear_env();
    emu.run(&elf_file);
    emu.clear_env();
    emu.run(&elf_file);
  Link      : 0x0
  Info      : 0x0
  AddrAlign : 0x8
  EntSize   : 0x0
load_section() sh_offset = 00001508, sh_memsz = 00001a00
sh_flags = 3
sh_flags = 3
sh_flags = 3
sh_flags = 48
sh_flags = 0
sh_flags = 0
sh_flags = 0
sh_flags = 0
zsh: segmentation fault (core dumped)  RUST_BACKTRACE=1 cargo run -- --machine sifive_u --elf-file

Segmentation Faultを起こしてしまったが、少し修正して動作するようになった(が、--releaseオプションだと相変わらず落ちる...)ので、差分を確認してみることにした。

1回目 2回目 差分
5.318 5.419 -0.101
5.848 5.36 0.488
5.259 5.283 -0.024
5.444 5.334 0.11
5.382 5.293 0.089
5.205 5.116 0.089
5.629 5.835 -0.206
5.355 5.403 -0.048
5.76 6.504 -0.744
6.107 5.833 0.274
平均 -0.0073

差分は非常に小さい。ということでTCGへの変換部分が遅いわけではない、と...では純粋にTCGの処理速度が遅いということなのか...?