diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2022-11-10 03:56:02 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-10 17:26:02 +0530 |
commit | 110a0ebe690f83a21c87f1ef1a6a51af67e2a5fc (patch) | |
tree | 7da8bbe4db832f3011913e65654e3ef4cb1b63c3 | |
parent | bc33a4b2e06dd5518e0d1bbf7b538d0b00df214d (diff) |
perf(core): minimize trivial heap allocations in `resolve_async_ops` (#16584)
* Use stack allocated array for 16 promises and spill rest to heap. the
exact number can change, maybe 128? (tokio's coop budget limit)
* Avoid v8::Global::clone for global context.
* Do not open global opresolve when its not needed.
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | core/Cargo.toml | 1 | ||||
-rw-r--r-- | core/runtime.rs | 18 |
3 files changed, 15 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock index df49cb67b..f4fa9ce78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -943,6 +943,7 @@ dependencies = [ "serde", "serde_json", "serde_v8", + "smallvec", "sourcemap", "tokio", "url", diff --git a/core/Cargo.toml b/core/Cargo.toml index d6b869138..c72497bbf 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -32,6 +32,7 @@ pin-project = "1.0.11" serde = { version = "1.0.136", features = ["derive"] } serde_json = { version = "1.0.79", features = ["preserve_order"] } serde_v8 = { version = "0.69.0", path = "../serde_v8" } +smallvec = "1.8" sourcemap = "6.1" url = { version = "2.3.1", features = ["serde", "expose_internals"] } v8 = { version = "0.54.0", default-features = false } diff --git a/core/runtime.rs b/core/runtime.rs index b5e2141fb..21e6e7570 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -32,6 +32,7 @@ use futures::future::FutureExt; use futures::stream::FuturesUnordered; use futures::stream::StreamExt; use futures::task::AtomicWaker; +use smallvec::SmallVec; use std::any::Any; use std::cell::RefCell; use std::collections::HashMap; @@ -1972,10 +1973,13 @@ impl JsRuntime { // Send finished responses to JS fn resolve_async_ops(&mut self, cx: &mut Context) -> Result<(), Error> { let isolate = self.v8_isolate.as_mut().unwrap(); - - let js_recv_cb_handle = self.state.borrow().js_recv_cb.clone().unwrap(); - let global_realm = self.state.borrow().global_realm.clone().unwrap(); - let scope = &mut global_realm.handle_scope(isolate); + let scope = &mut self + .state + .borrow() + .global_realm + .as_ref() + .unwrap() + .handle_scope(isolate); // We return async responses to JS in unbounded batches (may change), // each batch is a flat vector of tuples: @@ -1984,7 +1988,10 @@ impl JsRuntime { // which contains a value OR an error, encoded as a tuple. // This batch is received in JS via the special `arguments` variable // and then each tuple is used to resolve or reject promises - let mut args: Vec<v8::Local<v8::Value>> = vec![]; + // + // This can handle 16 promises (32 / 2) futures in a single batch without heap + // allocations. + let mut args: SmallVec<[v8::Local<v8::Value>; 32]> = SmallVec::new(); // Now handle actual ops. { @@ -2010,6 +2017,7 @@ impl JsRuntime { return Ok(()); } + let js_recv_cb_handle = self.state.borrow().js_recv_cb.clone().unwrap(); let tc_scope = &mut v8::TryCatch::new(scope); let js_recv_cb = js_recv_cb_handle.open(tc_scope); let this = v8::undefined(tc_scope).into(); |