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キャッシュによる命令変換の高速化の効果を確かめた。