Skip to content

Commit

Permalink
feat: add a knob for reset stack
Browse files Browse the repository at this point in the history
  • Loading branch information
Duslia committed Aug 30, 2022
1 parent 573ae0c commit 391c309
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
16 changes: 13 additions & 3 deletions crates/runtime/src/instance/allocator/pooling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,11 +887,16 @@ struct StackPool {
max_instances: usize,
page_size: usize,
index_allocator: Mutex<PoolingAllocationState>,
reset_stack_page: bool,
}

#[cfg(all(feature = "async", unix))]
impl StackPool {
fn new(instance_limits: &InstanceLimits, stack_size: usize) -> Result<Self> {
fn new(
instance_limits: &InstanceLimits,
stack_size: usize,
reset_stack_page: bool,
) -> Result<Self> {
use rustix::mm::{mprotect, MprotectFlags};

let page_size = crate::page_size();
Expand Down Expand Up @@ -931,6 +936,7 @@ impl StackPool {
stack_size,
max_instances,
page_size,
reset_stack_page,
// We always use a `NextAvailable` strategy for stack
// allocation. We don't want or need an affinity policy
// here: stacks do not benefit from being allocated to the
Expand Down Expand Up @@ -997,7 +1003,9 @@ impl StackPool {
let index = (start_of_stack - base) / self.stack_size;
assert!(index < self.max_instances);

decommit_stack_pages(bottom_of_stack as _, stack_size).unwrap();
if self.reset_stack_page {
decommit_stack_pages(bottom_of_stack as _, stack_size).unwrap();
}

self.index_allocator.lock().unwrap().free(SlotId(index));
}
Expand All @@ -1024,6 +1032,7 @@ impl PoolingInstanceAllocator {
instance_limits: InstanceLimits,
stack_size: usize,
tunables: &Tunables,
reset_stack_page: bool,
) -> Result<Self> {
if instance_limits.count == 0 {
bail!("the instance count limit cannot be zero");
Expand All @@ -1032,11 +1041,12 @@ impl PoolingInstanceAllocator {
let instances = InstancePool::new(strategy, &instance_limits, tunables)?;

drop(stack_size); // suppress unused warnings w/o async feature
drop(reset_stack_page); // suppress unused warnings w/o async feature

Ok(Self {
instances: instances,
#[cfg(all(feature = "async", unix))]
stacks: StackPool::new(&instance_limits, stack_size)?,
stacks: StackPool::new(&instance_limits, stack_size, reset_stack_page)?,
#[cfg(all(feature = "async", windows))]
stack_size,
})
Expand Down
23 changes: 21 additions & 2 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ pub struct Config {
pub(crate) memory_init_cow: bool,
pub(crate) memory_guaranteed_dense_image_size: u64,
pub(crate) force_memory_init_memfd: bool,
#[cfg(feature = "async")]
pub(crate) reset_stack_page: bool,
}

/// User-provided configuration for the compiler.
Expand Down Expand Up @@ -196,6 +198,8 @@ impl Config {
memory_init_cow: true,
memory_guaranteed_dense_image_size: 16 << 20,
force_memory_init_memfd: false,
#[cfg(feature = "async")]
reset_stack_page: true,
};
#[cfg(compiler)]
{
Expand Down Expand Up @@ -341,6 +345,20 @@ impl Config {
self
}

/// Configures whether or not to reset stack pages after once execution.
///
/// Reset stack pages will cost a lot in multi thread environment. It is
/// purely a defense-in-depth thing and is not required for correctness.
/// In some cases there is no need to care much about safety. You can set
/// it to `false`. If you don't know what you are doing, just use the
/// default configuration.
#[cfg(feature = "async")]
#[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
pub fn reset_stack_page(&mut self, size: usize) -> &mut Self {
self.async_stack_size = size;
self
}

/// Configures whether DWARF debug information will be emitted during
/// compilation.
///
Expand Down Expand Up @@ -1413,10 +1431,10 @@ impl Config {

pub(crate) fn build_allocator(&self) -> Result<Box<dyn InstanceAllocator>> {
#[cfg(feature = "async")]
let stack_size = self.async_stack_size;
let (stack_size, reset_stack_page) = (self.async_stack_size, self.reset_stack_page);

#[cfg(not(feature = "async"))]
let stack_size = 0;
let (stack_size, reset_stack_page) = (0, true);

match self.allocation_strategy {
InstanceAllocationStrategy::OnDemand => Ok(Box::new(OnDemandInstanceAllocator::new(
Expand All @@ -1432,6 +1450,7 @@ impl Config {
instance_limits,
stack_size,
&self.tunables,
reset_stack_page,
)?)),
}
}
Expand Down

0 comments on commit 391c309

Please sign in to comment.