@@ -11,7 +11,7 @@ use crate::memory::Memory;
1111use crate :: { Error , ISA_A , ISA_B , ISA_MOP , RISCV_PAGESIZE } ;
1212
1313const RISCV_PAGESIZE_MASK : u64 = RISCV_PAGESIZE as u64 - 1 ;
14- const INSTRUCTION_CACHE_SIZE : usize = 2048 ;
14+ const INSTRUCTION_CACHE_SIZE : usize = 4096 ;
1515
1616pub trait InstDecoder {
1717 fn decode < M : Memory > ( & mut self , memory : & mut M , pc : u64 ) -> Result < Instruction , Error > ;
@@ -105,14 +105,14 @@ impl Decoder {
105105 let instruction_cache_key = {
106106 // according to RISC-V instruction encoding, the lowest bit in PC will always be zero
107107 let pc = pc >> 1 ;
108- // This indexing strategy optimizes instruction cache utilization by improving the distribution of addresses.
109- // - `pc >> 5`: Incorporates higher bits to ensure a more even spread across cache indices.
110- // - `pc << 1`: Spreads lower-bit information into higher positions, enhancing variability.
111- // - `^` (XOR): Further randomizes index distribution, reducing cache conflicts and improving hit rates.
112- //
113- // This approach helps balance cache efficiency between local execution and remote function calls,
114- // reducing hotspots and improving overall performance .
115- ( ( pc >> 5 ) ^ ( pc << 1 ) ) as usize % INSTRUCTION_CACHE_SIZE
108+ // Here we try to balance between local code and remote code. At times,
109+ // we can find the code jumping to a remote function(e.g., memcpy or
110+ // alloc), then resumes execution at a local location. Previous cache
111+ // key only optimizes for local operations, while this new cache key
112+ // balances the code between a 8192-byte local region, and certain remote
113+ // code region. Notice the value 12 and 8 here are chosen by empirical
114+ // evidence .
115+ ( ( pc & 0xFF ) | ( pc >> 12 << 8 ) ) as usize % INSTRUCTION_CACHE_SIZE
116116 } ;
117117 let cached_instruction = self . instructions_cache [ instruction_cache_key] ;
118118 if cached_instruction. 0 == pc {
0 commit comments