From 7a3a5bc3ae150288b9dab4723566fd4b71f1881c Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Mon, 9 Mar 2026 16:47:52 +0200 Subject: [PATCH] feat(runner): add protocol mode to CLI and benchmark config --- README.md | 8 ++-- runner/src/args.rs | 6 ++- runner/src/config/mod.rs | 100 ++++++++++++++++++++++++++------------- runner/src/main.rs | 14 ++---- server/src/main.rs | 2 +- 5 files changed, 83 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index d09332f..d436c3e 100644 --- a/README.md +++ b/README.md @@ -43,22 +43,23 @@ cargo build --release Terminal 1 - Start server: ```bash -./target/release/server --mode x25519 --listen 127.0.0.1:4433 +./target/release/server --mode x25519 --proto raw --listen 127.0.0.1:4433 ``` Terminal 2 - Run benchmark: ```bash -./target/release/runner --server 127.0.0.1:4433 --mode x25519 --iters 100 --warmup 10 +./target/release/runner --server 127.0.0.1:4433 --proto raw --mode x25519 --iters 100 --warmup 10 ``` ### Run Matrix Benchmarks -Create a config file (`matrix.toml`): +Create a config file (`benchmarks.toml`): ```toml [[benchmarks]] server = "127.0.0.1:4433" +proto = "raw" mode = "x25519" payload = 1024 iters = 100 @@ -67,6 +68,7 @@ concurrency = 1 [[benchmarks]] server = "127.0.0.1:4433" +proto = "http1" mode = "x25519mlkem768" payload = 1024 iters = 100 diff --git a/runner/src/args.rs b/runner/src/args.rs index 2b40b37..491cff6 100644 --- a/runner/src/args.rs +++ b/runner/src/args.rs @@ -6,7 +6,11 @@ use std::{net::SocketAddr, path::PathBuf}; #[derive(Debug, Parser)] #[command(name = "runner", version, about)] pub struct Args { - /// Key exchange mode. + /// Protocol carrier mode + #[arg(long, default_value = "raw")] + pub proto: ProtocolMode, + + /// Key exchange mode #[arg(long, default_value = "x25519")] pub mode: KeyExchangeMode, diff --git a/runner/src/config/mod.rs b/runner/src/config/mod.rs index 81f36c4..1451fd5 100644 --- a/runner/src/config/mod.rs +++ b/runner/src/config/mod.rs @@ -12,6 +12,7 @@ use std::{fs::read_to_string, net::SocketAddr, path::Path}; #[derive(Debug, Clone, Deserialize)] pub struct BenchmarkConfig { + pub proto: ProtocolMode, pub mode: KeyExchangeMode, pub payload: u32, pub iters: u32, @@ -29,48 +30,57 @@ pub struct Config { /// /// # Errors /// Returns an error if the file cannot be read or parsed. -pub fn load_from_file(path: &Path) -> error::Result { - let content = read_to_string(path).map_err(|source| ConfigError::ReadError { - source, - path: path.to_owned(), - })?; +impl TryFrom<&Path> for Config { + type Error = error::Error; - let src = NamedSource::new(path.display().to_string(), content.clone()); - - let config = toml::from_str::(&content).map_err(|source| { - let span = source - .span() - .map(|s| SourceSpan::new(s.start.into(), s.end - s.start)); - - ConfigError::TomlParseError { - src: src.clone(), - span, + fn try_from(path: &Path) -> Result { + let content = read_to_string(path).map_err(|source| ConfigError::ReadError { source, - } - })?; + path: path.to_owned(), + })?; - validate_config(&config, &content, path)?; + let src = NamedSource::new(path.display().to_string(), content.clone()); - Ok(config) + let config = toml::from_str::(&content).map_err(|source| { + let span = source + .span() + .map(|s| SourceSpan::new(s.start.into(), s.end - s.start)); + + ConfigError::TomlParseError { + src: src.clone(), + span, + source, + } + })?; + + validate_config(&config, &content, path)?; + + Ok(config) + } } /// Create benchmark configuration from CLI arguments. /// /// # Errors -/// Never returns an error, but returns Result for consistency. -pub fn load_from_cli(args: &Args) -> error::Result { - Ok(Config { - benchmarks: vec![BenchmarkConfig { - mode: args.mode, - payload: args.payload_bytes, - iters: args.iters, - warmup: args.warmup, - concurrency: args.concurrency, - server: args - .server - .ok_or_else(|| common::Error::config("--server ir required"))?, - }], - }) +/// Returns an error if `--server` was not provided. +impl TryFrom for Config { + type Error = error::Error; + + fn try_from(args: Args) -> Result { + Ok(Self { + benchmarks: vec![BenchmarkConfig { + proto: args.proto, + mode: args.mode, + payload: args.payload_bytes, + iters: args.iters, + warmup: args.warmup, + concurrency: args.concurrency, + server: args + .server + .ok_or_else(|| common::Error::config("--server is required"))?, + }], + }) + } } #[cfg(test)] @@ -80,6 +90,7 @@ mod tests { const VALID_CONFIG: &str = r#" [[benchmarks]] +proto = "raw" mode = "x25519" payload = 1024 iters = 100 @@ -88,6 +99,7 @@ concurrency = 1 server = "127.0.0.1:4433" [[benchmarks]] +proto = "http1" mode = "x25519mlkem768" payload = 4096 iters = 50 @@ -104,6 +116,7 @@ server = "127.0.0.1:4433" fn valid_single_benchmark() { let toml = r#" [[benchmarks]] +proto = "raw" mode = "x25519" payload = 1024 iters = 100 @@ -125,10 +138,26 @@ server = "127.0.0.1:4433" assert_eq!(config.benchmarks[1].mode, KeyExchangeMode::X25519Mlkem768); } + #[test] + fn invalid_proto() { + let toml = r#" +[[benchmarks]] +proto = "invalid_proto" +mode = "x25519" +payload = 1024 +iters = 100 +warmup = 10 +concurrency = 1 +server = "127.0.0.1:4433" +"#; + assert_err!(toml::from_str::(toml)); + } + #[test] fn invalid_mode() { let toml = r#" [[benchmarks]] +proto = "raw" mode = "invalid_mode" payload = 1024 iters = 100 @@ -143,6 +172,7 @@ server = "127.0.0.1:4433" fn payload_zero_validation() { let toml = r#" [[benchmarks]] +proto = "raw" mode = "x25519" payload = 0 iters = 100 @@ -158,6 +188,7 @@ server = "127.0.0.1:4433" fn iters_zero_validation() { let toml = r#" [[benchmarks]] +proto = "raw" mode = "x25519" payload = 1024 iters = 0 @@ -173,6 +204,7 @@ server = "127.0.0.1:4433" fn concurrency_zero_validation() { let toml = r#" [[benchmarks]] +proto = "raw" mode = "x25519" payload = 1024 iters = 100 @@ -195,6 +227,7 @@ server = "127.0.0.1:4433" fn server_mode_fallback() { let toml = r#" [[benchmarks]] +proto = "raw" mode = "x25519" payload = 1024 iters = 100 @@ -211,6 +244,7 @@ server = "127.0.0.1:4433" fn server_mode_mlkem() { let toml = r#" [[benchmarks]] +proto = "raw" mode = "x25519mlkem768" payload = 1024 iters = 100 diff --git a/runner/src/main.rs b/runner/src/main.rs index c206963..dd3d6e0 100644 --- a/runner/src/main.rs +++ b/runner/src/main.rs @@ -12,12 +12,7 @@ mod config; mod error; mod tls; -use crate::{ - args::Args, - bench::run_benchmark, - config::{load_from_cli, load_from_file}, - tls::build_tls_config, -}; +use crate::{args::Args, bench::run_benchmark, config::Config, tls::build_tls_config}; use clap::Parser; use miette::{Context, IntoDiagnostic}; use rustls::pki_types::ServerName; @@ -47,12 +42,12 @@ async fn main() -> miette::Result<()> { let args = Args::parse(); - let config = if let Some(config_path) = &args.config { + let config: Config = if let Some(config_path) = &args.config { info!(config_file = %config_path.display(), "loading config from file"); - load_from_file(config_path)? + config_path.as_path().try_into()? } else { info!("using CLI arguments"); - load_from_cli(&args)? + args.try_into()? }; let server_name = ServerName::try_from("localhost".to_string()) @@ -61,6 +56,7 @@ async fn main() -> miette::Result<()> { for benchmark in &config.benchmarks { info!( + proto = %benchmark.proto, mode = %benchmark.mode, payload = benchmark.payload, iters = benchmark.iters, diff --git a/server/src/main.rs b/server/src/main.rs index 272157d..c309ef6 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -24,7 +24,7 @@ struct Args { #[arg(long, default_value = "x25519")] mode: KeyExchangeMode, - /// Protocol carrier + /// Protocol carrier mode #[arg(long, default_value = "raw")] proto: ProtocolMode,