Eagerly create ModuleMemoryImages (#3914)

This commit removes the currently existing laziness-via-`OnceCell` when
a `Module` is created for creating a `ModuleMemoryImages` data
structure. Processing of data is now already shifted to compile time for
the wasm module which means that creating a `ModuleMemoryImages` is
either cheap because the module is backed by a file on disk, it's a
single `write` into the kernel to a memfd, or it's cheap as it's not
supported. This should help make module instantiation time more
deterministic, even for the first instantiation of a module.
This commit is contained in:
Alex Crichton
2022-03-10 12:23:34 -06:00
committed by GitHub
parent 0df4e961c0
commit bc1170c2dd

View File

@@ -4,7 +4,6 @@ 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;
@@ -114,10 +113,8 @@ 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 initialization images for memories, if any. Note that module /// A set of initialization images for memories, if any.
/// instantiation (hence the need for lazy init) may happen for the same memory_images: Option<ModuleMemoryImages>,
/// module concurrently in multiple Stores, so we use a OnceCell.
memory_images: OnceCell<Option<ModuleMemoryImages>>,
} }
impl Module { impl Module {
@@ -557,17 +554,17 @@ impl Module {
&signatures, &signatures,
) )
}) })
.collect(); .collect::<Result<Vec<_>>>()?;
return Ok(Self { return Ok(Self {
inner: Arc::new(ModuleInner { inner: Arc::new(ModuleInner {
engine: engine.clone(), engine: engine.clone(),
types, types,
module,
artifact_upvars: modules, artifact_upvars: modules,
module_upvars, module_upvars,
signatures, signatures,
memory_images: OnceCell::new(), memory_images: memory_images(engine, &module)?,
module,
}), }),
}); });
@@ -579,14 +576,14 @@ impl Module {
artifact_upvars: &[usize], artifact_upvars: &[usize],
module_upvars: &[serialization::SerializedModuleUpvar], module_upvars: &[serialization::SerializedModuleUpvar],
signatures: &Arc<SignatureCollection>, signatures: &Arc<SignatureCollection>,
) -> Module { ) -> Result<Module> {
let module = artifacts[module_index].clone(); let module = artifacts[module_index].clone();
Module { Ok(Module {
inner: Arc::new(ModuleInner { inner: Arc::new(ModuleInner {
engine: engine.clone(), engine: engine.clone(),
types: types.clone(), types: types.clone(),
memory_images: memory_images(engine, &module)?,
module, module,
memory_images: OnceCell::new(),
artifact_upvars: artifact_upvars artifact_upvars: artifact_upvars
.iter() .iter()
.map(|i| artifacts[*i].clone()) .map(|i| artifacts[*i].clone())
@@ -604,10 +601,10 @@ impl Module {
signatures, signatures,
) )
}) })
.collect(), .collect::<Result<Vec<_>>>()?,
signatures: signatures.clone(), signatures: signatures.clone(),
}), }),
} })
} }
} }
@@ -711,8 +708,8 @@ impl 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(),
memory_images: memory_images(&self.inner.engine, &module)?,
module, module,
memory_images: 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())
@@ -1025,18 +1022,8 @@ impl wasmtime_runtime::ModuleRuntimeInfo for ModuleInner {
} }
fn memory_image(&self, memory: DefinedMemoryIndex) -> Result<Option<&Arc<MemoryImage>>> { fn memory_image(&self, memory: DefinedMemoryIndex) -> Result<Option<&Arc<MemoryImage>>> {
if !self.engine.config().memory_init_cow { Ok(self
return Ok(None); .memory_images
}
let images = self.memory_images.get_or_try_init(|| {
ModuleMemoryImages::new(
self.module.module(),
self.module.wasm_data(),
Some(self.module.mmap()),
)
})?;
Ok(images
.as_ref() .as_ref()
.and_then(|images| images.get_memory_image(memory))) .and_then(|images| images.get_memory_image(memory)))
} }
@@ -1149,3 +1136,16 @@ impl wasmtime_runtime::ModuleRuntimeInfo for BareModuleInfo {
} }
} }
} }
/// Helper method to construct a `ModuleMemoryImages` for an associated
/// `CompiledModule`.
fn memory_images(engine: &Engine, module: &CompiledModule) -> Result<Option<ModuleMemoryImages>> {
// If initialization via copy-on-write is explicitly disabled in
// configuration then this path is skipped entirely.
if !engine.config().memory_init_cow {
return Ok(None);
}
// ... otherwise logic is delegated to the `ModuleMemoryImages::new` constructor
ModuleMemoryImages::new(module.module(), module.wasm_data(), Some(module.mmap()))
}