summaryrefslogtreecommitdiff
path: root/cli/tools/bench/reporters.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/bench/reporters.rs')
-rw-r--r--cli/tools/bench/reporters.rs300
1 files changed, 300 insertions, 0 deletions
diff --git a/cli/tools/bench/reporters.rs b/cli/tools/bench/reporters.rs
new file mode 100644
index 000000000..6b1e885a9
--- /dev/null
+++ b/cli/tools/bench/reporters.rs
@@ -0,0 +1,300 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+use serde::Serialize;
+
+use super::*;
+
+pub trait BenchReporter {
+ fn report_group_summary(&mut self);
+ fn report_plan(&mut self, plan: &BenchPlan);
+ fn report_end(&mut self, report: &BenchReport);
+ fn report_register(&mut self, desc: &BenchDescription);
+ fn report_wait(&mut self, desc: &BenchDescription);
+ fn report_output(&mut self, output: &str);
+ fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult);
+}
+
+#[derive(Debug, Serialize)]
+struct JsonReporterOutput {
+ runtime: String,
+ cpu: String,
+ benches: Vec<JsonReporterBench>,
+}
+
+impl Default for JsonReporterOutput {
+ fn default() -> Self {
+ Self {
+ runtime: format!("{} {}", get_user_agent(), env!("TARGET")),
+ cpu: mitata::cpu::name(),
+ benches: vec![],
+ }
+ }
+}
+
+#[derive(Debug, Serialize)]
+struct JsonReporterBench {
+ origin: String,
+ group: Option<String>,
+ name: String,
+ baseline: bool,
+ results: Vec<BenchResult>,
+}
+
+#[derive(Debug, Serialize)]
+pub struct JsonReporter(JsonReporterOutput);
+
+impl JsonReporter {
+ pub fn new() -> Self {
+ Self(Default::default())
+ }
+}
+
+impl BenchReporter for JsonReporter {
+ fn report_group_summary(&mut self) {}
+ #[cold]
+ fn report_plan(&mut self, _plan: &BenchPlan) {}
+
+ fn report_end(&mut self, _report: &BenchReport) {
+ match write_json_to_stdout(self) {
+ Ok(_) => (),
+ Err(e) => println!("{e}"),
+ }
+ }
+
+ fn report_register(&mut self, _desc: &BenchDescription) {}
+
+ fn report_wait(&mut self, _desc: &BenchDescription) {}
+
+ fn report_output(&mut self, _output: &str) {}
+
+ fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) {
+ if desc.warmup {
+ return;
+ }
+
+ let maybe_bench = self.0.benches.iter_mut().find(|bench| {
+ bench.origin == desc.origin
+ && bench.group == desc.group
+ && bench.name == desc.name
+ && bench.baseline == desc.baseline
+ });
+
+ if let Some(bench) = maybe_bench {
+ bench.results.push(result.clone());
+ } else {
+ self.0.benches.push(JsonReporterBench {
+ origin: desc.origin.clone(),
+ group: desc.group.clone(),
+ name: desc.name.clone(),
+ baseline: desc.baseline,
+ results: vec![result.clone()],
+ });
+ }
+ }
+}
+
+pub struct ConsoleReporter {
+ name: String,
+ show_output: bool,
+ has_ungrouped: bool,
+ group: Option<String>,
+ baseline: bool,
+ group_measurements: Vec<(BenchDescription, BenchStats)>,
+ options: Option<mitata::reporter::Options>,
+}
+
+impl ConsoleReporter {
+ pub fn new(show_output: bool) -> Self {
+ Self {
+ show_output,
+ group: None,
+ options: None,
+ baseline: false,
+ name: String::new(),
+ has_ungrouped: false,
+ group_measurements: Vec::new(),
+ }
+ }
+}
+
+impl BenchReporter for ConsoleReporter {
+ #[cold]
+ fn report_plan(&mut self, plan: &BenchPlan) {
+ use std::sync::atomic::AtomicBool;
+ use std::sync::atomic::Ordering;
+ static FIRST_PLAN: AtomicBool = AtomicBool::new(true);
+
+ self.report_group_summary();
+
+ self.group = None;
+ self.baseline = false;
+ self.name = String::new();
+ self.group_measurements.clear();
+ self.options = Some(mitata::reporter::Options::new(
+ &plan.names.iter().map(|x| x.as_str()).collect::<Vec<&str>>(),
+ ));
+
+ let options = self.options.as_mut().unwrap();
+
+ options.percentiles = true;
+ options.colors = colors::use_color();
+
+ if FIRST_PLAN
+ .compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
+ .is_ok()
+ {
+ println!("{}", colors::gray(format!("cpu: {}", mitata::cpu::name())));
+ println!(
+ "{}\n",
+ colors::gray(format!(
+ "runtime: deno {} ({})",
+ crate::version::deno(),
+ env!("TARGET")
+ ))
+ );
+ } else {
+ println!();
+ }
+
+ println!(
+ "{}\n{}\n{}",
+ colors::gray(&plan.origin),
+ mitata::reporter::header(options),
+ mitata::reporter::br(options)
+ );
+ }
+
+ fn report_register(&mut self, _desc: &BenchDescription) {}
+
+ fn report_wait(&mut self, desc: &BenchDescription) {
+ self.name = desc.name.clone();
+
+ match &desc.group {
+ None => {
+ self.has_ungrouped = true;
+ }
+
+ Some(group) => {
+ if self.group.is_none()
+ && self.has_ungrouped
+ && self.group_measurements.is_empty()
+ {
+ println!();
+ }
+
+ if self.group.is_none() || group != self.group.as_ref().unwrap() {
+ self.report_group_summary();
+ }
+
+ if (self.group.is_none() && self.has_ungrouped)
+ || (self.group.is_some() && self.group_measurements.is_empty())
+ {
+ println!();
+ }
+
+ self.group = Some(group.clone());
+ }
+ }
+ }
+
+ fn report_output(&mut self, output: &str) {
+ if self.show_output {
+ print!("{} {}", colors::gray(format!("{}:", self.name)), output)
+ }
+ }
+
+ fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) {
+ if desc.warmup {
+ return;
+ }
+
+ let options = self.options.as_ref().unwrap();
+
+ match result {
+ BenchResult::Ok(stats) => {
+ let mut desc = desc.clone();
+
+ if desc.baseline && !self.baseline {
+ self.baseline = true;
+ } else {
+ desc.baseline = false;
+ }
+
+ println!(
+ "{}",
+ mitata::reporter::benchmark(
+ &desc.name,
+ &mitata::reporter::BenchmarkStats {
+ avg: stats.avg,
+ min: stats.min,
+ max: stats.max,
+ p75: stats.p75,
+ p99: stats.p99,
+ p995: stats.p995,
+ },
+ options
+ )
+ );
+
+ self.group_measurements.push((desc, stats.clone()));
+ }
+
+ BenchResult::Failed(js_error) => {
+ println!(
+ "{}",
+ mitata::reporter::benchmark_error(
+ &desc.name,
+ &mitata::reporter::Error {
+ stack: None,
+ message: format_test_error(js_error),
+ },
+ options
+ )
+ )
+ }
+ };
+ }
+
+ fn report_group_summary(&mut self) {
+ let options = match self.options.as_ref() {
+ None => return,
+ Some(options) => options,
+ };
+
+ if 2 <= self.group_measurements.len()
+ && (self.group.is_some() || (self.group.is_none() && self.baseline))
+ {
+ println!(
+ "\n{}",
+ mitata::reporter::summary(
+ &self
+ .group_measurements
+ .iter()
+ .map(|(d, s)| mitata::reporter::GroupBenchmark {
+ name: d.name.clone(),
+ baseline: d.baseline,
+ group: d.group.as_deref().unwrap_or("").to_owned(),
+
+ stats: mitata::reporter::BenchmarkStats {
+ avg: s.avg,
+ min: s.min,
+ max: s.max,
+ p75: s.p75,
+ p99: s.p99,
+ p995: s.p995,
+ },
+ })
+ .collect::<Vec<mitata::reporter::GroupBenchmark>>(),
+ options
+ )
+ );
+ }
+
+ self.baseline = false;
+ self.group_measurements.clear();
+ }
+
+ fn report_end(&mut self, _: &BenchReport) {
+ self.report_group_summary();
+ }
+}