From eb961ba832f27bd8fec14127a20a2f81499d7d2d Mon Sep 17 00:00:00 2001 From: Zaid <161572905+iammdzaidalam@users.noreply.github.com> Date: Sat, 21 Mar 2026 03:48:45 +0530 Subject: [PATCH] bench: lazily initialize script benchmarks --- benches/benches/scripts.rs | 73 +++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/benches/benches/scripts.rs b/benches/benches/scripts.rs index b185966773c..0d20e3fc952 100644 --- a/benches/benches/scripts.rs +++ b/benches/benches/scripts.rs @@ -1,6 +1,7 @@ #![allow(unused_crate_dependencies, missing_docs)] use boa_engine::{ - Context, JsValue, Source, js_string, optimizer::OptimizerOptions, script::Script, + Context, JsValue, Source, js_string, object::JsObject, optimizer::OptimizerOptions, + script::Script, }; use criterion::{Criterion, criterion_group, criterion_main}; use std::{path::Path, time::Duration}; @@ -9,6 +10,39 @@ use std::{path::Path, time::Duration}; #[global_allocator] static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; +struct PreparedScriptBench { + context: Context, + function: JsObject, +} + +fn prepare_script_bench(path: &Path) -> PreparedScriptBench { + let code = std::fs::read_to_string(path).unwrap(); + + let mut context = Context::default(); + context.set_optimizer_options(OptimizerOptions::empty()); + + boa_runtime::register( + boa_runtime::extensions::ConsoleExtension(boa_runtime::NullLogger), + None, + &mut context, + ) + .expect("Runtime registration failed"); + + let script = Script::parse(Source::from_bytes(&code), None, &mut context).unwrap(); + script.codeblock(&mut context).unwrap(); + script.evaluate(&mut context).unwrap(); + + let function = context + .global_object() + .get(js_string!("main"), &mut context) + .unwrap_or_else(|_| panic!("No main function defined in script: {}", path.display())) + .as_callable() + .unwrap_or_else(|| panic!("'main' is not a function in script: {}", path.display())) + .clone(); + + PreparedScriptBench { context, function } +} + fn bench_scripts(c: &mut Criterion) { let scripts_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("scripts"); @@ -26,49 +60,24 @@ fn bench_scripts(c: &mut Criterion) { for entry in scripts { let path = entry.path(); - let code = std::fs::read_to_string(path).unwrap(); - // Create a nice benchmark name from the relative path let rel_path = path.strip_prefix(&scripts_dir).unwrap().with_extension(""); let name = rel_path.display().to_string(); let mut group = c.benchmark_group(&name); - // Use reduced sample size for slow benchmarks (e.g., v8-benches) if rel_path.starts_with("v8-benches") { group.sample_size(10); group.measurement_time(Duration::from_secs(5)); } - let context = &mut Context::default(); - - // Disable optimizations - context.set_optimizer_options(OptimizerOptions::empty()); - - // Register runtime for console.log support - boa_runtime::register( - boa_runtime::extensions::ConsoleExtension(boa_runtime::NullLogger), - None, - context, - ) - .expect("Runtime registration failed"); - - // Parse and compile once, outside the benchmark loop - let script = Script::parse(Source::from_bytes(&code), None, context).unwrap(); - script.codeblock(context).unwrap(); - - // Evaluate once to define the main function - script.evaluate(context).unwrap(); + let path = path.to_path_buf(); + let mut prepared: Option = None; - // Get the main function - let function = context - .global_object() - .get(js_string!("main"), context) - .unwrap_or_else(|_| panic!("No main function defined in script: {}", path.display())) - .as_callable() - .unwrap_or_else(|| panic!("'main' is not a function in script: {}", path.display())) - .clone(); + group.bench_function("Execution", move |b| { + let prepared = prepared.get_or_insert_with(|| prepare_script_bench(&path)); + let function = prepared.function.clone(); + let context = &mut prepared.context; - group.bench_function("Execution", |b| { b.iter(|| function.call(&JsValue::undefined(), &[], context)); }); group.finish();