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).
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -1890,9 +1890,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.8.0"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oorandom"
|
name = "oorandom"
|
||||||
@@ -3377,6 +3377,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"object",
|
"object",
|
||||||
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
"psm",
|
"psm",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ lazy_static = "1.4"
|
|||||||
rayon = { version = "1.0", optional = true }
|
rayon = { version = "1.0", optional = true }
|
||||||
object = { version = "0.27", default-features = false, features = ['read_core', 'elf'] }
|
object = { version = "0.27", default-features = false, features = ['read_core', 'elf'] }
|
||||||
async-trait = { version = "0.1.51", optional = true }
|
async-trait = { version = "0.1.51", optional = true }
|
||||||
|
once_cell = "1.9"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = "0.3.7"
|
winapi = "0.3.7"
|
||||||
|
|||||||
@@ -690,6 +690,9 @@ impl<'a> Instantiator<'a> {
|
|||||||
// properly referenced while in use by the store.
|
// properly referenced while in use by the store.
|
||||||
store.modules_mut().register(&self.cur.module);
|
store.modules_mut().register(&self.cur.module);
|
||||||
|
|
||||||
|
// Initialize any memfd images now.
|
||||||
|
let memfds = self.cur.module.memfds()?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// The first thing we do is issue an instance allocation request
|
// The first thing we do is issue an instance allocation request
|
||||||
// to the instance allocator. This, on success, will give us an
|
// to the instance allocator. This, on success, will give us an
|
||||||
@@ -708,7 +711,7 @@ impl<'a> Instantiator<'a> {
|
|||||||
.allocate(InstanceAllocationRequest {
|
.allocate(InstanceAllocationRequest {
|
||||||
module: compiled_module.module(),
|
module: compiled_module.module(),
|
||||||
unique_id: Some(compiled_module.unique_id()),
|
unique_id: Some(compiled_module.unique_id()),
|
||||||
memfds: self.cur.module.memfds(),
|
memfds,
|
||||||
image_base: compiled_module.code().as_ptr() as usize,
|
image_base: compiled_module.code().as_ptr() as usize,
|
||||||
functions: compiled_module.functions(),
|
functions: compiled_module.functions(),
|
||||||
imports: self.cur.build(),
|
imports: self.cur.build(),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use crate::{Engine, ModuleType};
|
use crate::{Engine, ModuleType};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -108,8 +109,11 @@ struct ModuleInner {
|
|||||||
types: Arc<TypeTables>,
|
types: Arc<TypeTables>,
|
||||||
/// Registered shared signature for the module.
|
/// Registered shared signature for the module.
|
||||||
signatures: Arc<SignatureCollection>,
|
signatures: Arc<SignatureCollection>,
|
||||||
/// a set of memfd images for memories, if any.
|
/// A set of memfd images for memories, if any. Note that module
|
||||||
memfds: Option<Arc<ModuleMemFds>>,
|
/// instantiation (hence the need for lazy init) may happen for the
|
||||||
|
/// same module concurrently in multiple Stores, so we use a
|
||||||
|
/// OnceCell.
|
||||||
|
memfds: OnceCell<Option<Arc<ModuleMemFds>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
@@ -531,8 +535,6 @@ impl Module {
|
|||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let memfds = ModuleMemFds::new(module.module(), module.wasm_data())?;
|
|
||||||
|
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
inner: Arc::new(ModuleInner {
|
inner: Arc::new(ModuleInner {
|
||||||
engine: engine.clone(),
|
engine: engine.clone(),
|
||||||
@@ -541,7 +543,7 @@ impl Module {
|
|||||||
artifact_upvars: modules,
|
artifact_upvars: modules,
|
||||||
module_upvars,
|
module_upvars,
|
||||||
signatures,
|
signatures,
|
||||||
memfds,
|
memfds: OnceCell::new(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -555,13 +557,12 @@ impl Module {
|
|||||||
signatures: &Arc<SignatureCollection>,
|
signatures: &Arc<SignatureCollection>,
|
||||||
) -> Result<Module> {
|
) -> Result<Module> {
|
||||||
let module = artifacts[module_index].clone();
|
let module = artifacts[module_index].clone();
|
||||||
let memfds = ModuleMemFds::new(module.module(), module.wasm_data())?;
|
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
inner: Arc::new(ModuleInner {
|
inner: Arc::new(ModuleInner {
|
||||||
engine: engine.clone(),
|
engine: engine.clone(),
|
||||||
types: types.clone(),
|
types: types.clone(),
|
||||||
module,
|
module,
|
||||||
memfds,
|
memfds: OnceCell::new(),
|
||||||
artifact_upvars: artifact_upvars
|
artifact_upvars: artifact_upvars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| artifacts[*i].clone())
|
.map(|i| artifacts[*i].clone())
|
||||||
@@ -682,13 +683,12 @@ impl Module {
|
|||||||
modules: &PrimaryMap<ModuleIndex, Module>,
|
modules: &PrimaryMap<ModuleIndex, Module>,
|
||||||
) -> Result<Module> {
|
) -> Result<Module> {
|
||||||
let module = self.inner.artifact_upvars[artifact_index].clone();
|
let module = self.inner.artifact_upvars[artifact_index].clone();
|
||||||
let memfds = ModuleMemFds::new(module.module(), module.wasm_data())?;
|
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
inner: Arc::new(ModuleInner {
|
inner: Arc::new(ModuleInner {
|
||||||
types: self.inner.types.clone(),
|
types: self.inner.types.clone(),
|
||||||
engine: self.inner.engine.clone(),
|
engine: self.inner.engine.clone(),
|
||||||
module,
|
module,
|
||||||
memfds,
|
memfds: OnceCell::new(),
|
||||||
artifact_upvars: artifact_upvars
|
artifact_upvars: artifact_upvars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| self.inner.artifact_upvars[*i].clone())
|
.map(|i| self.inner.artifact_upvars[*i].clone())
|
||||||
@@ -723,8 +723,14 @@ impl Module {
|
|||||||
&self.inner.signatures
|
&self.inner.signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn memfds(&self) -> Option<&Arc<ModuleMemFds>> {
|
pub(crate) fn memfds(&self) -> Result<Option<&Arc<ModuleMemFds>>> {
|
||||||
self.inner.memfds.as_ref()
|
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.
|
/// Looks up the module upvar value at the `index` specified.
|
||||||
|
|||||||
Reference in New Issue
Block a user