前回の続き。自作Binary Translation型RISC-Vエミュレータの最適化作業をしている。TCGの最適化やRefCellへの書き換えをしてもあまり変わらなかったので、もう何が原因なのか良く分からなくなってきた。とりあえず実行時に発生してしまう細かなメモリコピーを削減するしかあるまい。
現状の実装ではメモリを確保してコピーをしたり、transmute()
を何度も繰り返してしまう(transmute()
自体は問題ないと思うけれども)部分があるのでそれを徹底的に最適化していった。Rustのメモリ制約の中でうまく最適化をしていくのはなかなか慣れない作業だが、可能な限り不要なコピーを消していく。
さて、残りの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の処理速度が遅いということなのか...?