From f58dd88ebead27100452164dc5f560873ac5f681 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Feb 2022 15:47:13 -0600 Subject: [PATCH] Update memfd support with a runtime toggle (#3778) This commit updates the `memfd` support in Wasmtime to have a runtime toggle as to whether it's used or not. The compile-time feature gating `memfd` support is now also re-enabled by default, but the new runtime switch is still disabled-by-default. Additionally this commit updates our fuzz oracle to turn on/off the memfd flag to re-enable fuzzing with memfd on oss-fuzz. --- Cargo.toml | 1 + crates/fuzzing/src/generators.rs | 4 +++- crates/wasmtime/Cargo.toml | 11 ++++++++++- crates/wasmtime/src/config.rs | 30 ++++++++++++++++++++++++++++++ crates/wasmtime/src/lib.rs | 15 +++++++++++++++ crates/wasmtime/src/module.rs | 3 +++ 6 files changed, 62 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d9aad06ce82c..97050d5b1eaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,7 @@ default = [ "wasmtime/parallel-compilation", "wasi-nn", "pooling-allocator", + "memfd", ] jitdump = ["wasmtime/jitdump"] vtune = ["wasmtime/vtune"] diff --git a/crates/fuzzing/src/generators.rs b/crates/fuzzing/src/generators.rs index 0af5246dd410..157d0335b342 100644 --- a/crates/fuzzing/src/generators.rs +++ b/crates/fuzzing/src/generators.rs @@ -61,6 +61,7 @@ pub struct WasmtimeConfig { pub(crate) consume_fuel: bool, memory_config: MemoryConfig, force_jump_veneers: bool, + memfd: bool, } #[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)] @@ -99,7 +100,8 @@ impl Config { .cranelift_nan_canonicalization(self.wasmtime.canonicalize_nans) .cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime()) .interruptable(self.wasmtime.interruptable) - .consume_fuel(self.wasmtime.consume_fuel); + .consume_fuel(self.wasmtime.consume_fuel) + .memfd(self.wasmtime.memfd); // If the wasm-smith-generated module use nan canonicalization then we // don't need to enable it, but if it doesn't enable it already then we diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 2a6e450db86e..f49343d66ace 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -51,7 +51,16 @@ wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync" } maintenance = { status = "actively-developed" } [features] -default = ['async', 'cache', 'wat', 'jitdump', 'parallel-compilation', 'cranelift', 'pooling-allocator'] +default = [ + 'async', + 'cache', + 'wat', + 'jitdump', + 'parallel-compilation', + 'cranelift', + 'pooling-allocator', + 'memfd', +] # An on-by-default feature enabling runtime compilation of WebAssembly modules # with the Cranelift compiler. Cranelift is the default compilation backend of diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index b2f47c8a420b..cb17036db329 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -104,6 +104,7 @@ pub struct Config { pub(crate) module_version: ModuleVersionStrategy, pub(crate) parallel_compilation: bool, pub(crate) paged_memory_initialization: bool, + pub(crate) memfd: bool, } impl Config { @@ -129,6 +130,7 @@ impl Config { parallel_compilation: true, // Default to paged memory initialization when using uffd on linux paged_memory_initialization: cfg!(all(target_os = "linux", feature = "uffd")), + memfd: false, }; #[cfg(compiler)] { @@ -1170,6 +1172,33 @@ impl Config { self } + /// Configures whether `memfd`, if supported, will be used to initialize + /// applicable module memories. + /// + /// This is a Linux-specific feature since `memfd` is only supported on + /// Linux. Support for this is also enabled by default at compile time but + /// is otherwise disabled at runtime by default. This feature needs to be + /// enabled to `true` for support to be used. + /// + /// Also note that even if this feature is enabled it may not be applicable + /// to all memories in all wasm modules. At this time memories must meet + /// specific criteria to be memfd-initialized: + /// + /// * Only memories defined in the module can be initialized this way. + /// * Data segments for memory must use statically known offsets. + /// * Data segments for memory must all be in-bounds. + /// + /// If all of the above applies, this setting is enabled, and the current + /// platform is Linux the `memfd` will be used to efficiently initialize + /// linear memories with `mmap` to avoid copying data from initializers into + /// linear memory. + #[cfg(feature = "memfd")] + #[cfg_attr(nightlydoc, doc(cfg(feature = "memfd")))] + pub fn memfd(&mut self, memfd: bool) -> &mut Self { + self.memfd = memfd; + self + } + pub(crate) fn build_allocator(&self) -> Result> { #[cfg(feature = "async")] let stack_size = self.async_stack_size; @@ -1239,6 +1268,7 @@ impl Clone for Config { module_version: self.module_version.clone(), parallel_compilation: self.parallel_compilation, paged_memory_initialization: self.paged_memory_initialization, + memfd: self.memfd, } } } diff --git a/crates/wasmtime/src/lib.rs b/crates/wasmtime/src/lib.rs index 5b743f929cbb..a67d7dda4fad 100644 --- a/crates/wasmtime/src/lib.rs +++ b/crates/wasmtime/src/lib.rs @@ -275,6 +275,21 @@ //! all architectures for both the JIT compiler and the `wasmtime compile` CLI //! command. //! +//! * `pooling-allocator` - Enabled by default, this feature adds support for +//! the pooling allocation strategy enabled via +//! [`Config::allocation_strategy`]. The pooling allocator can enable more +//! efficient reuse of resources for high-concurrency and +//! high-instantiation-count scenarios. +//! +//! * `memfd` - Enabled by default, this feature builds in support for a +//! Linux-specific feature of creating a `memfd` where applicable for a +//! [`Module`]'s initial memory. This makes instantiation much faster by +//! `mmap`-ing the initial memory image into place instead of copying memory +//! into place, allowing sharing pages that end up only getting read and +//! otherwise using copy-on-write for efficient initialization of memory. Note +//! that this is simply compile-time support and this must also be enabled at +//! run-time via [`Config::memfd`]. +//! //! ## Examples //! //! In addition to the examples below be sure to check out the [online embedding diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index 2feb19ed0140..8dcaafe82c06 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -724,6 +724,9 @@ impl Module { } pub(crate) fn memfds(&self) -> Result>> { + if !self.engine().config().memfd { + return Ok(None); + } Ok(self .inner .memfds