2022-01-07 22:09:52 -05:00
|
|
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
2020-08-28 09:03:50 -04:00
|
|
|
|
|
|
|
use super::Result;
|
2021-03-25 14:17:37 -04:00
|
|
|
use std::{collections::HashMap, path::Path, process::Command, time::Duration};
|
2020-08-28 09:03:50 -04:00
|
|
|
pub use test_util::{parse_wrk_output, 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 = "20s";
|
|
|
|
|
2022-03-23 09:54:22 -04:00
|
|
|
pub fn benchmark(
|
2021-03-25 14:17:37 -04:00
|
|
|
target_path: &Path,
|
2020-08-28 09:03:50 -04:00
|
|
|
) -> Result<HashMap<String, HttpBenchmarkResult>> {
|
|
|
|
let deno_exe = test_util::deno_exe_path();
|
|
|
|
let deno_exe = deno_exe.to_str().unwrap();
|
|
|
|
|
|
|
|
let hyper_hello_exe = target_path.join("test_server");
|
|
|
|
let hyper_hello_exe = hyper_hello_exe.to_str().unwrap();
|
|
|
|
|
|
|
|
let core_http_json_ops_exe = target_path.join("examples/http_bench_json_ops");
|
|
|
|
let core_http_json_ops_exe = core_http_json_ops_exe.to_str().unwrap();
|
|
|
|
|
|
|
|
let mut res = HashMap::new();
|
|
|
|
|
|
|
|
// "deno_tcp" was once called "deno"
|
|
|
|
res.insert("deno_tcp".to_string(), deno_tcp(deno_exe)?);
|
|
|
|
// res.insert("deno_udp".to_string(), deno_udp(deno_exe)?);
|
|
|
|
res.insert("deno_http".to_string(), deno_http(deno_exe)?);
|
2021-04-08 18:34:15 -04:00
|
|
|
res.insert("deno_http_native".to_string(), deno_http_native(deno_exe)?);
|
2021-04-12 15:55:05 -04:00
|
|
|
// "core_http_json_ops" previously had a "bin op" counterpart called "core_http_bin_ops",
|
|
|
|
// which was previously also called "deno_core_http_bench", "deno_core_single"
|
2020-08-28 09:03:50 -04:00
|
|
|
res.insert(
|
|
|
|
"core_http_json_ops".to_string(),
|
|
|
|
core_http_json_ops(core_http_json_ops_exe)?,
|
|
|
|
);
|
|
|
|
// "node_http" was once called "node"
|
|
|
|
res.insert("node_http".to_string(), node_http()?);
|
|
|
|
res.insert("node_tcp".to_string(), node_tcp()?);
|
|
|
|
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]>,
|
|
|
|
) -> 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()?
|
|
|
|
};
|
|
|
|
|
|
|
|
std::thread::sleep(Duration::from_secs(5)); // wait for server to wake up. TODO racy.
|
|
|
|
|
|
|
|
let wrk = test_util::prebuilt_tool_path("wrk");
|
|
|
|
assert!(wrk.is_file());
|
|
|
|
|
|
|
|
let wrk_cmd = &[
|
|
|
|
wrk.to_str().unwrap(),
|
|
|
|
"-d",
|
|
|
|
DURATION,
|
|
|
|
"--latency",
|
|
|
|
&format!("http://127.0.0.1:{}/", port),
|
|
|
|
];
|
|
|
|
println!("{}", wrk_cmd.join(" "));
|
|
|
|
let output = test_util::run_collect(wrk_cmd, None, None, None, true).0;
|
|
|
|
|
2021-04-08 12:04:02 -04:00
|
|
|
std::thread::sleep(Duration::from_secs(1)); // wait to capture failure. TODO racy.
|
|
|
|
|
2020-08-28 09:03:50 -04:00
|
|
|
println!("{}", output);
|
|
|
|
assert!(
|
|
|
|
server.try_wait()?.map_or(true, |s| s.success()),
|
|
|
|
"server ended with error"
|
|
|
|
);
|
|
|
|
|
|
|
|
server.kill()?;
|
|
|
|
if let Some(mut origin) = origin {
|
|
|
|
origin.kill()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(parse_wrk_output(&output))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_port() -> u16 {
|
|
|
|
static mut NEXT_PORT: u16 = 4544;
|
|
|
|
|
|
|
|
let port = unsafe { NEXT_PORT };
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
NEXT_PORT += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
port
|
|
|
|
}
|
|
|
|
|
|
|
|
fn server_addr(port: u16) -> String {
|
|
|
|
format!("0.0.0.0:{}", port)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn deno_tcp(deno_exe: &str) -> Result<HttpBenchmarkResult> {
|
|
|
|
let port = get_port();
|
|
|
|
println!("http_benchmark testing DENO tcp.");
|
|
|
|
run(
|
|
|
|
&[
|
|
|
|
deno_exe,
|
|
|
|
"run",
|
|
|
|
"--allow-net",
|
|
|
|
"cli/bench/deno_tcp.ts",
|
|
|
|
&server_addr(port),
|
|
|
|
],
|
|
|
|
port,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn deno_http(deno_exe: &str) -> Result<HttpBenchmarkResult> {
|
|
|
|
let port = get_port();
|
|
|
|
println!("http_benchmark testing DENO using net/http.");
|
|
|
|
run(
|
|
|
|
&[
|
|
|
|
deno_exe,
|
|
|
|
"run",
|
|
|
|
"--allow-net",
|
|
|
|
"--reload",
|
|
|
|
"--unstable",
|
2021-02-02 06:05:46 -05:00
|
|
|
"test_util/std/http/bench.ts",
|
2020-08-28 09:03:50 -04:00
|
|
|
&server_addr(port),
|
|
|
|
],
|
|
|
|
port,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-04-08 18:34:15 -04:00
|
|
|
fn deno_http_native(deno_exe: &str) -> Result<HttpBenchmarkResult> {
|
|
|
|
let port = get_port();
|
|
|
|
println!("http_benchmark testing DENO using native bindings.");
|
|
|
|
run(
|
|
|
|
&[
|
|
|
|
deno_exe,
|
|
|
|
"run",
|
|
|
|
"--allow-net",
|
|
|
|
"--reload",
|
|
|
|
"cli/bench/deno_http_native.js",
|
|
|
|
&server_addr(port),
|
|
|
|
],
|
|
|
|
port,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-08-28 09:03:50 -04:00
|
|
|
fn core_http_json_ops(exe: &str) -> Result<HttpBenchmarkResult> {
|
|
|
|
println!("http_benchmark testing CORE http_bench_json_ops");
|
|
|
|
run(&[exe], 4544, None, None)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn node_http() -> Result<HttpBenchmarkResult> {
|
|
|
|
let port = get_port();
|
|
|
|
println!("http_benchmark testing NODE.");
|
|
|
|
run(
|
|
|
|
&["node", "cli/bench/node_http.js", &port.to_string()],
|
|
|
|
port,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn node_tcp() -> Result<HttpBenchmarkResult> {
|
|
|
|
let port = get_port();
|
|
|
|
println!("http_benchmark testing node_tcp.js");
|
|
|
|
run(
|
|
|
|
&["node", "cli/bench/node_tcp.js", &port.to_string()],
|
|
|
|
port,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn hyper_http(exe: &str) -> Result<HttpBenchmarkResult> {
|
|
|
|
let port = get_port();
|
|
|
|
println!("http_benchmark testing RUST hyper");
|
2020-11-09 09:38:29 -05:00
|
|
|
run(&[exe, &port.to_string()], port, None, None)
|
2020-08-28 09:03:50 -04:00
|
|
|
}
|