diff --git a/bin/light-base/src/json_rpc_service.rs b/bin/light-base/src/json_rpc_service.rs index 0aa54b1823..ec385d9165 100644 --- a/bin/light-base/src/json_rpc_service.rs +++ b/bin/light-base/src/json_rpc_service.rs @@ -595,7 +595,7 @@ impl Background { // We yield once between each request in order to politely let other tasks // do some work and not monopolize the CPU. - crate::util::yield_once().await; + crate::util::yield_twice().await; } } .boxed(), diff --git a/bin/light-base/src/runtime_service.rs b/bin/light-base/src/runtime_service.rs index dc255f4ae8..feca2fa872 100644 --- a/bin/light-base/src/runtime_service.rs +++ b/bin/light-base/src/runtime_service.rs @@ -2017,7 +2017,7 @@ impl SuccessfulRuntime { heap_pages: &Option>, ) -> Result { // Since compiling the runtime is a CPU-intensive operation, we yield once before. - crate::util::yield_once().await; + crate::util::yield_twice().await; // Parameters for `HostVmPrototype::new`. let module = code.as_ref().ok_or(RuntimeError::CodeNotFound)?; diff --git a/bin/light-base/src/sync_service/standalone.rs b/bin/light-base/src/sync_service/standalone.rs index a3d1ce1945..8005330733 100644 --- a/bin/light-base/src/sync_service/standalone.rs +++ b/bin/light-base/src/sync_service/standalone.rs @@ -135,7 +135,7 @@ pub(super) async fn start_standalone_chain( // in a row would prevent all the other tasks in the background from running. // In order to provide a better granularity, we force a yield after each // verification. - crate::util::yield_once().await; + crate::util::yield_twice().await; } queue_empty diff --git a/bin/light-base/src/util.rs b/bin/light-base/src/util.rs index d36545eda4..494da2d871 100644 --- a/bin/light-base/src/util.rs +++ b/bin/light-base/src/util.rs @@ -16,14 +16,25 @@ // along with this program. If not, see . /// Use in an asynchronous context to interrupt the current task execution and schedule it back. +/// Twice. /// /// This function is useful in order to guarantee a fine granularity of tasks execution time in /// situations where a CPU-heavy task is being performed. -pub async fn yield_once() { - let mut pending = true; +/// +/// We do not yield once, but twice. +/// The reason is that, at the time of writing, `FuturesUnordered` yields to the outside after +/// one of its futures has yielded twice. We use `FuturesUnordered` in the Wasm node. +/// Yielding to the outside is important in the context of the browser node because it gives +/// time to the browser to run its own events loop. +/// See +/// See for a discussion about a proper +/// solution. +// TODO: this is a complete hack ^ +pub async fn yield_twice() { + let mut num_pending_remain = 2; futures::future::poll_fn(move |cx| { - if pending { - pending = false; + if num_pending_remain > 0 { + num_pending_remain -= 1; cx.waker().wake_by_ref(); core::task::Poll::Pending } else { diff --git a/bin/wasm-node/CHANGELOG.md b/bin/wasm-node/CHANGELOG.md index c2a8eb7ad5..0d09d3e466 100644 --- a/bin/wasm-node/CHANGELOG.md +++ b/bin/wasm-node/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Fixed + +- CPU-heavy operations such as verifying finality proofs or compiling the runtime will now better respect the CPU rate limit. ([#2803](https://github.com/paritytech/smoldot/pull/2803)) + ## 0.7.0 - 2022-09-28 ### Removed