Skip to content

Commit 95b7b6c

Browse files
committed
[WIP] Introduce per-module cache files to reduce FS overhead
1 parent 31ecab4 commit 95b7b6c

File tree

3 files changed

+90
-11
lines changed

3 files changed

+90
-11
lines changed

src/driver/aot.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,8 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
328328
let isa = crate::build_isa(sess, false);
329329

330330
let mut builder =
331-
ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
331+
ObjectBuilder::new(isa, name.clone() + ".o", cranelift_module::default_libcall_names())
332+
.unwrap();
332333

333334
// Disable function sections by default on MSVC as it causes significant slowdowns with link.exe.
334335
// Maybe link.exe has exponential behavior when there are many sections with the same name? Also
@@ -340,7 +341,7 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
340341
sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections),
341342
);
342343

343-
UnwindModule::new(ObjectModule::new(builder), true)
344+
UnwindModule::new(ObjectModule::new(builder), &name, true)
344345
}
345346

346347
fn emit_cgu(

src/driver/jit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule<JITModule>, CodegenCx) {
2424
let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
2525
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
2626
jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info));
27-
let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false);
27+
let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), "jit", false);
2828

2929
let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name);
3030

src/unwind_module.rs

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use std::borrow::Cow;
2+
use std::cell::Cell;
3+
use std::fs::File;
4+
use std::io::{BufWriter, Write};
5+
use std::path::PathBuf;
6+
17
use cranelift_codegen::Context;
28
use cranelift_codegen::control::ControlPlane;
39
use cranelift_codegen::incremental_cache::CacheKvStore;
@@ -8,19 +14,30 @@ use cranelift_module::{
814
ModuleReloc, ModuleResult,
915
};
1016
use cranelift_object::{ObjectModule, ObjectProduct};
17+
use rustc_data_structures::fx::FxHashMap;
18+
use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
1119

1220
use crate::UnwindContext;
1321

1422
/// A wrapper around a [Module] which adds any defined function to the [UnwindContext].
1523
pub(crate) struct UnwindModule<T> {
1624
pub(crate) module: T,
1725
unwind_context: UnwindContext,
26+
cache: Option<Box<dyn CacheKvStore + Send>>,
1827
}
1928

2029
impl<T: Module> UnwindModule<T> {
21-
pub(crate) fn new(mut module: T, pic_eh_frame: bool) -> Self {
30+
pub(crate) fn new(mut module: T, cgu_name: &str, pic_eh_frame: bool) -> Self {
2231
let unwind_context = UnwindContext::new(&mut module, pic_eh_frame);
23-
UnwindModule { module, unwind_context }
32+
let cache = match std::env::var("CG_CLIF_FUNCTION_CACHE").as_deref() {
33+
Err(_) => None,
34+
Ok("naive") => Some(Box::new(FileCache) as Box<dyn CacheKvStore + Send>),
35+
Ok("module") => {
36+
Some(Box::new(ModuleCache::new(cgu_name)) as Box<dyn CacheKvStore + Send>)
37+
}
38+
_ => panic!(),
39+
};
40+
UnwindModule { module, unwind_context, cache }
2441
}
2542
}
2643

@@ -91,13 +108,13 @@ impl<T: Module> Module for UnwindModule<T> {
91108
ctx: &mut Context,
92109
ctrl_plane: &mut ControlPlane,
93110
) -> ModuleResult<()> {
94-
if std::env::var("CG_CLIF_FUNCTION_CACHE").as_deref() == Ok("naive") {
111+
if let Some(cache) = &mut self.cache {
95112
if ctx.func.layout.blocks().nth(1).is_none()
96113
|| ctx.func.layout.blocks().nth(2).is_none()
97114
{
98115
ctx.compile(self.module.isa(), ctrl_plane)?;
99116
} else {
100-
ctx.compile_with_cache(self.module.isa(), &mut Cache, ctrl_plane)?;
117+
ctx.compile_with_cache(self.module.isa(), &mut **cache, ctrl_plane)?;
101118
}
102119
} else {
103120
ctx.compile(self.module.isa(), ctrl_plane)?;
@@ -132,18 +149,18 @@ impl<T: Module> Module for UnwindModule<T> {
132149
}
133150
}
134151

135-
struct Cache;
152+
struct FileCache;
136153

137-
impl Cache {
154+
impl FileCache {
138155
fn file_for_key(&self, key: &[u8]) -> String {
139156
let mut path = key.iter().map(|b| format!("{:02x}", b)).collect::<String>();
140157
path.push_str(".clif_cache");
141158
"/home/bjorn/Projects/cg_clif/cache/".to_owned() + &path
142159
}
143160
}
144161

145-
impl CacheKvStore for Cache {
146-
fn get(&self, key: &[u8]) -> Option<std::borrow::Cow<'_, [u8]>> {
162+
impl CacheKvStore for FileCache {
163+
fn get(&self, key: &[u8]) -> Option<Cow<'_, [u8]>> {
147164
let path = self.file_for_key(key);
148165
if std::fs::exists(&path).unwrap() {
149166
Some(std::fs::read(path).unwrap().into())
@@ -157,3 +174,64 @@ impl CacheKvStore for Cache {
157174
std::fs::write(path, val).unwrap();
158175
}
159176
}
177+
178+
struct ModuleCache {
179+
file: PathBuf,
180+
entries: FxHashMap<[u8; 32], (OwnedSlice, Cell<bool>)>,
181+
}
182+
183+
impl ModuleCache {
184+
fn new(name: &str) -> Self {
185+
let file = PathBuf::from("/home/bjorn/Projects/cg_clif/cache/".to_owned() + &name);
186+
187+
if !file.exists() {
188+
return ModuleCache { file, entries: FxHashMap::default() };
189+
}
190+
191+
let data = std::fs::read(&file).unwrap();
192+
let mut data = slice_owned(data, |data| &data);
193+
let mut entries = FxHashMap::default();
194+
while !data.is_empty() {
195+
let key: [u8; 32] = data[..32].try_into().unwrap();
196+
let size = u32::from_le_bytes(data[32..36].try_into().unwrap());
197+
entries.insert(
198+
key,
199+
(data.clone().slice(|data| &data[20..size as usize + 36]), Cell::new(false)),
200+
);
201+
data = data.slice(|data| &data[size as usize + 36..]);
202+
}
203+
204+
ModuleCache { file, entries }
205+
}
206+
}
207+
208+
impl Drop for ModuleCache {
209+
fn drop(&mut self) {
210+
let mut buf_writer = BufWriter::new(File::create(&self.file).unwrap());
211+
for (key, (data, accessed)) in &self.entries {
212+
if !accessed.get() {
213+
continue;
214+
}
215+
buf_writer.write_all(key).unwrap();
216+
buf_writer.write_all(&u32::to_le_bytes(data.len() as u32)).unwrap();
217+
buf_writer.write_all(data).unwrap();
218+
}
219+
buf_writer.into_inner().unwrap();
220+
}
221+
}
222+
223+
impl CacheKvStore for ModuleCache {
224+
fn get(&self, key: &[u8]) -> Option<Cow<'_, [u8]>> {
225+
if let Some((data, accessed)) = self.entries.get::<[u8; 32]>(key.try_into().unwrap()) {
226+
accessed.set(true);
227+
Some(Cow::Borrowed(&*data))
228+
} else {
229+
None
230+
}
231+
}
232+
233+
fn insert(&mut self, key: &[u8], val: Vec<u8>) {
234+
self.entries
235+
.insert(key.try_into().unwrap(), (slice_owned(val, |val| &val), Cell::new(true)));
236+
}
237+
}

0 commit comments

Comments
 (0)