diff --git a/http2/benchmark.py b/http2/benchmark.py index c182649..e5a3b22 100644 --- a/http2/benchmark.py +++ b/http2/benchmark.py @@ -1,31 +1,99 @@ +import argparse +import shlex import subprocess import time import os +import signal -def run_benchmark(): - print(f"Running HTTP/2 without TLS benchmark ...") +BUILD_DIR = "./build" +SERVER_BINARY_NAME = "h2_echo_server" +CLIENT_BINARY_NAME = "h2_bench_client" +SERVER_BINARY_PATH = os.path.join(BUILD_DIR, SERVER_BINARY_NAME) +CLIENT_BINARY_PATH = os.path.join(BUILD_DIR, CLIENT_BINARY_NAME) - server_process = subprocess.Popen(["./build/h2_echo_server"]) - time.sleep(1) # wait for server to start + +def _client_host_from_remote_target(remote_host): + if "@" in remote_host: + return remote_host.split("@", 1)[1] + return remote_host + + +def _start_server(remote_host): + if not remote_host: + return subprocess.Popen([SERVER_BINARY_PATH]) + + remote_binary_path = f"/tmp/{SERVER_BINARY_NAME}" + + subprocess.run( + ["ssh", remote_host, f"rm -f {shlex.quote(remote_binary_path)}"], + check=True, + ) + subprocess.run( + ["scp", SERVER_BINARY_PATH, f"{remote_host}:{remote_binary_path}"], + check=True, + ) + + remote_command = ( + f"chmod +x {shlex.quote(remote_binary_path)} && " + f"{shlex.quote(remote_binary_path)}" + ) + + # Pass the `-t` option multiple times to ensure a pseudo-terminal is allocated, so that we can send a SIGTERM signal to the remote process, not the `ssh` process itself. This allows us to properly terminate the remote server when the benchmark is done. + return subprocess.Popen(["ssh", "-tt", remote_host, remote_command], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0) + + +def run_benchmark(remote_host=None): + print("Running HTTP/2 without TLS benchmark ...") + + client_host = "127.0.0.1" + if remote_host: + client_host = _client_host_from_remote_target(remote_host) + print(f"Starting remote server via SSH on {remote_host} ...") + else: + print("Starting local server ...") + + server_process = _start_server(remote_host) + time.sleep(2) # wait for server to start + + if server_process.poll() is not None: + raise RuntimeError(f"{SERVER_BINARY_NAME} failed to start") try: subprocess.run([ - "./build/h2_bench_client", + CLIENT_BINARY_PATH, "--stderrthreshold=0", "--benchmark_counters_tabular=true", - ], capture_output=False, text=True) + f"--host={client_host}", + ], capture_output=False, text=True, check=True) except subprocess.CalledProcessError as e: - print(f"Error running HTTP/2 client:\n{e.output}") + print(f"Error running HTTP/2 client: {e}") except Exception as e: print(f"Failed to start/run HTTP/2 client: {e}") finally: - server_process.terminate() - server_process.wait() + if server_process.poll() is None: + server_process.terminate() + server_process.wait() + if __name__ == "__main__": - if not os.path.isdir("build"): + parser = argparse.ArgumentParser(description="Run HTTP/2 benchmark") + parser.add_argument( + "--remote-host", + help="SSH target for remote h2_echo_server, e.g. user@10.0.0.5", + ) + args = parser.parse_args() + + if not os.path.isdir(BUILD_DIR): print("Error: 'build' directory not found. Please compile the project first.") exit(1) + + if not os.path.isfile(SERVER_BINARY_PATH): + print(f"Error: '{SERVER_BINARY_PATH}' not found. Please compile the project first.") + exit(1) + + if not os.path.isfile(CLIENT_BINARY_PATH): + print(f"Error: '{CLIENT_BINARY_PATH}' not found. Please compile the project first.") + exit(1) print("Starting benchmarks...") - run_benchmark() + run_benchmark(remote_host=args.remote_host) diff --git a/http2/results.txt b/http2/results.txt index 4ef6e18..a29ff3a 100644 --- a/http2/results.txt +++ b/http2/results.txt @@ -1,4 +1,4 @@ -2026-03-11T19:12:36+00:00 +2026-03-18T03:53:29+00:00 Running ./build/h2_bench_client Run on (2 X 2450 MHz CPU s) CPU Caches: @@ -6,12 +6,19 @@ CPU Caches: L1 Instruction 32 KiB (x1) L2 Unified 512 KiB (x1) L3 Unified 32768 KiB (x1) -Load Average: 0.27, 0.65, 0.49 +Load Average: 0.48, 0.24, 0.11 --------------------------------------------------------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations items_per_second p10_latency_ms p50_latency_ms p90_latency_ms p99_latency_ms --------------------------------------------------------------------------------------------------------------------------------------------- -BM_HTTP2Client/0 61713 ns 27767 ns 20047 36.0145k/s 0.042291 0.05026 0.06686 0.12446 -BM_HTTP2Client/1024 70859 ns 36578 ns 20824 27.3387k/s 0.06296 0.06762 0.07477 0.09962 -BM_HTTP2Client/131072 46753895 ns 454124 ns 100 2.20204k/s 42.962 43.9969 87.689 91.4688 +BM_HTTP2Client/0 69540 ns 35423 ns 20002 28.23k/s 0.06082 0.06532 0.07368 0.14472 +BM_HTTP2Client/1024 73996 ns 37409 ns 19361 26.7319k/s 0.05987 0.06916 0.07918 0.177689 +BM_HTTP2Client/2048 79365 ns 40345 ns 18347 24.7861k/s 0.06806 0.07213 0.08655 0.20568 +BM_HTTP2Client/4096 97370 ns 48575 ns 15427 20.5865k/s 0.08071 0.08598 0.11125 0.27893 +BM_HTTP2Client/8192 106721 ns 52152 ns 10000 19.1748k/s 0.07369 0.0967 0.14 0.29226 +BM_HTTP2Client/16384 153717 ns 77756 ns 8547 12.8607k/s 0.12328 0.13408 0.172549 0.34857 +BM_HTTP2Client/32768 214652 ns 121252 ns 5857 8.24726k/s 0.19138 0.20315 0.23542 0.404201 +BM_HTTP2Client/65536 356799 ns 189867 ns 3626 5.26684k/s 0.28469 0.29941 0.3921 1.44324 +BM_HTTP2Client/131072 487052 ns 320039 ns 2082 3.12462k/s 0.45225 0.4656 0.52445 0.77176 Starting benchmarks... Running HTTP/2 without TLS benchmark ... +Starting local server ...