diff options
author | Maxime Chevalier-Boisvert <[email protected]> | 2024-06-07 17:59:59 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2024-06-07 21:59:59 +0000 |
commit | 0d91887c6aa740d3226407cafa1f27c62fd119f4 (patch) | |
tree | cd939cbe7442253b943a425ac3c853826e500ad0 /yjit/src | |
parent | 425e630ce73cf79fa5529df199dde47fc109a5de (diff) |
YJIT: implement cache for recently encoded/decoded contexts (#10938)
* YJIT: implement cache for recently encoded/decoded contexts
* Increase cache size to 512
Diffstat (limited to 'yjit/src')
-rw-r--r-- | yjit/src/core.rs | 73 |
1 files changed, 51 insertions, 22 deletions
diff --git a/yjit/src/core.rs b/yjit/src/core.rs index 2a8dde7087..0cfd7d9124 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -15,12 +15,14 @@ use crate::utils::*; use crate::disasm::*; use core::ffi::c_void; use std::cell::*; -use std::collections::HashSet; use std::fmt; use std::mem; use std::mem::transmute; use std::ops::Range; use std::rc::Rc; +use std::collections::HashSet; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; use mem::MaybeUninit; use std::ptr; use ptr::NonNull; @@ -839,10 +841,12 @@ enum CtxOp { EndOfCode, } -// Cache of the last context encoded +const CTX_CACHE_SIZE: usize = 512; + +// Cache of the last contexts encoded // Empirically this saves a few percent of memory // We can experiment with varying the size of this cache -static mut LAST_CTX_ENCODED: Option<(Context, u32)> = None; +static mut CTX_CACHE: Option<[(Context, u32); CTX_CACHE_SIZE]> = None; impl Context { pub fn encode(&self) -> u32 { @@ -852,20 +856,8 @@ impl Context { return 0; } - /* - // If this context was previously decoded and was not changed since - if self.decoded_from != 0 && Self::decode(self.decoded_from) == *self { - return self.decoded_from; - } - */ - - // If this context was recently encoded (cache check) - unsafe { - if let Some((ctx, idx)) = LAST_CTX_ENCODED { - if ctx == *self { - return idx; - } - } + if let Some(idx) = Self::cache_get(self) { + return idx; } let context_data = CodegenGlobals::get_context_data(); @@ -878,9 +870,7 @@ impl Context { let idx = self.encode_into(context_data); let idx: u32 = idx.try_into().unwrap(); - unsafe { - LAST_CTX_ENCODED = Some((*self, idx)); - } + Self::cache_set(self, idx); // In debug mode, check that the round-trip decoding always matches debug_assert!(Self::decode(idx) == *self); @@ -896,12 +886,51 @@ impl Context { let context_data = CodegenGlobals::get_context_data(); let ctx = Self::decode_from(context_data, start_idx as usize); - // Keep track of the fact that this context was previously encoded - //ctx.decoded_from = start_idx; + Self::cache_set(&ctx, start_idx); ctx } + // Lookup the context in a cache of recently encoded/decoded contexts + fn cache_get(ctx: &Context) -> Option<u32> + { + unsafe { + if CTX_CACHE == None { + return None; + } + + let cache = CTX_CACHE.as_mut().unwrap(); + + let mut hasher = DefaultHasher::new(); + ctx.hash(&mut hasher); + let ctx_hash = hasher.finish() as usize; + let cache_entry = &cache[ctx_hash % CTX_CACHE_SIZE]; + + if cache_entry.0 == *ctx { + return Some(cache_entry.1); + } + + return None; + } + } + + // Store an entry in a cache of recently encoded/decoded contexts + fn cache_set(ctx: &Context, idx: u32) + { + unsafe { + if CTX_CACHE == None { + CTX_CACHE = Some( [(Context::default(), 0); CTX_CACHE_SIZE] ); + } + + let mut hasher = DefaultHasher::new(); + ctx.hash(&mut hasher); + let ctx_hash = hasher.finish() as usize; + + let cache = CTX_CACHE.as_mut().unwrap(); + cache[ctx_hash % CTX_CACHE_SIZE] = (*ctx, idx); + } + } + // Encode into a compressed context representation in a bit vector fn encode_into(&self, bits: &mut BitVector) -> usize { let start_idx = bits.num_bits(); |