mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 00:29:09 -05:00
167 lines
4.4 KiB
Rust
167 lines
4.4 KiB
Rust
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use std::collections::HashMap;
|
|
use std::net::TcpStream;
|
|
use std::path::Path;
|
|
use std::process::Command;
|
|
use std::sync::atomic::AtomicU16;
|
|
use std::sync::atomic::Ordering;
|
|
use std::time::Duration;
|
|
use std::time::Instant;
|
|
|
|
use super::Result;
|
|
|
|
pub use test_util::parse_wrk_output;
|
|
pub use test_util::WrkOutput as HttpBenchmarkResult;
|
|
// Some of the benchmarks in this file have been renamed. In case the history
|
|
// somehow gets messed up:
|
|
// "node_http" was once called "node"
|
|
// "deno_tcp" was once called "deno"
|
|
// "deno_http" was once called "deno_net_http"
|
|
|
|
const DURATION: &str = "10s";
|
|
|
|
pub fn benchmark(
|
|
target_path: &Path,
|
|
) -> Result<HashMap<String, HttpBenchmarkResult>> {
|
|
let deno_exe = test_util::deno_exe_path();
|
|
let deno_exe = deno_exe.to_string();
|
|
|
|
let hyper_hello_exe = target_path.join("test_server");
|
|
let hyper_hello_exe = hyper_hello_exe.to_str().unwrap();
|
|
|
|
let mut res = HashMap::new();
|
|
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
|
let http_dir = manifest_dir.join("bench").join("http");
|
|
for entry in std::fs::read_dir(&http_dir)? {
|
|
let entry = entry?;
|
|
let pathbuf = entry.path();
|
|
let path = pathbuf.to_str().unwrap();
|
|
if path.ends_with(".lua") {
|
|
continue;
|
|
}
|
|
let file_stem = pathbuf.file_stem().unwrap().to_str().unwrap();
|
|
|
|
let lua_script = http_dir.join(format!("{file_stem}.lua"));
|
|
let mut maybe_lua = None;
|
|
if lua_script.exists() {
|
|
maybe_lua = Some(lua_script.to_str().unwrap());
|
|
}
|
|
|
|
let port = get_port();
|
|
// deno run -A --unstable <path> <addr>
|
|
res.insert(
|
|
file_stem.to_string(),
|
|
run(
|
|
&[
|
|
deno_exe.as_str(),
|
|
"run",
|
|
"--allow-all",
|
|
"--unstable",
|
|
"--enable-testing-features-do-not-use",
|
|
path,
|
|
&server_addr(port),
|
|
],
|
|
port,
|
|
None,
|
|
None,
|
|
maybe_lua,
|
|
)?,
|
|
);
|
|
}
|
|
|
|
res.insert("hyper".to_string(), hyper_http(hyper_hello_exe)?);
|
|
|
|
Ok(res)
|
|
}
|
|
|
|
fn run(
|
|
server_cmd: &[&str],
|
|
port: u16,
|
|
env: Option<Vec<(String, String)>>,
|
|
origin_cmd: Option<&[&str]>,
|
|
lua_script: Option<&str>,
|
|
) -> Result<HttpBenchmarkResult> {
|
|
// Wait for port 4544 to become available.
|
|
// TODO Need to use SO_REUSEPORT with tokio::net::TcpListener.
|
|
std::thread::sleep(Duration::from_secs(5));
|
|
|
|
let mut origin = None;
|
|
if let Some(cmd) = origin_cmd {
|
|
let mut com = Command::new(cmd[0]);
|
|
com.args(&cmd[1..]);
|
|
if let Some(env) = env.clone() {
|
|
com.envs(env);
|
|
}
|
|
origin = Some(com.spawn()?);
|
|
};
|
|
|
|
println!("{}", server_cmd.join(" "));
|
|
let mut server = {
|
|
let mut com = Command::new(server_cmd[0]);
|
|
com.args(&server_cmd[1..]);
|
|
if let Some(env) = env {
|
|
com.envs(env);
|
|
}
|
|
com.spawn()?
|
|
};
|
|
|
|
// Wait for server to wake up.
|
|
let now = Instant::now();
|
|
let addr = format!("127.0.0.1:{port}");
|
|
while now.elapsed().as_secs() < 30 {
|
|
if TcpStream::connect(&addr).is_ok() {
|
|
break;
|
|
}
|
|
std::thread::sleep(Duration::from_millis(10));
|
|
}
|
|
TcpStream::connect(&addr).expect("Failed to connect to server in time");
|
|
println!("Server took {} ms to start", now.elapsed().as_millis());
|
|
|
|
let wrk = test_util::prebuilt_tool_path("wrk");
|
|
assert!(wrk.is_file());
|
|
|
|
let addr = format!("http://{addr}/");
|
|
let wrk = wrk.to_string();
|
|
let mut wrk_cmd = vec![wrk.as_str(), "-d", DURATION, "--latency", &addr];
|
|
|
|
if let Some(lua_script) = lua_script {
|
|
wrk_cmd.push("-s");
|
|
wrk_cmd.push(lua_script);
|
|
}
|
|
|
|
println!("{}", wrk_cmd.join(" "));
|
|
let output = test_util::run_collect(&wrk_cmd, None, None, None, true).0;
|
|
|
|
std::thread::sleep(Duration::from_secs(1)); // wait to capture failure. TODO racy.
|
|
|
|
println!("{output}");
|
|
assert!(
|
|
server.try_wait()?.map(|s| s.success()).unwrap_or(true),
|
|
"server ended with error"
|
|
);
|
|
|
|
server.kill()?;
|
|
if let Some(mut origin) = origin {
|
|
origin.kill()?;
|
|
}
|
|
|
|
Ok(parse_wrk_output(&output))
|
|
}
|
|
|
|
static NEXT_PORT: AtomicU16 = AtomicU16::new(4544);
|
|
pub(crate) fn get_port() -> u16 {
|
|
let p = NEXT_PORT.load(Ordering::SeqCst);
|
|
NEXT_PORT.store(p.wrapping_add(1), Ordering::SeqCst);
|
|
p
|
|
}
|
|
|
|
fn server_addr(port: u16) -> String {
|
|
format!("0.0.0.0:{port}")
|
|
}
|
|
|
|
fn hyper_http(exe: &str) -> Result<HttpBenchmarkResult> {
|
|
let port = get_port();
|
|
println!("http_benchmark testing RUST hyper");
|
|
run(&[exe, &port.to_string()], port, None, None, None)
|
|
}
|