diff --git a/Cargo.lock b/Cargo.lock index 42409b8d..5860cd48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,6 +211,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + [[package]] name = "byteorder" version = "1.5.0" @@ -286,7 +292,7 @@ version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.96", @@ -345,6 +351,7 @@ dependencies = [ "shellexpand", "simplelog", "sysinfo", + "tabled", "temp-env", "tempfile", "test-with", @@ -798,6 +805,12 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -1515,6 +1528,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "papergrid" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b0f8def1f117e13c895f3eda65a7b5650688da29d6ad04635f61bc7b92eebd" +dependencies = [ + "bytecount", + "fnv", + "unicode-width", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -2329,6 +2353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", + "quote", "unicode-ident", ] @@ -2396,6 +2421,29 @@ dependencies = [ "libc", ] +[[package]] +name = "tabled" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6709222f3973137427ce50559cd564dc187a95b9cfe01613d2f4e93610e510a" +dependencies = [ + "papergrid", + "tabled_derive", +] + +[[package]] +name = "tabled_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931be476627d4c54070a1f3a9739ccbfec9b36b39815106a20cce2243bbcefe1" +dependencies = [ + "heck 0.4.1", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "task-local-extensions" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index a249389a..9f5767e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ shellexpand = { version = "3.1.1", features = ["tilde"] } addr2line = "0.25" gimli = "0.32" open = "5.3.2" +tabled = "0.17" [target.'cfg(target_os = "linux")'.dependencies] procfs = "0.17.0" diff --git a/src/run/poll_results.rs b/src/run/poll_results.rs index 255c5019..06319cfd 100644 --- a/src/run/poll_results.rs +++ b/src/run/poll_results.rs @@ -1,6 +1,8 @@ use std::time::Duration; use console::style; +use tabled::settings::Style; +use tabled::{Table, Tabled}; use tokio::time::{Instant, sleep}; use crate::api_client::{ @@ -14,6 +16,26 @@ use super::run_environment::RunEnvironmentProvider; const RUN_PROCESSING_MAX_DURATION: Duration = Duration::from_secs(60 * 5); // 5 minutes const POLLING_INTERVAL: Duration = Duration::from_secs(1); +#[derive(Tabled)] +struct BenchmarkRow { + #[tabled(rename = "Benchmark")] + name: String, + #[tabled(rename = "Time")] + time: String, +} + +fn build_benchmark_table(results: &[crate::api_client::FetchLocalRunBenchmarkResult]) -> String { + let table_rows: Vec = results + .iter() + .map(|result| BenchmarkRow { + name: result.benchmark.name.clone(), + time: helpers::format_duration(result.time, Some(2)), + }) + .collect(); + + Table::new(&table_rows).with(Style::modern()).to_string() +} + #[allow(clippy::borrowed_box)] pub async fn poll_results( api_client: &CodSpeedAPIClient, @@ -100,21 +122,65 @@ pub async fn poll_results( if !response.run.results.is_empty() { start_group!("Benchmark results"); - for result in response.run.results { - let benchmark_name = result.benchmark.name; - let time = helpers::format_duration(result.time, Some(2)); - info!("{}: {}", benchmark_name, style(time).bold()); + let table = build_benchmark_table(&response.run.results); + info!("\n{table}"); - if output_json { + if output_json { + for result in response.run.results { log_json!(format!( "{{\"event\": \"benchmark_ran\", \"name\": \"{}\", \"time\": \"{}\"}}", - benchmark_name, result.time, + result.benchmark.name, result.time, )); } } + end_group!(); } Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::api_client::{FetchLocalRunBenchmark, FetchLocalRunBenchmarkResult}; + + #[test] + fn test_benchmark_table_formatting() { + let results = vec![ + FetchLocalRunBenchmarkResult { + benchmark: FetchLocalRunBenchmark { + name: "benchmark_fast".to_string(), + }, + time: 0.001234, // 1.23 ms + }, + FetchLocalRunBenchmarkResult { + benchmark: FetchLocalRunBenchmark { + name: "benchmark_slow".to_string(), + }, + time: 1.5678, // 1.57 s + }, + FetchLocalRunBenchmarkResult { + benchmark: FetchLocalRunBenchmark { + name: "benchmark_medium".to_string(), + }, + time: 0.000567, // 567 µs + }, + ]; + + let table = build_benchmark_table(&results); + + insta::assert_snapshot!(table, @r###" + ┌──────────────────┬───────────┐ + │ Benchmark │ Time │ + ├──────────────────┼───────────┤ + │ benchmark_fast │ 1.23 ms │ + ├──────────────────┼───────────┤ + │ benchmark_slow │ 1.57 s │ + ├──────────────────┼───────────┤ + │ benchmark_medium │ 567.00 µs │ + └──────────────────┴───────────┘ + "###); + } +}