From 4305bb4bd8ec3747031ee92baa8e55d50d22b47c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 8 Jun 2022 17:33:38 +0530 Subject: chore(bench): generalized HTTP benchmarks framework (#14815) --- cli/bench/deno_http_native.js | 19 ---- cli/bench/deno_http_native_headers.js | 22 ---- cli/bench/deno_tcp.ts | 33 ------ cli/bench/http.rs | 156 ++++++++++++----------------- cli/bench/http/deno_http_native.js | 19 ++++ cli/bench/http/deno_http_native_headers.js | 22 ++++ cli/bench/http/deno_tcp.ts | 33 ++++++ cli/bench/http/node_http.js | 9 ++ cli/bench/http/node_tcp.js | 18 ++++ cli/bench/node_http.js | 9 -- cli/bench/node_tcp.js | 18 ---- cli/bench/node_tcp_proxy.js | 69 ------------- 12 files changed, 163 insertions(+), 264 deletions(-) delete mode 100644 cli/bench/deno_http_native.js delete mode 100644 cli/bench/deno_http_native_headers.js delete mode 100644 cli/bench/deno_tcp.ts create mode 100644 cli/bench/http/deno_http_native.js create mode 100644 cli/bench/http/deno_http_native_headers.js create mode 100644 cli/bench/http/deno_tcp.ts create mode 100644 cli/bench/http/node_http.js create mode 100644 cli/bench/http/node_tcp.js delete mode 100644 cli/bench/node_http.js delete mode 100644 cli/bench/node_tcp.js delete mode 100644 cli/bench/node_tcp_proxy.js (limited to 'cli') diff --git a/cli/bench/deno_http_native.js b/cli/bench/deno_http_native.js deleted file mode 100644 index a45416ada..000000000 --- a/cli/bench/deno_http_native.js +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -const addr = Deno.args[0] || "127.0.0.1:4500"; -const [hostname, port] = addr.split(":"); -const listener = Deno.listen({ hostname, port: Number(port) }); -console.log("Server listening on", addr); - -const encoder = new TextEncoder(); -const body = encoder.encode("Hello World"); - -for await (const conn of listener) { - (async () => { - const requests = Deno.serveHttp(conn); - for await (const event of requests) { - event.respondWith(new Response(body)) - .catch((e) => console.log(e)); - } - })(); -} diff --git a/cli/bench/deno_http_native_headers.js b/cli/bench/deno_http_native_headers.js deleted file mode 100644 index 23ef1e060..000000000 --- a/cli/bench/deno_http_native_headers.js +++ /dev/null @@ -1,22 +0,0 @@ -const addr = Deno.args[0] || "127.0.0.1:4500"; -const [hostname, port] = addr.split(":"); -const listener = Deno.listen({ hostname, port: Number(port) }); -console.log("Server listening on", addr); - -for await (const conn of listener) { - (async () => { - const requests = Deno.serveHttp(conn); - for await (const { respondWith } of requests) { - respondWith( - new Response("Hello World", { - status: 200, - headers: { - server: "deno", - "content-type": "text/plain", - }, - }), - ) - .catch((e) => console.log(e)); - } - })(); -} diff --git a/cli/bench/deno_tcp.ts b/cli/bench/deno_tcp.ts deleted file mode 100644 index 43b4d2264..000000000 --- a/cli/bench/deno_tcp.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -// Used for benchmarking Deno's networking. -// TODO(bartlomieju): Replace this with a real HTTP server once -// https://github.com/denoland/deno/issues/726 is completed. -// Note: this is a keep-alive server. -const addr = Deno.args[0] || "127.0.0.1:4500"; -const [hostname, port] = addr.split(":"); -const listener = Deno.listen({ hostname, port: Number(port) }); -const response = new TextEncoder().encode( - "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n", -); -async function handle(conn: Deno.Conn): Promise { - const buffer = new Uint8Array(1024); - try { - while (true) { - await conn.read(buffer); - await conn.write(response); - } - } catch (e) { - if ( - !(e instanceof Deno.errors.BrokenPipe) && - !(e instanceof Deno.errors.ConnectionReset) - ) { - throw e; - } - } - conn.close(); -} - -console.log("Listening on", addr); -for await (const conn of listener) { - handle(conn); -} diff --git a/cli/bench/http.rs b/cli/bench/http.rs index b000bc285..83f8eef8b 100644 --- a/cli/bench/http.rs +++ b/cli/bench/http.rs @@ -25,21 +25,62 @@ pub fn benchmark( let core_http_json_ops_exe = core_http_json_ops_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.clone())? { + let entry = entry?; + let pathbuf = entry.path(); + let path = pathbuf.to_str().unwrap(); + let name = entry.file_name().into_string().unwrap(); + let file_stem = pathbuf.file_stem().unwrap().to_str().unwrap(); + + let lua_script = http_dir.join(format!("{}.lua", file_stem)); + let mut maybe_lua = None; + if lua_script.exists() { + maybe_lua = Some(lua_script.to_str().unwrap()); + } + + let port = get_port(); + if name.starts_with("node") { + // node + res.insert( + name, + run( + &["node", path, &port.to_string()], + port, + None, + None, + maybe_lua, + )?, + ); + } else { + // deno run -A --unstable + res.insert( + name, + run( + &[ + deno_exe, + "run", + "--allow-all", + "--unstable", + path, + &server_addr(port), + ], + port, + None, + None, + maybe_lua, + )?, + ); + } + } - // "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)?); - res.insert("deno_http_native".to_string(), deno_http_native(deno_exe)?); // "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" 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) @@ -50,6 +91,7 @@ fn run( port: u16, env: Option>, origin_cmd: Option<&[&str]>, + lua_script: Option<&str>, ) -> Result { // Wait for port 4544 to become available. // TODO Need to use SO_REUSEPORT with tokio::net::TcpListener. @@ -80,15 +122,17 @@ fn run( 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), - ]; + let addr = format!("http://127.0.0.1:{}/", port); + let mut wrk_cmd = + vec![wrk.to_str().unwrap(), "-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; + 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. @@ -122,89 +166,13 @@ fn server_addr(port: u16) -> String { format!("0.0.0.0:{}", port) } -fn deno_tcp(deno_exe: &str) -> Result { - 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 { - let port = get_port(); - println!("http_benchmark testing DENO using net/http."); - run( - &[ - deno_exe, - "run", - "--allow-net", - "--reload", - "--unstable", - "test_util/std/http/bench.ts", - &server_addr(port), - ], - port, - None, - None, - ) -} - -fn deno_http_native(deno_exe: &str) -> Result { - 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, - ) -} - fn core_http_json_ops(exe: &str) -> Result { println!("http_benchmark testing CORE http_bench_json_ops"); - run(&[exe], 4544, None, None) -} - -fn node_http() -> Result { - 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 { - let port = get_port(); - println!("http_benchmark testing node_tcp.js"); - run( - &["node", "cli/bench/node_tcp.js", &port.to_string()], - port, - None, - None, - ) + run(&[exe], 4544, None, None, None) } fn hyper_http(exe: &str) -> Result { let port = get_port(); println!("http_benchmark testing RUST hyper"); - run(&[exe, &port.to_string()], port, None, None) + run(&[exe, &port.to_string()], port, None, None, None) } diff --git a/cli/bench/http/deno_http_native.js b/cli/bench/http/deno_http_native.js new file mode 100644 index 000000000..a45416ada --- /dev/null +++ b/cli/bench/http/deno_http_native.js @@ -0,0 +1,19 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +const addr = Deno.args[0] || "127.0.0.1:4500"; +const [hostname, port] = addr.split(":"); +const listener = Deno.listen({ hostname, port: Number(port) }); +console.log("Server listening on", addr); + +const encoder = new TextEncoder(); +const body = encoder.encode("Hello World"); + +for await (const conn of listener) { + (async () => { + const requests = Deno.serveHttp(conn); + for await (const event of requests) { + event.respondWith(new Response(body)) + .catch((e) => console.log(e)); + } + })(); +} diff --git a/cli/bench/http/deno_http_native_headers.js b/cli/bench/http/deno_http_native_headers.js new file mode 100644 index 000000000..23ef1e060 --- /dev/null +++ b/cli/bench/http/deno_http_native_headers.js @@ -0,0 +1,22 @@ +const addr = Deno.args[0] || "127.0.0.1:4500"; +const [hostname, port] = addr.split(":"); +const listener = Deno.listen({ hostname, port: Number(port) }); +console.log("Server listening on", addr); + +for await (const conn of listener) { + (async () => { + const requests = Deno.serveHttp(conn); + for await (const { respondWith } of requests) { + respondWith( + new Response("Hello World", { + status: 200, + headers: { + server: "deno", + "content-type": "text/plain", + }, + }), + ) + .catch((e) => console.log(e)); + } + })(); +} diff --git a/cli/bench/http/deno_tcp.ts b/cli/bench/http/deno_tcp.ts new file mode 100644 index 000000000..43b4d2264 --- /dev/null +++ b/cli/bench/http/deno_tcp.ts @@ -0,0 +1,33 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +// Used for benchmarking Deno's networking. +// TODO(bartlomieju): Replace this with a real HTTP server once +// https://github.com/denoland/deno/issues/726 is completed. +// Note: this is a keep-alive server. +const addr = Deno.args[0] || "127.0.0.1:4500"; +const [hostname, port] = addr.split(":"); +const listener = Deno.listen({ hostname, port: Number(port) }); +const response = new TextEncoder().encode( + "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n", +); +async function handle(conn: Deno.Conn): Promise { + const buffer = new Uint8Array(1024); + try { + while (true) { + await conn.read(buffer); + await conn.write(response); + } + } catch (e) { + if ( + !(e instanceof Deno.errors.BrokenPipe) && + !(e instanceof Deno.errors.ConnectionReset) + ) { + throw e; + } + } + conn.close(); +} + +console.log("Listening on", addr); +for await (const conn of listener) { + handle(conn); +} diff --git a/cli/bench/http/node_http.js b/cli/bench/http/node_http.js new file mode 100644 index 000000000..3380c86a5 --- /dev/null +++ b/cli/bench/http/node_http.js @@ -0,0 +1,9 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +const http = require("http"); +const port = process.argv[2] || "4544"; +console.log("port", port); +http + .Server((req, res) => { + res.end("Hello World"); + }) + .listen(port); diff --git a/cli/bench/http/node_tcp.js b/cli/bench/http/node_tcp.js new file mode 100644 index 000000000..cb51a63a5 --- /dev/null +++ b/cli/bench/http/node_tcp.js @@ -0,0 +1,18 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +// Note: this is a keep-alive server. +const { Server } = require("net"); +const port = process.argv[2] || "4544"; +console.log("port", port); + +const response = Buffer.from( + "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n", +); + +Server((socket) => { + socket.on("data", (_) => { + socket.write(response); + }); + socket.on("error", (_) => { + socket.destroy(); + }); +}).listen(port); diff --git a/cli/bench/node_http.js b/cli/bench/node_http.js deleted file mode 100644 index 3380c86a5..000000000 --- a/cli/bench/node_http.js +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -const http = require("http"); -const port = process.argv[2] || "4544"; -console.log("port", port); -http - .Server((req, res) => { - res.end("Hello World"); - }) - .listen(port); diff --git a/cli/bench/node_tcp.js b/cli/bench/node_tcp.js deleted file mode 100644 index cb51a63a5..000000000 --- a/cli/bench/node_tcp.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -// Note: this is a keep-alive server. -const { Server } = require("net"); -const port = process.argv[2] || "4544"; -console.log("port", port); - -const response = Buffer.from( - "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n", -); - -Server((socket) => { - socket.on("data", (_) => { - socket.write(response); - }); - socket.on("error", (_) => { - socket.destroy(); - }); -}).listen(port); diff --git a/cli/bench/node_tcp_proxy.js b/cli/bench/node_tcp_proxy.js deleted file mode 100644 index 8b4b958d7..000000000 --- a/cli/bench/node_tcp_proxy.js +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -const net = require("net"); - -process.on("uncaughtException", function (error) { - console.error(error); -}); - -if (process.argv.length != 4) { - console.log("usage: %s ", process.argv[1]); - process.exit(); -} - -const localport = process.argv[2]; -const remoteport = process.argv[3]; - -const remotehost = "127.0.0.1"; - -const server = net.createServer(function (localsocket) { - const remotesocket = new net.Socket(); - - remotesocket.connect(remoteport, remotehost); - - localsocket.on("data", function (data) { - const flushed = remotesocket.write(data); - if (!flushed) { - localsocket.pause(); - } - }); - - remotesocket.on("data", function (data) { - const flushed = localsocket.write(data); - if (!flushed) { - remotesocket.pause(); - } - }); - - localsocket.on("drain", function () { - remotesocket.resume(); - }); - - remotesocket.on("drain", function () { - localsocket.resume(); - }); - - localsocket.on("close", function () { - remotesocket.end(); - }); - - remotesocket.on("close", function () { - localsocket.end(); - }); - - localsocket.on("error", function () { - localsocket.end(); - }); - - remotesocket.on("error", function () { - remotesocket.end(); - }); -}); - -server.listen(localport); - -console.log( - "redirecting connections from 127.0.0.1:%d to %s:%d", - localport, - remotehost, - remoteport, -); -- cgit v1.2.3