FPGA開発日記

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

Binary Translation型エミュレータを作る(TCGのキャッシュ化による高速化)

Binary Translation方式の命令セットエミュレータのRust実装をしている。前回、ロードストア命令をTLBに対応させて高速化した。これに続いて、命令用のTCGをキャッシュ化により高速化させる。これまでは命令を変換する際にキャッシュを持たず常にTCG変換を行っているので時間がかかる。これをキャッシュに蓄えることで高速化したい。

キャッシュ化にあたり、RustのHashMapを使用する。PCアドレスをキーとしてTCGのメモリバッファを格納する。

pub struct EmuEnv {
...
    pub m_tb_text_hashmap: HashMap<u64, Rc<RefCell<MemoryMap>>>,
    pub m_curr_tb_text_mem: Rc<RefCell<MemoryMap>>,
...

TCGに変換した後にHashMapに格納する。TCG変換処理前にPCアドレスを使ってHashMapを探索し、ヒットすれば変換処理を行わない。

            // まずはHashMapをPCアドレスで探索してヒットするかをチェックする
            let tb_text_mem = match self.m_tb_text_hashmap.get(&self.m_pc[0]) {
                // ヒットした場合はTCGをそのまま返す
                Some(mem_map) => {
                    // println!("HashMap search hit! {:016x}", &self.m_pc[0]);
                    Rc::clone(&mem_map)
                }
                None => {
                    // println!("HashMap search miss! {:016x}", &self.m_pc[0]);
                    // Make tb instruction region (temporary 1024byte)
                    let tb_text_mem = match MemoryMap::new(
                        0x4000,
...
                        Err(e) => panic!("Error: {}", e),
                    };
                    // HashMapに変換後のTCGを格納する
                    self.m_tb_text_hashmap.insert(self.m_pc[0], Rc::clone(&tb_text_mem));
                    self.m_curr_tb_text_mem = Rc::clone(&tb_text_mem);
           
                    self.m_tcg_vec.clear();

さらにsfence.vma時にはHashMapをクリアする。

    pub fn helper_func_sfence_vma(emu: &mut EmuEnv, _dest: u64, _imm: u64, _csr_addr: u64, _dummy: u64) -> usize {
        // Clear TLB
        for idx in 0..4096 {
            emu.m_tlb_vec[idx] = 0xdeadbeef_01234567;
        }
        emu.m_tb_text_hashmap.clear();
        return 0;
    }

これでTCGのキャッシュ化が完了した。性能向上を確認しよう。

  • キャッシュを使用しない場合:rv64ui-v-ldの実行時間
81.8308 ns finished
Result: MEM[0x1000] = 00000001
  • キャッシュを使用する場合:rv64ui-v-ldの実行時間
5.1159 ns finished
Result: MEM[0x1000] = 00000001

おお、かなり高速化されたぞ。うまく行っているようだ。一応定量的なデータを取ってみた。メモリアクセスのTLBの適用と、さらにTCGキャッシュによる命令変換の高速化の効果を確かめた。

f:id:msyksphinz:20201023232024p:plain

やはりTCGキャッシュの高速化の効果が絶大のようだ。これでさらにQEMUに近づいたかな?