use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
use deno_core::FsModuleLoader;
use deno_core::ModuleCodeString;
use deno_core::resolve_path;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmResolver;
use deno_runtime::deno_fs::RealFs;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use deno_runtime::worker::MainWorker;
use deno_runtime::worker::WorkerOptions;
use deno_runtime::worker::WorkerServiceOptions;
#[allow(clippy::disallowed_types, reason = "example binary")]
type Sys = sys_traits::impls::RealSys;
fn bootstrap_once() -> MainWorker {
#[allow(
clippy::disallowed_methods,
reason = "example binary, no `initial_cwd` to thread"
)]
let cwd = std::env::current_dir().unwrap();
let main_module = resolve_path("./startup_bench.js", &cwd).unwrap();
let fs = Arc::new(RealFs);
let permission_desc_parser =
Arc::new(RuntimePermissionDescriptorParser::new(Sys::default()));
let options = WorkerOptions {
startup_snapshot: deno_snapshots::CLI_SNAPSHOT,
residual_lazy_js_sources: deno_snapshots::RESIDUAL_LAZY_JS,
residual_lazy_esm_sources: deno_snapshots::RESIDUAL_LAZY_ESM,
..Default::default()
};
MainWorker::bootstrap_from_options::<
DenoInNpmPackageChecker,
NpmResolver<Sys>,
Sys,
>(
&main_module,
WorkerServiceOptions {
deno_rt_native_addon_loader: None,
module_loader: Rc::new(FsModuleLoader),
permissions: PermissionsContainer::new(
permission_desc_parser,
Permissions::none_without_prompt(),
),
blob_store: std::sync::Arc::new(
deno_runtime::deno_web::BlobStore::default(),
)
as std::sync::Arc<dyn deno_runtime::deno_web::BlobStoreTrait>,
broadcast_channel: Default::default(),
feature_checker: Default::default(),
node_services: Default::default(),
npm_process_state_provider: Default::default(),
root_cert_store_provider: Default::default(),
fetch_dns_resolver: Default::default(),
shared_array_buffer_store: Default::default(),
compiled_wasm_module_store: Default::default(),
v8_code_cache: Default::default(),
fs,
bundle_provider: None,
},
options,
)
}
fn one_iter() -> Duration {
let start = Instant::now();
let mut worker = bootstrap_once();
worker
.execute_script("[startup_bench]", ModuleCodeString::from_static("1 + 1"))
.expect("execute_script failed");
let elapsed = start.elapsed();
drop(worker);
elapsed
}
fn summarize(label: &str, samples: &mut [Duration]) {
samples.sort();
let n = samples.len();
let min = samples[0];
let p50 = samples[n / 2];
let p95 = samples[(n * 95) / 100];
let max = samples[n - 1];
let sum: Duration = samples.iter().sum();
let mean = sum / n as u32;
#[allow(clippy::print_stdout, reason = "example output")]
{
println!(
"{label:>10} n={n:<3} min={:>7.2?} p50={:>7.2?} mean={:>7.2?} p95={:>7.2?} max={:>7.2?}",
min, p50, mean, p95, max,
);
}
}
fn main() {
let iters: usize = std::env::args()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(20);
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let _guard = rt.enter();
let warmup = one_iter();
#[allow(clippy::print_stdout, reason = "example output")]
{
println!(
" warmup n=1 {warmup:?} (V8 platform init + first bootstrap)"
);
}
let mut samples = Vec::with_capacity(iters);
for _ in 0..iters {
samples.push(one_iter());
}
summarize("steady", &mut samples);
}