From 684fe922c837a802d04e32bb627f2752fe512d31 Mon Sep 17 00:00:00 2001 From: Daichi Fukui Date: Wed, 22 May 2024 04:39:32 +0000 Subject: [PATCH 1/7] Allow wasmer-wasix to block the current thread A WasiEnv now has a flag that signifies if it's allowed to block the current thread and the flag is expected to be referenced when the current thread can be blocked for optimising the performance. In addition, the flag is set true when wasm modules are invoked via the CLI. wasmer-wasix uses a tokio runtime for many things according to #4299, but tokio does not always bring the best performance in Wasmer as described in #4738, hence this update. Signed-off-by: Daichi Fukui --- lib/wasix/src/state/env.rs | 9 +++++++++ lib/wasix/src/state/func_env.rs | 2 ++ 2 files changed, 11 insertions(+) diff --git a/lib/wasix/src/state/env.rs b/lib/wasix/src/state/env.rs index a43c9d29155..bd4420e04dc 100644 --- a/lib/wasix/src/state/env.rs +++ b/lib/wasix/src/state/env.rs @@ -359,6 +359,8 @@ pub struct WasiEnv { /// not be cloned when `WasiEnv` is cloned) /// TODO: We should move this outside of `WasiEnv` with some refactoring inner: WasiInstanceHandlesPointer, + + pub allow_blocking_current_thread: bool, } impl std::fmt::Debug for WasiEnv { @@ -387,6 +389,7 @@ impl Clone for WasiEnv { enable_exponential_cpu_backoff: self.enable_exponential_cpu_backoff, replaying_journal: self.replaying_journal, disable_fs_cleanup: self.disable_fs_cleanup, + allow_blocking_current_thread: self.allow_blocking_current_thread, } } } @@ -427,6 +430,7 @@ impl WasiEnv { enable_exponential_cpu_backoff: self.enable_exponential_cpu_backoff, replaying_journal: false, disable_fs_cleanup: self.disable_fs_cleanup, + allow_blocking_current_thread: false, }; Ok((new_env, handle)) } @@ -556,6 +560,7 @@ impl WasiEnv { bin_factory: init.bin_factory, capabilities: init.capabilities, disable_fs_cleanup: false, + allow_blocking_current_thread: false, }; env.owned_handles.push(thread); @@ -1279,4 +1284,8 @@ impl WasiEnv { Box::pin(async {}) } } + + pub fn allow_blocking_current_thread(&mut self, enable: bool) { + self.allow_blocking_current_thread = enable; + } } diff --git a/lib/wasix/src/state/func_env.rs b/lib/wasix/src/state/func_env.rs index 0934c95ec41..f483655315a 100644 --- a/lib/wasix/src/state/func_env.rs +++ b/lib/wasix/src/state/func_env.rs @@ -158,6 +158,8 @@ impl WasiFunctionEnv { env.state.fs.set_is_wasix(is_wasix_module); + env.allow_blocking_current_thread(true); + // If the stack offset and size is not set then do so if update_layout { // Set the base stack From 50f7207afb42d9938ac1394e4cac4af210fd9aa6 Mon Sep 17 00:00:00 2001 From: Daichi Fukui Date: Sat, 25 May 2024 07:22:12 +0000 Subject: [PATCH 2/7] Allow more consistent sleep form of poll_oneoff Allow different sleep form of poll_oneoff, which just sleeps for relative time using std::thread::sleep. That form of poll_oneoff is only available if there is only one subscription and it is allowed to block the current thread, contributing to more consistent sleep times. This update would help improve the real-time performance of wasmer. Closes: #4738 Signed-off-by: Daichi Fukui --- lib/wasix/src/syscalls/wasi/poll_oneoff.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/wasix/src/syscalls/wasi/poll_oneoff.rs b/lib/wasix/src/syscalls/wasi/poll_oneoff.rs index 2f9885c2963..8f82ac45ea9 100644 --- a/lib/wasix/src/syscalls/wasi/poll_oneoff.rs +++ b/lib/wasix/src/syscalls/wasi/poll_oneoff.rs @@ -220,6 +220,7 @@ where let pid = ctx.data().pid(); let tid = ctx.data().tid(); + let subs_len = subs.len(); // Determine if we are in silent polling mode let mut env = ctx.data(); @@ -379,10 +380,20 @@ where Some(time) } }; + let allow_blocking_current_thread = env.allow_blocking_current_thread; let tasks = env.tasks().clone(); let timeout = async move { if let Some(timeout) = timeout { - tasks.sleep_now(timeout).await; + if subs_len == 1 && allow_blocking_current_thread { + // Here, `poll_oneoff` is merely in a sleeping state + // due to a single relative timer event. This particular scenario was + // added following experimental findings indicating that std::thread::sleep + // yields more consistent sleep durations, allowing wasmer to meet + // real-time demands with greater precision. + std::thread::sleep(timeout); + } else { + tasks.sleep_now(timeout).await; + } } else { InfiniteSleep::default().await } From cb68ee97436bd861c27b4e439b457dc51e1ef76d Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Thu, 23 May 2024 21:28:03 +1000 Subject: [PATCH 3/7] Fixed the review comments --- lib/wasix/src/capabilities.rs | 6 ++ lib/wasix/src/state/env.rs | 7 +- lib/wasix/src/syscalls/wasi/poll_oneoff.rs | 81 ++++++++++++---------- 3 files changed, 53 insertions(+), 41 deletions(-) diff --git a/lib/wasix/src/capabilities.rs b/lib/wasix/src/capabilities.rs index fae47feac7d..1e87c80455c 100644 --- a/lib/wasix/src/capabilities.rs +++ b/lib/wasix/src/capabilities.rs @@ -56,6 +56,10 @@ pub struct CapabilityThreadingV1 { /// time that it will pause the CPU) /// (default = off) pub enable_exponential_cpu_backoff: Option, + + /// Switches to a blocking sleep implementation instead + /// of the asynchronous runtime based implementation + pub enable_blocking_sleep: bool, } impl CapabilityThreadingV1 { @@ -64,11 +68,13 @@ impl CapabilityThreadingV1 { max_threads, enable_asynchronous_threading, enable_exponential_cpu_backoff, + enable_blocking_sleep: _, } = other; self.enable_asynchronous_threading |= enable_asynchronous_threading; if let Some(val) = enable_exponential_cpu_backoff { self.enable_exponential_cpu_backoff = Some(val); } self.max_threads = max_threads.or(self.max_threads); + self.enable_blocking_sleep |= other.enable_blocking_sleep; } } diff --git a/lib/wasix/src/state/env.rs b/lib/wasix/src/state/env.rs index bd4420e04dc..18162370ad1 100644 --- a/lib/wasix/src/state/env.rs +++ b/lib/wasix/src/state/env.rs @@ -359,8 +359,6 @@ pub struct WasiEnv { /// not be cloned when `WasiEnv` is cloned) /// TODO: We should move this outside of `WasiEnv` with some refactoring inner: WasiInstanceHandlesPointer, - - pub allow_blocking_current_thread: bool, } impl std::fmt::Debug for WasiEnv { @@ -389,7 +387,6 @@ impl Clone for WasiEnv { enable_exponential_cpu_backoff: self.enable_exponential_cpu_backoff, replaying_journal: self.replaying_journal, disable_fs_cleanup: self.disable_fs_cleanup, - allow_blocking_current_thread: self.allow_blocking_current_thread, } } } @@ -430,7 +427,6 @@ impl WasiEnv { enable_exponential_cpu_backoff: self.enable_exponential_cpu_backoff, replaying_journal: false, disable_fs_cleanup: self.disable_fs_cleanup, - allow_blocking_current_thread: false, }; Ok((new_env, handle)) } @@ -560,7 +556,6 @@ impl WasiEnv { bin_factory: init.bin_factory, capabilities: init.capabilities, disable_fs_cleanup: false, - allow_blocking_current_thread: false, }; env.owned_handles.push(thread); @@ -1286,6 +1281,6 @@ impl WasiEnv { } pub fn allow_blocking_current_thread(&mut self, enable: bool) { - self.allow_blocking_current_thread = enable; + self.capabilities.threading.enable_blocking_sleep = enable; } } diff --git a/lib/wasix/src/syscalls/wasi/poll_oneoff.rs b/lib/wasix/src/syscalls/wasi/poll_oneoff.rs index 8f82ac45ea9..33424dd638d 100644 --- a/lib/wasix/src/syscalls/wasi/poll_oneoff.rs +++ b/lib/wasix/src/syscalls/wasi/poll_oneoff.rs @@ -380,20 +380,54 @@ where Some(time) } }; - let allow_blocking_current_thread = env.allow_blocking_current_thread; + + // Function to process a timeout + let process_timeout = { + let clock_subs = clock_subs.clone(); + |ctx: &FunctionEnvMut<'a, WasiEnv>| { + // The timeout has triggered so lets add that event + if clock_subs.is_empty() { + tracing::warn!("triggered_timeout (without any clock subscriptions)",); + } + let mut evts = Vec::new(); + for (clock_info, userdata) in clock_subs { + let evt = Event { + userdata, + error: Errno::Success, + type_: Eventtype::Clock, + u: EventUnion { clock: 0 }, + }; + Span::current().record( + "seen", + &format!( + "clock(id={},userdata={})", + clock_info.clock_id as u32, evt.userdata + ), + ); + evts.push(evt); + } + evts + } + }; + + #[cfg(feature = "sys")] + if env.capabilities.threading.enable_blocking_sleep && subs_len == 1 { + // Here, `poll_oneoff` is merely in a sleeping state + // due to a single relative timer event. This particular scenario was + // added following experimental findings indicating that std::thread::sleep + // yields more consistent sleep durations, allowing wasmer to meet + // real-time demands with greater precision. + if let Some(timeout) = timeout { + std::thread::sleep(timeout); + process_events(&ctx, process_timeout(&ctx)); + return Ok(Errno::Success); + } + } + let tasks = env.tasks().clone(); let timeout = async move { if let Some(timeout) = timeout { - if subs_len == 1 && allow_blocking_current_thread { - // Here, `poll_oneoff` is merely in a sleeping state - // due to a single relative timer event. This particular scenario was - // added following experimental findings indicating that std::thread::sleep - // yields more consistent sleep durations, allowing wasmer to meet - // real-time demands with greater precision. - std::thread::sleep(timeout); - } else { - tasks.sleep_now(timeout).await; - } + tasks.sleep_now(timeout).await; } else { InfiniteSleep::default().await } @@ -425,30 +459,7 @@ where // Process the events process_events(ctx, evts) } - Err(Errno::Timedout) => { - // The timeout has triggered so lets add that event - if clock_subs.is_empty() { - tracing::warn!("triggered_timeout (without any clock subscriptions)",); - } - let mut evts = Vec::new(); - for (clock_info, userdata) in clock_subs { - let evt = Event { - userdata, - error: Errno::Success, - type_: Eventtype::Clock, - u: EventUnion { clock: 0 }, - }; - Span::current().record( - "seen", - &format!( - "clock(id={},userdata={})", - clock_info.clock_id as u32, evt.userdata - ), - ); - evts.push(evt); - } - process_events(ctx, evts) - } + Err(Errno::Timedout) => process_events(&ctx, process_timeout(&ctx)), // If nonblocking the Errno::Again needs to be turned into an empty list Err(Errno::Again) => process_events(ctx, Default::default()), // Otherwise process the error From fb12c95b9b56459d0f5cb173acce59d4941a9b10 Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Thu, 23 May 2024 21:30:53 +1000 Subject: [PATCH 4/7] Minor fix --- lib/wasix/src/capabilities.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wasix/src/capabilities.rs b/lib/wasix/src/capabilities.rs index 1e87c80455c..fb47c122087 100644 --- a/lib/wasix/src/capabilities.rs +++ b/lib/wasix/src/capabilities.rs @@ -68,13 +68,13 @@ impl CapabilityThreadingV1 { max_threads, enable_asynchronous_threading, enable_exponential_cpu_backoff, - enable_blocking_sleep: _, + enable_blocking_sleep, } = other; self.enable_asynchronous_threading |= enable_asynchronous_threading; if let Some(val) = enable_exponential_cpu_backoff { self.enable_exponential_cpu_backoff = Some(val); } self.max_threads = max_threads.or(self.max_threads); - self.enable_blocking_sleep |= other.enable_blocking_sleep; + self.enable_blocking_sleep |= enable_blocking_sleep; } } From 1d7c0dfe8d4fe5f8e31352087b86bd8976f7da14 Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Thu, 23 May 2024 21:37:58 +1000 Subject: [PATCH 5/7] Turned blocking sleeps off by default rather than on by default --- lib/wasix/src/state/func_env.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/wasix/src/state/func_env.rs b/lib/wasix/src/state/func_env.rs index f483655315a..0934c95ec41 100644 --- a/lib/wasix/src/state/func_env.rs +++ b/lib/wasix/src/state/func_env.rs @@ -158,8 +158,6 @@ impl WasiFunctionEnv { env.state.fs.set_is_wasix(is_wasix_module); - env.allow_blocking_current_thread(true); - // If the stack offset and size is not set then do so if update_layout { // Set the base stack From 12e082dbf546dfc408d37107970fad1cb5dcbb4c Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Thu, 23 May 2024 21:39:16 +1000 Subject: [PATCH 6/7] Cleaned the interface --- lib/wasix/src/state/env.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/wasix/src/state/env.rs b/lib/wasix/src/state/env.rs index 18162370ad1..a43c9d29155 100644 --- a/lib/wasix/src/state/env.rs +++ b/lib/wasix/src/state/env.rs @@ -1279,8 +1279,4 @@ impl WasiEnv { Box::pin(async {}) } } - - pub fn allow_blocking_current_thread(&mut self, enable: bool) { - self.capabilities.threading.enable_blocking_sleep = enable; - } } From 2c6a3a40cbba3ad08ad3c84ad09fc7605c8bdb6c Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Thu, 23 May 2024 21:50:21 +1000 Subject: [PATCH 7/7] Linting fix --- lib/wasix/src/syscalls/wasi/poll_oneoff.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wasix/src/syscalls/wasi/poll_oneoff.rs b/lib/wasix/src/syscalls/wasi/poll_oneoff.rs index 33424dd638d..98f3a501e81 100644 --- a/lib/wasix/src/syscalls/wasi/poll_oneoff.rs +++ b/lib/wasix/src/syscalls/wasi/poll_oneoff.rs @@ -459,7 +459,7 @@ where // Process the events process_events(ctx, evts) } - Err(Errno::Timedout) => process_events(&ctx, process_timeout(&ctx)), + Err(Errno::Timedout) => process_events(ctx, process_timeout(ctx)), // If nonblocking the Errno::Again needs to be turned into an empty list Err(Errno::Again) => process_events(ctx, Default::default()), // Otherwise process the error