From c9bcfa584aa98d20f372b2c7ec55b8b325a8c674 Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Sat, 8 Aug 2026 00:01:14 +0200 Subject: [PATCH 01/13] fix: add missing gungraun dhat metrics --- .../src/adapters/rust/gungraun.rs | 5 +++++ .../src/results/adapter_results.rs | 20 +++++++++++++++++++ .../src/project/measure/built_in.rs | 12 +++++++++++ 3 files changed, 37 insertions(+) diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun.rs b/lib/bencher_adapter/src/adapters/rust/gungraun.rs index cc169e63a..adc83e84a 100644 --- a/lib/bencher_adapter/src/adapters/rust/gungraun.rs +++ b/lib/bencher_adapter/src/adapters/rust/gungraun.rs @@ -214,12 +214,17 @@ fn dhat_tool_measures<'a>() .map(|(metric_name, json)| match metric_name.as_str() { gungraun::TotalBytes::NAME_STR => GungraunMeasure::TotalBytes(json), gungraun::TotalBlocks::NAME_STR => GungraunMeasure::TotalBlocks(json), + gungraun::TotalUnits::NAME_STR => GungraunMeasure::TotalUnits(json), + gungraun::TotalEvents::NAME_STR => GungraunMeasure::TotalEvents(json), + gungraun::TotalLifetimes::NAME_STR => GungraunMeasure::TotalLifetimes(json), gungraun::AtTGmaxBytes::NAME_STR => GungraunMeasure::AtTGmaxBytes(json), gungraun::AtTGmaxBlocks::NAME_STR => GungraunMeasure::AtTGmaxBlocks(json), gungraun::AtTEndBytes::NAME_STR => GungraunMeasure::AtTEndBytes(json), gungraun::AtTEndBlocks::NAME_STR => GungraunMeasure::AtTEndBlocks(json), gungraun::ReadsBytes::NAME_STR => GungraunMeasure::ReadsBytes(json), gungraun::WritesBytes::NAME_STR => GungraunMeasure::WritesBytes(json), + gungraun::MaximumBytes::NAME_STR => GungraunMeasure::MaximumBytes(json), + gungraun::MaximumBlocks::NAME_STR => GungraunMeasure::MaximumBlocks(json), _ => GungraunMeasure::Unknown, }) .collect() diff --git a/lib/bencher_adapter/src/results/adapter_results.rs b/lib/bencher_adapter/src/results/adapter_results.rs index 8bcdc81f0..d1b9d8602 100644 --- a/lib/bencher_adapter/src/results/adapter_results.rs +++ b/lib/bencher_adapter/src/results/adapter_results.rs @@ -100,12 +100,17 @@ pub enum GungraunMeasure { */ TotalBytes(JsonNewMetric), TotalBlocks(JsonNewMetric), + TotalUnits(JsonNewMetric), + TotalEvents(JsonNewMetric), + TotalLifetimes(JsonNewMetric), AtTGmaxBytes(JsonNewMetric), AtTGmaxBlocks(JsonNewMetric), AtTEndBytes(JsonNewMetric), AtTEndBlocks(JsonNewMetric), ReadsBytes(JsonNewMetric), WritesBytes(JsonNewMetric), + MaximumBytes(JsonNewMetric), + MaximumBlocks(JsonNewMetric), /* * Memcheck tool: @@ -430,6 +435,15 @@ impl AdapterResults { GungraunMeasure::TotalBlocks(json_metric) => { (built_in::gungraun::TotalBlocks::name_id(), json_metric) }, + GungraunMeasure::TotalUnits(json_metric) => { + (built_in::gungraun::TotalUnits::name_id(), json_metric) + }, + GungraunMeasure::TotalEvents(json_metric) => { + (built_in::gungraun::TotalEvents::name_id(), json_metric) + }, + GungraunMeasure::TotalLifetimes(json_metric) => { + (built_in::gungraun::TotalLifetimes::name_id(), json_metric) + }, GungraunMeasure::AtTGmaxBytes(json_metric) => { (built_in::gungraun::AtTGmaxBytes::name_id(), json_metric) }, @@ -448,6 +462,12 @@ impl AdapterResults { GungraunMeasure::WritesBytes(json_metric) => { (built_in::gungraun::WritesBytes::name_id(), json_metric) }, + GungraunMeasure::MaximumBytes(json_metric) => { + (built_in::gungraun::MaximumBytes::name_id(), json_metric) + }, + GungraunMeasure::MaximumBlocks(json_metric) => { + (built_in::gungraun::MaximumBlocks::name_id(), json_metric) + }, // Memcheck GungraunMeasure::MemcheckErrors(json_metric) => { (built_in::gungraun::MemcheckErrors::name_id(), json_metric) diff --git a/lib/bencher_json/src/project/measure/built_in.rs b/lib/bencher_json/src/project/measure/built_in.rs index 68f949fc9..d474c9a9d 100644 --- a/lib/bencher_json/src/project/measure/built_in.rs +++ b/lib/bencher_json/src/project/measure/built_in.rs @@ -185,6 +185,16 @@ pub mod gungraun { create_measure!(TotalBytes, "Total bytes", "total-bytes", BYTES); create_measure!(TotalBlocks, "Total blocks", "total-blocks", "blocks"); create_measure!(AtTGmaxBytes, "At t-gmax bytes", "at-t-gmax-bytes", BYTES); + + create_measure!(TotalUnits, "Total units", "total-units", "units"); + create_measure!(TotalEvents, "Total events", "total-events", "events"); + create_measure!( + TotalLifetimes, + "Total lifetimes", + "total-lifetimes", + "lifetimes" + ); + create_measure!( AtTGmaxBlocks, "At t-gmax blocks", @@ -195,6 +205,8 @@ pub mod gungraun { create_measure!(AtTEndBlocks, "At t-end blocks", "at-t-end-blocks", "blocks"); create_measure!(ReadsBytes, "Reads bytes", "reads-bytes", BYTES); create_measure!(WritesBytes, "Writes bytes", "writes-bytes", BYTES); + create_measure!(MaximumBytes, "Maximum bytes", "maximum-bytes", BYTES); + create_measure!(MaximumBlocks, "Maximum blocks", "maximum-blocks", "blocks"); // Memcheck create_measure!( From f1b3a7c26f328fd9e4ffbf30de56689480c8a3f7 Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Sat, 8 Aug 2026 15:52:28 +0200 Subject: [PATCH 02/13] Implement gungraun json parser --- Cargo.lock | 36 +++ Cargo.toml | 1 + lib/bencher_adapter/Cargo.toml | 1 + .../src/adapters/rust/gungraun_json.rs | 264 ++++++++++++++++++ lib/bencher_adapter/src/adapters/rust/mod.rs | 7 +- 5 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 lib/bencher_adapter/src/adapters/rust/gungraun_json.rs diff --git a/Cargo.lock b/Cargo.lock index 27ac9cb57..f44d0b922 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1084,6 +1084,7 @@ version = "0.6.11" dependencies = [ "bencher_json", "criterion", + "gungraun-summary", "literally", "nom", "ordered-float", @@ -3082,6 +3083,16 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +[[package]] +name = "either-or-both" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717164c227120ba9ddf3e2b32305fc0122741d3ee41a54968eae7573ee01933" +dependencies = [ + "indexmap", + "serde", +] + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -4268,6 +4279,31 @@ dependencies = [ "subtle", ] +[[package]] +name = "gungraun-runner" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c68c92812da579a2510a2cc702d5aa3251992b9662d4a98502ca46e0cbe16e" +dependencies = [ + "either-or-both", + "indexmap", + "serde", +] + +[[package]] +name = "gungraun-summary" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f967da1beab0153f3f1e52408a71d3bd0fbea3c9e0bf0431f9a3a3c9e96130" +dependencies = [ + "either-or-both", + "gungraun-runner", + "indexmap", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "h2" version = "0.4.14" diff --git a/Cargo.toml b/Cargo.toml index d83c054cb..103486749 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -113,6 +113,7 @@ futures-util = "0.3" gix = { version = "0.83", default-features = false } gix-hash = { version = "0.25", features = ["sha1"] } git-validate = "0.7" +gungraun-summary = { version = "6" } hex = "0.4" http = "1.4" http-body-util = "0.1" diff --git a/lib/bencher_adapter/Cargo.toml b/lib/bencher_adapter/Cargo.toml index 63de9b1ed..ef4c11d93 100644 --- a/lib/bencher_adapter/Cargo.toml +++ b/lib/bencher_adapter/Cargo.toml @@ -12,6 +12,7 @@ plus = ["bencher_json/plus"] [dependencies] bencher_json = { workspace = true, features = ["server"] } +gungraun-summary.workspace = true literally.workspace = true nom.workspace = true ordered-float.workspace = true diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs new file mode 100644 index 000000000..efe1292fe --- /dev/null +++ b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs @@ -0,0 +1,264 @@ +use bencher_json::{BenchmarkName, JsonNewMetric, project::report::JsonAverage}; + +use gungraun_summary::{ + either_or_both::EitherOrBoth, + util::SummaryByVersion, + v6::{ + CachegrindMetric, DhatMetric, ErrorMetric, EventKind, Metric, MetricsDiff, MetricsSummary, + ToolMetricSummary, ValgrindTool, + }, +}; + +use crate::{Adaptable, AdapterResults, Settings, results::adapter_results::GungraunMeasure}; + +pub struct AdapterRustGungraunJson; + +impl Adaptable for AdapterRustGungraunJson { + fn parse(input: &str, settings: Settings) -> Option { + match settings.average { + None => {}, + Some(JsonAverage::Mean | JsonAverage::Median) => { + return None; // 'gungraun' results are for a single run only. + }, + } + + // Clean up the input by removing ANSI escape codes: + let input = strip_ansi_escapes::strip_str(input); + + parse_multiple(&input).and_then(AdapterResults::new_gungraun) + } +} + +fn parse_multiple(input: &str) -> Option)>> { + let parsed = input.lines().filter_map(parse_line).collect::>(); + + (!parsed.is_empty()).then_some(parsed) +} + +fn parse_line(input: &str) -> Option<(BenchmarkName, Vec)> { + // Using the version aware gungraun_summary parsing method to simplify adapting gungraun summary + // version updates. At the moment there's just v6 + let summary = match gungraun_summary::util::parse_slice(input.as_bytes()) { + Ok(summary_by_version) => match summary_by_version { + SummaryByVersion::V6(benchmark_summary) => benchmark_summary, + _ => return None, + }, + Err(_) => return None, + }; + + let name: BenchmarkName = if let Some(id) = &summary.id { + format!("{}::{id}", summary.module_path) + } else { + summary.module_path + } + .parse() + .ok()?; + + let measures = summary + .profiles + .0 + .into_iter() + .flat_map(|profile| match profile.summaries.total.summary { + ToolMetricSummary::Cachegrind(metrics_summary) => { + parse_cachegrind_metrics_summary(metrics_summary) + }, + ToolMetricSummary::Callgrind(metrics_summary) => { + parse_callgrind_metrics_summary(metrics_summary) + }, + ToolMetricSummary::Dhat(metrics_summary) => parse_dhat_metrics_summary(metrics_summary), + ToolMetricSummary::ErrorTool(metrics_summary) => match profile.tool { + ValgrindTool::Memcheck => parse_memcheck_metrics_summary(metrics_summary), + ValgrindTool::Helgrind => parse_helgind_metrics_summary(metrics_summary), + ValgrindTool::DRD => parse_drd_metrics_summary(metrics_summary), + // These other tools are no error tools and are already covered + ValgrindTool::Callgrind + | ValgrindTool::Cachegrind + | ValgrindTool::DHAT + // These tools don't have a metric output (covered by `ToolMetricSummary::None`) + | ValgrindTool::Massif + | ValgrindTool::BBV => vec![], + }, + ToolMetricSummary::None => vec![], + }) + .collect(); + + Some((name, measures)) +} + +fn parse_drd_metrics_summary(metrics_summary: MetricsSummary) -> Vec { + metrics_summary + .0 + .into_iter() + .filter_map(|(metric, diff)| diff_to_json(&diff).map(|json| (metric, json))) + .map(|(metric, json)| match metric { + ErrorMetric::Contexts => GungraunMeasure::DrdContexts(json), + ErrorMetric::Errors => GungraunMeasure::DrdErrors(json), + ErrorMetric::SuppressedContexts => GungraunMeasure::DrdSuppressedContexts(json), + ErrorMetric::SuppressedErrors => GungraunMeasure::DrdSuppressedErrors(json), + }) + .collect() +} + +fn parse_helgind_metrics_summary( + metrics_summary: MetricsSummary, +) -> Vec { + metrics_summary + .0 + .into_iter() + .filter_map(|(metric, diff)| diff_to_json(&diff).map(|json| (metric, json))) + .map(|(metric, json)| match metric { + ErrorMetric::Contexts => GungraunMeasure::HelgrindContexts(json), + ErrorMetric::Errors => GungraunMeasure::HelgrindErrors(json), + ErrorMetric::SuppressedContexts => GungraunMeasure::HelgrindSuppressedContexts(json), + ErrorMetric::SuppressedErrors => GungraunMeasure::HelgrindSuppressedErrors(json), + }) + .collect() +} + +fn parse_memcheck_metrics_summary( + metrics_summary: MetricsSummary, +) -> Vec { + metrics_summary + .0 + .into_iter() + .filter_map(|(metric, diff)| diff_to_json(&diff).map(|json| (metric, json))) + .map(|(metric, json)| match metric { + ErrorMetric::Contexts => GungraunMeasure::MemcheckContexts(json), + ErrorMetric::Errors => GungraunMeasure::MemcheckErrors(json), + ErrorMetric::SuppressedContexts => GungraunMeasure::MemcheckSuppressedContexts(json), + ErrorMetric::SuppressedErrors => GungraunMeasure::MemcheckSuppressedErrors(json), + }) + .collect() +} + +fn parse_callgrind_metrics_summary( + metrics_summary: MetricsSummary, +) -> Vec { + metrics_summary + .0 + .into_iter() + .filter_map(|(event_kind, diff)| diff_to_json(&diff).map(|json| (event_kind, json))) + .map(|(event_kind, json)| match event_kind { + EventKind::AcCost1 => GungraunMeasure::L1BadTemporalLocality(json), + EventKind::AcCost2 => GungraunMeasure::LLBadTemporalLocality(json), + EventKind::Bc => GungraunMeasure::ExecutedConditionalBranches(json), + EventKind::Bcm => GungraunMeasure::MispredictedConditionalBranches(json), + EventKind::Bi => GungraunMeasure::ExecutedIndirectBranches(json), + EventKind::Bim => GungraunMeasure::MispredictedIndirectBranches(json), + EventKind::D1MissRate => GungraunMeasure::L1DataCacheMissRate(json), + EventKind::D1mr => GungraunMeasure::L1DataCacheReadMisses(json), + EventKind::D1mw => GungraunMeasure::L1DataCacheWriteMisses(json), + EventKind::DLdmr => GungraunMeasure::DirtyMissDataRead(json), + EventKind::DLdmw => GungraunMeasure::DirtyMissDataWrite(json), + EventKind::DLmr => GungraunMeasure::LLDataCacheReadMisses(json), + EventKind::DLmw => GungraunMeasure::LLDataCacheWriteMisses(json), + EventKind::Dr => GungraunMeasure::DataCacheReads(json), + EventKind::Dw => GungraunMeasure::DataCacheWrites(json), + EventKind::EstimatedCycles => GungraunMeasure::EstimatedCycles(json), + EventKind::Ge => GungraunMeasure::GlobalBusEvents(json), + EventKind::I1MissRate => GungraunMeasure::L1InstrCacheMissRate(json), + EventKind::I1mr => GungraunMeasure::L1InstrCacheReadMisses(json), + EventKind::ILdmr => GungraunMeasure::DirtyMissInstructionRead(json), + EventKind::ILmr => GungraunMeasure::LLInstrCacheReadMisses(json), + EventKind::Ir => GungraunMeasure::Instructions(json), + EventKind::L1HitRate => GungraunMeasure::L1HitRate(json), + EventKind::L1hits => GungraunMeasure::L1Hits(json), + EventKind::LLHitRate => GungraunMeasure::LLHitRate(json), + EventKind::LLMissRate => GungraunMeasure::LLCacheMissRate(json), + EventKind::LLdMissRate => GungraunMeasure::LLDataCacheMissRate(json), + EventKind::LLhits => GungraunMeasure::LLHits(json), + EventKind::LLiMissRate => GungraunMeasure::LLInstrCacheMissRate(json), + EventKind::RamHitRate => GungraunMeasure::RamHitRate(json), + EventKind::RamHits => GungraunMeasure::RamHits(json), + EventKind::SpLoss1 => GungraunMeasure::L1BadSpatialLocality(json), + EventKind::SpLoss2 => GungraunMeasure::LLBadSpatialLocality(json), + EventKind::SysCount => GungraunMeasure::NumberSystemCalls(json), + EventKind::SysCpuTime => GungraunMeasure::CpuTimeSystemCalls(json), + EventKind::SysTime => GungraunMeasure::TimeSystemCalls(json), + EventKind::TotalRW => GungraunMeasure::TotalReadWrite(json), + }) + .collect() +} + +fn parse_cachegrind_metrics_summary( + metrics_summary: MetricsSummary, +) -> Vec { + metrics_summary + .0 + .into_iter() + .filter_map(|(metric, diff)| diff_to_json(&diff).map(|json| (metric, json))) + .map(|(metric, json)| match metric { + CachegrindMetric::Bc => GungraunMeasure::ExecutedConditionalBranches(json), + CachegrindMetric::Bcm => GungraunMeasure::MispredictedConditionalBranches(json), + CachegrindMetric::Bi => GungraunMeasure::ExecutedIndirectBranches(json), + CachegrindMetric::Bim => GungraunMeasure::MispredictedIndirectBranches(json), + CachegrindMetric::D1MissRate => GungraunMeasure::L1DataCacheMissRate(json), + CachegrindMetric::D1mr => GungraunMeasure::L1DataCacheReadMisses(json), + CachegrindMetric::D1mw => GungraunMeasure::L1DataCacheWriteMisses(json), + CachegrindMetric::DLmr => GungraunMeasure::LLDataCacheReadMisses(json), + CachegrindMetric::DLmw => GungraunMeasure::LLDataCacheWriteMisses(json), + CachegrindMetric::Dr => GungraunMeasure::DataCacheReads(json), + CachegrindMetric::Dw => GungraunMeasure::DataCacheWrites(json), + CachegrindMetric::EstimatedCycles => GungraunMeasure::EstimatedCycles(json), + CachegrindMetric::I1MissRate => GungraunMeasure::L1InstrCacheMissRate(json), + CachegrindMetric::I1mr => GungraunMeasure::L1InstrCacheReadMisses(json), + CachegrindMetric::ILmr => GungraunMeasure::LLInstrCacheReadMisses(json), + CachegrindMetric::Ir => GungraunMeasure::Instructions(json), + CachegrindMetric::L1HitRate => GungraunMeasure::L1HitRate(json), + CachegrindMetric::L1hits => GungraunMeasure::L1Hits(json), + CachegrindMetric::LLHitRate => GungraunMeasure::LLHitRate(json), + CachegrindMetric::LLMissRate => GungraunMeasure::LLCacheMissRate(json), + CachegrindMetric::LLdMissRate => GungraunMeasure::LLDataCacheMissRate(json), + CachegrindMetric::LLhits => GungraunMeasure::LLHits(json), + CachegrindMetric::LLiMissRate => GungraunMeasure::LLInstrCacheMissRate(json), + CachegrindMetric::RamHitRate => GungraunMeasure::RamHitRate(json), + CachegrindMetric::RamHits => GungraunMeasure::RamHits(json), + CachegrindMetric::TotalRW => GungraunMeasure::TotalReadWrite(json), + }) + .collect() +} + +fn parse_dhat_metrics_summary(metrics_summary: MetricsSummary) -> Vec { + metrics_summary + .0 + .into_iter() + .filter_map(|(metric, diff)| diff_to_json(&diff).map(|json| (metric, json))) + .map(|(metric, json)| match metric { + DhatMetric::AtTEndBlocks => GungraunMeasure::AtTEndBlocks(json), + DhatMetric::AtTEndBytes => GungraunMeasure::AtTEndBytes(json), + DhatMetric::AtTGmaxBlocks => GungraunMeasure::AtTGmaxBlocks(json), + DhatMetric::AtTGmaxBytes => GungraunMeasure::AtTGmaxBytes(json), + DhatMetric::MaximumBlocks => GungraunMeasure::MaximumBlocks(json), + DhatMetric::MaximumBytes => GungraunMeasure::MaximumBytes(json), + DhatMetric::ReadsBytes => GungraunMeasure::ReadsBytes(json), + DhatMetric::TotalBlocks => GungraunMeasure::TotalBlocks(json), + DhatMetric::TotalBytes => GungraunMeasure::TotalBytes(json), + DhatMetric::TotalEvents => GungraunMeasure::TotalEvents(json), + DhatMetric::TotalLifetimes => GungraunMeasure::TotalLifetimes(json), + DhatMetric::TotalUnits => GungraunMeasure::TotalUnits(json), + DhatMetric::WritesBytes => GungraunMeasure::WritesBytes(json), + }) + .collect() +} + +fn diff_to_json(diff: &MetricsDiff) -> Option { + let metric = match diff.metrics { + EitherOrBoth::Left(new) | EitherOrBoth::Both(new, _) => new, + EitherOrBoth::Right(_) => return None, + }; + + #[expect( + clippy::cast_precision_loss, + reason = "bencher metrics have f64 precision" + )] + let value = match metric { + Metric::Int(int) => int as f64, + Metric::Float(float) => float, + }; + + Some(JsonNewMetric { + value: value.into(), + lower_value: None, + upper_value: None, + }) +} diff --git a/lib/bencher_adapter/src/adapters/rust/mod.rs b/lib/bencher_adapter/src/adapters/rust/mod.rs index 29bea2c2b..11216840f 100644 --- a/lib/bencher_adapter/src/adapters/rust/mod.rs +++ b/lib/bencher_adapter/src/adapters/rust/mod.rs @@ -1,9 +1,13 @@ pub mod bench; pub mod criterion; pub mod gungraun; +pub mod gungraun_json; pub mod iai; -use self::{criterion::AdapterRustCriterion, gungraun::AdapterRustGungraun, iai::AdapterRustIai}; +use self::{ + criterion::AdapterRustCriterion, gungraun::AdapterRustGungraun, + gungraun_json::AdapterRustGungraunJson, iai::AdapterRustIai, +}; use crate::{Adaptable, AdapterResults, Settings}; use bench::AdapterRustBench; @@ -15,6 +19,7 @@ impl Adaptable for AdapterRust { .or_else(|| AdapterRustCriterion::parse(input, settings)) .or_else(|| AdapterRustIai::parse(input, settings)) .or_else(|| AdapterRustGungraun::parse(input, settings)) + .or_else(|| AdapterRustGungraunJson::parse(input, settings)) } } From 56cd044182163b5b17f39f2a76fb7e4f95b7a18e Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Sat, 8 Aug 2026 15:53:09 +0200 Subject: [PATCH 03/13] Register rust_gungraun_json adapter --- lib/bencher_adapter/src/lib.rs | 3 ++- lib/bencher_json/src/project/report.rs | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/bencher_adapter/src/lib.rs b/lib/bencher_adapter/src/lib.rs index 193c3fafd..c96e25781 100644 --- a/lib/bencher_adapter/src/lib.rs +++ b/lib/bencher_adapter/src/lib.rs @@ -18,7 +18,7 @@ use adapters::{ ruby::{AdapterRuby, benchmark::AdapterRubyBenchmark}, rust::{ AdapterRust, bench::AdapterRustBench, criterion::AdapterRustCriterion, - gungraun::AdapterRustGungraun, iai::AdapterRustIai, + gungraun::AdapterRustGungraun, gungraun_json::AdapterRustGungraunJson, iai::AdapterRustIai, }, shell::{AdapterShell, hyperfine::AdapterShellHyperfine}, }; @@ -65,6 +65,7 @@ impl Adaptable for Adapter { Adapter::RustCriterion => AdapterRustCriterion::parse(input, settings), Adapter::RustIai => AdapterRustIai::parse(input, settings), Adapter::RustGungraun => AdapterRustGungraun::parse(input, settings), + Adapter::RustGungraunJson => AdapterRustGungraunJson::parse(input, settings), Adapter::Shell => AdapterShell::parse(input, settings), Adapter::ShellHyperfine => AdapterShellHyperfine::parse(input, settings), } diff --git a/lib/bencher_json/src/project/report.rs b/lib/bencher_json/src/project/report.rs index 3f33d6267..1a256f7d2 100644 --- a/lib/bencher_json/src/project/report.rs +++ b/lib/bencher_json/src/project/report.rs @@ -90,6 +90,7 @@ const RUST_BENCH_INT: i32 = 21; const RUST_CRITERION_INT: i32 = 22; const RUST_IAI_INT: i32 = 23; const RUST_GUNGRAUN_INT: i32 = 24; +const RUST_GUNGRAUN_JSON_INT: i32 = 25; const CPP_INT: i32 = 30; const CPP_GOOGLE_INT: i32 = 31; const CPP_CATCH2_INT: i32 = 32; @@ -132,6 +133,7 @@ pub enum Adapter { // https://github.com/bencherdev/bencher/issues/619 #[serde(alias = "rust_iai_callgrind")] RustGungraun = RUST_GUNGRAUN_INT, + RustGungraunJson = RUST_GUNGRAUN_JSON_INT, Cpp = CPP_INT, CppGoogle = CPP_GOOGLE_INT, CppCatch2 = CPP_CATCH2_INT, @@ -179,6 +181,7 @@ impl Adapter { | Self::RustCriterion | Self::RustIai | Self::RustGungraun + | Self::RustGungraunJson | Self::CppGoogle | Self::CppCatch2 | Self::GoBench @@ -206,6 +209,7 @@ impl fmt::Display for Adapter { Self::RustCriterion => write!(f, "rust_criterion"), Self::RustIai => write!(f, "rust_iai"), Self::RustGungraun => write!(f, "rust_gungraun"), + Self::RustGungraunJson => write!(f, "rust_gungraun_json"), Self::Cpp => write!(f, "cpp"), Self::CppGoogle => write!(f, "cpp_google"), Self::CppCatch2 => write!(f, "cpp_catch2"), @@ -239,8 +243,8 @@ mod adapter { DART_BENCHMARK_HARNESS_INT, DART_INT, GO_BENCH_INT, GO_INT, JAVA_INT, JAVA_JMH_INT, JS_BENCHMARK_INT, JS_INT, JS_TIME_INT, JS_VITEST_INT, JSON_INT, MAGIC_INT, PYTHON_ASV_INT, PYTHON_INT, PYTHON_PYTEST_INT, RUBY_BENCHMARK_INT, RUBY_INT, RUST_BENCH_INT, - RUST_CRITERION_INT, RUST_GUNGRAUN_INT, RUST_IAI_INT, RUST_INT, SHELL_HYPERFINE_INT, - SHELL_INT, + RUST_CRITERION_INT, RUST_GUNGRAUN_INT, RUST_GUNGRAUN_JSON_INT, RUST_IAI_INT, RUST_INT, + SHELL_HYPERFINE_INT, SHELL_INT, }; #[derive(Debug, thiserror::Error)] @@ -266,6 +270,7 @@ mod adapter { Self::RustCriterion => RUST_CRITERION_INT.to_sql(out), Self::RustIai => RUST_IAI_INT.to_sql(out), Self::RustGungraun => RUST_GUNGRAUN_INT.to_sql(out), + Self::RustGungraunJson => RUST_GUNGRAUN_JSON_INT.to_sql(out), Self::Cpp => CPP_INT.to_sql(out), Self::CppGoogle => CPP_GOOGLE_INT.to_sql(out), Self::CppCatch2 => CPP_CATCH2_INT.to_sql(out), From d08cfab8bc30792d5df9e3f211fea76443b3976f Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Sat, 8 Aug 2026 20:40:18 +0200 Subject: [PATCH 04/13] Add tests for gungraun json parser --- .../src/adapters/rust/gungraun_json.rs | 368 ++++++++++++++++++ lib/bencher_adapter/src/adapters/rust/mod.rs | 13 +- .../gungraun/json_multiple_benchmarks.txt | 17 + .../rust/gungraun/json_multiple_tools.txt | 16 + .../rust/gungraun/json_no_id_no_details.txt | 14 + .../tool_output/rust/gungraun/json_not_v6.txt | 14 + .../json_one_cachegrind_all_metrics.txt | 16 + .../json_one_callgrind_all_metrics.txt | 15 + .../rust/gungraun/json_one_callgrind_diff.txt | 14 + .../json_one_callgrind_no_diff_new.txt | 14 + .../json_one_callgrind_no_diff_old.txt | 14 + .../gungraun/json_one_dhat_all_metrics.txt | 17 + .../gungraun/json_one_drd_all_metrics.txt | 19 + .../json_one_helgrind_all_metrics.txt | 19 + .../json_one_memcheck_all_metrics.txt | 19 + .../json_one_tool_without_metrics.txt | 17 + 16 files changed, 605 insertions(+), 1 deletion(-) create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_benchmarks.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_tools.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_no_id_no_details.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_not_v6.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_cachegrind_all_metrics.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_all_metrics.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_diff.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_new.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_old.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_dhat_all_metrics.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_drd_all_metrics.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_helgrind_all_metrics.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_memcheck_all_metrics.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_one_tool_without_metrics.txt diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs index efe1292fe..59f06d832 100644 --- a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs +++ b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs @@ -262,3 +262,371 @@ fn diff_to_json(diff: &MetricsDiff) -> Option { upper_value: None, }) } + +#[cfg(test)] +pub(crate) mod test_rust_gungraun_json { + use crate::{ + AdapterResults, Settings, + adapters::test_util::{convert_file_path, opt_convert_file_path}, + }; + use bencher_json::project::measure::built_in::{BuiltInMeasure as _, gungraun::*}; + use ordered_float::OrderedFloat; + use pretty_assertions::assert_eq; + + use super::AdapterRustGungraunJson; + use std::collections::HashMap; + + #[test] + fn not_v6() { + let results = opt_convert_file_path::( + "./tool_output/rust/gungraun/json_not_v6.txt", + Settings::default(), + ); + + assert!(results.is_none()); + } + + #[test] + fn no_id_no_details() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_no_id_no_details.txt", + ); + + let expected = HashMap::from([(D1MissRate::SLUG_STR, 0.1), (D1mr::SLUG_STR, 6.0)]); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100", + ); + } + + #[test] + fn one_callgrind_diff() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + + #[test] + fn one_callgrind_no_diff_new() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_no_diff_new.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + + #[test] + fn one_callgrind_no_diff_old() { + let expected = HashMap::new(); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_no_diff_old.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn one_callgrind_all_metrics() { + let expected = HashMap::from([ + (AcCost1::SLUG_STR, 0.0), + (AcCost2::SLUG_STR, 100.0), + (Bc::SLUG_STR, 200.0), + (Bcm::SLUG_STR, 300.0), + (Bi::SLUG_STR, 400.0), + (Bim::SLUG_STR, 500.0), + (D1MissRate::SLUG_STR, 0.0), + (D1mr::SLUG_STR, 600.0), + (D1mw::SLUG_STR, 700.0), + (DLdmr::SLUG_STR, 800.0), + (DLdmw::SLUG_STR, 900.0), + (DLmr::SLUG_STR, 1000.0), + (DLmw::SLUG_STR, 1100.0), + (Dr::SLUG_STR, 1200.0), + (Dw::SLUG_STR, 1300.0), + (EstimatedCycles::SLUG_STR, 1400.0), + (GlobalBusEvents::SLUG_STR, 1500.0), + (I1MissRate::SLUG_STR, 0.1), + (I1mr::SLUG_STR, 1600.0), + (ILdmr::SLUG_STR, 1700.0), + (ILmr::SLUG_STR, 1800.0), + (Instructions::SLUG_STR, 1900.0), + (L1HitRate::SLUG_STR, 0.2), + (L1Hits::SLUG_STR, 2000.0), + (LLHitRate::SLUG_STR, 0.3), + (LLMissRate::SLUG_STR, 0.4), + (LLdMissRate::SLUG_STR, 0.5), + (LLHits::SLUG_STR, 2100.0), + (LLiMissRate::SLUG_STR, 0.6), + (RamHitRate::SLUG_STR, 0.7), + (RamHits::SLUG_STR, 2200.0), + (SpLoss1::SLUG_STR, 2300.0), + (SpLoss2::SLUG_STR, 2400.0), + (SysCount::SLUG_STR, 2500.0), + (SysCpuTime::SLUG_STR, 2600.0), + (SysTime::SLUG_STR, 2700.0), + (TotalReadWrite::SLUG_STR, 2800.0), + ]); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_all_metrics.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn one_cachegrind_all_metrics() { + let expected = HashMap::from([ + (Bc::SLUG_STR, 0.0), + (Bcm::SLUG_STR, 100.0), + (Bi::SLUG_STR, 200.0), + (Bim::SLUG_STR, 300.0), + (D1MissRate::SLUG_STR, 0.0), + (D1mr::SLUG_STR, 400.0), + (D1mw::SLUG_STR, 500.0), + (DLmr::SLUG_STR, 600.0), + (DLmw::SLUG_STR, 700.0), + (Dr::SLUG_STR, 800.0), + (Dw::SLUG_STR, 900.0), + (EstimatedCycles::SLUG_STR, 1000.0), + (I1MissRate::SLUG_STR, 0.1), + (I1mr::SLUG_STR, 1100.0), + (ILmr::SLUG_STR, 1200.0), + (Instructions::SLUG_STR, 1300.0), + (L1HitRate::SLUG_STR, 0.2), + (L1Hits::SLUG_STR, 1400.0), + (LLHitRate::SLUG_STR, 0.3), + (LLMissRate::SLUG_STR, 0.4), + (LLdMissRate::SLUG_STR, 0.5), + (LLHits::SLUG_STR, 1500.0), + (LLiMissRate::SLUG_STR, 0.6), + (RamHitRate::SLUG_STR, 0.7), + (RamHits::SLUG_STR, 1600.0), + (TotalReadWrite::SLUG_STR, 1700.0), + ]); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_cachegrind_all_metrics.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn one_dhat_all_metrics() { + let expected = HashMap::from([ + (AtTEndBlocks::SLUG_STR, 0.0), + (AtTEndBytes::SLUG_STR, 1.0), + (AtTGmaxBlocks::SLUG_STR, 2.0), + (AtTGmaxBytes::SLUG_STR, 3.0), + (MaximumBlocks::SLUG_STR, 4.0), + (MaximumBytes::SLUG_STR, 5.0), + (ReadsBytes::SLUG_STR, 6.0), + (TotalBlocks::SLUG_STR, 7.0), + (TotalBytes::SLUG_STR, 8.0), + (TotalEvents::SLUG_STR, 9.0), + (TotalLifetimes::SLUG_STR, 10.0), + (TotalUnits::SLUG_STR, 11.0), + (WritesBytes::SLUG_STR, 12.0), + ]); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_dhat_all_metrics.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn one_memcheck_all_metrics() { + let expected = HashMap::from([ + (MemcheckContexts::SLUG_STR, 0.0), + (MemcheckErrors::SLUG_STR, 1.0), + (MemcheckSuppressedContexts::SLUG_STR, 2.0), + (MemcheckSuppressedErrors::SLUG_STR, 3.0), + ]); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_memcheck_all_metrics.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn one_helgrind_all_metrics() { + let expected = HashMap::from([ + (HelgrindContexts::SLUG_STR, 0.0), + (HelgrindErrors::SLUG_STR, 1.0), + (HelgrindSuppressedContexts::SLUG_STR, 2.0), + (HelgrindSuppressedErrors::SLUG_STR, 3.0), + ]); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_helgrind_all_metrics.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn one_drd_all_metrics() { + let expected = HashMap::from([ + (DrdContexts::SLUG_STR, 0.0), + (DrdErrors::SLUG_STR, 1.0), + (DrdSuppressedContexts::SLUG_STR, 2.0), + (DrdSuppressedErrors::SLUG_STR, 3.0), + ]); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_drd_all_metrics.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn one_tool_without_metrics() { + let expected = HashMap::new(); + + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_tool_without_metrics.txt", + ); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn multiple_tools() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_multiple_tools.txt", + ); + + let expected = HashMap::from([ + // Callgrid + (D1MissRate::SLUG_STR, 0.1), + (D1mr::SLUG_STR, 6.0), + // DHAT + (AtTEndBlocks::SLUG_STR, 1.0), + ]); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + #[test] + fn multiple_benchmarks() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_multiple_benchmarks.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let expected = HashMap::from([ + // Callgrid + (D1MissRate::SLUG_STR, 0.1), + (D1mr::SLUG_STR, 6.0), + // DHAT + (AtTEndBlocks::SLUG_STR, 1.0), + ]); + + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::first_id", + ); + } + { + let expected = HashMap::from([ + (MemcheckContexts::SLUG_STR, 0.0), + (MemcheckErrors::SLUG_STR, 1.0), + (MemcheckSuppressedContexts::SLUG_STR, 2.0), + (MemcheckSuppressedErrors::SLUG_STR, 3.0), + ]); + + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::second_id", + ); + } + } + + pub fn validate_adapter_rust_gungraun_json(results: &AdapterResults) { + let expected = HashMap::from([(D1MissRate::SLUG_STR, 0.1), (D1mr::SLUG_STR, 6.0)]); + + assert_eq!(results.inner.len(), 1); + compare_benchmark( + &expected, + results, + "play_game::bench_play_game_group::bench_play_game_100::some_id", + ); + } + + fn compare_benchmark( + expected: &HashMap<&str, f64>, + results: &AdapterResults, + benchmark_name: &str, + ) { + let actual = results.get(benchmark_name).unwrap(); + assert_eq!(actual.inner.len(), expected.len()); + + for (key, value) in expected { + let metric = actual.get(key).unwrap(); + assert_eq!(metric.value, OrderedFloat::from(*value)); + assert_eq!(metric.lower_value, None); + assert_eq!(metric.upper_value, None); + } + } +} diff --git a/lib/bencher_adapter/src/adapters/rust/mod.rs b/lib/bencher_adapter/src/adapters/rust/mod.rs index 11216840f..3acc1d422 100644 --- a/lib/bencher_adapter/src/adapters/rust/mod.rs +++ b/lib/bencher_adapter/src/adapters/rust/mod.rs @@ -29,7 +29,7 @@ mod test_rust { use crate::adapters::{ rust::{ bench::test_rust_bench, criterion::test_rust_criterion, gungraun::test_rust_gungraun, - iai::test_rust_iai, + gungraun_json::test_rust_gungraun_json, iai::test_rust_iai, }, test_util::convert_file_path, }; @@ -63,4 +63,15 @@ mod test_rust { &test_rust_gungraun::OptionalMetrics::default(), ); } + + #[test] + fn adapter_rust_gungraun_json() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", + ); + + dbg!(&results); + + test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + } } diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_benchmarks.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_benchmarks.txt new file mode 100644 index 000000000..a4c8fff96 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_benchmarks.txt @@ -0,0 +1,17 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"first_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":6}}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":6}}}}}}},"tool":"Callgrind"},{"flamegraphs":[],"log_paths":["/dhat.bench_play_game_100.log"],"out_paths":["/dhat.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Right":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/dhat.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Dhat":{"AtTEndBlocks":{"diffs":null,"metrics":{"Left":{"Int":1}}}}}}],"total":{"regressions":[],"summary":{"Dhat":{"AtTEndBlocks":{"diffs":null,"metrics":{"Left":{"Int":1}}}}}}},"tool":"DHAT"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"second_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/memcheck.bench_play_game_100.log"],"out_paths":["/memcheck.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":"HEAP SUMMARY:\n in use at exit: 544 bytes in 1 blocks\n total heap usage: 115 allocs, 114 frees, 3,255 bytes allocated\n\nLEAK SUMMARY:\n definitely lost: 0 bytes in 0 blocks\n indirectly lost: 0 bytes in 0 blocks\n possibly lost: 0 bytes in 0 blocks\n still reachable: 544 bytes in 1 blocks\n suppressed: 0 bytes in 0 blocks\nRerun with --leak-check=full to see details of leaked memory\n\nFor lists of detected and suppressed errors, rerun with: -s","parent_pid":12345,"part":null,"path":"/memcheck.bench_play_game_100.log","pid":23456,"thread":null}},"metrics_summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}],"total":{"regressions":[],"summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}},"tool":"Memcheck"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_tools.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_tools.txt new file mode 100644 index 000000000..378807f28 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_multiple_tools.txt @@ -0,0 +1,16 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":6}}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":6}}}}}}},"tool":"Callgrind"},{"flamegraphs":[],"log_paths":["/dhat.bench_play_game_100.log"],"out_paths":["/dhat.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Right":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/dhat.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Dhat":{"AtTEndBlocks":{"diffs":null,"metrics":{"Left":{"Int":1}}}}}}],"total":{"regressions":[],"summary":{"Dhat":{"AtTEndBlocks":{"diffs":null,"metrics":{"Left":{"Int":1}}}}}}},"tool":"DHAT"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_no_id_no_details.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_no_id_no_details.txt new file mode 100644 index 000000000..67c150a55 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_no_id_no_details.txt @@ -0,0 +1,14 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":null,"kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Both":[{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1},{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/bencher/examples/rust/gungraun/target/gungraun/game/play_game/bench_play_game_group/bench_play_game_100/callgrind.bench_play_game_100.out.old","pid":23456,"thread":1}]},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Float":0.1},{"Float":0.1}]}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Int":6},{"Int":6}]}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Float":0.1},{"Float":0.1}]}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Int":6},{"Int":6}]}}}}}},"tool":"Callgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_not_v6.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_not_v6.txt new file mode 100644 index 000000000..02c2d8f37 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_not_v6.txt @@ -0,0 +1,14 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":null,"kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Both":[{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1},{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/bencher/examples/rust/gungraun/target/gungraun/game/play_game/bench_play_game_group/bench_play_game_100/callgrind.bench_play_game_100.out.old","pid":23456,"thread":1}]},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Float":0.1},{"Float":0.1}]}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Int":6},{"Int":6}]}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Float":0.1},{"Float":0.1}]}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Int":6},{"Int":6}]}}}}}},"tool":"Callgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"5"} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_cachegrind_all_metrics.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_cachegrind_all_metrics.txt new file mode 100644 index 000000000..14841b66c --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_cachegrind_all_metrics.txt @@ -0,0 +1,16 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/cachegrind.bench_play_game_100.log"],"out_paths":["/cachegrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/cachegrind.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Cachegrind":{"Bc":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Bcm":{"diffs":null,"metrics":{"Left":{"Int":100}}},"Bi":{"diffs":null,"metrics":{"Left":{"Int":200}}},"Bim":{"diffs":null,"metrics":{"Left":{"Int":300}}},"D1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.0}}},"D1mr":{"diffs":null,"metrics":{"Left":{"Int":400}}},"D1mw":{"diffs":null,"metrics":{"Left":{"Int":500}}},"DLmr":{"diffs":null,"metrics":{"Left":{"Int":600}}},"DLmw":{"diffs":null,"metrics":{"Left":{"Int":700}}},"Dr":{"diffs":null,"metrics":{"Left":{"Int":800}}},"Dw":{"diffs":null,"metrics":{"Left":{"Int":900}}},"EstimatedCycles":{"diffs":null,"metrics":{"Left":{"Int":1000}}},"I1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.1}}},"I1mr":{"diffs":null,"metrics":{"Left":{"Int":1100}}},"ILmr":{"diffs":null,"metrics":{"Left":{"Int":1200}}},"Ir":{"diffs":null,"metrics":{"Left":{"Int":1300}}},"L1HitRate":{"diffs":null,"metrics":{"Left":{"Float":0.2}}},"L1hits":{"diffs":null,"metrics":{"Left":{"Int":1400}}},"LLHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.3}}},"LLMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.4}}},"LLdMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.5}}},"LLhits":{"diffs":null,"metrics":{"Left":{"Int":1500}}},"LLiMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.6}}},"RamHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.7}}},"RamHits":{"diffs":null,"metrics":{"Left":{"Int":1600}}},"TotalRW":{"diffs":null,"metrics":{"Left":{"Int":1700}}}}}}],"total":{"regressions":[],"summary":{"Cachegrind":{"Bc":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Bcm":{"diffs":null,"metrics":{"Left":{"Int":100}}},"Bi":{"diffs":null,"metrics":{"Left":{"Int":200}}},"Bim":{"diffs":null,"metrics":{"Left":{"Int":300}}},"D1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.0}}},"D1mr":{"diffs":null,"metrics":{"Left":{"Int":400}}},"D1mw":{"diffs":null,"metrics":{"Left":{"Int":500}}},"DLmr":{"diffs":null,"metrics":{"Left":{"Int":600}}},"DLmw":{"diffs":null,"metrics":{"Left":{"Int":700}}},"Dr":{"diffs":null,"metrics":{"Left":{"Int":800}}},"Dw":{"diffs":null,"metrics":{"Left":{"Int":900}}},"EstimatedCycles":{"diffs":null,"metrics":{"Left":{"Int":1000}}},"I1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.1}}},"I1mr":{"diffs":null,"metrics":{"Left":{"Int":1100}}},"ILmr":{"diffs":null,"metrics":{"Left":{"Int":1200}}},"Ir":{"diffs":null,"metrics":{"Left":{"Int":1300}}},"L1HitRate":{"diffs":null,"metrics":{"Left":{"Float":0.2}}},"L1hits":{"diffs":null,"metrics":{"Left":{"Int":1400}}},"LLHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.3}}},"LLMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.4}}},"LLdMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.5}}},"LLhits":{"diffs":null,"metrics":{"Left":{"Int":1500}}},"LLiMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.6}}},"RamHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.7}}},"RamHits":{"diffs":null,"metrics":{"Left":{"Int":1600}}},"TotalRW":{"diffs":null,"metrics":{"Left":{"Int":1700}}}}}}},"tool":"Cachegrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_all_metrics.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_all_metrics.txt new file mode 100644 index 000000000..2b669fc31 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_all_metrics.txt @@ -0,0 +1,15 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Callgrind":{"AcCost1":{"diffs":null,"metrics":{"Left":{"Int":0}}},"AcCost2":{"diffs":null,"metrics":{"Left":{"Int":100}}},"Bc":{"diffs":null,"metrics":{"Left":{"Int":200}}},"Bcm":{"diffs":null,"metrics":{"Left":{"Int":300}}},"Bi":{"diffs":null,"metrics":{"Left":{"Int":400}}},"Bim":{"diffs":null,"metrics":{"Left":{"Int":500}}},"D1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.0}}},"D1mr":{"diffs":null,"metrics":{"Left":{"Int":600}}},"D1mw":{"diffs":null,"metrics":{"Left":{"Int":700}}},"DLdmr":{"diffs":null,"metrics":{"Left":{"Int":800}}},"DLdmw":{"diffs":null,"metrics":{"Left":{"Int":900}}},"DLmr":{"diffs":null,"metrics":{"Left":{"Int":1000}}},"DLmw":{"diffs":null,"metrics":{"Left":{"Int":1100}}},"Dr":{"diffs":null,"metrics":{"Left":{"Int":1200}}},"Dw":{"diffs":null,"metrics":{"Left":{"Int":1300}}},"EstimatedCycles":{"diffs":null,"metrics":{"Left":{"Int":1400}}},"Ge":{"diffs":null,"metrics":{"Left":{"Int":1500}}},"I1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.1}}},"I1mr":{"diffs":null,"metrics":{"Left":{"Int":1600}}},"ILdmr":{"diffs":null,"metrics":{"Left":{"Int":1700}}},"ILmr":{"diffs":null,"metrics":{"Left":{"Int":1800}}},"Ir":{"diffs":null,"metrics":{"Left":{"Int":1900}}},"L1HitRate":{"diffs":null,"metrics":{"Left":{"Float":0.2}}},"L1hits":{"diffs":null,"metrics":{"Left":{"Int":2000}}},"LLHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.3}}},"LLMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.4}}},"LLdMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.5}}},"LLhits":{"diffs":null,"metrics":{"Left":{"Int":2100}}},"LLiMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.6}}},"RamHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.7}}},"RamHits":{"diffs":null,"metrics":{"Left":{"Int":2200}}},"SpLoss1":{"diffs":null,"metrics":{"Left":{"Int":2300}}},"SpLoss2":{"diffs":null,"metrics":{"Left":{"Int":2400}}},"SysCount":{"diffs":null,"metrics":{"Left":{"Int":2500}}},"SysCpuTime":{"diffs":null,"metrics":{"Left":{"Int":2600}}},"SysTime":{"diffs":null,"metrics":{"Left":{"Int":2700}}},"TotalRW":{"diffs":null,"metrics":{"Left":{"Int":2800}}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"AcCost1":{"diffs":null,"metrics":{"Left":{"Int":0}}},"AcCost2":{"diffs":null,"metrics":{"Left":{"Int":100}}},"Bc":{"diffs":null,"metrics":{"Left":{"Int":200}}},"Bcm":{"diffs":null,"metrics":{"Left":{"Int":300}}},"Bi":{"diffs":null,"metrics":{"Left":{"Int":400}}},"Bim":{"diffs":null,"metrics":{"Left":{"Int":500}}},"D1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.0}}},"D1mr":{"diffs":null,"metrics":{"Left":{"Int":600}}},"D1mw":{"diffs":null,"metrics":{"Left":{"Int":700}}},"DLdmr":{"diffs":null,"metrics":{"Left":{"Int":800}}},"DLdmw":{"diffs":null,"metrics":{"Left":{"Int":900}}},"DLmr":{"diffs":null,"metrics":{"Left":{"Int":1000}}},"DLmw":{"diffs":null,"metrics":{"Left":{"Int":1100}}},"Dr":{"diffs":null,"metrics":{"Left":{"Int":1200}}},"Dw":{"diffs":null,"metrics":{"Left":{"Int":1300}}},"EstimatedCycles":{"diffs":null,"metrics":{"Left":{"Int":1400}}},"Ge":{"diffs":null,"metrics":{"Left":{"Int":1500}}},"I1MissRate":{"diffs":null,"metrics":{"Left":{"Float":0.1}}},"I1mr":{"diffs":null,"metrics":{"Left":{"Int":1600}}},"ILdmr":{"diffs":null,"metrics":{"Left":{"Int":1700}}},"ILmr":{"diffs":null,"metrics":{"Left":{"Int":1800}}},"Ir":{"diffs":null,"metrics":{"Left":{"Int":1900}}},"L1HitRate":{"diffs":null,"metrics":{"Left":{"Float":0.2}}},"L1hits":{"diffs":null,"metrics":{"Left":{"Int":2000}}},"LLHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.3}}},"LLMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.4}}},"LLdMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.5}}},"LLhits":{"diffs":null,"metrics":{"Left":{"Int":2100}}},"LLiMissRate":{"diffs":null,"metrics":{"Left":{"Float":0.6}}},"RamHitRate":{"diffs":null,"metrics":{"Left":{"Float":0.7}}},"RamHits":{"diffs":null,"metrics":{"Left":{"Int":2200}}},"SpLoss1":{"diffs":null,"metrics":{"Left":{"Int":2300}}},"SpLoss2":{"diffs":null,"metrics":{"Left":{"Int":2400}}},"SysCount":{"diffs":null,"metrics":{"Left":{"Int":2500}}},"SysCpuTime":{"diffs":null,"metrics":{"Left":{"Int":2600}}},"SysTime":{"diffs":null,"metrics":{"Left":{"Int":2700}}},"TotalRW":{"diffs":null,"metrics":{"Left":{"Int":2800}}}}}}},"tool":"Callgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_diff.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_diff.txt new file mode 100644 index 000000000..36396d38c --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_diff.txt @@ -0,0 +1,14 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Both":[{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1},{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/bencher/examples/rust/gungraun/target/gungraun/game/play_game/bench_play_game_group/bench_play_game_100/callgrind.bench_play_game_100.out.old","pid":23456,"thread":1}]},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Float":0.1},{"Float":0.1}]}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Int":6},{"Int":6}]}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Float":0.1},{"Float":0.1}]}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Both":[{"Int":6},{"Int":6}]}}}}}},"tool":"Callgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_new.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_new.txt new file mode 100644 index 000000000..5a154c076 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_new.txt @@ -0,0 +1,14 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":6}}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":6}}}}}}},"tool":"Callgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_old.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_old.txt new file mode 100644 index 000000000..7c50bcc66 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_callgrind_no_diff_old.txt @@ -0,0 +1,14 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Right":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Right":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Right":{"Int":6}}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Right":{"Float":0.1}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Right":{"Int":6}}}}}}},"tool":"Callgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_dhat_all_metrics.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_dhat_all_metrics.txt new file mode 100644 index 000000000..56436ee40 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_dhat_all_metrics.txt @@ -0,0 +1,17 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/dhat.bench_play_game_100.log"],"out_paths":["/dhat.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Right":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/dhat.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Dhat":{"AtTEndBlocks":{"diffs":null,"metrics":{"Left":{"Int":0}}},"AtTEndBytes":{"diffs":null,"metrics":{"Left":{"Int":1}}},"AtTGmaxBlocks":{"diffs":null,"metrics":{"Left":{"Int":2}}},"AtTGmaxBytes":{"diffs":null,"metrics":{"Left":{"Int":3}}},"MaximumBlocks":{"diffs":null,"metrics":{"Left":{"Int":4}}},"MaximumBytes":{"diffs":null,"metrics":{"Left":{"Int":5}}},"ReadsBytes":{"diffs":null,"metrics":{"Left":{"Int":6}}},"TotalBlocks":{"diffs":null,"metrics":{"Left":{"Int":7}}},"TotalBytes":{"diffs":null,"metrics":{"Left":{"Int":8}}},"TotalEvents":{"diffs":null,"metrics":{"Left":{"Int":9}}},"TotalLifetimes":{"diffs":null,"metrics":{"Left":{"Int":10}}},"TotalUnits":{"diffs":null,"metrics":{"Left":{"Int":11}}},"WritesBytes":{"diffs":null,"metrics":{"Left":{"Int":12}}}}}}],"total":{"regressions":[],"summary":{"Dhat":{"AtTEndBlocks":{"diffs":null,"metrics":{"Left":{"Int":0}}},"AtTEndBytes":{"diffs":null,"metrics":{"Left":{"Int":1}}},"AtTGmaxBlocks":{"diffs":null,"metrics":{"Left":{"Int":2}}},"AtTGmaxBytes":{"diffs":null,"metrics":{"Left":{"Int":3}}},"MaximumBlocks":{"diffs":null,"metrics":{"Left":{"Int":4}}},"MaximumBytes":{"diffs":null,"metrics":{"Left":{"Int":5}}},"ReadsBytes":{"diffs":null,"metrics":{"Left":{"Int":6}}},"TotalBlocks":{"diffs":null,"metrics":{"Left":{"Int":7}}},"TotalBytes":{"diffs":null,"metrics":{"Left":{"Int":8}}},"TotalEvents":{"diffs":null,"metrics":{"Left":{"Int":9}}},"TotalLifetimes":{"diffs":null,"metrics":{"Left":{"Int":10}}},"TotalUnits":{"diffs":null,"metrics":{"Left":{"Int":11}}},"WritesBytes":{"diffs":null,"metrics":{"Left":{"Int":12}}}}}}},"tool":"DHAT"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_drd_all_metrics.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_drd_all_metrics.txt new file mode 100644 index 000000000..3aa2fc5de --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_drd_all_metrics.txt @@ -0,0 +1,19 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/drd.bench_play_game_100.log"],"out_paths":["/drd.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":12345,"part":null,"path":"/drd.bench_play_game_100.log","pid":23456,"thread":null}},"metrics_summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}],"total":{"regressions":[],"summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}},"tool":"DRD"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_helgrind_all_metrics.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_helgrind_all_metrics.txt new file mode 100644 index 000000000..c1e0edbb4 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_helgrind_all_metrics.txt @@ -0,0 +1,19 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/helgrind.bench_play_game_100.log"],"out_paths":["/helgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":12345,"part":null,"path":"/helgrind.bench_play_game_100.log","pid":23456,"thread":null}},"metrics_summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}],"total":{"regressions":[],"summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}},"tool":"Helgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_memcheck_all_metrics.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_memcheck_all_metrics.txt new file mode 100644 index 000000000..075e8c3d7 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_memcheck_all_metrics.txt @@ -0,0 +1,19 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/memcheck.bench_play_game_100.log"],"out_paths":["/memcheck.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":"HEAP SUMMARY:\n in use at exit: 544 bytes in 1 blocks\n total heap usage: 115 allocs, 114 frees, 3,255 bytes allocated\n\nLEAK SUMMARY:\n definitely lost: 0 bytes in 0 blocks\n indirectly lost: 0 bytes in 0 blocks\n possibly lost: 0 bytes in 0 blocks\n still reachable: 544 bytes in 1 blocks\n suppressed: 0 bytes in 0 blocks\nRerun with --leak-check=full to see details of leaked memory\n\nFor lists of detected and suppressed errors, rerun with: -s","parent_pid":12345,"part":null,"path":"/memcheck.bench_play_game_100.log","pid":23456,"thread":null}},"metrics_summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}],"total":{"regressions":[],"summary":{"ErrorTool":{"Contexts":{"diffs":null,"metrics":{"Left":{"Int":0}}},"Errors":{"diffs":null,"metrics":{"Left":{"Int":1}}},"SuppressedContexts":{"diffs":null,"metrics":{"Left":{"Int":2}}},"SuppressedErrors":{"diffs":null,"metrics":{"Left":{"Int":3}}}}}}},"tool":"Memcheck"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_one_tool_without_metrics.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_tool_without_metrics.txt new file mode 100644 index 000000000..8126815a9 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_one_tool_without_metrics.txt @@ -0,0 +1,17 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"some_id","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/massif.bench_play_game_100.log"],"out_paths":["/massif.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":12345,"part":null,"path":"/massif.bench_play_game_100.log","pid":23456,"thread":null}},"metrics_summary":"None"}],"total":{"regressions":[],"summary":"None"}},"tool":"Massif"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... From 0657e75bd8f0943cee943e72bb5aca1ccc767d40 Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Sat, 8 Aug 2026 20:40:57 +0200 Subject: [PATCH 05/13] Bump gungraun version in example --- examples/rust/gungraun/Cargo.lock | 117 ++++++++++++++++++++++++------ examples/rust/gungraun/Cargo.toml | 2 +- 2 files changed, 96 insertions(+), 23 deletions(-) diff --git a/examples/rust/gungraun/Cargo.lock b/examples/rust/gungraun/Cargo.lock index 94fbe7d6d..ccf6570e9 100644 --- a/examples/rust/gungraun/Cargo.lock +++ b/examples/rust/gungraun/Cargo.lock @@ -3,12 +3,15 @@ version = 4 [[package]] -name = "bincode" -version = "1.3.3" +name = "bincode-next" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "1d6626829353ae29293be5c86f42de5f0468bc758af074b0c7d08f07e538ccbc" dependencies = [ + "pastey", + "rapidhash", "serde", + "unty-next", ] [[package]] @@ -29,9 +32,25 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.114", ] +[[package]] +name = "either-or-both" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717164c227120ba9ddf3e2b32305fc0122741d3ee41a54968eae7573ee01933" +dependencies = [ + "indexmap", + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "game" version = "0.1.0" @@ -41,11 +60,11 @@ dependencies = [ [[package]] name = "gungraun" -version = "0.18.0" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7548ffb27cd5b2a15832eda0045a3f3298c83c3c04ff9eec647d61822e7effa" +checksum = "9300d38d30facf6870c15bc9e243edcc47e5ddc270c9d2c1ae824a00b1faea79" dependencies = [ - "bincode", + "bincode-next", "derive_more", "gungraun-macros", "gungraun-runner", @@ -53,29 +72,46 @@ dependencies = [ [[package]] name = "gungraun-macros" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35c7fb6133421db1cf752b7a2838d9277a26810ccaeeca7aa449f96ad7c2b01" +checksum = "d7f3214bae6cfd6739f4f29edb262bae439c6393a7b7b12c4eeb96417c2e50df" dependencies = [ "derive_more", - "proc-macro-error2", + "proc-macro-error3", "proc-macro2", "quote", "rustc_version", "serde", "serde_json", - "syn", + "syn 2.0.114", ] [[package]] name = "gungraun-runner" -version = "0.18.0" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365ec7a45b5dd0b147b2efd3e3f9517274ce567c6226c8e84c0a3350f66d4375" +checksum = "47c68c92812da579a2510a2cc702d5aa3251992b9662d4a98502ca46e0cbe16e" dependencies = [ + "either-or-both", "serde", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.17" @@ -89,25 +125,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + +[[package]] +name = "proc-macro-error-attr3" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "b0084e6206a967a2dad822180626b2f6b07a3b379325e8f1ec0438e33a469ba7" dependencies = [ "proc-macro2", "quote", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "proc-macro-error3" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "0cf066225f2373bc711684792b69bdeac0356019b007e721090c24d92d5d5a50" dependencies = [ - "proc-macro-error-attr2", + "proc-macro-error-attr3", "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] @@ -128,6 +170,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rapidhash" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" +dependencies = [ + "rustversion", +] + [[package]] name = "rustc_version" version = "0.4.1" @@ -137,6 +188,12 @@ dependencies = [ "semver", ] +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + [[package]] name = "semver" version = "1.0.27" @@ -170,7 +227,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -197,12 +254,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unty-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16062d030850f35054e37746427b9febb74a2f24c9c6dd6fa2d0c13c5f53221e" + [[package]] name = "zmij" version = "1.0.20" diff --git a/examples/rust/gungraun/Cargo.toml b/examples/rust/gungraun/Cargo.toml index bfb6407d2..6582b72cc 100644 --- a/examples/rust/gungraun/Cargo.toml +++ b/examples/rust/gungraun/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" publish = false [dev-dependencies] -gungraun = "0.18.0" +gungraun = "0.19.4" [[bench]] name = "play_game" From 02e4a21d0bb9ca29880bfc423fa1111913398699 Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Sun, 9 Aug 2026 01:51:55 +0200 Subject: [PATCH 06/13] Regenerate types for rust_gungraun_json adapter --- services/api/openapi.json | 1 + services/console/src/types/bencher.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/services/api/openapi.json b/services/api/openapi.json index 984250e3b..9c68bbd45 100644 --- a/services/api/openapi.json +++ b/services/api/openapi.json @@ -11845,6 +11845,7 @@ "rust_criterion", "rust_iai", "rust_gungraun", + "rust_gungraun_json", "cpp", "cpp_google", "cpp_catch2", diff --git a/services/console/src/types/bencher.ts b/services/console/src/types/bencher.ts index 1a9b207a7..d638da2fd 100644 --- a/services/console/src/types/bencher.ts +++ b/services/console/src/types/bencher.ts @@ -1047,6 +1047,7 @@ export enum Adapter { RustCriterion = "rust_criterion", RustIai = "rust_iai", RustGungraun = "rust_gungraun", + RustGungraunJson = "rust_gungraun_json", Cpp = "cpp", CppGoogle = "cpp_google", CppCatch2 = "cpp_catch2", From b4544de0b56a5f73f9fba127c29449fcd015f7f8 Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Mon, 10 Aug 2026 19:25:20 +0200 Subject: [PATCH 07/13] fix missing from_sql for RUST_GU8NGRAUN_JSON_INT --- lib/bencher_json/src/project/report.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/bencher_json/src/project/report.rs b/lib/bencher_json/src/project/report.rs index 1a256f7d2..9d74e2c92 100644 --- a/lib/bencher_json/src/project/report.rs +++ b/lib/bencher_json/src/project/report.rs @@ -311,6 +311,7 @@ mod adapter { RUST_CRITERION_INT => Ok(Self::RustCriterion), RUST_IAI_INT => Ok(Self::RustIai), RUST_GUNGRAUN_INT => Ok(Self::RustGungraun), + RUST_GUNGRAUN_JSON_INT => Ok(Self::RustGungraunJson), CPP_INT => Ok(Self::Cpp), CPP_GOOGLE_INT => Ok(Self::CppGoogle), CPP_CATCH2_INT => Ok(Self::CppCatch2), From 1f105e3f3dcff97574705e625f271db609f6566e Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Tue, 11 Aug 2026 00:36:27 +0200 Subject: [PATCH 08/13] rust_gungraun adapter delegate to rust_gungraun_json, rust_gungraun_stdout --- lib/bencher_adapter/src/adapters/magic.rs | 18 +- .../src/adapters/rust/gungraun.rs | 1209 +--------------- .../src/adapters/rust/gungraun_stdout.rs | 1216 +++++++++++++++++ lib/bencher_adapter/src/adapters/rust/mod.rs | 43 +- lib/bencher_adapter/src/lib.rs | 6 +- lib/bencher_json/src/project/report.rs | 10 +- services/api/openapi.json | 1 + services/console/src/types/bencher.ts | 1 + 8 files changed, 1287 insertions(+), 1217 deletions(-) create mode 100644 lib/bencher_adapter/src/adapters/rust/gungraun_stdout.rs diff --git a/lib/bencher_adapter/src/adapters/magic.rs b/lib/bencher_adapter/src/adapters/magic.rs index 591364f5d..b8f1821b7 100644 --- a/lib/bencher_adapter/src/adapters/magic.rs +++ b/lib/bencher_adapter/src/adapters/magic.rs @@ -36,7 +36,8 @@ mod test_magic { python::{asv::test_python_asv, pytest::test_python_pytest}, ruby::benchmark::test_ruby_benchmark, rust::{ - bench::test_rust_bench, criterion::test_rust_criterion, gungraun::test_rust_gungraun, + bench::test_rust_bench, criterion::test_rust_criterion, + gungraun_json::test_rust_gungraun_json, gungraun_stdout::test_rust_gungraun_stdout, iai::test_rust_iai, }, shell::hyperfine::test_shell_hyperfine, @@ -147,17 +148,26 @@ mod test_magic { } #[test] - fn adapter_magic_rust_gungraun() { + fn adapter_magic_rust_gungraun_stdout() { let results = convert_file_path::( "./tool_output/rust/gungraun/without-optional-metrics.txt", ); - test_rust_gungraun::validate_adapter_rust_gungraun( + test_rust_gungraun_stdout::validate_adapter_rust_gungraun_stdout( &results, - &test_rust_gungraun::OptionalMetrics::default(), + &test_rust_gungraun_stdout::OptionalMetrics::default(), ); } + #[test] + fn adapter_magic_rust_gungraun_json() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", + ); + + test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + } + #[test] fn adapter_magic_shell_hyperfine() { let results = convert_file_path::("./tool_output/shell/hyperfine/two.json"); diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun.rs b/lib/bencher_adapter/src/adapters/rust/gungraun.rs index adc83e84a..8701c64b5 100644 --- a/lib/bencher_adapter/src/adapters/rust/gungraun.rs +++ b/lib/bencher_adapter/src/adapters/rust/gungraun.rs @@ -1,1211 +1,46 @@ -use std::ops::Neg as _; +use crate::Adaptable; -use bencher_json::{ - BenchmarkName, JsonNewMetric, - project::{ - measure::built_in::{BuiltInMeasure as _, gungraun}, - report::JsonAverage, - }, -}; -use nom::{ - IResult, Parser, - branch::alt, - bytes::complete::{is_a, is_not, tag, take_until1}, - character::complete::{char, space0, space1}, - combinator::{map, opt, peek, recognize}, - error::Error, - multi::{many0, many1}, - sequence::{delimited, preceded, terminated}, -}; - -use crate::{ - Adaptable, Settings, - adapters::util::parse_f64, - results::adapter_results::{AdapterResults, GungraunMeasure}, -}; +use super::{gungraun_json::AdapterRustGungraunJson, gungraun_stdout::AdapterRustGungraunStdout}; pub struct AdapterRustGungraun; impl Adaptable for AdapterRustGungraun { - fn parse(input: &str, settings: Settings) -> Option { - match settings.average { - None => {}, - Some(JsonAverage::Mean | JsonAverage::Median) => { - return None; // 'gungraun' results are for a single run only. - }, - } - - // Clean up the input by removing ANSI escape codes: - let input = strip_ansi_escapes::strip_str(input); - - let benchmarks = match multiple_benchmarks().parse(&*input) { - Err(error) => { - debug_assert!(false, "Error parsing input:\n{error:#?}"); - return None; - }, - Ok((remainder, benchmarks)) => { - debug_assert_eq!(remainder.len(), 0, "Unparsed trailing input:\n{remainder}"); - benchmarks - }, - }; - - AdapterResults::new_gungraun(benchmarks) + fn parse(input: &str, settings: crate::Settings) -> Option { + AdapterRustGungraunJson::parse(input, settings) + .or_else(|| AdapterRustGungraunStdout::parse(input, settings)) } } -fn multiple_benchmarks<'a>() --> impl Parser<&'a str, Output = Vec<(BenchmarkName, Vec)>, Error = Error<&'a str>> -{ - map( - many0(alt(( - // Try to parse a single benchmark: - single_benchmark(), - // Otherwise, parse/ignore unrelated lines: - map(terminated(not_line_ending(), opt(line_ending())), |_| None), - // Otherwise, parse/ignore empty lines: - map(line_ending(), |_| None), - ))), - // Skip 'None' resulting from empty/unrelated lines: - |benchmarks| benchmarks.into_iter().flatten().collect(), - ) -} - -fn single_benchmark<'a>() --> impl Parser<&'a str, Output = Option<(BenchmarkName, Vec)>, Error = Error<&'a str>> -{ - map( - ( - terminated( - recognize(( - is_not(":\r\n \t"), - tag("::"), - is_not(":\r\n \t"), - tag("::"), - not_benchmark_name_end(), - )), - benchmark_name_end(), - ), - many0(alt(( - // Callgrind tool if it was enabled: - callgrind_tool_measures(), - // Cachegrind tool if it was enabled: - cachegrind_tool_measures(), - // Add DHAT tool measures if it was enabled: - dhat_tool_measures(), - // Add Memcheck tool measures if it was enabled: - memcheck_tool_measures(), - // Add Helgrind tool measures if it was enabled: - helgrind_tool_measures(), - // Add Drd tool measures if it was enabled: - drd_tool_measures(), - ))), - ), - |(benchmark_name, measures)| { - // trim here to avoid loose `\r` chars at the end of the string because of the - // `not_benchmark_name_end` parser. It's maybe not a bad idea anyways. - let benchmark_name = benchmark_name.trim().parse().ok()?; - let measures = measures.into_iter().flatten().collect(); - - Some((benchmark_name, measures)) - }, - ) -} - -fn callgrind_tool_measures<'a>() --> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { - map( - preceded(opt(tool_name_line("CALLGRIND")), many1(metric_line())), - |metrics| { - metrics - .into_iter() - .map(|(metric_name, json)| match metric_name.as_str() { - gungraun::Instructions::NAME_STR => GungraunMeasure::Instructions(json), - gungraun::L1Hits::NAME_STR => GungraunMeasure::L1Hits(json), - gungraun::L2Hits::NAME_STR => GungraunMeasure::L2Hits(json), - gungraun::LLHits::NAME_STR => GungraunMeasure::LLHits(json), - gungraun::RamHits::NAME_STR => GungraunMeasure::RamHits(json), - gungraun::TotalReadWrite::NAME_STR => GungraunMeasure::TotalReadWrite(json), - gungraun::EstimatedCycles::NAME_STR => GungraunMeasure::EstimatedCycles(json), - gungraun::Dr::NAME_STR => GungraunMeasure::DataCacheReads(json), - gungraun::Dw::NAME_STR => GungraunMeasure::DataCacheWrites(json), - gungraun::I1mr::NAME_STR => GungraunMeasure::L1InstrCacheReadMisses(json), - gungraun::D1mr::NAME_STR => GungraunMeasure::L1DataCacheReadMisses(json), - gungraun::D1mw::NAME_STR => GungraunMeasure::L1DataCacheWriteMisses(json), - gungraun::ILmr::NAME_STR => GungraunMeasure::LLInstrCacheReadMisses(json), - gungraun::DLmr::NAME_STR => GungraunMeasure::LLDataCacheReadMisses(json), - gungraun::DLmw::NAME_STR => GungraunMeasure::LLDataCacheWriteMisses(json), - gungraun::I1MissRate::NAME_STR => GungraunMeasure::L1InstrCacheMissRate(json), - gungraun::LLiMissRate::NAME_STR => GungraunMeasure::LLInstrCacheMissRate(json), - gungraun::D1MissRate::NAME_STR => GungraunMeasure::L1DataCacheMissRate(json), - gungraun::LLdMissRate::NAME_STR => GungraunMeasure::LLDataCacheMissRate(json), - gungraun::LLMissRate::NAME_STR => GungraunMeasure::LLCacheMissRate(json), - gungraun::L1HitRate::NAME_STR => GungraunMeasure::L1HitRate(json), - gungraun::LLHitRate::NAME_STR => GungraunMeasure::LLHitRate(json), - gungraun::RamHitRate::NAME_STR => GungraunMeasure::RamHitRate(json), - gungraun::SysCount::NAME_STR => GungraunMeasure::NumberSystemCalls(json), - gungraun::SysTime::NAME_STR => GungraunMeasure::TimeSystemCalls(json), - gungraun::SysCpuTime::NAME_STR => GungraunMeasure::CpuTimeSystemCalls(json), - gungraun::GlobalBusEvents::NAME_STR => GungraunMeasure::GlobalBusEvents(json), - gungraun::Bc::NAME_STR => GungraunMeasure::ExecutedConditionalBranches(json), - gungraun::Bcm::NAME_STR => { - GungraunMeasure::MispredictedConditionalBranches(json) - }, - gungraun::Bi::NAME_STR => GungraunMeasure::ExecutedIndirectBranches(json), - gungraun::Bim::NAME_STR => GungraunMeasure::MispredictedIndirectBranches(json), - gungraun::ILdmr::NAME_STR => GungraunMeasure::DirtyMissInstructionRead(json), - gungraun::DLdmr::NAME_STR => GungraunMeasure::DirtyMissDataRead(json), - gungraun::DLdmw::NAME_STR => GungraunMeasure::DirtyMissDataWrite(json), - gungraun::AcCost1::NAME_STR => GungraunMeasure::L1BadTemporalLocality(json), - gungraun::AcCost2::NAME_STR => GungraunMeasure::LLBadTemporalLocality(json), - gungraun::SpLoss1::NAME_STR => GungraunMeasure::L1BadSpatialLocality(json), - gungraun::SpLoss2::NAME_STR => GungraunMeasure::LLBadSpatialLocality(json), - _ => GungraunMeasure::Unknown, - }) - .collect() - }, - ) -} - -fn cachegrind_tool_measures<'a>() --> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { - map( - preceded(tool_name_line("CACHEGRIND"), many1(metric_line())), - |metrics| { - metrics - .into_iter() - .map(|(metric_name, json)| match metric_name.as_str() { - gungraun::Instructions::NAME_STR => GungraunMeasure::Instructions(json), - gungraun::L1Hits::NAME_STR => GungraunMeasure::L1Hits(json), - gungraun::L2Hits::NAME_STR => GungraunMeasure::L2Hits(json), - gungraun::LLHits::NAME_STR => GungraunMeasure::LLHits(json), - gungraun::RamHits::NAME_STR => GungraunMeasure::RamHits(json), - gungraun::TotalReadWrite::NAME_STR => GungraunMeasure::TotalReadWrite(json), - gungraun::EstimatedCycles::NAME_STR => GungraunMeasure::EstimatedCycles(json), - gungraun::Dr::NAME_STR => GungraunMeasure::DataCacheReads(json), - gungraun::Dw::NAME_STR => GungraunMeasure::DataCacheWrites(json), - gungraun::I1mr::NAME_STR => GungraunMeasure::L1InstrCacheReadMisses(json), - gungraun::D1mr::NAME_STR => GungraunMeasure::L1DataCacheReadMisses(json), - gungraun::D1mw::NAME_STR => GungraunMeasure::L1DataCacheWriteMisses(json), - gungraun::ILmr::NAME_STR => GungraunMeasure::LLInstrCacheReadMisses(json), - gungraun::DLmr::NAME_STR => GungraunMeasure::LLDataCacheReadMisses(json), - gungraun::DLmw::NAME_STR => GungraunMeasure::LLDataCacheWriteMisses(json), - gungraun::I1MissRate::NAME_STR => GungraunMeasure::L1InstrCacheMissRate(json), - gungraun::LLiMissRate::NAME_STR => GungraunMeasure::LLInstrCacheMissRate(json), - gungraun::D1MissRate::NAME_STR => GungraunMeasure::L1DataCacheMissRate(json), - gungraun::LLdMissRate::NAME_STR => GungraunMeasure::LLDataCacheMissRate(json), - gungraun::LLMissRate::NAME_STR => GungraunMeasure::LLCacheMissRate(json), - gungraun::L1HitRate::NAME_STR => GungraunMeasure::L1HitRate(json), - gungraun::LLHitRate::NAME_STR => GungraunMeasure::LLHitRate(json), - gungraun::RamHitRate::NAME_STR => GungraunMeasure::RamHitRate(json), - _ => GungraunMeasure::Unknown, - }) - .collect() - }, - ) -} - -fn dhat_tool_measures<'a>() --> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { - map( - preceded(tool_name_line("DHAT"), many1(metric_line())), - |metrics| { - metrics - .into_iter() - .map(|(metric_name, json)| match metric_name.as_str() { - gungraun::TotalBytes::NAME_STR => GungraunMeasure::TotalBytes(json), - gungraun::TotalBlocks::NAME_STR => GungraunMeasure::TotalBlocks(json), - gungraun::TotalUnits::NAME_STR => GungraunMeasure::TotalUnits(json), - gungraun::TotalEvents::NAME_STR => GungraunMeasure::TotalEvents(json), - gungraun::TotalLifetimes::NAME_STR => GungraunMeasure::TotalLifetimes(json), - gungraun::AtTGmaxBytes::NAME_STR => GungraunMeasure::AtTGmaxBytes(json), - gungraun::AtTGmaxBlocks::NAME_STR => GungraunMeasure::AtTGmaxBlocks(json), - gungraun::AtTEndBytes::NAME_STR => GungraunMeasure::AtTEndBytes(json), - gungraun::AtTEndBlocks::NAME_STR => GungraunMeasure::AtTEndBlocks(json), - gungraun::ReadsBytes::NAME_STR => GungraunMeasure::ReadsBytes(json), - gungraun::WritesBytes::NAME_STR => GungraunMeasure::WritesBytes(json), - gungraun::MaximumBytes::NAME_STR => GungraunMeasure::MaximumBytes(json), - gungraun::MaximumBlocks::NAME_STR => GungraunMeasure::MaximumBlocks(json), - _ => GungraunMeasure::Unknown, - }) - .collect() - }, - ) -} - -fn memcheck_tool_measures<'a>() --> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { - map( - preceded(tool_name_line("MEMCHECK"), many1(metric_line())), - |metrics| { - metrics - .into_iter() - .map(|(metric_name, json)| match metric_name.as_str() { - gungraun::MemcheckErrors::NAME_STR => GungraunMeasure::MemcheckErrors(json), - gungraun::MemcheckContexts::NAME_STR => GungraunMeasure::MemcheckContexts(json), - gungraun::MemcheckSuppressedErrors::NAME_STR => { - GungraunMeasure::MemcheckSuppressedErrors(json) - }, - gungraun::MemcheckSuppressedContexts::NAME_STR => { - GungraunMeasure::MemcheckSuppressedContexts(json) - }, - _ => GungraunMeasure::Unknown, - }) - .collect() - }, - ) -} - -fn helgrind_tool_measures<'a>() --> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { - map( - preceded(tool_name_line("HELGRIND"), many1(metric_line())), - |metrics| { - metrics - .into_iter() - .map(|(metric_name, json)| match metric_name.as_str() { - gungraun::HelgrindErrors::NAME_STR => GungraunMeasure::HelgrindErrors(json), - gungraun::HelgrindContexts::NAME_STR => GungraunMeasure::HelgrindContexts(json), - gungraun::HelgrindSuppressedErrors::NAME_STR => { - GungraunMeasure::HelgrindSuppressedErrors(json) - }, - gungraun::HelgrindSuppressedContexts::NAME_STR => { - GungraunMeasure::HelgrindSuppressedContexts(json) - }, - _ => GungraunMeasure::Unknown, - }) - .collect() - }, - ) -} - -fn drd_tool_measures<'a>() --> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { - map( - preceded(tool_name_line("DRD"), many1(metric_line())), - |metrics| { - metrics - .into_iter() - .map(|(metric_name, json)| match metric_name.as_str() { - gungraun::DrdErrors::NAME_STR => GungraunMeasure::DrdErrors(json), - gungraun::DrdContexts::NAME_STR => GungraunMeasure::DrdContexts(json), - gungraun::DrdSuppressedErrors::NAME_STR => { - GungraunMeasure::DrdSuppressedErrors(json) - }, - gungraun::DrdSuppressedContexts::NAME_STR => { - GungraunMeasure::DrdSuppressedContexts(json) - }, - _ => GungraunMeasure::Unknown, - }) - .collect() - }, - ) -} - -fn tool_name_line<'a>( - tool_name: &'static str, -) -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { - delimited( - (space1, many1(tag("=")), tag(" ")), - tag(tool_name), - (tag(" "), many1(tag("=")), line_ending()), - ) -} - -fn metric_line<'a>() --> impl Parser<&'a str, Output = (String, JsonNewMetric), Error = Error<&'a str>> { - map( - ( - space1, - is_not(":\r\n"), - char(':'), - space1, - // the current run value: - parse_f64, - char('|'), - alt(( - // No previous run: - recognize(( - tag("N/A"), - space1, - delimited(char('('), many1(char('*')), char(')')), - )), - // Comparison to previous run: - recognize(( - parse_f64, - space0, - alt(( - recognize(delimited(char('('), tag("No change"), char(')'))), - recognize(( - delimited(char('('), alt((infinity, percent)), char(')')), - space1, - delimited(char('['), alt((infinity, factor)), char(']')), - )), - )), - )), - )), - line_ending(), - ), - |(_, metric_name, _, _, current_value, _, _, _)| { - ( - metric_name.to_owned(), - JsonNewMetric { - value: current_value.into(), - lower_value: None, - upper_value: None, - }, - ) - }, - ) -} - -fn infinity(input: &str) -> IResult<&str, f64> { - map( - ( - alt((many1(char('+')), many1(char('-')))), - tag("inf"), - alt((many1(char('+')), many1(char('-')))), - ), - |(signs, _, _)| { - // The indexing is safe due to the usage of `many1` above - #[expect(clippy::indexing_slicing, reason = "many1 guarantees non-empty vec")] - let sign = signs[0]; - if sign == '+' { - f64::INFINITY - } else { - f64::NEG_INFINITY - } - }, - ) - .parse(input) -} - -fn factor(input: &str) -> IResult<&str, f64> { - map( - (alt((char('+'), char('-'))), parse_f64, char('x')), - |(sign, num, _)| { - if sign == '+' { num } else { num.neg() } - }, - ) - .parse(input) -} - -fn percent(input: &str) -> IResult<&str, f64> { - map( - (alt((char('+'), char('-'))), parse_f64, char('%')), - |(sign, num, _)| { - if sign == '+' { num } else { num.neg() } - }, - ) - .parse(input) -} - -fn line_ending<'a>() -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { - is_a("\r\n") -} - -fn not_line_ending<'a>() -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { - // Note: `not(line_ending)` doesn't work here, as it won't consume the matched characters - is_not("\r\n") -} - -/// Parser that matches the benchmark name ending sequence, excluding the two spaces -fn benchmark_name_end<'a>() --> impl Parser<&'a str, Output = (&'a str, &'a str), Error = Error<&'a str>> { - // we only peek here so the `metric_line` parser can match the first spaces too - (line_ending(), peek(tag(" "))) -} - -/// A parser that matches input until it encounters the benchmark name end sequence. -/// -/// Similar to the `benchmark_name_end` parser, this parser addresses an unusual behavior in -/// `gungraun` (iai-callgrind) by allowing benchmark names to span multiple lines. While this -/// behavior is not a bug in `gungraun`, it deviates from the original intent. If there are multiple -/// lines they don't start with two spaces, so we can use that as test for the end of the benchmark -/// name. -fn not_benchmark_name_end<'a>() -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { - // Ignore the `\r\n` possibility here and instead trim the benchmark name later - take_until1("\n ") -} - #[cfg(test)] pub(crate) mod test_rust_gungraun { - use crate::{AdapterResults, adapters::test_util::convert_file_path}; - use bencher_json::project::measure::built_in::{BuiltInMeasure as _, gungraun}; - use ordered_float::OrderedFloat; - use pretty_assertions::assert_eq; - - use super::AdapterRustGungraun; - use std::collections::HashMap; - - #[test] - fn without_optional_metrics() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/without-optional-metrics.txt", - ); - - validate_adapter_rust_gungraun(&results, &OptionalMetrics::default()); - } - - #[test] - fn with_dhat() { - let results = - convert_file_path::("./tool_output/rust/gungraun/with-dhat.txt"); - - validate_adapter_rust_gungraun( - &results, - &OptionalMetrics { - dhat: true, - ..Default::default() - }, - ); - } - - #[test] - fn with_dhat_first_then_callgrind() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/dhat-then-callgrind.txt", - ); - - validate_adapter_rust_gungraun( - &results, - &OptionalMetrics { - dhat: true, - ..Default::default() - }, - ); - } - - #[test] - fn with_dhat_and_global_bus_events() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/with-dhat-and-global-bus-events.txt", - ); - - validate_adapter_rust_gungraun( - &results, - &OptionalMetrics { - dhat: true, - global_bus_events: true, - }, - ); - } - - #[test] - fn delta() { - let results = - convert_file_path::("./tool_output/rust/gungraun/delta.txt"); - - validate_adapter_rust_gungraun(&results, &OptionalMetrics::default()); - } - - #[test] - fn delta_with_infinity() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/delta_with_inf.txt", - ); - - assert_eq!(results.inner.len(), 2); - - { - let expected = HashMap::from([ - (gungraun::Instructions::SLUG_STR, 1_734.0), - (gungraun::L1Hits::SLUG_STR, 2_359.0), - (gungraun::L2Hits::SLUG_STR, 0.0), - (gungraun::RamHits::SLUG_STR, 3.0), - (gungraun::TotalReadWrite::SLUG_STR, 0.0), - (gungraun::EstimatedCycles::SLUG_STR, 2_464.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci short:10", - ); - } - - { - let expected = HashMap::from([ - (gungraun::Instructions::SLUG_STR, 26_214_734.0), - (gungraun::L1Hits::SLUG_STR, 35_638_619.0), - (gungraun::L2Hits::SLUG_STR, 0.0), - (gungraun::RamHits::SLUG_STR, 3.0), - (gungraun::TotalReadWrite::SLUG_STR, 35_638_622.0), - (gungraun::EstimatedCycles::SLUG_STR, 35_638_724.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci long:30", - ); - } - } - - #[test] - fn with_summary_and_regressions() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/with-summary-and-regressions.txt", - ); - - validate_adapter_rust_gungraun(&results, &OptionalMetrics::default()); - } - - #[test] - fn with_gungraun_summary() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/with-gungraun-summary.txt", - ); - - validate_adapter_rust_gungraun(&results, &OptionalMetrics::default()); - } - - #[test] - fn ansi_escapes_issue_345() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/ansi-escapes.txt", - ); - - validate_adapter_rust_gungraun(&results, &OptionalMetrics::default()); - } - - #[test] - fn with_ge() { - let results = - convert_file_path::("./tool_output/rust/gungraun/with-ge.txt"); + use crate::adapters::{ + rust::{ + gungraun_json::test_rust_gungraun_json::validate_adapter_rust_gungraun_json, + gungraun_stdout::{AdapterRustGungraunStdout, test_rust_gungraun_stdout}, + }, + test_util::convert_file_path, + }; - validate_adapter_rust_gungraun( - &results, - &OptionalMetrics { - global_bus_events: true, - ..Default::default() - }, - ); - } + use super::AdapterRustGungraunJson; #[test] - fn without_cachesim() { - use gungraun::*; - - let results = convert_file_path::( - "./tool_output/rust/gungraun/without-cachesim.txt", + fn json() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", ); - assert_eq!(results.inner.len(), 2); - - { - let expected = HashMap::from([(Instructions::SLUG_STR, 1734.0)]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci short:10", - ); - } - - { - let expected = HashMap::from([(Instructions::SLUG_STR, 26_214_734.0)]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci long:30", - ); - } + validate_adapter_rust_gungraun_json(&results); } #[test] - fn callgrind_mixed_order() { - use gungraun::*; - - let results = convert_file_path::( - "./tool_output/rust/gungraun/callgrind-mixed-order.txt", - ); - - assert_eq!(results.inner.len(), 2); - - let expected = HashMap::from([ - (Instructions::SLUG_STR, 1.0), - (Dr::SLUG_STR, 2.0), - (Dw::SLUG_STR, 3.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::callgrind_format mixed_1", + fn stdout() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/without-optional-metrics.txt", ); - compare_benchmark( - &expected, + test_rust_gungraun_stdout::validate_adapter_rust_gungraun_stdout( &results, - "rust_iai_callgrind::custom_format::callgrind_format mixed_2", + &test_rust_gungraun_stdout::OptionalMetrics::default(), ); } - - #[test] - fn callgrind_ll_hits() { - use gungraun::*; - - let results = convert_file_path::( - "./tool_output/rust/gungraun/callgrind-ll-hits.txt", - ); - - assert_eq!(results.inner.len(), 2); - - { - let expected = - HashMap::from([(Instructions::SLUG_STR, 10.0), (LLHits::SLUG_STR, 20.0)]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::callgrind_format ll_hits", - ); - } - - { - let expected = HashMap::from([(Instructions::SLUG_STR, 1.0), (LLHits::SLUG_STR, 2.0)]); - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::callgrind_format ll_hits_mixed", - ); - } - } - - #[test] - fn callgrind_all() { - use gungraun::*; - - let results = convert_file_path::( - "./tool_output/rust/gungraun/callgrind-all.txt", - ); - - assert_eq!(results.inner.len(), 2); - - { - let expected = HashMap::from([ - (Instructions::SLUG_STR, 1.0), - (Dr::SLUG_STR, 2.0), - (Dw::SLUG_STR, 3.0), - (I1mr::SLUG_STR, 4.0), - (D1mr::SLUG_STR, 5.0), - (D1mw::SLUG_STR, 6.0), - (ILmr::SLUG_STR, 7.0), - (DLmr::SLUG_STR, 8.0), - (DLmw::SLUG_STR, 9.0), - (I1MissRate::SLUG_STR, 10.0), - (LLiMissRate::SLUG_STR, 11.0), - (D1MissRate::SLUG_STR, 12.0), - (LLdMissRate::SLUG_STR, 13.0), - (LLMissRate::SLUG_STR, 14.0), - (L1Hits::SLUG_STR, 15.0), - (L2Hits::SLUG_STR, 16.0), - (RamHits::SLUG_STR, 17.0), - (L1HitRate::SLUG_STR, 18.0), - (LLHitRate::SLUG_STR, 19.0), - (RamHitRate::SLUG_STR, 20.0), - (TotalReadWrite::SLUG_STR, 21.0), - (EstimatedCycles::SLUG_STR, 22.0), - (SysCount::SLUG_STR, 23.0), - (SysTime::SLUG_STR, 24.0), - (SysCpuTime::SLUG_STR, 25.0), - (GlobalBusEvents::SLUG_STR, 26.0), - (Bc::SLUG_STR, 27.0), - (Bcm::SLUG_STR, 28.0), - (Bi::SLUG_STR, 29.0), - (Bim::SLUG_STR, 30.0), - (ILdmr::SLUG_STR, 31.0), - (DLdmr::SLUG_STR, 32.0), - (DLdmw::SLUG_STR, 33.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::callgrind_format all_with_wb", - ); - } - - { - let expected = HashMap::from([ - (Instructions::SLUG_STR, 1.0), - (Dr::SLUG_STR, 2.0), - (Dw::SLUG_STR, 3.0), - (I1mr::SLUG_STR, 4.0), - (D1mr::SLUG_STR, 5.0), - (D1mw::SLUG_STR, 6.0), - (ILmr::SLUG_STR, 7.0), - (DLmr::SLUG_STR, 8.0), - (DLmw::SLUG_STR, 9.0), - (I1MissRate::SLUG_STR, 10.0), - (LLiMissRate::SLUG_STR, 11.0), - (D1MissRate::SLUG_STR, 12.0), - (LLdMissRate::SLUG_STR, 13.0), - (LLMissRate::SLUG_STR, 14.0), - (L1Hits::SLUG_STR, 15.0), - (L2Hits::SLUG_STR, 16.0), - (RamHits::SLUG_STR, 17.0), - (L1HitRate::SLUG_STR, 18.0), - (LLHitRate::SLUG_STR, 19.0), - (RamHitRate::SLUG_STR, 20.0), - (TotalReadWrite::SLUG_STR, 21.0), - (EstimatedCycles::SLUG_STR, 22.0), - (SysCount::SLUG_STR, 23.0), - (SysTime::SLUG_STR, 24.0), - (SysCpuTime::SLUG_STR, 25.0), - (GlobalBusEvents::SLUG_STR, 26.0), - (Bc::SLUG_STR, 27.0), - (Bcm::SLUG_STR, 28.0), - (Bi::SLUG_STR, 29.0), - (Bim::SLUG_STR, 30.0), - (AcCost1::SLUG_STR, 31.0), - (AcCost2::SLUG_STR, 32.0), - (SpLoss1::SLUG_STR, 33.0), - (SpLoss2::SLUG_STR, 34.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::callgrind_format all_with_cachuse", - ); - } - } - - #[test] - fn cachegrind() { - use gungraun::*; - - let results = - convert_file_path::("./tool_output/rust/gungraun/cachegrind.txt"); - - assert_eq!(results.inner.len(), 3); - - { - let expected = HashMap::from([(Instructions::SLUG_STR, 1.0)]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::cachegrind_format just_instructions", - ); - } - - { - let expected = HashMap::from([ - (I1MissRate::SLUG_STR, 1.0), - (Dr::SLUG_STR, 2.0), - (EstimatedCycles::SLUG_STR, 3.0), - (TotalReadWrite::SLUG_STR, 4.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::cachegrind_format metrics_mixed", - ); - } - - { - let expected = HashMap::from([ - (Instructions::SLUG_STR, 1.0), - (Dr::SLUG_STR, 2.0), - (Dw::SLUG_STR, 3.0), - (I1mr::SLUG_STR, 4.0), - (D1mr::SLUG_STR, 5.0), - (D1mw::SLUG_STR, 6.0), - (ILmr::SLUG_STR, 7.0), - (DLmr::SLUG_STR, 8.0), - (DLmw::SLUG_STR, 9.0), - (I1MissRate::SLUG_STR, 10.0), - (LLiMissRate::SLUG_STR, 11.0), - (D1MissRate::SLUG_STR, 12.0), - (LLdMissRate::SLUG_STR, 13.0), - (LLMissRate::SLUG_STR, 14.0), - (L1Hits::SLUG_STR, 15.0), - (L2Hits::SLUG_STR, 16.0), - (RamHits::SLUG_STR, 17.0), - (L1HitRate::SLUG_STR, 18.0), - (LLHitRate::SLUG_STR, 19.0), - (RamHitRate::SLUG_STR, 20.0), - (TotalReadWrite::SLUG_STR, 21.0), - (EstimatedCycles::SLUG_STR, 22.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::cachegrind_format all_metrics", - ); - } - } - - #[test] - fn memcheck() { - use gungraun::*; - - let results = - convert_file_path::("./tool_output/rust/gungraun/memcheck.txt"); - - assert_eq!(results.inner.len(), 3); - - { - let expected = HashMap::from([(MemcheckErrors::SLUG_STR, 1.0)]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::memcheck_format just_errors", - ); - } - - { - let expected = HashMap::from([ - (MemcheckContexts::SLUG_STR, 1.0), - (MemcheckSuppressedContexts::SLUG_STR, 2.0), - (MemcheckSuppressedErrors::SLUG_STR, 3.0), - (MemcheckErrors::SLUG_STR, 4.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::memcheck_format metrics_mixed", - ); - } - - { - let expected = HashMap::from([ - (MemcheckErrors::SLUG_STR, 1.0), - (MemcheckContexts::SLUG_STR, 2.0), - (MemcheckSuppressedErrors::SLUG_STR, 3.0), - (MemcheckSuppressedContexts::SLUG_STR, 4.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::memcheck_format all_metrics", - ); - } - } - - #[test] - fn helgrind() { - use gungraun::*; - - let results = - convert_file_path::("./tool_output/rust/gungraun/helgrind.txt"); - - assert_eq!(results.inner.len(), 3); - - { - let expected = HashMap::from([(HelgrindErrors::SLUG_STR, 1.0)]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::helgrind_format just_errors", - ); - } - - { - let expected = HashMap::from([ - (HelgrindContexts::SLUG_STR, 1.0), - (HelgrindSuppressedContexts::SLUG_STR, 2.0), - (HelgrindSuppressedErrors::SLUG_STR, 3.0), - (HelgrindErrors::SLUG_STR, 4.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::helgrind_format metrics_mixed", - ); - } - - { - let expected = HashMap::from([ - (HelgrindErrors::SLUG_STR, 1.0), - (HelgrindContexts::SLUG_STR, 2.0), - (HelgrindSuppressedErrors::SLUG_STR, 3.0), - (HelgrindSuppressedContexts::SLUG_STR, 4.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::helgrind_format all_metrics", - ); - } - } - - #[test] - fn drd() { - use gungraun::*; - - let results = - convert_file_path::("./tool_output/rust/gungraun/drd.txt"); - - assert_eq!(results.inner.len(), 3); - - { - let expected = HashMap::from([(DrdErrors::SLUG_STR, 1.0)]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::drd_format just_errors", - ); - } - - { - let expected = HashMap::from([ - (DrdContexts::SLUG_STR, 1.0), - (DrdSuppressedContexts::SLUG_STR, 2.0), - (DrdSuppressedErrors::SLUG_STR, 3.0), - (DrdErrors::SLUG_STR, 4.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::drd_format metrics_mixed", - ); - } - - { - let expected = HashMap::from([ - (DrdErrors::SLUG_STR, 1.0), - (DrdContexts::SLUG_STR, 2.0), - (DrdSuppressedErrors::SLUG_STR, 3.0), - (DrdSuppressedContexts::SLUG_STR, 4.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::custom_format::drd_format all_metrics", - ); - } - } - - #[test] - fn name_multiple_lines() { - use gungraun::*; - - let results = convert_file_path::( - "./tool_output/rust/gungraun/name_on_multiple_lines.txt", - ); - - assert_eq!(results.inner.len(), 2); - - { - let mut expected = HashMap::new(); - - expected.extend([ - (Instructions::SLUG_STR, 1.0), - (L1Hits::SLUG_STR, 2.0), - (L2Hits::SLUG_STR, 3.0), - (RamHits::SLUG_STR, 4.0), - (TotalReadWrite::SLUG_STR, 5.0), - (EstimatedCycles::SLUG_STR, 6.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench::multiple_lines id:string with two\nlines", - ); - } - - { - let mut expected = HashMap::new(); - - expected.extend([ - (Instructions::SLUG_STR, 7.0), - (L1Hits::SLUG_STR, 8.0), - (L2Hits::SLUG_STR, 9.0), - (RamHits::SLUG_STR, 10.0), - (TotalReadWrite::SLUG_STR, 11.0), - (EstimatedCycles::SLUG_STR, 12.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench::multiple_lines id:string with multiple\nlines\nand one more", - ); - } - } - - #[test] - fn name_multiple_lines_mixed() { - use gungraun::*; - - let results = convert_file_path::( - "./tool_output/rust/gungraun/name_on_multiple_lines_mixed.txt", - ); - - assert_eq!(results.inner.len(), 3); - - { - let mut expected = HashMap::new(); - - expected.extend([ - (Instructions::SLUG_STR, 1.0), - (L1Hits::SLUG_STR, 2.0), - (L2Hits::SLUG_STR, 3.0), - (RamHits::SLUG_STR, 4.0), - (TotalReadWrite::SLUG_STR, 5.0), - (EstimatedCycles::SLUG_STR, 6.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench::multiple_lines id:first with one line", - ); - } - - { - let mut expected = HashMap::new(); - - expected.extend([ - (Instructions::SLUG_STR, 7.0), - (L1Hits::SLUG_STR, 8.0), - (L2Hits::SLUG_STR, 9.0), - (RamHits::SLUG_STR, 10.0), - (TotalReadWrite::SLUG_STR, 11.0), - (EstimatedCycles::SLUG_STR, 12.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench::multiple_lines id:two\nlines", - ); - } - - { - let mut expected = HashMap::new(); - - expected.extend([ - (Instructions::SLUG_STR, 13.0), - (L1Hits::SLUG_STR, 14.0), - (L2Hits::SLUG_STR, 15.0), - (RamHits::SLUG_STR, 16.0), - (TotalReadWrite::SLUG_STR, 17.0), - (EstimatedCycles::SLUG_STR, 18.0), - ]); - - compare_benchmark( - &expected, - &results, - "rust_iai_callgrind::bench::multiple_lines id:last with one line", - ); - } - } - - #[derive(Default)] - pub struct OptionalMetrics { - pub global_bus_events: bool, - pub dhat: bool, - } - - pub fn validate_adapter_rust_gungraun( - results: &AdapterResults, - optional_metrics: &OptionalMetrics, - ) { - assert_eq!(results.inner.len(), 2); - - { - let mut expected = HashMap::new(); - - expected.extend([ - (gungraun::Instructions::SLUG_STR, 1_734.0), - (gungraun::L1Hits::SLUG_STR, 2_359.0), - (gungraun::L2Hits::SLUG_STR, 0.0), - (gungraun::RamHits::SLUG_STR, 3.0), - (gungraun::TotalReadWrite::SLUG_STR, 2_362.0), - (gungraun::EstimatedCycles::SLUG_STR, 2_464.0), - ]); - - if optional_metrics.global_bus_events { - expected.insert(gungraun::GlobalBusEvents::SLUG_STR, 2.0); - } - - if optional_metrics.dhat { - expected.extend([ - (gungraun::TotalBytes::SLUG_STR, 29_499.0), - (gungraun::TotalBlocks::SLUG_STR, 2_806.0), - (gungraun::AtTGmaxBytes::SLUG_STR, 378.0), - (gungraun::AtTGmaxBlocks::SLUG_STR, 34.0), - (gungraun::AtTEndBytes::SLUG_STR, 0.0), - (gungraun::AtTEndBlocks::SLUG_STR, 0.0), - (gungraun::ReadsBytes::SLUG_STR, 57_725.0), - (gungraun::WritesBytes::SLUG_STR, 73_810.0), - ]); - } - - compare_benchmark( - &expected, - results, - "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci short:10", - ); - } - - { - let mut expected = HashMap::new(); - - expected.extend([ - (gungraun::Instructions::SLUG_STR, 26_214_734.0), - (gungraun::L1Hits::SLUG_STR, 35_638_619.0), - (gungraun::L2Hits::SLUG_STR, 0.0), - (gungraun::RamHits::SLUG_STR, 3.0), - (gungraun::TotalReadWrite::SLUG_STR, 35_638_622.0), - (gungraun::EstimatedCycles::SLUG_STR, 35_638_724.0), - ]); - - if optional_metrics.global_bus_events { - expected.insert(gungraun::GlobalBusEvents::SLUG_STR, 10.0); - } - - if optional_metrics.dhat { - expected.extend([ - (gungraun::TotalBytes::SLUG_STR, 26_294_939.0), - (gungraun::TotalBlocks::SLUG_STR, 2_328_086.0), - (gungraun::AtTGmaxBytes::SLUG_STR, 933_718.0), - (gungraun::AtTGmaxBlocks::SLUG_STR, 18_344.0), - (gungraun::AtTEndBytes::SLUG_STR, 0.0), - (gungraun::AtTEndBlocks::SLUG_STR, 0.0), - (gungraun::ReadsBytes::SLUG_STR, 47_577_425.0), - (gungraun::WritesBytes::SLUG_STR, 37_733_810.0), - ]); - } - - compare_benchmark( - &expected, - results, - "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci long:30", - ); - } - } - - fn compare_benchmark( - expected: &HashMap<&str, f64>, - results: &AdapterResults, - benchmark_name: &str, - ) { - let actual = results.get(benchmark_name).unwrap(); - assert_eq!(actual.inner.len(), expected.len()); - - for (key, value) in expected { - let metric = actual.get(key).unwrap(); - assert_eq!(metric.value, OrderedFloat::from(*value)); - assert_eq!(metric.lower_value, None); - assert_eq!(metric.upper_value, None); - } - } } diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun_stdout.rs b/lib/bencher_adapter/src/adapters/rust/gungraun_stdout.rs new file mode 100644 index 000000000..cc55b935f --- /dev/null +++ b/lib/bencher_adapter/src/adapters/rust/gungraun_stdout.rs @@ -0,0 +1,1216 @@ +use std::ops::Neg as _; + +use bencher_json::{ + BenchmarkName, JsonNewMetric, + project::{ + measure::built_in::{BuiltInMeasure as _, gungraun}, + report::JsonAverage, + }, +}; +use nom::{ + IResult, Parser, + branch::alt, + bytes::complete::{is_a, is_not, tag, take_until1}, + character::complete::{char, space0, space1}, + combinator::{map, opt, peek, recognize}, + error::Error, + multi::{many0, many1}, + sequence::{delimited, preceded, terminated}, +}; + +use crate::{ + Adaptable, Settings, + adapters::util::parse_f64, + results::adapter_results::{AdapterResults, GungraunMeasure}, +}; + +pub struct AdapterRustGungraunStdout; + +impl Adaptable for AdapterRustGungraunStdout { + fn parse(input: &str, settings: Settings) -> Option { + match settings.average { + None => {}, + Some(JsonAverage::Mean | JsonAverage::Median) => { + return None; // 'gungraun' results are for a single run only. + }, + } + + // Clean up the input by removing ANSI escape codes: + let input = strip_ansi_escapes::strip_str(input); + + let benchmarks = match multiple_benchmarks().parse(&*input) { + Err(error) => { + debug_assert!(false, "Error parsing input:\n{error:#?}"); + return None; + }, + Ok((remainder, benchmarks)) => { + debug_assert_eq!(remainder.len(), 0, "Unparsed trailing input:\n{remainder}"); + benchmarks + }, + }; + + AdapterResults::new_gungraun(benchmarks) + } +} + +fn multiple_benchmarks<'a>() +-> impl Parser<&'a str, Output = Vec<(BenchmarkName, Vec)>, Error = Error<&'a str>> +{ + map( + many0(alt(( + // Try to parse a single benchmark: + single_benchmark(), + // Otherwise, parse/ignore unrelated lines: + map(terminated(not_line_ending(), opt(line_ending())), |_| None), + // Otherwise, parse/ignore empty lines: + map(line_ending(), |_| None), + ))), + // Skip 'None' resulting from empty/unrelated lines: + |benchmarks| benchmarks.into_iter().flatten().collect(), + ) +} + +fn single_benchmark<'a>() +-> impl Parser<&'a str, Output = Option<(BenchmarkName, Vec)>, Error = Error<&'a str>> +{ + map( + ( + terminated( + recognize(( + is_not(":\r\n \t"), + tag("::"), + is_not(":\r\n \t"), + tag("::"), + not_benchmark_name_end(), + )), + benchmark_name_end(), + ), + many0(alt(( + // Callgrind tool if it was enabled: + callgrind_tool_measures(), + // Cachegrind tool if it was enabled: + cachegrind_tool_measures(), + // Add DHAT tool measures if it was enabled: + dhat_tool_measures(), + // Add Memcheck tool measures if it was enabled: + memcheck_tool_measures(), + // Add Helgrind tool measures if it was enabled: + helgrind_tool_measures(), + // Add Drd tool measures if it was enabled: + drd_tool_measures(), + ))), + ), + |(benchmark_name, measures)| { + // trim here to avoid loose `\r` chars at the end of the string because of the + // `not_benchmark_name_end` parser. It's maybe not a bad idea anyways. + let benchmark_name = benchmark_name.trim().parse().ok()?; + let measures = measures.into_iter().flatten().collect(); + + Some((benchmark_name, measures)) + }, + ) +} + +fn callgrind_tool_measures<'a>() +-> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { + map( + preceded(opt(tool_name_line("CALLGRIND")), many1(metric_line())), + |metrics| { + metrics + .into_iter() + .map(|(metric_name, json)| match metric_name.as_str() { + gungraun::Instructions::NAME_STR => GungraunMeasure::Instructions(json), + gungraun::L1Hits::NAME_STR => GungraunMeasure::L1Hits(json), + gungraun::L2Hits::NAME_STR => GungraunMeasure::L2Hits(json), + gungraun::LLHits::NAME_STR => GungraunMeasure::LLHits(json), + gungraun::RamHits::NAME_STR => GungraunMeasure::RamHits(json), + gungraun::TotalReadWrite::NAME_STR => GungraunMeasure::TotalReadWrite(json), + gungraun::EstimatedCycles::NAME_STR => GungraunMeasure::EstimatedCycles(json), + gungraun::Dr::NAME_STR => GungraunMeasure::DataCacheReads(json), + gungraun::Dw::NAME_STR => GungraunMeasure::DataCacheWrites(json), + gungraun::I1mr::NAME_STR => GungraunMeasure::L1InstrCacheReadMisses(json), + gungraun::D1mr::NAME_STR => GungraunMeasure::L1DataCacheReadMisses(json), + gungraun::D1mw::NAME_STR => GungraunMeasure::L1DataCacheWriteMisses(json), + gungraun::ILmr::NAME_STR => GungraunMeasure::LLInstrCacheReadMisses(json), + gungraun::DLmr::NAME_STR => GungraunMeasure::LLDataCacheReadMisses(json), + gungraun::DLmw::NAME_STR => GungraunMeasure::LLDataCacheWriteMisses(json), + gungraun::I1MissRate::NAME_STR => GungraunMeasure::L1InstrCacheMissRate(json), + gungraun::LLiMissRate::NAME_STR => GungraunMeasure::LLInstrCacheMissRate(json), + gungraun::D1MissRate::NAME_STR => GungraunMeasure::L1DataCacheMissRate(json), + gungraun::LLdMissRate::NAME_STR => GungraunMeasure::LLDataCacheMissRate(json), + gungraun::LLMissRate::NAME_STR => GungraunMeasure::LLCacheMissRate(json), + gungraun::L1HitRate::NAME_STR => GungraunMeasure::L1HitRate(json), + gungraun::LLHitRate::NAME_STR => GungraunMeasure::LLHitRate(json), + gungraun::RamHitRate::NAME_STR => GungraunMeasure::RamHitRate(json), + gungraun::SysCount::NAME_STR => GungraunMeasure::NumberSystemCalls(json), + gungraun::SysTime::NAME_STR => GungraunMeasure::TimeSystemCalls(json), + gungraun::SysCpuTime::NAME_STR => GungraunMeasure::CpuTimeSystemCalls(json), + gungraun::GlobalBusEvents::NAME_STR => GungraunMeasure::GlobalBusEvents(json), + gungraun::Bc::NAME_STR => GungraunMeasure::ExecutedConditionalBranches(json), + gungraun::Bcm::NAME_STR => { + GungraunMeasure::MispredictedConditionalBranches(json) + }, + gungraun::Bi::NAME_STR => GungraunMeasure::ExecutedIndirectBranches(json), + gungraun::Bim::NAME_STR => GungraunMeasure::MispredictedIndirectBranches(json), + gungraun::ILdmr::NAME_STR => GungraunMeasure::DirtyMissInstructionRead(json), + gungraun::DLdmr::NAME_STR => GungraunMeasure::DirtyMissDataRead(json), + gungraun::DLdmw::NAME_STR => GungraunMeasure::DirtyMissDataWrite(json), + gungraun::AcCost1::NAME_STR => GungraunMeasure::L1BadTemporalLocality(json), + gungraun::AcCost2::NAME_STR => GungraunMeasure::LLBadTemporalLocality(json), + gungraun::SpLoss1::NAME_STR => GungraunMeasure::L1BadSpatialLocality(json), + gungraun::SpLoss2::NAME_STR => GungraunMeasure::LLBadSpatialLocality(json), + _ => GungraunMeasure::Unknown, + }) + .collect() + }, + ) +} + +fn cachegrind_tool_measures<'a>() +-> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { + map( + preceded(tool_name_line("CACHEGRIND"), many1(metric_line())), + |metrics| { + metrics + .into_iter() + .map(|(metric_name, json)| match metric_name.as_str() { + gungraun::Instructions::NAME_STR => GungraunMeasure::Instructions(json), + gungraun::L1Hits::NAME_STR => GungraunMeasure::L1Hits(json), + gungraun::L2Hits::NAME_STR => GungraunMeasure::L2Hits(json), + gungraun::LLHits::NAME_STR => GungraunMeasure::LLHits(json), + gungraun::RamHits::NAME_STR => GungraunMeasure::RamHits(json), + gungraun::TotalReadWrite::NAME_STR => GungraunMeasure::TotalReadWrite(json), + gungraun::EstimatedCycles::NAME_STR => GungraunMeasure::EstimatedCycles(json), + gungraun::Dr::NAME_STR => GungraunMeasure::DataCacheReads(json), + gungraun::Dw::NAME_STR => GungraunMeasure::DataCacheWrites(json), + gungraun::I1mr::NAME_STR => GungraunMeasure::L1InstrCacheReadMisses(json), + gungraun::D1mr::NAME_STR => GungraunMeasure::L1DataCacheReadMisses(json), + gungraun::D1mw::NAME_STR => GungraunMeasure::L1DataCacheWriteMisses(json), + gungraun::ILmr::NAME_STR => GungraunMeasure::LLInstrCacheReadMisses(json), + gungraun::DLmr::NAME_STR => GungraunMeasure::LLDataCacheReadMisses(json), + gungraun::DLmw::NAME_STR => GungraunMeasure::LLDataCacheWriteMisses(json), + gungraun::I1MissRate::NAME_STR => GungraunMeasure::L1InstrCacheMissRate(json), + gungraun::LLiMissRate::NAME_STR => GungraunMeasure::LLInstrCacheMissRate(json), + gungraun::D1MissRate::NAME_STR => GungraunMeasure::L1DataCacheMissRate(json), + gungraun::LLdMissRate::NAME_STR => GungraunMeasure::LLDataCacheMissRate(json), + gungraun::LLMissRate::NAME_STR => GungraunMeasure::LLCacheMissRate(json), + gungraun::L1HitRate::NAME_STR => GungraunMeasure::L1HitRate(json), + gungraun::LLHitRate::NAME_STR => GungraunMeasure::LLHitRate(json), + gungraun::RamHitRate::NAME_STR => GungraunMeasure::RamHitRate(json), + _ => GungraunMeasure::Unknown, + }) + .collect() + }, + ) +} + +fn dhat_tool_measures<'a>() +-> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { + map( + preceded(tool_name_line("DHAT"), many1(metric_line())), + |metrics| { + metrics + .into_iter() + .map(|(metric_name, json)| match metric_name.as_str() { + gungraun::TotalBytes::NAME_STR => GungraunMeasure::TotalBytes(json), + gungraun::TotalBlocks::NAME_STR => GungraunMeasure::TotalBlocks(json), + gungraun::TotalUnits::NAME_STR => GungraunMeasure::TotalUnits(json), + gungraun::TotalEvents::NAME_STR => GungraunMeasure::TotalEvents(json), + gungraun::TotalLifetimes::NAME_STR => GungraunMeasure::TotalLifetimes(json), + gungraun::AtTGmaxBytes::NAME_STR => GungraunMeasure::AtTGmaxBytes(json), + gungraun::AtTGmaxBlocks::NAME_STR => GungraunMeasure::AtTGmaxBlocks(json), + gungraun::AtTEndBytes::NAME_STR => GungraunMeasure::AtTEndBytes(json), + gungraun::AtTEndBlocks::NAME_STR => GungraunMeasure::AtTEndBlocks(json), + gungraun::ReadsBytes::NAME_STR => GungraunMeasure::ReadsBytes(json), + gungraun::WritesBytes::NAME_STR => GungraunMeasure::WritesBytes(json), + gungraun::MaximumBytes::NAME_STR => GungraunMeasure::MaximumBytes(json), + gungraun::MaximumBlocks::NAME_STR => GungraunMeasure::MaximumBlocks(json), + _ => GungraunMeasure::Unknown, + }) + .collect() + }, + ) +} + +fn memcheck_tool_measures<'a>() +-> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { + map( + preceded(tool_name_line("MEMCHECK"), many1(metric_line())), + |metrics| { + metrics + .into_iter() + .map(|(metric_name, json)| match metric_name.as_str() { + gungraun::MemcheckErrors::NAME_STR => GungraunMeasure::MemcheckErrors(json), + gungraun::MemcheckContexts::NAME_STR => GungraunMeasure::MemcheckContexts(json), + gungraun::MemcheckSuppressedErrors::NAME_STR => { + GungraunMeasure::MemcheckSuppressedErrors(json) + }, + gungraun::MemcheckSuppressedContexts::NAME_STR => { + GungraunMeasure::MemcheckSuppressedContexts(json) + }, + _ => GungraunMeasure::Unknown, + }) + .collect() + }, + ) +} + +fn helgrind_tool_measures<'a>() +-> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { + map( + preceded(tool_name_line("HELGRIND"), many1(metric_line())), + |metrics| { + metrics + .into_iter() + .map(|(metric_name, json)| match metric_name.as_str() { + gungraun::HelgrindErrors::NAME_STR => GungraunMeasure::HelgrindErrors(json), + gungraun::HelgrindContexts::NAME_STR => GungraunMeasure::HelgrindContexts(json), + gungraun::HelgrindSuppressedErrors::NAME_STR => { + GungraunMeasure::HelgrindSuppressedErrors(json) + }, + gungraun::HelgrindSuppressedContexts::NAME_STR => { + GungraunMeasure::HelgrindSuppressedContexts(json) + }, + _ => GungraunMeasure::Unknown, + }) + .collect() + }, + ) +} + +fn drd_tool_measures<'a>() +-> impl Parser<&'a str, Output = Vec, Error = Error<&'a str>> { + map( + preceded(tool_name_line("DRD"), many1(metric_line())), + |metrics| { + metrics + .into_iter() + .map(|(metric_name, json)| match metric_name.as_str() { + gungraun::DrdErrors::NAME_STR => GungraunMeasure::DrdErrors(json), + gungraun::DrdContexts::NAME_STR => GungraunMeasure::DrdContexts(json), + gungraun::DrdSuppressedErrors::NAME_STR => { + GungraunMeasure::DrdSuppressedErrors(json) + }, + gungraun::DrdSuppressedContexts::NAME_STR => { + GungraunMeasure::DrdSuppressedContexts(json) + }, + _ => GungraunMeasure::Unknown, + }) + .collect() + }, + ) +} + +fn tool_name_line<'a>( + tool_name: &'static str, +) -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { + delimited( + (space1, many1(tag("=")), tag(" ")), + tag(tool_name), + (tag(" "), many1(tag("=")), line_ending()), + ) +} + +fn metric_line<'a>() +-> impl Parser<&'a str, Output = (String, JsonNewMetric), Error = Error<&'a str>> { + map( + ( + space1, + is_not(":\r\n"), + char(':'), + space1, + // the current run value: + parse_f64, + char('|'), + alt(( + // No previous run: + recognize(( + tag("N/A"), + space1, + delimited(char('('), many1(char('*')), char(')')), + )), + // Comparison to previous run: + recognize(( + parse_f64, + space0, + alt(( + recognize(delimited(char('('), tag("No change"), char(')'))), + recognize(( + delimited(char('('), alt((infinity, percent)), char(')')), + space1, + delimited(char('['), alt((infinity, factor)), char(']')), + )), + )), + )), + )), + line_ending(), + ), + |(_, metric_name, _, _, current_value, _, _, _)| { + ( + metric_name.to_owned(), + JsonNewMetric { + value: current_value.into(), + lower_value: None, + upper_value: None, + }, + ) + }, + ) +} + +fn infinity(input: &str) -> IResult<&str, f64> { + map( + ( + alt((many1(char('+')), many1(char('-')))), + tag("inf"), + alt((many1(char('+')), many1(char('-')))), + ), + |(signs, _, _)| { + // The indexing is safe due to the usage of `many1` above + #[expect(clippy::indexing_slicing, reason = "many1 guarantees non-empty vec")] + let sign = signs[0]; + if sign == '+' { + f64::INFINITY + } else { + f64::NEG_INFINITY + } + }, + ) + .parse(input) +} + +fn factor(input: &str) -> IResult<&str, f64> { + map( + (alt((char('+'), char('-'))), parse_f64, char('x')), + |(sign, num, _)| { + if sign == '+' { num } else { num.neg() } + }, + ) + .parse(input) +} + +fn percent(input: &str) -> IResult<&str, f64> { + map( + (alt((char('+'), char('-'))), parse_f64, char('%')), + |(sign, num, _)| { + if sign == '+' { num } else { num.neg() } + }, + ) + .parse(input) +} + +fn line_ending<'a>() -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { + is_a("\r\n") +} + +fn not_line_ending<'a>() -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { + // Note: `not(line_ending)` doesn't work here, as it won't consume the matched characters + is_not("\r\n") +} + +/// Parser that matches the benchmark name ending sequence, excluding the two spaces +fn benchmark_name_end<'a>() +-> impl Parser<&'a str, Output = (&'a str, &'a str), Error = Error<&'a str>> { + // we only peek here so the `metric_line` parser can match the first spaces too + (line_ending(), peek(tag(" "))) +} + +/// A parser that matches input until it encounters the benchmark name end sequence. +/// +/// Similar to the `benchmark_name_end` parser, this parser addresses an unusual behavior in +/// `gungraun` (iai-callgrind) by allowing benchmark names to span multiple lines. While this +/// behavior is not a bug in `gungraun`, it deviates from the original intent. If there are multiple +/// lines they don't start with two spaces, so we can use that as test for the end of the benchmark +/// name. +fn not_benchmark_name_end<'a>() -> impl Parser<&'a str, Output = &'a str, Error = Error<&'a str>> { + // Ignore the `\r\n` possibility here and instead trim the benchmark name later + take_until1("\n ") +} + +#[cfg(test)] +pub(crate) mod test_rust_gungraun_stdout { + use crate::{AdapterResults, adapters::test_util::convert_file_path}; + use bencher_json::project::measure::built_in::{BuiltInMeasure as _, gungraun}; + use ordered_float::OrderedFloat; + use pretty_assertions::assert_eq; + + use super::AdapterRustGungraunStdout; + use std::collections::HashMap; + + #[test] + fn without_optional_metrics() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/without-optional-metrics.txt", + ); + + validate_adapter_rust_gungraun_stdout(&results, &OptionalMetrics::default()); + } + + #[test] + fn with_dhat() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/with-dhat.txt", + ); + + validate_adapter_rust_gungraun_stdout( + &results, + &OptionalMetrics { + dhat: true, + ..Default::default() + }, + ); + } + + #[test] + fn with_dhat_first_then_callgrind() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/dhat-then-callgrind.txt", + ); + + validate_adapter_rust_gungraun_stdout( + &results, + &OptionalMetrics { + dhat: true, + ..Default::default() + }, + ); + } + + #[test] + fn with_dhat_and_global_bus_events() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/with-dhat-and-global-bus-events.txt", + ); + + validate_adapter_rust_gungraun_stdout( + &results, + &OptionalMetrics { + dhat: true, + global_bus_events: true, + }, + ); + } + + #[test] + fn delta() { + let results = + convert_file_path::("./tool_output/rust/gungraun/delta.txt"); + + validate_adapter_rust_gungraun_stdout(&results, &OptionalMetrics::default()); + } + + #[test] + fn delta_with_infinity() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/delta_with_inf.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let expected = HashMap::from([ + (gungraun::Instructions::SLUG_STR, 1_734.0), + (gungraun::L1Hits::SLUG_STR, 2_359.0), + (gungraun::L2Hits::SLUG_STR, 0.0), + (gungraun::RamHits::SLUG_STR, 3.0), + (gungraun::TotalReadWrite::SLUG_STR, 0.0), + (gungraun::EstimatedCycles::SLUG_STR, 2_464.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci short:10", + ); + } + + { + let expected = HashMap::from([ + (gungraun::Instructions::SLUG_STR, 26_214_734.0), + (gungraun::L1Hits::SLUG_STR, 35_638_619.0), + (gungraun::L2Hits::SLUG_STR, 0.0), + (gungraun::RamHits::SLUG_STR, 3.0), + (gungraun::TotalReadWrite::SLUG_STR, 35_638_622.0), + (gungraun::EstimatedCycles::SLUG_STR, 35_638_724.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci long:30", + ); + } + } + + #[test] + fn with_summary_and_regressions() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/with-summary-and-regressions.txt", + ); + + validate_adapter_rust_gungraun_stdout(&results, &OptionalMetrics::default()); + } + + #[test] + fn with_gungraun_summary() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/with-gungraun-summary.txt", + ); + + validate_adapter_rust_gungraun_stdout(&results, &OptionalMetrics::default()); + } + + #[test] + fn ansi_escapes_issue_345() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/ansi-escapes.txt", + ); + + validate_adapter_rust_gungraun_stdout(&results, &OptionalMetrics::default()); + } + + #[test] + fn with_ge() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/with-ge.txt", + ); + + validate_adapter_rust_gungraun_stdout( + &results, + &OptionalMetrics { + global_bus_events: true, + ..Default::default() + }, + ); + } + + #[test] + fn without_cachesim() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/without-cachesim.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let expected = HashMap::from([(Instructions::SLUG_STR, 1734.0)]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci short:10", + ); + } + + { + let expected = HashMap::from([(Instructions::SLUG_STR, 26_214_734.0)]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci long:30", + ); + } + } + + #[test] + fn callgrind_mixed_order() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/callgrind-mixed-order.txt", + ); + + assert_eq!(results.inner.len(), 2); + + let expected = HashMap::from([ + (Instructions::SLUG_STR, 1.0), + (Dr::SLUG_STR, 2.0), + (Dw::SLUG_STR, 3.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::callgrind_format mixed_1", + ); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::callgrind_format mixed_2", + ); + } + + #[test] + fn callgrind_ll_hits() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/callgrind-ll-hits.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let expected = + HashMap::from([(Instructions::SLUG_STR, 10.0), (LLHits::SLUG_STR, 20.0)]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::callgrind_format ll_hits", + ); + } + + { + let expected = HashMap::from([(Instructions::SLUG_STR, 1.0), (LLHits::SLUG_STR, 2.0)]); + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::callgrind_format ll_hits_mixed", + ); + } + } + + #[test] + fn callgrind_all() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/callgrind-all.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let expected = HashMap::from([ + (Instructions::SLUG_STR, 1.0), + (Dr::SLUG_STR, 2.0), + (Dw::SLUG_STR, 3.0), + (I1mr::SLUG_STR, 4.0), + (D1mr::SLUG_STR, 5.0), + (D1mw::SLUG_STR, 6.0), + (ILmr::SLUG_STR, 7.0), + (DLmr::SLUG_STR, 8.0), + (DLmw::SLUG_STR, 9.0), + (I1MissRate::SLUG_STR, 10.0), + (LLiMissRate::SLUG_STR, 11.0), + (D1MissRate::SLUG_STR, 12.0), + (LLdMissRate::SLUG_STR, 13.0), + (LLMissRate::SLUG_STR, 14.0), + (L1Hits::SLUG_STR, 15.0), + (L2Hits::SLUG_STR, 16.0), + (RamHits::SLUG_STR, 17.0), + (L1HitRate::SLUG_STR, 18.0), + (LLHitRate::SLUG_STR, 19.0), + (RamHitRate::SLUG_STR, 20.0), + (TotalReadWrite::SLUG_STR, 21.0), + (EstimatedCycles::SLUG_STR, 22.0), + (SysCount::SLUG_STR, 23.0), + (SysTime::SLUG_STR, 24.0), + (SysCpuTime::SLUG_STR, 25.0), + (GlobalBusEvents::SLUG_STR, 26.0), + (Bc::SLUG_STR, 27.0), + (Bcm::SLUG_STR, 28.0), + (Bi::SLUG_STR, 29.0), + (Bim::SLUG_STR, 30.0), + (ILdmr::SLUG_STR, 31.0), + (DLdmr::SLUG_STR, 32.0), + (DLdmw::SLUG_STR, 33.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::callgrind_format all_with_wb", + ); + } + + { + let expected = HashMap::from([ + (Instructions::SLUG_STR, 1.0), + (Dr::SLUG_STR, 2.0), + (Dw::SLUG_STR, 3.0), + (I1mr::SLUG_STR, 4.0), + (D1mr::SLUG_STR, 5.0), + (D1mw::SLUG_STR, 6.0), + (ILmr::SLUG_STR, 7.0), + (DLmr::SLUG_STR, 8.0), + (DLmw::SLUG_STR, 9.0), + (I1MissRate::SLUG_STR, 10.0), + (LLiMissRate::SLUG_STR, 11.0), + (D1MissRate::SLUG_STR, 12.0), + (LLdMissRate::SLUG_STR, 13.0), + (LLMissRate::SLUG_STR, 14.0), + (L1Hits::SLUG_STR, 15.0), + (L2Hits::SLUG_STR, 16.0), + (RamHits::SLUG_STR, 17.0), + (L1HitRate::SLUG_STR, 18.0), + (LLHitRate::SLUG_STR, 19.0), + (RamHitRate::SLUG_STR, 20.0), + (TotalReadWrite::SLUG_STR, 21.0), + (EstimatedCycles::SLUG_STR, 22.0), + (SysCount::SLUG_STR, 23.0), + (SysTime::SLUG_STR, 24.0), + (SysCpuTime::SLUG_STR, 25.0), + (GlobalBusEvents::SLUG_STR, 26.0), + (Bc::SLUG_STR, 27.0), + (Bcm::SLUG_STR, 28.0), + (Bi::SLUG_STR, 29.0), + (Bim::SLUG_STR, 30.0), + (AcCost1::SLUG_STR, 31.0), + (AcCost2::SLUG_STR, 32.0), + (SpLoss1::SLUG_STR, 33.0), + (SpLoss2::SLUG_STR, 34.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::callgrind_format all_with_cachuse", + ); + } + } + + #[test] + fn cachegrind() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/cachegrind.txt", + ); + + assert_eq!(results.inner.len(), 3); + + { + let expected = HashMap::from([(Instructions::SLUG_STR, 1.0)]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::cachegrind_format just_instructions", + ); + } + + { + let expected = HashMap::from([ + (I1MissRate::SLUG_STR, 1.0), + (Dr::SLUG_STR, 2.0), + (EstimatedCycles::SLUG_STR, 3.0), + (TotalReadWrite::SLUG_STR, 4.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::cachegrind_format metrics_mixed", + ); + } + + { + let expected = HashMap::from([ + (Instructions::SLUG_STR, 1.0), + (Dr::SLUG_STR, 2.0), + (Dw::SLUG_STR, 3.0), + (I1mr::SLUG_STR, 4.0), + (D1mr::SLUG_STR, 5.0), + (D1mw::SLUG_STR, 6.0), + (ILmr::SLUG_STR, 7.0), + (DLmr::SLUG_STR, 8.0), + (DLmw::SLUG_STR, 9.0), + (I1MissRate::SLUG_STR, 10.0), + (LLiMissRate::SLUG_STR, 11.0), + (D1MissRate::SLUG_STR, 12.0), + (LLdMissRate::SLUG_STR, 13.0), + (LLMissRate::SLUG_STR, 14.0), + (L1Hits::SLUG_STR, 15.0), + (L2Hits::SLUG_STR, 16.0), + (RamHits::SLUG_STR, 17.0), + (L1HitRate::SLUG_STR, 18.0), + (LLHitRate::SLUG_STR, 19.0), + (RamHitRate::SLUG_STR, 20.0), + (TotalReadWrite::SLUG_STR, 21.0), + (EstimatedCycles::SLUG_STR, 22.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::cachegrind_format all_metrics", + ); + } + } + + #[test] + fn memcheck() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/memcheck.txt", + ); + + assert_eq!(results.inner.len(), 3); + + { + let expected = HashMap::from([(MemcheckErrors::SLUG_STR, 1.0)]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::memcheck_format just_errors", + ); + } + + { + let expected = HashMap::from([ + (MemcheckContexts::SLUG_STR, 1.0), + (MemcheckSuppressedContexts::SLUG_STR, 2.0), + (MemcheckSuppressedErrors::SLUG_STR, 3.0), + (MemcheckErrors::SLUG_STR, 4.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::memcheck_format metrics_mixed", + ); + } + + { + let expected = HashMap::from([ + (MemcheckErrors::SLUG_STR, 1.0), + (MemcheckContexts::SLUG_STR, 2.0), + (MemcheckSuppressedErrors::SLUG_STR, 3.0), + (MemcheckSuppressedContexts::SLUG_STR, 4.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::memcheck_format all_metrics", + ); + } + } + + #[test] + fn helgrind() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/helgrind.txt", + ); + + assert_eq!(results.inner.len(), 3); + + { + let expected = HashMap::from([(HelgrindErrors::SLUG_STR, 1.0)]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::helgrind_format just_errors", + ); + } + + { + let expected = HashMap::from([ + (HelgrindContexts::SLUG_STR, 1.0), + (HelgrindSuppressedContexts::SLUG_STR, 2.0), + (HelgrindSuppressedErrors::SLUG_STR, 3.0), + (HelgrindErrors::SLUG_STR, 4.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::helgrind_format metrics_mixed", + ); + } + + { + let expected = HashMap::from([ + (HelgrindErrors::SLUG_STR, 1.0), + (HelgrindContexts::SLUG_STR, 2.0), + (HelgrindSuppressedErrors::SLUG_STR, 3.0), + (HelgrindSuppressedContexts::SLUG_STR, 4.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::helgrind_format all_metrics", + ); + } + } + + #[test] + fn drd() { + use gungraun::*; + + let results = + convert_file_path::("./tool_output/rust/gungraun/drd.txt"); + + assert_eq!(results.inner.len(), 3); + + { + let expected = HashMap::from([(DrdErrors::SLUG_STR, 1.0)]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::drd_format just_errors", + ); + } + + { + let expected = HashMap::from([ + (DrdContexts::SLUG_STR, 1.0), + (DrdSuppressedContexts::SLUG_STR, 2.0), + (DrdSuppressedErrors::SLUG_STR, 3.0), + (DrdErrors::SLUG_STR, 4.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::drd_format metrics_mixed", + ); + } + + { + let expected = HashMap::from([ + (DrdErrors::SLUG_STR, 1.0), + (DrdContexts::SLUG_STR, 2.0), + (DrdSuppressedErrors::SLUG_STR, 3.0), + (DrdSuppressedContexts::SLUG_STR, 4.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::custom_format::drd_format all_metrics", + ); + } + } + + #[test] + fn name_multiple_lines() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/name_on_multiple_lines.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let mut expected = HashMap::new(); + + expected.extend([ + (Instructions::SLUG_STR, 1.0), + (L1Hits::SLUG_STR, 2.0), + (L2Hits::SLUG_STR, 3.0), + (RamHits::SLUG_STR, 4.0), + (TotalReadWrite::SLUG_STR, 5.0), + (EstimatedCycles::SLUG_STR, 6.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench::multiple_lines id:string with two\nlines", + ); + } + + { + let mut expected = HashMap::new(); + + expected.extend([ + (Instructions::SLUG_STR, 7.0), + (L1Hits::SLUG_STR, 8.0), + (L2Hits::SLUG_STR, 9.0), + (RamHits::SLUG_STR, 10.0), + (TotalReadWrite::SLUG_STR, 11.0), + (EstimatedCycles::SLUG_STR, 12.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench::multiple_lines id:string with multiple\nlines\nand one more", + ); + } + } + + #[test] + fn name_multiple_lines_mixed() { + use gungraun::*; + + let results = convert_file_path::( + "./tool_output/rust/gungraun/name_on_multiple_lines_mixed.txt", + ); + + assert_eq!(results.inner.len(), 3); + + { + let mut expected = HashMap::new(); + + expected.extend([ + (Instructions::SLUG_STR, 1.0), + (L1Hits::SLUG_STR, 2.0), + (L2Hits::SLUG_STR, 3.0), + (RamHits::SLUG_STR, 4.0), + (TotalReadWrite::SLUG_STR, 5.0), + (EstimatedCycles::SLUG_STR, 6.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench::multiple_lines id:first with one line", + ); + } + + { + let mut expected = HashMap::new(); + + expected.extend([ + (Instructions::SLUG_STR, 7.0), + (L1Hits::SLUG_STR, 8.0), + (L2Hits::SLUG_STR, 9.0), + (RamHits::SLUG_STR, 10.0), + (TotalReadWrite::SLUG_STR, 11.0), + (EstimatedCycles::SLUG_STR, 12.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench::multiple_lines id:two\nlines", + ); + } + + { + let mut expected = HashMap::new(); + + expected.extend([ + (Instructions::SLUG_STR, 13.0), + (L1Hits::SLUG_STR, 14.0), + (L2Hits::SLUG_STR, 15.0), + (RamHits::SLUG_STR, 16.0), + (TotalReadWrite::SLUG_STR, 17.0), + (EstimatedCycles::SLUG_STR, 18.0), + ]); + + compare_benchmark( + &expected, + &results, + "rust_iai_callgrind::bench::multiple_lines id:last with one line", + ); + } + } + + #[derive(Default)] + pub struct OptionalMetrics { + pub global_bus_events: bool, + pub dhat: bool, + } + + pub fn validate_adapter_rust_gungraun_stdout( + results: &AdapterResults, + optional_metrics: &OptionalMetrics, + ) { + assert_eq!(results.inner.len(), 2); + + { + let mut expected = HashMap::new(); + + expected.extend([ + (gungraun::Instructions::SLUG_STR, 1_734.0), + (gungraun::L1Hits::SLUG_STR, 2_359.0), + (gungraun::L2Hits::SLUG_STR, 0.0), + (gungraun::RamHits::SLUG_STR, 3.0), + (gungraun::TotalReadWrite::SLUG_STR, 2_362.0), + (gungraun::EstimatedCycles::SLUG_STR, 2_464.0), + ]); + + if optional_metrics.global_bus_events { + expected.insert(gungraun::GlobalBusEvents::SLUG_STR, 2.0); + } + + if optional_metrics.dhat { + expected.extend([ + (gungraun::TotalBytes::SLUG_STR, 29_499.0), + (gungraun::TotalBlocks::SLUG_STR, 2_806.0), + (gungraun::AtTGmaxBytes::SLUG_STR, 378.0), + (gungraun::AtTGmaxBlocks::SLUG_STR, 34.0), + (gungraun::AtTEndBytes::SLUG_STR, 0.0), + (gungraun::AtTEndBlocks::SLUG_STR, 0.0), + (gungraun::ReadsBytes::SLUG_STR, 57_725.0), + (gungraun::WritesBytes::SLUG_STR, 73_810.0), + ]); + } + + compare_benchmark( + &expected, + results, + "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci short:10", + ); + } + + { + let mut expected = HashMap::new(); + + expected.extend([ + (gungraun::Instructions::SLUG_STR, 26_214_734.0), + (gungraun::L1Hits::SLUG_STR, 35_638_619.0), + (gungraun::L2Hits::SLUG_STR, 0.0), + (gungraun::RamHits::SLUG_STR, 3.0), + (gungraun::TotalReadWrite::SLUG_STR, 35_638_622.0), + (gungraun::EstimatedCycles::SLUG_STR, 35_638_724.0), + ]); + + if optional_metrics.global_bus_events { + expected.insert(gungraun::GlobalBusEvents::SLUG_STR, 10.0); + } + + if optional_metrics.dhat { + expected.extend([ + (gungraun::TotalBytes::SLUG_STR, 26_294_939.0), + (gungraun::TotalBlocks::SLUG_STR, 2_328_086.0), + (gungraun::AtTGmaxBytes::SLUG_STR, 933_718.0), + (gungraun::AtTGmaxBlocks::SLUG_STR, 18_344.0), + (gungraun::AtTEndBytes::SLUG_STR, 0.0), + (gungraun::AtTEndBlocks::SLUG_STR, 0.0), + (gungraun::ReadsBytes::SLUG_STR, 47_577_425.0), + (gungraun::WritesBytes::SLUG_STR, 37_733_810.0), + ]); + } + + compare_benchmark( + &expected, + results, + "rust_iai_callgrind::bench_fibonacci_group::bench_fibonacci long:30", + ); + } + } + + fn compare_benchmark( + expected: &HashMap<&str, f64>, + results: &AdapterResults, + benchmark_name: &str, + ) { + let actual = results.get(benchmark_name).unwrap(); + assert_eq!(actual.inner.len(), expected.len()); + + for (key, value) in expected { + let metric = actual.get(key).unwrap(); + assert_eq!(metric.value, OrderedFloat::from(*value)); + assert_eq!(metric.lower_value, None); + assert_eq!(metric.upper_value, None); + } + } +} diff --git a/lib/bencher_adapter/src/adapters/rust/mod.rs b/lib/bencher_adapter/src/adapters/rust/mod.rs index 3acc1d422..48c5ef21d 100644 --- a/lib/bencher_adapter/src/adapters/rust/mod.rs +++ b/lib/bencher_adapter/src/adapters/rust/mod.rs @@ -2,12 +2,10 @@ pub mod bench; pub mod criterion; pub mod gungraun; pub mod gungraun_json; +pub mod gungraun_stdout; pub mod iai; -use self::{ - criterion::AdapterRustCriterion, gungraun::AdapterRustGungraun, - gungraun_json::AdapterRustGungraunJson, iai::AdapterRustIai, -}; +use self::{criterion::AdapterRustCriterion, gungraun::AdapterRustGungraun, iai::AdapterRustIai}; use crate::{Adaptable, AdapterResults, Settings}; use bench::AdapterRustBench; @@ -19,7 +17,6 @@ impl Adaptable for AdapterRust { .or_else(|| AdapterRustCriterion::parse(input, settings)) .or_else(|| AdapterRustIai::parse(input, settings)) .or_else(|| AdapterRustGungraun::parse(input, settings)) - .or_else(|| AdapterRustGungraunJson::parse(input, settings)) } } @@ -28,8 +25,9 @@ mod test_rust { use super::AdapterRust; use crate::adapters::{ rust::{ - bench::test_rust_bench, criterion::test_rust_criterion, gungraun::test_rust_gungraun, - gungraun_json::test_rust_gungraun_json, iai::test_rust_iai, + bench::test_rust_bench, criterion::test_rust_criterion, + gungraun_json::test_rust_gungraun_json, gungraun_stdout::test_rust_gungraun_stdout, + iai::test_rust_iai, }, test_util::convert_file_path, }; @@ -54,24 +52,23 @@ mod test_rust { #[test] fn adapter_rust_gungraun() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/without-optional-metrics.txt", - ); + { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", + ); - test_rust_gungraun::validate_adapter_rust_gungraun( - &results, - &test_rust_gungraun::OptionalMetrics::default(), - ); - } - - #[test] - fn adapter_rust_gungraun_json() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", - ); + test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + } - dbg!(&results); + { + let results = convert_file_path::( + "./tool_output/rust/gungraun/without-optional-metrics.txt", + ); - test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + test_rust_gungraun_stdout::validate_adapter_rust_gungraun_stdout( + &results, + &test_rust_gungraun_stdout::OptionalMetrics::default(), + ); + } } } diff --git a/lib/bencher_adapter/src/lib.rs b/lib/bencher_adapter/src/lib.rs index c96e25781..3fa538be8 100644 --- a/lib/bencher_adapter/src/lib.rs +++ b/lib/bencher_adapter/src/lib.rs @@ -18,7 +18,8 @@ use adapters::{ ruby::{AdapterRuby, benchmark::AdapterRubyBenchmark}, rust::{ AdapterRust, bench::AdapterRustBench, criterion::AdapterRustCriterion, - gungraun::AdapterRustGungraun, gungraun_json::AdapterRustGungraunJson, iai::AdapterRustIai, + gungraun_json::AdapterRustGungraunJson, gungraun_stdout::AdapterRustGungraunStdout, + iai::AdapterRustIai, }, shell::{AdapterShell, hyperfine::AdapterShellHyperfine}, }; @@ -27,6 +28,8 @@ pub use bencher_json::{BenchmarkName, JsonNewMetric}; pub use error::AdapterError; pub use results::{AdapterResultsArray, adapter_results::AdapterResults}; +use crate::adapters::rust::gungraun::AdapterRustGungraun; + pub trait Adaptable { fn convert(&self, input: &str, settings: Settings) -> Option { Self::parse(input, settings) @@ -66,6 +69,7 @@ impl Adaptable for Adapter { Adapter::RustIai => AdapterRustIai::parse(input, settings), Adapter::RustGungraun => AdapterRustGungraun::parse(input, settings), Adapter::RustGungraunJson => AdapterRustGungraunJson::parse(input, settings), + Adapter::RustGungraunStdout => AdapterRustGungraunStdout::parse(input, settings), Adapter::Shell => AdapterShell::parse(input, settings), Adapter::ShellHyperfine => AdapterShellHyperfine::parse(input, settings), } diff --git a/lib/bencher_json/src/project/report.rs b/lib/bencher_json/src/project/report.rs index 9d74e2c92..014ea2361 100644 --- a/lib/bencher_json/src/project/report.rs +++ b/lib/bencher_json/src/project/report.rs @@ -91,6 +91,7 @@ const RUST_CRITERION_INT: i32 = 22; const RUST_IAI_INT: i32 = 23; const RUST_GUNGRAUN_INT: i32 = 24; const RUST_GUNGRAUN_JSON_INT: i32 = 25; +const RUST_GUNGRAUN_STDOUT_INT: i32 = 26; const CPP_INT: i32 = 30; const CPP_GOOGLE_INT: i32 = 31; const CPP_CATCH2_INT: i32 = 32; @@ -134,6 +135,7 @@ pub enum Adapter { #[serde(alias = "rust_iai_callgrind")] RustGungraun = RUST_GUNGRAUN_INT, RustGungraunJson = RUST_GUNGRAUN_JSON_INT, + RustGungraunStdout = RUST_GUNGRAUN_STDOUT_INT, Cpp = CPP_INT, CppGoogle = CPP_GOOGLE_INT, CppCatch2 = CPP_CATCH2_INT, @@ -182,6 +184,7 @@ impl Adapter { | Self::RustIai | Self::RustGungraun | Self::RustGungraunJson + | Self::RustGungraunStdout | Self::CppGoogle | Self::CppCatch2 | Self::GoBench @@ -210,6 +213,7 @@ impl fmt::Display for Adapter { Self::RustIai => write!(f, "rust_iai"), Self::RustGungraun => write!(f, "rust_gungraun"), Self::RustGungraunJson => write!(f, "rust_gungraun_json"), + Self::RustGungraunStdout => write!(f, "rust_gungraun_stdout"), Self::Cpp => write!(f, "cpp"), Self::CppGoogle => write!(f, "cpp_google"), Self::CppCatch2 => write!(f, "cpp_catch2"), @@ -243,8 +247,8 @@ mod adapter { DART_BENCHMARK_HARNESS_INT, DART_INT, GO_BENCH_INT, GO_INT, JAVA_INT, JAVA_JMH_INT, JS_BENCHMARK_INT, JS_INT, JS_TIME_INT, JS_VITEST_INT, JSON_INT, MAGIC_INT, PYTHON_ASV_INT, PYTHON_INT, PYTHON_PYTEST_INT, RUBY_BENCHMARK_INT, RUBY_INT, RUST_BENCH_INT, - RUST_CRITERION_INT, RUST_GUNGRAUN_INT, RUST_GUNGRAUN_JSON_INT, RUST_IAI_INT, RUST_INT, - SHELL_HYPERFINE_INT, SHELL_INT, + RUST_CRITERION_INT, RUST_GUNGRAUN_INT, RUST_GUNGRAUN_JSON_INT, RUST_GUNGRAUN_STDOUT_INT, + RUST_IAI_INT, RUST_INT, SHELL_HYPERFINE_INT, SHELL_INT, }; #[derive(Debug, thiserror::Error)] @@ -271,6 +275,7 @@ mod adapter { Self::RustIai => RUST_IAI_INT.to_sql(out), Self::RustGungraun => RUST_GUNGRAUN_INT.to_sql(out), Self::RustGungraunJson => RUST_GUNGRAUN_JSON_INT.to_sql(out), + Self::RustGungraunStdout => RUST_GUNGRAUN_STDOUT_INT.to_sql(out), Self::Cpp => CPP_INT.to_sql(out), Self::CppGoogle => CPP_GOOGLE_INT.to_sql(out), Self::CppCatch2 => CPP_CATCH2_INT.to_sql(out), @@ -312,6 +317,7 @@ mod adapter { RUST_IAI_INT => Ok(Self::RustIai), RUST_GUNGRAUN_INT => Ok(Self::RustGungraun), RUST_GUNGRAUN_JSON_INT => Ok(Self::RustGungraunJson), + RUST_GUNGRAUN_STDOUT_INT => Ok(Self::RustGungraunStdout), CPP_INT => Ok(Self::Cpp), CPP_GOOGLE_INT => Ok(Self::CppGoogle), CPP_CATCH2_INT => Ok(Self::CppCatch2), diff --git a/services/api/openapi.json b/services/api/openapi.json index 9c68bbd45..5957f1d45 100644 --- a/services/api/openapi.json +++ b/services/api/openapi.json @@ -11846,6 +11846,7 @@ "rust_iai", "rust_gungraun", "rust_gungraun_json", + "rust_gungraun_stdout", "cpp", "cpp_google", "cpp_catch2", diff --git a/services/console/src/types/bencher.ts b/services/console/src/types/bencher.ts index d638da2fd..d67af06f5 100644 --- a/services/console/src/types/bencher.ts +++ b/services/console/src/types/bencher.ts @@ -1048,6 +1048,7 @@ export enum Adapter { RustIai = "rust_iai", RustGungraun = "rust_gungraun", RustGungraunJson = "rust_gungraun_json", + RustGungraunStdout = "rust_gungraun_stdout", Cpp = "cpp", CppGoogle = "cpp_google", CppCatch2 = "cpp_catch2", From b834f4d9db4ee421f508c33749b9223a369fa5de Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Tue, 11 Aug 2026 02:03:52 +0200 Subject: [PATCH 09/13] fix RustIaiCallgrind to RustGungraun, add new json, stdout adapters in the console --- .../components/adapter/BenchmarkHarnessFallback.tsx | 2 +- .../src/components/adapter/BenchmarkHarnessInner.tsx | 2 +- services/console/src/components/adapter/adapter.ts | 4 ++++ services/console/src/components/adapter/name.ts | 10 +++++++--- .../components/console/deck/hand/card/ViewCard.tsx | 12 ++++++++---- services/console/src/pages/rust/gungraun.astro | 2 +- 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/services/console/src/components/adapter/BenchmarkHarnessFallback.tsx b/services/console/src/components/adapter/BenchmarkHarnessFallback.tsx index e56387d20..d00093ebc 100644 --- a/services/console/src/components/adapter/BenchmarkHarnessFallback.tsx +++ b/services/console/src/components/adapter/BenchmarkHarnessFallback.tsx @@ -53,8 +53,8 @@ const BenchmarkHarnessFallback = () => ( adapters={[ Adapter.RustBench, Adapter.RustCriterion, + Adapter.RustGungraun, Adapter.RustIai, - Adapter.RustIaiCallgrind, ]} /> ( adapters={[ Adapter.RustBench, Adapter.RustCriterion, + Adapter.RustGungraun, Adapter.RustIai, - Adapter.RustIaiCallgrind, ]} /> { case Adapter.RustCriterion: case Adapter.RustIai: case Adapter.RustGungraun: + case Adapter.RustGungraunJson: + case Adapter.RustGungraunStdout: return RUST_ICON; case Adapter.CppGoogle: case Adapter.CppCatch2: @@ -63,6 +65,8 @@ export const adapterCommand = (isConsole: boolean, adapter: null | Adapter) => { case Adapter.RustCriterion: case Adapter.RustIai: case Adapter.RustGungraun: + case Adapter.RustGungraunJson: + case Adapter.RustGungraunStdout: return `bencher run${host} "cargo bench"`; case Adapter.CppGoogle: return `bencher run${host} "make benchmarks --benchmark_format=json"`; diff --git a/services/console/src/components/adapter/name.ts b/services/console/src/components/adapter/name.ts index 76bbeac6e..43448d968 100644 --- a/services/console/src/components/adapter/name.ts +++ b/services/console/src/components/adapter/name.ts @@ -12,8 +12,10 @@ export const adapterName = (adapter: Adapter): string => { return "Criterion"; case Adapter.RustIai: return "Iai"; - case Adapter.RustIaiCallgrind: - return "Iai-Callgrind"; + case Adapter.RustGungraun: + case Adapter.RustGungraunJson: + case Adapter.RustGungraunStdout: + return "Gungraun"; case Adapter.CppGoogle: return "Google Benchmark"; case Adapter.CppCatch2: @@ -51,7 +53,9 @@ export const adapterCommand = (isConsole: boolean, adapter: null | Adapter) => { return `bencher run${host} "cargo +nightly bench"`; case Adapter.RustCriterion: case Adapter.RustIai: - case Adapter.RustIaiCallgrind: + case Adapter.RustGungraun: + case Adapter.RustGungraunJson: + case Adapter.RustGungraunStdout: return `bencher run${host} "cargo bench"`; case Adapter.CppGoogle: return `bencher run${host} "make benchmarks --benchmark_format=json"`; diff --git a/services/console/src/components/console/deck/hand/card/ViewCard.tsx b/services/console/src/components/console/deck/hand/card/ViewCard.tsx index 21735b8c8..6b4ae72ad 100644 --- a/services/console/src/components/console/deck/hand/card/ViewCard.tsx +++ b/services/console/src/components/console/deck/hand/card/ViewCard.tsx @@ -462,8 +462,10 @@ const AdapterCard = (props: Props) => { return "-rust-criterion"; case Adapter.RustIai: return "-rust-iai"; - case Adapter.RustIaiCallgrind: - return "-rust-iai-callgrind"; + case Adapter.RustGungraun: + case Adapter.RustGungraunJson: + case Adapter.RustGungraunStdout: + return "-rust-gungraun"; case Adapter.ShellHyperfine: return "_%EF%B8%8F-shell-hyperfine"; default: @@ -511,8 +513,10 @@ const AdapterCard = (props: Props) => { return "Rust Criterion"; case Adapter.RustIai: return "Rust Iai"; - case Adapter.RustIaiCallgrind: - return "Rust Iai-Callgrind"; + case Adapter.RustGungraun: + case Adapter.RustGungraunJson: + case Adapter.RustGungraunStdout: + return "Rust Gungraun"; case Adapter.ShellHyperfine: return "Shell Hyperfine"; default: diff --git a/services/console/src/pages/rust/gungraun.astro b/services/console/src/pages/rust/gungraun.astro index d497f045a..d4a94dd61 100644 --- a/services/console/src/pages/rust/gungraun.astro +++ b/services/console/src/pages/rust/gungraun.astro @@ -46,7 +46,7 @@ import CallToAction from "../../components/landing/CallToAction.astro";
Learn More From a65851181fdfab2ab6ac994b5e7aa01090af026f Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Wed, 12 Aug 2026 01:14:37 +0200 Subject: [PATCH 10/13] add gungraun pretty json parser --- lib/bencher_adapter/src/adapters/magic.rs | 18 +- .../src/adapters/rust/gungraun.rs | 18 +- .../src/adapters/rust/gungraun_json.rs | 181 +++++++++++++-- lib/bencher_adapter/src/adapters/rust/mod.rs | 8 + .../json_pretty_mixed_foreign_ndjson.txt | 123 ++++++++++ ...pretty_mixed_foreign_pretty_and_ndjson.txt | 128 ++++++++++ ...json_pretty_mixed_ndjson_two_callgrind.txt | 119 ++++++++++ .../gungraun/json_pretty_one_callgrind.txt | 114 +++++++++ .../json_pretty_one_callgrind_indented.txt | 116 ++++++++++ .../gungraun/json_pretty_two_callgrind.txt | 219 ++++++++++++++++++ 10 files changed, 1016 insertions(+), 28 deletions(-) create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_ndjson.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_pretty_and_ndjson.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_ndjson_two_callgrind.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind_indented.txt create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_two_callgrind.txt diff --git a/lib/bencher_adapter/src/adapters/magic.rs b/lib/bencher_adapter/src/adapters/magic.rs index b8f1821b7..d7a263b10 100644 --- a/lib/bencher_adapter/src/adapters/magic.rs +++ b/lib/bencher_adapter/src/adapters/magic.rs @@ -161,11 +161,21 @@ mod test_magic { #[test] fn adapter_magic_rust_gungraun_json() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", - ); + { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_one_callgrind.txt", + ); + + test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + } + + { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", + ); - test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + } } #[test] diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun.rs b/lib/bencher_adapter/src/adapters/rust/gungraun.rs index 8701c64b5..5209980db 100644 --- a/lib/bencher_adapter/src/adapters/rust/gungraun.rs +++ b/lib/bencher_adapter/src/adapters/rust/gungraun.rs @@ -25,11 +25,21 @@ pub(crate) mod test_rust_gungraun { #[test] fn json() { - let results = convert_file_path::( - "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", - ); + { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + + { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_one_callgrind.txt", + ); - validate_adapter_rust_gungraun_json(&results); + validate_adapter_rust_gungraun_json(&results); + } } #[test] diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs index 59f06d832..0ae80a2ee 100644 --- a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs +++ b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs @@ -4,10 +4,12 @@ use gungraun_summary::{ either_or_both::EitherOrBoth, util::SummaryByVersion, v6::{ - CachegrindMetric, DhatMetric, ErrorMetric, EventKind, Metric, MetricsDiff, MetricsSummary, - ToolMetricSummary, ValgrindTool, + BenchmarkSummary, CachegrindMetric, DhatMetric, ErrorMetric, EventKind, Metric, + MetricsDiff, MetricsSummary, ToolMetricSummary, ValgrindTool, }, }; +use std::fmt::Write as _; +use std::str::Lines; use crate::{Adaptable, AdapterResults, Settings, results::adapter_results::GungraunMeasure}; @@ -29,30 +31,53 @@ impl Adaptable for AdapterRustGungraunJson { } } +/// Parse json output in pretty and ndjson format +/// +/// Although it is currently not a possibility with gungraun cli/env options, this parser handles +/// mixed pretty and ndjson format making bencher future proof in that regard. The parser also +/// ignores intermixed json output from other tools or cargo itself, for example `cargo bench +/// --message-format=json`. fn parse_multiple(input: &str) -> Option)>> { - let parsed = input.lines().filter_map(parse_line).collect::>(); + let mut lines = input.lines(); + + let mut parsed = vec![]; + while let Some(line) = lines.next() { + let trimmed = line.trim(); + if trimmed == "{" { + let indent = line.len() - line.trim_start().len(); + if let Some(one) = parse_benchmark_pretty(&mut lines, indent) { + parsed.push(one); + } + } else if trimmed.starts_with('{') + && trimmed.ends_with('}') + && let Some(one) = parse_benchmark(line) + { + parsed.push(one); + } + } (!parsed.is_empty()).then_some(parsed) } -fn parse_line(input: &str) -> Option<(BenchmarkName, Vec)> { - // Using the version aware gungraun_summary parsing method to simplify adapting gungraun summary - // version updates. At the moment there's just v6 - let summary = match gungraun_summary::util::parse_slice(input.as_bytes()) { - Ok(summary_by_version) => match summary_by_version { - SummaryByVersion::V6(benchmark_summary) => benchmark_summary, - _ => return None, - }, - Err(_) => return None, - }; - - let name: BenchmarkName = if let Some(id) = &summary.id { - format!("{}::{id}", summary.module_path) - } else { - summary.module_path +fn parse_benchmark_pretty( + lines: &mut Lines<'_>, + indent: usize, +) -> Option<(BenchmarkName, Vec)> { + let mut payload = "{".to_owned(); + for line in lines { + writeln!(payload, "{line}").ok()?; + + let trimmed = line.trim(); + if trimmed == "}" && line.len() - line.trim_start().len() == indent { + break; + } } - .parse() - .ok()?; + + parse_benchmark(payload.as_str()) +} + +fn parse_benchmark(input: &str) -> Option<(BenchmarkName, Vec)> { + let (name, summary) = parse_json(input.as_bytes())?; let measures = summary .profiles @@ -85,6 +110,28 @@ fn parse_line(input: &str) -> Option<(BenchmarkName, Vec)> { Some((name, measures)) } +fn parse_json(input: &[u8]) -> Option<(BenchmarkName, BenchmarkSummary)> { + // Using the version aware gungraun_summary parsing method to simplify adapting gungraun summary + // version updates. At the moment there's just v6 + let summary = match gungraun_summary::util::parse_slice(input) { + Ok(summary_by_version) => match summary_by_version { + SummaryByVersion::V6(benchmark_summary) => benchmark_summary, + _ => return None, + }, + Err(_) => return None, + }; + + let name: BenchmarkName = if let Some(id) = &summary.id { + format!("{}::{id}", summary.module_path) + } else { + summary.module_path.clone() + } + .parse() + .ok()?; + + Some((name, summary)) +} + fn parse_drd_metrics_summary(metrics_summary: MetricsSummary) -> Vec { metrics_summary .0 @@ -603,6 +650,100 @@ pub(crate) mod test_rust_gungraun_json { } } + #[test] + fn pretty_one_callgrind() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_one_callgrind.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + + #[test] + fn pretty_two_callgrind() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_two_callgrind.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let expected = HashMap::from([(D1MissRate::SLUG_STR, 0.1), (D1mr::SLUG_STR, 6.0)]); + + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::first", + ); + } + + { + let expected = HashMap::from([(D1MissRate::SLUG_STR, 0.2), (D1mr::SLUG_STR, 7.0)]); + + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::second", + ); + } + } + + #[test] + fn pretty_mixed_ndjson_two_callgrind() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_mixed_ndjson_two_callgrind.txt", + ); + + assert_eq!(results.inner.len(), 2); + + { + let expected = HashMap::from([(D1MissRate::SLUG_STR, 0.1), (D1mr::SLUG_STR, 6.0)]); + + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::first", + ); + } + + { + let expected = HashMap::from([(D1MissRate::SLUG_STR, 0.2), (D1mr::SLUG_STR, 7.0)]); + + compare_benchmark( + &expected, + &results, + "play_game::bench_play_game_group::bench_play_game_100::second", + ); + } + } + + #[test] + fn pretty_mixed_with_foreign_ndjson() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_mixed_foreign_ndjson.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + + #[test] + fn pretty_mixed_with_foreign_pretty_and_ndjson() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_mixed_foreign_pretty_and_ndjson.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + + #[test] + fn pretty_one_callgrind_indented() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_one_callgrind_indented.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + pub fn validate_adapter_rust_gungraun_json(results: &AdapterResults) { let expected = HashMap::from([(D1MissRate::SLUG_STR, 0.1), (D1mr::SLUG_STR, 6.0)]); diff --git a/lib/bencher_adapter/src/adapters/rust/mod.rs b/lib/bencher_adapter/src/adapters/rust/mod.rs index 48c5ef21d..ed7e5410a 100644 --- a/lib/bencher_adapter/src/adapters/rust/mod.rs +++ b/lib/bencher_adapter/src/adapters/rust/mod.rs @@ -52,6 +52,14 @@ mod test_rust { #[test] fn adapter_rust_gungraun() { + { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_pretty_one_callgrind.txt", + ); + + test_rust_gungraun_json::validate_adapter_rust_gungraun_json(&results); + } + { let results = convert_file_path::( "./tool_output/rust/gungraun/json_one_callgrind_diff.txt", diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_ndjson.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_ndjson.txt new file mode 100644 index 000000000..a7c448cac --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_ndjson.txt @@ -0,0 +1,123 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +... some foreign json taken out from a real cargo bench --message-format=json run + +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12","manifest_path":"/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.12/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"unicode_ident","src_path":"/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.12/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":false,"overflow_checks":false,"test":false},"features":[],"filenames":["/bencher/examples/rust/gungraun/target/release/deps/libunicode_ident-b9304a74ccd3330d.rlib","/bencher/examples/rust/gungraun/target/release/deps/libunicode_ident-b9304a74ccd3330d.rmeta"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/bencher/examples/rust/gungraun/target/release/build/serde_core-203a77995644e753/out"} +{"reason":"build-finished","success":true} + +{ + "baselines": [ + null, + null + ], + "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", + "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", + "details": null, + "function_name": "bench_play_game_100", + "id": "some_id", + "kind": "LibraryBenchmark", + "module_path": "play_game::bench_play_game_group::bench_play_game_100", + "package_dir": "/bencher/examples/rust/gungraun", + "profiles": [ + { + "flamegraphs": [], + "log_paths": [ + "/callgrind.bench_play_game_100.log" + ], + "out_paths": [ + "/callgrind.bench_play_game_100.out" + ], + "summaries": { + "parts": [ + { + "details": { + "Left": { + "command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", + "details": null, + "parent_pid": null, + "part": 1, + "path": "/callgrind.bench_play_game_100.out", + "pid": 12345, + "thread": 1 + } + }, + "metrics_summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + ], + "total": { + "regressions": [], + "summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + }, + "tool": "Callgrind" + } + ], + "project_root": "/bencher/examples/rust/gungraun", + "summary_output": null, + "version": "6" +} + +and some json output after it + +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12","manifest_path":"/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.12/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"unicode_ident","src_path":"/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.12/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":false,"overflow_checks":false,"test":false},"features":[],"filenames":["/bencher/examples/rust/gungraun/target/release/deps/libunicode_ident-b9304a74ccd3330d.rlib","/bencher/examples/rust/gungraun/target/release/deps/libunicode_ident-b9304a74ccd3330d.rmeta"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/bencher/examples/rust/gungraun/target/release/build/serde_core-203a77995644e753/out"} +{"reason":"build-finished","success":true} + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_pretty_and_ndjson.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_pretty_and_ndjson.txt new file mode 100644 index 000000000..c8db4a945 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_foreign_pretty_and_ndjson.txt @@ -0,0 +1,128 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +... some foreign json taken out from a real cargo bench --message-format=json run + +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12","manifest_path":"/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.12/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"unicode_ident","src_path":"/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.12/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":false,"overflow_checks":false,"test":false},"features":[],"filenames":["/bencher/examples/rust/gungraun/target/release/deps/libunicode_ident-b9304a74ccd3330d.rlib","/bencher/examples/rust/gungraun/target/release/deps/libunicode_ident-b9304a74ccd3330d.rmeta"],"executable":null,"fresh":true} + +... this is not original cargo bench output. we just need some foreign pretty json mixed with ndjson +{ + "reason": "build-script-executed", + "package_id": "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", + "linked_libs": [], + "linked_paths": [], + "cfgs": [], + "env": [], + "out_dir": "/bencher/examples/rust/gungraun/target/release/build/serde_core-203a77995644e753/out" +} + +{"reason":"build-finished","success":true} + +{ + "baselines": [ + null, + null + ], + "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", + "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", + "details": null, + "function_name": "bench_play_game_100", + "id": "some_id", + "kind": "LibraryBenchmark", + "module_path": "play_game::bench_play_game_group::bench_play_game_100", + "package_dir": "/bencher/examples/rust/gungraun", + "profiles": [ + { + "flamegraphs": [], + "log_paths": [ + "/callgrind.bench_play_game_100.log" + ], + "out_paths": [ + "/callgrind.bench_play_game_100.out" + ], + "summaries": { + "parts": [ + { + "details": { + "Left": { + "command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", + "details": null, + "parent_pid": null, + "part": 1, + "path": "/callgrind.bench_play_game_100.out", + "pid": 12345, + "thread": 1 + } + }, + "metrics_summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + ], + "total": { + "regressions": [], + "summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + }, + "tool": "Callgrind" + } + ], + "project_root": "/bencher/examples/rust/gungraun", + "summary_output": null, + "version": "6" +} + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_ndjson_two_callgrind.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_ndjson_two_callgrind.txt new file mode 100644 index 000000000..d90a66fec --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_mixed_ndjson_two_callgrind.txt @@ -0,0 +1,119 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{ + "baselines": [ + null, + null + ], + "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", + "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", + "details": null, + "function_name": "bench_play_game_100", + "id": "first", + "kind": "LibraryBenchmark", + "module_path": "play_game::bench_play_game_group::bench_play_game_100", + "package_dir": "/bencher/examples/rust/gungraun", + "profiles": [ + { + "flamegraphs": [], + "log_paths": [ + "/callgrind.bench_play_game_100.log" + ], + "out_paths": [ + "/callgrind.bench_play_game_100.out" + ], + "summaries": { + "parts": [ + { + "details": { + "Left": { + "command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", + "details": null, + "parent_pid": null, + "part": 1, + "path": "/callgrind.bench_play_game_100.out", + "pid": 12345, + "thread": 1 + } + }, + "metrics_summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + ], + "total": { + "regressions": [], + "summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + }, + "tool": "Callgrind" + } + ], + "project_root": "/bencher/examples/rust/gungraun", + "summary_output": null, + "version": "6" +} + +some text between... + + +{"baselines":[null,null],"benchmark_exe":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad","benchmark_file":"/bencher/examples/rust/gungraun/benches/play_game.rs","details":null,"function_name":"bench_play_game_100","id":"second","kind":"LibraryBenchmark","module_path":"play_game::bench_play_game_group::bench_play_game_100","package_dir":"/bencher/examples/rust/gungraun","profiles":[{"flamegraphs":[],"log_paths":["/callgrind.bench_play_game_100.log"],"out_paths":["/callgrind.bench_play_game_100.out"],"summaries":{"parts":[{"details":{"Left":{"command":"/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000","details":null,"parent_pid":null,"part":1,"path":"/callgrind.bench_play_game_100.out","pid":12345,"thread":1}},"metrics_summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.2}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":7}}}}}}],"total":{"regressions":[],"summary":{"Callgrind":{"D1MissRate":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Float":0.2}}},"D1mr":{"diffs":{"diff_pct":"0","factor":"1"},"metrics":{"Left":{"Int":7}}}}}}},"tool":"Callgrind"}],"project_root":"/bencher/examples/rust/gungraun","summary_output":null,"version":"6"} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind.txt new file mode 100644 index 000000000..dbb47984c --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind.txt @@ -0,0 +1,114 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{ + "baselines": [ + null, + null + ], + "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", + "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", + "details": null, + "function_name": "bench_play_game_100", + "id": "some_id", + "kind": "LibraryBenchmark", + "module_path": "play_game::bench_play_game_group::bench_play_game_100", + "package_dir": "/bencher/examples/rust/gungraun", + "profiles": [ + { + "flamegraphs": [], + "log_paths": [ + "/callgrind.bench_play_game_100.log" + ], + "out_paths": [ + "/callgrind.bench_play_game_100.out" + ], + "summaries": { + "parts": [ + { + "details": { + "Left": { + "command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", + "details": null, + "parent_pid": null, + "part": 1, + "path": "/callgrind.bench_play_game_100.out", + "pid": 12345, + "thread": 1 + } + }, + "metrics_summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + ], + "total": { + "regressions": [], + "summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + }, + "tool": "Callgrind" + } + ], + "project_root": "/bencher/examples/rust/gungraun", + "summary_output": null, + "version": "6" +} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind_indented.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind_indented.txt new file mode 100644 index 000000000..0f18475d0 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_one_callgrind_indented.txt @@ -0,0 +1,116 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +... with some indentation + + { + "baselines": [ + null, + null + ], + "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", + "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", + "details": null, + "function_name": "bench_play_game_100", + "id": "some_id", + "kind": "LibraryBenchmark", + "module_path": "play_game::bench_play_game_group::bench_play_game_100", + "package_dir": "/bencher/examples/rust/gungraun", + "profiles": [ + { + "flamegraphs": [], + "log_paths": [ + "/callgrind.bench_play_game_100.log" + ], + "out_paths": [ + "/callgrind.bench_play_game_100.out" + ], + "summaries": { + "parts": [ + { + "details": { + "Left": { + "command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", + "details": null, + "parent_pid": null, + "part": 1, + "path": "/callgrind.bench_play_game_100.out", + "pid": 12345, + "thread": 1 + } + }, + "metrics_summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + ], + "total": { + "regressions": [], + "summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + }, + "tool": "Callgrind" + } + ], + "project_root": "/bencher/examples/rust/gungraun", + "summary_output": null, + "version": "6" + } + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_two_callgrind.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_two_callgrind.txt new file mode 100644 index 000000000..b75735130 --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_pretty_two_callgrind.txt @@ -0,0 +1,219 @@ +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +{ + "baselines": [ + null, + null + ], + "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", + "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", + "details": null, + "function_name": "bench_play_game_100", + "id": "first", + "kind": "LibraryBenchmark", + "module_path": "play_game::bench_play_game_group::bench_play_game_100", + "package_dir": "/bencher/examples/rust/gungraun", + "profiles": [ + { + "flamegraphs": [], + "log_paths": [ + "/callgrind.bench_play_game_100.log" + ], + "out_paths": [ + "/callgrind.bench_play_game_100.out" + ], + "summaries": { + "parts": [ + { + "details": { + "Left": { + "command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", + "details": null, + "parent_pid": null, + "part": 1, + "path": "/callgrind.bench_play_game_100.out", + "pid": 12345, + "thread": 1 + } + }, + "metrics_summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + ], + "total": { + "regressions": [], + "summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.1 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 6 + } + } + } + } + } + } + }, + "tool": "Callgrind" + } + ], + "project_root": "/bencher/examples/rust/gungraun", + "summary_output": null, + "version": "6" +} + +some text between + + +{ + "baselines": [ + null, + null + ], + "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", + "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", + "details": null, + "function_name": "bench_play_game_100", + "id": "second", + "kind": "LibraryBenchmark", + "module_path": "play_game::bench_play_game_group::bench_play_game_100", + "package_dir": "/bencher/examples/rust/gungraun", + "profiles": [ + { + "flamegraphs": [], + "log_paths": [ + "/callgrind.bench_play_game_100.log" + ], + "out_paths": [ + "/callgrind.bench_play_game_100.out" + ], + "summaries": { + "parts": [ + { + "details": { + "Left": { + "command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", + "details": null, + "parent_pid": null, + "part": 1, + "path": "/callgrind.bench_play_game_100.out", + "pid": 12345, + "thread": 1 + } + }, + "metrics_summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.2 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 7 + } + } + } + } + } + } + ], + "total": { + "regressions": [], + "summary": { + "Callgrind": { + "D1MissRate": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Float": 0.2 + } + } + }, + "D1mr": { + "diffs": { + "diff_pct": "0", + "factor": "1" + }, + "metrics": { + "Left": { + "Int": 7 + } + } + } + } + } + } + }, + "tool": "Callgrind" + } + ], + "project_root": "/bencher/examples/rust/gungraun", + "summary_output": null, + "version": "6" +} + + + +.... Some trailing text that should be ignored ... + + +.... Some trailing text that should be ignored ... +.... Some trailing text that should be ignored ... From ce66214f2e0662294ce69445a02ce15e064223f8 Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Wed, 12 Aug 2026 01:39:48 +0200 Subject: [PATCH 11/13] apply review and sort gungraun stdout before json --- lib/bencher_adapter/src/lib.rs | 2 +- lib/bencher_json/src/project/report.rs | 14 +++++++------- services/api/openapi.json | 2 +- services/console/src/components/adapter/adapter.ts | 4 ++-- services/console/src/components/adapter/name.ts | 4 ++-- .../components/console/deck/hand/card/ViewCard.tsx | 4 ++-- services/console/src/types/bencher.ts | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/bencher_adapter/src/lib.rs b/lib/bencher_adapter/src/lib.rs index 3fa538be8..44e542f5f 100644 --- a/lib/bencher_adapter/src/lib.rs +++ b/lib/bencher_adapter/src/lib.rs @@ -68,8 +68,8 @@ impl Adaptable for Adapter { Adapter::RustCriterion => AdapterRustCriterion::parse(input, settings), Adapter::RustIai => AdapterRustIai::parse(input, settings), Adapter::RustGungraun => AdapterRustGungraun::parse(input, settings), - Adapter::RustGungraunJson => AdapterRustGungraunJson::parse(input, settings), Adapter::RustGungraunStdout => AdapterRustGungraunStdout::parse(input, settings), + Adapter::RustGungraunJson => AdapterRustGungraunJson::parse(input, settings), Adapter::Shell => AdapterShell::parse(input, settings), Adapter::ShellHyperfine => AdapterShellHyperfine::parse(input, settings), } diff --git a/lib/bencher_json/src/project/report.rs b/lib/bencher_json/src/project/report.rs index 014ea2361..33bee299e 100644 --- a/lib/bencher_json/src/project/report.rs +++ b/lib/bencher_json/src/project/report.rs @@ -90,8 +90,8 @@ const RUST_BENCH_INT: i32 = 21; const RUST_CRITERION_INT: i32 = 22; const RUST_IAI_INT: i32 = 23; const RUST_GUNGRAUN_INT: i32 = 24; -const RUST_GUNGRAUN_JSON_INT: i32 = 25; -const RUST_GUNGRAUN_STDOUT_INT: i32 = 26; +const RUST_GUNGRAUN_STDOUT_INT: i32 = 25; +const RUST_GUNGRAUN_JSON_INT: i32 = 26; const CPP_INT: i32 = 30; const CPP_GOOGLE_INT: i32 = 31; const CPP_CATCH2_INT: i32 = 32; @@ -134,8 +134,8 @@ pub enum Adapter { // https://github.com/bencherdev/bencher/issues/619 #[serde(alias = "rust_iai_callgrind")] RustGungraun = RUST_GUNGRAUN_INT, - RustGungraunJson = RUST_GUNGRAUN_JSON_INT, RustGungraunStdout = RUST_GUNGRAUN_STDOUT_INT, + RustGungraunJson = RUST_GUNGRAUN_JSON_INT, Cpp = CPP_INT, CppGoogle = CPP_GOOGLE_INT, CppCatch2 = CPP_CATCH2_INT, @@ -183,8 +183,8 @@ impl Adapter { | Self::RustCriterion | Self::RustIai | Self::RustGungraun - | Self::RustGungraunJson | Self::RustGungraunStdout + | Self::RustGungraunJson | Self::CppGoogle | Self::CppCatch2 | Self::GoBench @@ -212,8 +212,8 @@ impl fmt::Display for Adapter { Self::RustCriterion => write!(f, "rust_criterion"), Self::RustIai => write!(f, "rust_iai"), Self::RustGungraun => write!(f, "rust_gungraun"), - Self::RustGungraunJson => write!(f, "rust_gungraun_json"), Self::RustGungraunStdout => write!(f, "rust_gungraun_stdout"), + Self::RustGungraunJson => write!(f, "rust_gungraun_json"), Self::Cpp => write!(f, "cpp"), Self::CppGoogle => write!(f, "cpp_google"), Self::CppCatch2 => write!(f, "cpp_catch2"), @@ -274,8 +274,8 @@ mod adapter { Self::RustCriterion => RUST_CRITERION_INT.to_sql(out), Self::RustIai => RUST_IAI_INT.to_sql(out), Self::RustGungraun => RUST_GUNGRAUN_INT.to_sql(out), - Self::RustGungraunJson => RUST_GUNGRAUN_JSON_INT.to_sql(out), Self::RustGungraunStdout => RUST_GUNGRAUN_STDOUT_INT.to_sql(out), + Self::RustGungraunJson => RUST_GUNGRAUN_JSON_INT.to_sql(out), Self::Cpp => CPP_INT.to_sql(out), Self::CppGoogle => CPP_GOOGLE_INT.to_sql(out), Self::CppCatch2 => CPP_CATCH2_INT.to_sql(out), @@ -316,8 +316,8 @@ mod adapter { RUST_CRITERION_INT => Ok(Self::RustCriterion), RUST_IAI_INT => Ok(Self::RustIai), RUST_GUNGRAUN_INT => Ok(Self::RustGungraun), - RUST_GUNGRAUN_JSON_INT => Ok(Self::RustGungraunJson), RUST_GUNGRAUN_STDOUT_INT => Ok(Self::RustGungraunStdout), + RUST_GUNGRAUN_JSON_INT => Ok(Self::RustGungraunJson), CPP_INT => Ok(Self::Cpp), CPP_GOOGLE_INT => Ok(Self::CppGoogle), CPP_CATCH2_INT => Ok(Self::CppCatch2), diff --git a/services/api/openapi.json b/services/api/openapi.json index 5957f1d45..e08ac4d3c 100644 --- a/services/api/openapi.json +++ b/services/api/openapi.json @@ -11845,8 +11845,8 @@ "rust_criterion", "rust_iai", "rust_gungraun", - "rust_gungraun_json", "rust_gungraun_stdout", + "rust_gungraun_json", "cpp", "cpp_google", "cpp_catch2", diff --git a/services/console/src/components/adapter/adapter.ts b/services/console/src/components/adapter/adapter.ts index 2a1994d76..8c08b0705 100644 --- a/services/console/src/components/adapter/adapter.ts +++ b/services/console/src/components/adapter/adapter.ts @@ -25,8 +25,8 @@ export const adapterIcon = (adapter: Adapter) => { case Adapter.RustCriterion: case Adapter.RustIai: case Adapter.RustGungraun: - case Adapter.RustGungraunJson: case Adapter.RustGungraunStdout: + case Adapter.RustGungraunJson: return RUST_ICON; case Adapter.CppGoogle: case Adapter.CppCatch2: @@ -65,8 +65,8 @@ export const adapterCommand = (isConsole: boolean, adapter: null | Adapter) => { case Adapter.RustCriterion: case Adapter.RustIai: case Adapter.RustGungraun: - case Adapter.RustGungraunJson: case Adapter.RustGungraunStdout: + case Adapter.RustGungraunJson: return `bencher run${host} "cargo bench"`; case Adapter.CppGoogle: return `bencher run${host} "make benchmarks --benchmark_format=json"`; diff --git a/services/console/src/components/adapter/name.ts b/services/console/src/components/adapter/name.ts index 43448d968..0facd7f4e 100644 --- a/services/console/src/components/adapter/name.ts +++ b/services/console/src/components/adapter/name.ts @@ -13,8 +13,8 @@ export const adapterName = (adapter: Adapter): string => { case Adapter.RustIai: return "Iai"; case Adapter.RustGungraun: - case Adapter.RustGungraunJson: case Adapter.RustGungraunStdout: + case Adapter.RustGungraunJson: return "Gungraun"; case Adapter.CppGoogle: return "Google Benchmark"; @@ -54,8 +54,8 @@ export const adapterCommand = (isConsole: boolean, adapter: null | Adapter) => { case Adapter.RustCriterion: case Adapter.RustIai: case Adapter.RustGungraun: - case Adapter.RustGungraunJson: case Adapter.RustGungraunStdout: + case Adapter.RustGungraunJson: return `bencher run${host} "cargo bench"`; case Adapter.CppGoogle: return `bencher run${host} "make benchmarks --benchmark_format=json"`; diff --git a/services/console/src/components/console/deck/hand/card/ViewCard.tsx b/services/console/src/components/console/deck/hand/card/ViewCard.tsx index 6b4ae72ad..7532a443d 100644 --- a/services/console/src/components/console/deck/hand/card/ViewCard.tsx +++ b/services/console/src/components/console/deck/hand/card/ViewCard.tsx @@ -463,8 +463,8 @@ const AdapterCard = (props: Props) => { case Adapter.RustIai: return "-rust-iai"; case Adapter.RustGungraun: - case Adapter.RustGungraunJson: case Adapter.RustGungraunStdout: + case Adapter.RustGungraunJson: return "-rust-gungraun"; case Adapter.ShellHyperfine: return "_%EF%B8%8F-shell-hyperfine"; @@ -514,8 +514,8 @@ const AdapterCard = (props: Props) => { case Adapter.RustIai: return "Rust Iai"; case Adapter.RustGungraun: - case Adapter.RustGungraunJson: case Adapter.RustGungraunStdout: + case Adapter.RustGungraunJson: return "Rust Gungraun"; case Adapter.ShellHyperfine: return "Shell Hyperfine"; diff --git a/services/console/src/types/bencher.ts b/services/console/src/types/bencher.ts index d67af06f5..b51cc5223 100644 --- a/services/console/src/types/bencher.ts +++ b/services/console/src/types/bencher.ts @@ -1047,8 +1047,8 @@ export enum Adapter { RustCriterion = "rust_criterion", RustIai = "rust_iai", RustGungraun = "rust_gungraun", - RustGungraunJson = "rust_gungraun_json", RustGungraunStdout = "rust_gungraun_stdout", + RustGungraunJson = "rust_gungraun_json", Cpp = "cpp", CppGoogle = "cpp_google", CppCatch2 = "cpp_catch2", From 4ff03d8a4febf05692b821c4296cbf07dbf3218d Mon Sep 17 00:00:00 2001 From: Everett Pompeii Date: Sat, 15 Aug 2026 05:38:39 +0000 Subject: [PATCH 12/13] fix(adapter): recover from an unterminated pretty json block `parse_multiple` handed a consumable `Lines` iterator to `parse_benchmark_pretty`, which drained it searching for a closing brace at the opening indent. When the output is truncated mid-write that brace never arrives, so the helper consumed the remainder of the input and every benchmark following the truncated block was dropped without an error. If a benchmark had already parsed, the result was non-empty and the loss was silent. Walk the lines by index so an unterminated block resumes on the line after the opening brace, mirroring how the iai adapter already iterates. The block scanner now returns the closing index and the block text instead of mutating shared state, so it cannot consume input on failure. --- .../src/adapters/rust/gungraun_json.rs | 57 +++++++++++-------- .../json_truncated_pretty_then_ndjson.txt | 8 +++ 2 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 lib/bencher_adapter/tool_output/rust/gungraun/json_truncated_pretty_then_ndjson.txt diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs index 0ae80a2ee..11bf28751 100644 --- a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs +++ b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs @@ -1,5 +1,6 @@ use bencher_json::{BenchmarkName, JsonNewMetric, project::report::JsonAverage}; +use crate::{Adaptable, AdapterResults, Settings, results::adapter_results::GungraunMeasure}; use gungraun_summary::{ either_or_both::EitherOrBoth, util::SummaryByVersion, @@ -8,10 +9,6 @@ use gungraun_summary::{ MetricsDiff, MetricsSummary, ToolMetricSummary, ValgrindTool, }, }; -use std::fmt::Write as _; -use std::str::Lines; - -use crate::{Adaptable, AdapterResults, Settings, results::adapter_results::GungraunMeasure}; pub struct AdapterRustGungraunJson; @@ -38,15 +35,22 @@ impl Adaptable for AdapterRustGungraunJson { /// ignores intermixed json output from other tools or cargo itself, for example `cargo bench /// --message-format=json`. fn parse_multiple(input: &str) -> Option)>> { - let mut lines = input.lines(); + let lines = input.lines().collect::>(); let mut parsed = vec![]; - while let Some(line) = lines.next() { + let mut index = 0; + while let Some(line) = lines.get(index) { let trimmed = line.trim(); if trimmed == "{" { let indent = line.len() - line.trim_start().len(); - if let Some(one) = parse_benchmark_pretty(&mut lines, indent) { - parsed.push(one); + // A block that is never closed is not a benchmark, so resume on the line after the + // opening brace instead of consuming the rest of the input. + if let Some((end, block)) = pretty_block(&lines, index, indent) { + if let Some(one) = parse_benchmark(&block) { + parsed.push(one); + } + index = end.saturating_add(1); + continue; } } else if trimmed.starts_with('{') && trimmed.ends_with('}') @@ -54,26 +58,24 @@ fn parse_multiple(input: &str) -> Option, - indent: usize, -) -> Option<(BenchmarkName, Vec)> { - let mut payload = "{".to_owned(); - for line in lines { - writeln!(payload, "{line}").ok()?; - - let trimmed = line.trim(); - if trimmed == "}" && line.len() - line.trim_start().len() == indent { - break; - } - } - - parse_benchmark(payload.as_str()) +/// Find the pretty printed block opened at `start`, returning the index of its closing line and +/// the block itself. Returns `None` if the block is never closed at the opening indent. +fn pretty_block(lines: &[&str], start: usize, indent: usize) -> Option<(usize, String)> { + let end = lines + .iter() + .enumerate() + .skip(start.saturating_add(1)) + .find_map(|(index, line)| { + (line.trim() == "}" && line.len() - line.trim_start().len() == indent).then_some(index) + })?; + + Some((end, lines.get(start..=end)?.join("\n"))) } fn parse_benchmark(input: &str) -> Option<(BenchmarkName, Vec)> { @@ -735,6 +737,15 @@ pub(crate) mod test_rust_gungraun_json { validate_adapter_rust_gungraun_json(&results); } + #[test] + fn truncated_pretty_then_ndjson() { + let results = convert_file_path::( + "./tool_output/rust/gungraun/json_truncated_pretty_then_ndjson.txt", + ); + + validate_adapter_rust_gungraun_json(&results); + } + #[test] fn pretty_one_callgrind_indented() { let results = convert_file_path::( diff --git a/lib/bencher_adapter/tool_output/rust/gungraun/json_truncated_pretty_then_ndjson.txt b/lib/bencher_adapter/tool_output/rust/gungraun/json_truncated_pretty_then_ndjson.txt new file mode 100644 index 000000000..affce3e8e --- /dev/null +++ b/lib/bencher_adapter/tool_output/rust/gungraun/json_truncated_pretty_then_ndjson.txt @@ -0,0 +1,8 @@ +running 0 tests + +{ + "baselines": [ + null, + null + ], +{"baselines": [null, null], "benchmark_exe": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad", "benchmark_file": "/bencher/examples/rust/gungraun/benches/play_game.rs", "details": null, "function_name": "bench_play_game_100", "id": "some_id", "kind": "LibraryBenchmark", "module_path": "play_game::bench_play_game_group::bench_play_game_100", "package_dir": "/bencher/examples/rust/gungraun", "profiles": [{"flamegraphs": [], "log_paths": ["/callgrind.bench_play_game_100.log"], "out_paths": ["/callgrind.bench_play_game_100.out"], "summaries": {"parts": [{"details": {"Both": [{"command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", "details": null, "parent_pid": null, "part": 1, "path": "/callgrind.bench_play_game_100.out", "pid": 12345, "thread": 1}, {"command": "/bencher/examples/rust/gungraun/target/release/deps/play_game-4a31ce0553c3b8ad --gungraun-run 00000 00000 00000", "details": null, "parent_pid": null, "part": 1, "path": "/bencher/examples/rust/gungraun/target/gungraun/game/play_game/bench_play_game_group/bench_play_game_100/callgrind.bench_play_game_100.out.old", "pid": 23456, "thread": 1}]}, "metrics_summary": {"Callgrind": {"D1MissRate": {"diffs": {"diff_pct": "0", "factor": "1"}, "metrics": {"Both": [{"Float": 0.1}, {"Float": 0.1}]}}, "D1mr": {"diffs": {"diff_pct": "0", "factor": "1"}, "metrics": {"Both": [{"Int": 6}, {"Int": 6}]}}}}}], "total": {"regressions": [], "summary": {"Callgrind": {"D1MissRate": {"diffs": {"diff_pct": "0", "factor": "1"}, "metrics": {"Both": [{"Float": 0.1}, {"Float": 0.1}]}}, "D1mr": {"diffs": {"diff_pct": "0", "factor": "1"}, "metrics": {"Both": [{"Int": 6}, {"Int": 6}]}}}}}}, "tool": "Callgrind"}], "project_root": "/bencher/examples/rust/gungraun", "summary_output": null, "version": "6"} From c3d4d7a2ec585ada9b2784a70a1dd3869338f99d Mon Sep 17 00:00:00 2001 From: Everett Pompeii Date: Sat, 15 Aug 2026 05:38:46 +0000 Subject: [PATCH 13/13] fix(adapter): correct parse_helgind_metrics_summary spelling Rename to `parse_helgrind_metrics_summary` to match the Helgrind tool it handles, alongside the sibling drd and memcheck parsers. --- lib/bencher_adapter/src/adapters/rust/gungraun_json.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs index 11bf28751..ebeadcb1b 100644 --- a/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs +++ b/lib/bencher_adapter/src/adapters/rust/gungraun_json.rs @@ -95,7 +95,7 @@ fn parse_benchmark(input: &str) -> Option<(BenchmarkName, Vec)> ToolMetricSummary::Dhat(metrics_summary) => parse_dhat_metrics_summary(metrics_summary), ToolMetricSummary::ErrorTool(metrics_summary) => match profile.tool { ValgrindTool::Memcheck => parse_memcheck_metrics_summary(metrics_summary), - ValgrindTool::Helgrind => parse_helgind_metrics_summary(metrics_summary), + ValgrindTool::Helgrind => parse_helgrind_metrics_summary(metrics_summary), ValgrindTool::DRD => parse_drd_metrics_summary(metrics_summary), // These other tools are no error tools and are already covered ValgrindTool::Callgrind @@ -148,7 +148,7 @@ fn parse_drd_metrics_summary(metrics_summary: MetricsSummary) -> Ve .collect() } -fn parse_helgind_metrics_summary( +fn parse_helgrind_metrics_summary( metrics_summary: MetricsSummary, ) -> Vec { metrics_summary