1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

feat(bench): Add JSON reporter for "deno bench" subcommand (#17595)

This commit is contained in:
Serhiy Barhamon 2023-02-12 19:40:45 +02:00 committed by GitHub
parent 5a83af4837
commit fc843d035c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 4 deletions

View file

@ -54,6 +54,7 @@ pub struct FileFlags {
pub struct BenchFlags {
pub files: FileFlags,
pub filter: Option<String>,
pub json: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
@ -717,6 +718,12 @@ fn clap_root(version: &str) -> Command {
fn bench_subcommand<'a>() -> Command<'a> {
runtime_args(Command::new("bench"), true, false)
.trailing_var_arg(true)
.arg(
Arg::new("json")
.long("json")
.help("UNSTABLE: Output benchmark result in JSON format")
.takes_value(false),
)
.arg(
Arg::new("ignore")
.long("ignore")
@ -2325,6 +2332,8 @@ fn bench_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
// interactive prompts, unless done by user code
flags.no_prompt = true;
let json = matches.is_present("json");
let ignore = match matches.values_of("ignore") {
Some(f) => f.map(PathBuf::from).collect(),
None => vec![],
@ -2359,6 +2368,7 @@ fn bench_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
flags.subcommand = DenoSubcommand::Bench(BenchFlags {
files: FileFlags { include, ignore },
filter,
json,
});
}
@ -6535,6 +6545,7 @@ mod tests {
let r = flags_from_vec(svec![
"deno",
"bench",
"--json",
"--unstable",
"--filter",
"- foo",
@ -6552,6 +6563,7 @@ mod tests {
Flags {
subcommand: DenoSubcommand::Bench(BenchFlags {
filter: Some("- foo".to_string()),
json: true,
files: FileFlags {
include: vec![PathBuf::from("dir1/"), PathBuf::from("dir2/")],
ignore: vec![],
@ -6576,6 +6588,7 @@ mod tests {
Flags {
subcommand: DenoSubcommand::Bench(BenchFlags {
filter: None,
json: false,
files: FileFlags {
include: vec![],
ignore: vec![],

View file

@ -105,6 +105,7 @@ impl CacheSetting {
pub struct BenchOptions {
pub files: FilesConfig,
pub filter: Option<String>,
pub json: bool,
}
impl BenchOptions {
@ -119,6 +120,7 @@ impl BenchOptions {
Some(bench_flags.files),
),
filter: bench_flags.filter,
json: bench_flags.json,
})
}
}

View file

@ -4,6 +4,7 @@ use crate::args::BenchOptions;
use crate::args::CliOptions;
use crate::args::TypeCheckMode;
use crate::colors;
use crate::display::write_json_to_stdout;
use crate::graph_util::graph_valid_with_cli_options;
use crate::ops;
use crate::proc_state::ProcState;
@ -13,6 +14,7 @@ use crate::util::file_watcher;
use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers;
use crate::util::path::is_supported_ext;
use crate::version::get_user_agent;
use crate::worker::create_main_worker_for_test_or_bench;
use deno_core::error::generic_error;
@ -41,6 +43,7 @@ use tokio::sync::mpsc::UnboundedSender;
#[derive(Debug, Clone)]
struct BenchSpecifierOptions {
filter: TestFilter,
json: bool,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
@ -62,7 +65,7 @@ pub enum BenchEvent {
Result(usize, BenchResult),
}
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum BenchResult {
Ok(BenchStats),
@ -109,7 +112,13 @@ impl BenchReport {
}
}
fn create_reporter(show_output: bool) -> Box<dyn BenchReporter + Send> {
fn create_reporter(
show_output: bool,
json: bool,
) -> Box<dyn BenchReporter + Send> {
if json {
return Box::new(JsonReporter::new());
}
Box::new(ConsoleReporter::new(show_output))
}
@ -123,6 +132,74 @@ pub trait BenchReporter {
fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult);
}
#[derive(Debug, Serialize)]
struct JsonReporterResult {
runtime: String,
cpu: String,
origin: String,
group: Option<String>,
name: String,
baseline: bool,
result: BenchResult,
}
impl JsonReporterResult {
fn new(
origin: String,
group: Option<String>,
name: String,
baseline: bool,
result: BenchResult,
) -> Self {
Self {
runtime: format!("{} {}", get_user_agent(), env!("TARGET")),
cpu: mitata::cpu::name(),
origin,
group,
name,
baseline,
result,
}
}
}
#[derive(Debug, Serialize)]
struct JsonReporter(Vec<JsonReporterResult>);
impl JsonReporter {
fn new() -> Self {
Self(vec![])
}
}
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) {
self.0.push(JsonReporterResult::new(
desc.origin.clone(),
desc.group.clone(),
desc.name.clone(),
desc.baseline,
result.clone(),
));
}
}
struct ConsoleReporter {
name: String,
show_output: bool,
@ -376,12 +453,14 @@ async fn bench_specifiers(
let (sender, mut receiver) = unbounded_channel::<BenchEvent>();
let option_for_handles = options.clone();
let join_handles = specifiers.into_iter().map(move |specifier| {
let ps = ps.clone();
let permissions = permissions.clone();
let specifier = specifier;
let sender = sender.clone();
let options = options.clone();
let options = option_for_handles.clone();
tokio::task::spawn_blocking(move || {
let future = bench_specifier(ps, permissions, specifier, sender, options);
@ -398,7 +477,8 @@ async fn bench_specifiers(
tokio::task::spawn(async move {
let mut used_only = false;
let mut report = BenchReport::new();
let mut reporter = create_reporter(log_level != Some(Level::Error));
let mut reporter =
create_reporter(log_level != Some(Level::Error), options.json);
let mut benches = IndexMap::new();
while let Some(event) = receiver.recv().await {
@ -509,6 +589,7 @@ pub async fn run_benchmarks(
specifiers,
BenchSpecifierOptions {
filter: TestFilter::from_flag(&bench_options.filter),
json: bench_options.json,
},
)
.await?;
@ -658,6 +739,7 @@ pub async fn run_benchmarks_with_watch(
specifiers,
BenchSpecifierOptions {
filter: TestFilter::from_flag(&bench_options.filter),
json: bench_options.json,
},
)
.await?;