From 2a24a0fbde84d179cbcf646fdcbb823bc9c5201d Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Wed, 2 Feb 2022 15:55:36 -0800 Subject: [PATCH] Make memfd image creation lazy (on first instantiation). As a followup to the recent memfd allocator work, this PR makes the memfd image creation occur on the first instantiation, rather than immediately when the `Module` is loaded. This shaves off a potentially surprising cost spike that would have otherwise occurred: prior to the memfd work, no allocator eagerly read the module's initial heap state into RAM. The behavior should now more closely resemble what happened before (and the improvements in overall instantiation time and performance, as compared to either eager init with pure-mmap memory or user-mode pagefault handling with uffd, remain). --- Cargo.lock | 5 +++-- crates/wasmtime/Cargo.toml | 1 + crates/wasmtime/src/instance.rs | 5 ++++- crates/wasmtime/src/module.rs | 28 +++++++++++++++++----------- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d95912d784..1b2ce6bd77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,9 +1890,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "oorandom" @@ -3377,6 +3377,7 @@ dependencies = [ "libc", "log", "object", + "once_cell", "paste", "psm", "rayon", diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 77402eb21c..2fc4440c71 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -37,6 +37,7 @@ lazy_static = "1.4" rayon = { version = "1.0", optional = true } object = { version = "0.27", default-features = false, features = ['read_core', 'elf'] } async-trait = { version = "0.1.51", optional = true } +once_cell = "1.9" [target.'cfg(target_os = "windows")'.dependencies] winapi = "0.3.7" diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 4161a10a54..1ec0ac8ab0 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -690,6 +690,9 @@ impl<'a> Instantiator<'a> { // properly referenced while in use by the store. store.modules_mut().register(&self.cur.module); + // Initialize any memfd images now. + let memfds = self.cur.module.memfds()?; + unsafe { // The first thing we do is issue an instance allocation request // to the instance allocator. This, on success, will give us an @@ -708,7 +711,7 @@ impl<'a> Instantiator<'a> { .allocate(InstanceAllocationRequest { module: compiled_module.module(), unique_id: Some(compiled_module.unique_id()), - memfds: self.cur.module.memfds(), + memfds, image_base: compiled_module.code().as_ptr() as usize, functions: compiled_module.functions(), imports: self.cur.build(), diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index 1662388e03..2feb19ed01 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -4,6 +4,7 @@ use crate::{ }; use crate::{Engine, ModuleType}; use anyhow::{bail, Context, Result}; +use once_cell::sync::OnceCell; use std::fs; use std::mem; use std::path::Path; @@ -108,8 +109,11 @@ struct ModuleInner { types: Arc, /// Registered shared signature for the module. signatures: Arc, - /// a set of memfd images for memories, if any. - memfds: Option>, + /// A set of memfd images for memories, if any. Note that module + /// instantiation (hence the need for lazy init) may happen for the + /// same module concurrently in multiple Stores, so we use a + /// OnceCell. + memfds: OnceCell>>, } impl Module { @@ -531,8 +535,6 @@ impl Module { }) .collect::>>()?; - let memfds = ModuleMemFds::new(module.module(), module.wasm_data())?; - return Ok(Self { inner: Arc::new(ModuleInner { engine: engine.clone(), @@ -541,7 +543,7 @@ impl Module { artifact_upvars: modules, module_upvars, signatures, - memfds, + memfds: OnceCell::new(), }), }); @@ -555,13 +557,12 @@ impl Module { signatures: &Arc, ) -> Result { let module = artifacts[module_index].clone(); - let memfds = ModuleMemFds::new(module.module(), module.wasm_data())?; Ok(Module { inner: Arc::new(ModuleInner { engine: engine.clone(), types: types.clone(), module, - memfds, + memfds: OnceCell::new(), artifact_upvars: artifact_upvars .iter() .map(|i| artifacts[*i].clone()) @@ -682,13 +683,12 @@ impl Module { modules: &PrimaryMap, ) -> Result { let module = self.inner.artifact_upvars[artifact_index].clone(); - let memfds = ModuleMemFds::new(module.module(), module.wasm_data())?; Ok(Module { inner: Arc::new(ModuleInner { types: self.inner.types.clone(), engine: self.inner.engine.clone(), module, - memfds, + memfds: OnceCell::new(), artifact_upvars: artifact_upvars .iter() .map(|i| self.inner.artifact_upvars[*i].clone()) @@ -723,8 +723,14 @@ impl Module { &self.inner.signatures } - pub(crate) fn memfds(&self) -> Option<&Arc> { - self.inner.memfds.as_ref() + pub(crate) fn memfds(&self) -> Result>> { + Ok(self + .inner + .memfds + .get_or_try_init(|| { + ModuleMemFds::new(self.inner.module.module(), self.inner.module.wasm_data()) + })? + .as_ref()) } /// Looks up the module upvar value at the `index` specified.