Skip to content

Commit

Permalink
Merge static/dynamic guard size options (#9528)
Browse files Browse the repository at this point in the history
* Merge static/dynamic guard size options

This commit is the first of what will likely be a few to refactor the
memory-related configuration options in Wasmtime. The end goal of these
refactorings is to fix some preexisting issues and additionally make the
configuration easier to understand for both users and implementors
alike. First on the chopping block here is to merge the
`dynamic_memory_guard_size` and `static_memory_guard_size` options into
one option. AFAIK there's not a strong reason to have separate
configuration options for these so it's hopefully simpler to have a
single `memory_guard_size` option which applies to all linear memories
equally.

I'll note that the old CLI options are preserved but are documented as
deprecated. We don't currently warn on using "deprecated options" so for
now the old options are just documented as deprecated and are otherwise
silently accepted.

* Fix compilation of C API

* Fix build of fuzzers
  • Loading branch information
alexcrichton authored Nov 1, 2024
1 parent 2d0c669 commit 48d5338
Show file tree
Hide file tree
Showing 19 changed files with 80 additions and 183 deletions.
14 changes: 3 additions & 11 deletions crates/c-api/include/wasmtime/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,20 +334,12 @@ WASMTIME_CONFIG_PROP(void, static_memory_forced, bool)
WASMTIME_CONFIG_PROP(void, static_memory_maximum_size, uint64_t)

/**
* \brief Configures the guard region size for "static" memory.
* \brief Configures the guard region size for linear memory.
*
* For more information see the Rust documentation at
* https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.static_memory_guard_size.
* https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.memory_guard_size.
*/
WASMTIME_CONFIG_PROP(void, static_memory_guard_size, uint64_t)

/**
* \brief Configures the guard region size for "dynamic" memory.
*
* For more information see the Rust documentation at
* https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.dynamic_memory_guard_size.
*/
WASMTIME_CONFIG_PROP(void, dynamic_memory_guard_size, uint64_t)
WASMTIME_CONFIG_PROP(void, memory_guard_size, uint64_t)

/**
* \brief Configures the size, in bytes, of the extra virtual memory space
Expand Down
9 changes: 2 additions & 7 deletions crates/c-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,8 @@ pub extern "C" fn wasmtime_config_static_memory_maximum_size_set(c: &mut wasm_co
}

#[no_mangle]
pub extern "C" fn wasmtime_config_static_memory_guard_size_set(c: &mut wasm_config_t, size: u64) {
c.config.static_memory_guard_size(size);
}

#[no_mangle]
pub extern "C" fn wasmtime_config_dynamic_memory_guard_size_set(c: &mut wasm_config_t, size: u64) {
c.config.dynamic_memory_guard_size(size);
pub extern "C" fn wasmtime_config_memory_guard_size_set(c: &mut wasm_config_t, size: u64) {
c.config.memory_guard_size(size);
}

#[no_mangle]
Expand Down
25 changes: 15 additions & 10 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,15 @@ wasmtime_option_group! {
/// Optimization level of generated code (0-2, s; default: 2)
pub opt_level: Option<wasmtime::OptLevel>,

/// Byte size of the guard region after dynamic memories are allocated
pub dynamic_memory_guard_size: Option<u64>,

/// Force using a "static" style for all wasm memories
pub static_memory_forced: Option<bool>,

/// Maximum size in bytes of wasm memory before it becomes dynamically
/// relocatable instead of up-front-reserved.
pub static_memory_maximum_size: Option<u64>,

/// Byte size of the guard region after static memories are allocated
pub static_memory_guard_size: Option<u64>,
/// Size, in bytes, of guard pages for linear memories.
pub memory_guard_size: Option<u64>,

/// Bytes to reserve at the end of linear memory for growth for dynamic
/// memories.
Expand Down Expand Up @@ -167,6 +164,12 @@ wasmtime_option_group! {

/// Enable or disable the use of host signal handlers for traps.
pub signals_based_traps: Option<bool>,

/// DEPRECATED: Use `-Cmemory-guard-size=N` instead.
pub dynamic_memory_guard_size: Option<u64>,

/// DEPRECATED: Use `-Cmemory-guard-size=N` instead.
pub static_memory_guard_size: Option<u64>,
}

enum Optimize {
Expand Down Expand Up @@ -636,13 +639,15 @@ impl CommonOptions {
config.static_memory_forced(enable);
}

if let Some(size) = self.opts.static_memory_guard_size {
config.static_memory_guard_size(size);
if let Some(size) = self
.opts
.static_memory_guard_size
.or(self.opts.dynamic_memory_guard_size)
.or(self.opts.memory_guard_size)
{
config.memory_guard_size(size);
}

if let Some(size) = self.opts.dynamic_memory_guard_size {
config.dynamic_memory_guard_size(size);
}
if let Some(size) = self.opts.dynamic_memory_reserved_for_growth {
config.dynamic_memory_reserved_for_growth(size);
}
Expand Down
4 changes: 2 additions & 2 deletions crates/environ/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl MemoryStyle {
Self::Static {
byte_reservation: tunables.static_memory_reservation,
},
tunables.static_memory_offset_guard_size,
tunables.memory_guard_size,
);
}

Expand All @@ -67,7 +67,7 @@ impl MemoryStyle {
Self::Dynamic {
reserve: tunables.dynamic_memory_growth_reserve,
},
tunables.dynamic_memory_offset_guard_size,
tunables.memory_guard_size,
)
}
}
Expand Down
21 changes: 5 additions & 16 deletions crates/environ/src/tunables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ pub struct Tunables {
/// the heap.
pub static_memory_reservation: u64,

/// The size in bytes of the offset guard for static heaps.
pub static_memory_offset_guard_size: u64,

/// The size in bytes of the offset guard for dynamic heaps.
pub dynamic_memory_offset_guard_size: u64,
/// The size, in bytes, of the guard page region for linear memories.
pub memory_guard_size: u64,

/// The size, in bytes, of reserved memory at the end of a "dynamic" memory,
/// before the guard page, that memory can grow into. This is intended to
Expand Down Expand Up @@ -108,8 +105,7 @@ impl Tunables {
// No virtual memory tricks are available on miri so make these
// limits quite conservative.
static_memory_reservation: 1 << 20,
static_memory_offset_guard_size: 0,
dynamic_memory_offset_guard_size: 0,
memory_guard_size: 0,
dynamic_memory_growth_reserve: 0,

// General options which have the same defaults regardless of
Expand All @@ -136,8 +132,7 @@ impl Tunables {
// impacts performance severely but allows us to have more than a
// few instances running around.
static_memory_reservation: 10 * (1 << 20),
static_memory_offset_guard_size: 0x1_0000,
dynamic_memory_offset_guard_size: 0x1_0000,
memory_guard_size: 0x1_0000,
dynamic_memory_growth_reserve: 1 << 20, // 1MB

..Tunables::default_miri()
Expand All @@ -154,13 +149,7 @@ impl Tunables {
// Coupled with a 2 GiB address space guard it lets us translate
// wasm offsets into x86 offsets as aggressively as we can.
static_memory_reservation: 1 << 32,
static_memory_offset_guard_size: 0x8000_0000,

// Size in bytes of the offset guard for dynamic memories.
//
// Allocate a small guard to optimize common cases but without
// wasting too much memory.
dynamic_memory_offset_guard_size: 0x1_0000,
memory_guard_size: 0x8000_0000,

// We've got lots of address space on 64-bit so use a larger
// grow-into-this area, but on 32-bit we aren't as lucky. Miri is
Expand Down
6 changes: 2 additions & 4 deletions crates/fuzzing/src/generators/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,7 @@ impl Config {
let memory_config = if pcc {
MemoryConfig::Normal(NormalMemoryConfig {
static_memory_maximum_size: Some(4 << 30), // 4 GiB
static_memory_guard_size: Some(2 << 30), // 2 GiB
dynamic_memory_guard_size: Some(0),
memory_guard_size: Some(2 << 30), // 2 GiB
dynamic_memory_reserved_for_growth: Some(0),
guard_before_linear_memory: false,
memory_init_cow: true,
Expand All @@ -286,9 +285,8 @@ impl Config {
MemoryConfig::CustomUnaligned => {
cfg.with_host_memory(Arc::new(UnalignedMemoryCreator))
.static_memory_maximum_size(0)
.dynamic_memory_guard_size(0)
.memory_guard_size(0)
.dynamic_memory_reserved_for_growth(0)
.static_memory_guard_size(0)
.guard_before_linear_memory(false)
.memory_init_cow(false);
}
Expand Down
20 changes: 5 additions & 15 deletions crates/fuzzing/src/generators/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ pub enum MemoryConfig {
#[allow(missing_docs)]
pub struct NormalMemoryConfig {
pub static_memory_maximum_size: Option<u64>,
pub static_memory_guard_size: Option<u64>,
pub dynamic_memory_guard_size: Option<u64>,
pub memory_guard_size: Option<u64>,
pub dynamic_memory_reserved_for_growth: Option<u64>,
pub guard_before_linear_memory: bool,
pub cranelift_enable_heap_access_spectre_mitigations: Option<bool>,
Expand All @@ -148,23 +147,15 @@ impl<'a> Arbitrary<'a> for NormalMemoryConfig {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
// This attempts to limit memory and guard sizes to 32-bit ranges so
// we don't exhaust a 64-bit address space easily.
let mut ret = Self {
Ok(Self {
static_memory_maximum_size: <Option<u32> as Arbitrary>::arbitrary(u)?.map(Into::into),
static_memory_guard_size: <Option<u32> as Arbitrary>::arbitrary(u)?.map(Into::into),
dynamic_memory_guard_size: <Option<u32> as Arbitrary>::arbitrary(u)?.map(Into::into),
memory_guard_size: <Option<u32> as Arbitrary>::arbitrary(u)?.map(Into::into),
dynamic_memory_reserved_for_growth: <Option<u32> as Arbitrary>::arbitrary(u)?
.map(Into::into),
guard_before_linear_memory: u.arbitrary()?,
cranelift_enable_heap_access_spectre_mitigations: u.arbitrary()?,
memory_init_cow: u.arbitrary()?,
};

if let Some(dynamic) = ret.dynamic_memory_guard_size {
let statik = ret.static_memory_guard_size.unwrap_or(2 << 30);
ret.static_memory_guard_size = Some(statik.max(dynamic));
}

Ok(ret)
})
}
}

Expand All @@ -173,8 +164,7 @@ impl NormalMemoryConfig {
pub fn apply_to(&self, config: &mut wasmtime::Config) {
config
.static_memory_maximum_size(self.static_memory_maximum_size.unwrap_or(0))
.static_memory_guard_size(self.static_memory_guard_size.unwrap_or(0))
.dynamic_memory_guard_size(self.dynamic_memory_guard_size.unwrap_or(0))
.memory_guard_size(self.memory_guard_size.unwrap_or(0))
.dynamic_memory_reserved_for_growth(
self.dynamic_memory_reserved_for_growth.unwrap_or(0),
)
Expand Down
2 changes: 1 addition & 1 deletion crates/misc/component-test-util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub fn config() -> Config {
// try to cut down on virtual memory usage by avoiding 4G reservations.
if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() {
config.static_memory_maximum_size(0);
config.dynamic_memory_guard_size(0);
config.memory_guard_size(0);
}
config
}
Expand Down
78 changes: 14 additions & 64 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ pub struct Config {
#[derive(Default, Clone)]
struct ConfigTunables {
static_memory_reservation: Option<u64>,
static_memory_offset_guard_size: Option<u64>,
dynamic_memory_offset_guard_size: Option<u64>,
memory_guard_size: Option<u64>,
dynamic_memory_growth_reserve: Option<u64>,
generate_native_debuginfo: Option<bool>,
parse_wasm_debuginfo: Option<bool>,
Expand Down Expand Up @@ -1305,7 +1304,7 @@ impl Config {
/// When using the pooling instance allocation strategy, all linear memories
/// will be created as "static" and the
/// [`Config::static_memory_maximum_size`] and
/// [`Config::static_memory_guard_size`] options will be used to configure
/// [`Config::memory_guard_size`] options will be used to configure
/// the virtual memory allocations of linear memories.
pub fn allocation_strategy(&mut self, strategy: InstanceAllocationStrategy) -> &mut Self {
self.allocation_strategy = strategy;
Expand Down Expand Up @@ -1426,7 +1425,7 @@ impl Config {
}

/// Configures the size, in bytes, of the guard region used at the end of a
/// static memory's address space reservation.
/// linear memory's address space reservation.
///
/// > Note: this value has important performance ramifications, be sure to
/// > understand what this value does before tweaking it and benchmarking.
Expand All @@ -1437,16 +1436,12 @@ impl Config {
/// Accelerating these memory accesses is the motivation for a guard after a
/// memory allocation.
///
/// Memories (both static and dynamic) can be configured with a guard at the
/// end of them which consists of unmapped virtual memory. This unmapped
/// memory will trigger a memory access violation (e.g. segfault) if
/// accessed. This allows JIT code to elide bounds checks if it can prove
/// that an access, if out of bounds, would hit the guard region. This means
/// that having such a guard of unmapped memory can remove the need for
/// bounds checks in JIT code.
///
/// For the difference between static and dynamic memories, see the
/// [`Config::static_memory_maximum_size`].
/// Memories can be configured with a guard at the end of them which
/// consists of unmapped virtual memory. This unmapped memory will trigger
/// a memory access violation (e.g. segfault) if accessed. This allows JIT
/// code to elide bounds checks if it can prove that an access, if out of
/// bounds, would hit the guard region. This means that having such a guard
/// of unmapped memory can remove the need for bounds checks in JIT code.
///
/// ## How big should the guard be?
///
Expand All @@ -1470,45 +1465,8 @@ impl Config {
/// allows eliminating almost all bounds checks on loads/stores with an
/// immediate offset of less than 2GB. On 32-bit platforms this defaults to
/// 64KB.
///
/// ## Errors
///
/// The `Engine::new` method will return an error if this option is smaller
/// than the value configured for [`Config::dynamic_memory_guard_size`].
pub fn static_memory_guard_size(&mut self, guard_size: u64) -> &mut Self {
self.tunables.static_memory_offset_guard_size = Some(guard_size);
self
}

/// Configures the size, in bytes, of the guard region used at the end of a
/// dynamic memory's address space reservation.
///
/// For the difference between static and dynamic memories, see the
/// [`Config::static_memory_maximum_size`]
///
/// For more information about what a guard is, see the documentation on
/// [`Config::static_memory_guard_size`].
///
/// Note that the size of the guard region for dynamic memories is not super
/// critical for performance. Making it reasonably-sized can improve
/// generated code slightly, but for maximum performance you'll want to lean
/// towards static memories rather than dynamic anyway.
///
/// Also note that the dynamic memory guard size must be smaller than the
/// static memory guard size, so if a large dynamic memory guard is
/// specified then the static memory guard size will also be automatically
/// increased.
///
/// ## Default
///
/// This value defaults to 64KB.
///
/// ## Errors
///
/// The `Engine::new` method will return an error if this option is larger
/// than the value configured for [`Config::static_memory_guard_size`].
pub fn dynamic_memory_guard_size(&mut self, guard_size: u64) -> &mut Self {
self.tunables.dynamic_memory_offset_guard_size = Some(guard_size);
pub fn memory_guard_size(&mut self, guard_size: u64) -> &mut Self {
self.tunables.memory_guard_size = Some(guard_size);
self
}

Expand Down Expand Up @@ -1974,8 +1932,7 @@ impl Config {

set_fields! {
static_memory_reservation
static_memory_offset_guard_size
dynamic_memory_offset_guard_size
memory_guard_size
dynamic_memory_growth_reserve
generate_native_debuginfo
parse_wasm_debuginfo
Expand Down Expand Up @@ -2012,10 +1969,6 @@ impl Config {
None
};

if tunables.static_memory_offset_guard_size < tunables.dynamic_memory_offset_guard_size {
bail!("static memory guard size cannot be smaller than dynamic memory guard size");
}

Ok((tunables, features))
}

Expand Down Expand Up @@ -2392,11 +2345,8 @@ impl fmt::Debug for Config {
if let Some(size) = self.tunables.static_memory_reservation {
f.field("static_memory_maximum_reservation", &size);
}
if let Some(size) = self.tunables.static_memory_offset_guard_size {
f.field("static_memory_guard_size", &size);
}
if let Some(size) = self.tunables.dynamic_memory_offset_guard_size {
f.field("dynamic_memory_guard_size", &size);
if let Some(size) = self.tunables.memory_guard_size {
f.field("memory_guard_size", &size);
}
if let Some(enable) = self.tunables.guard_before_linear_memory {
f.field("guard_before_linear_memory", &enable);
Expand Down
Loading

0 comments on commit 48d5338

Please sign in to comment.