1use std::{
2 collections::{hash_map::Entry, HashMap},
3 fs::{read_dir, DirBuilder, File},
4};
5
6use bonfida_utils::bench::Measures;
7use clap::{crate_name, crate_version, ArgMatches, Command};
8use gnuplot::{Figure, PlotOption};
9use regex::Regex;
10
11pub fn command() -> Command<'static> {
12 Command::new(crate_name!())
13 .version(crate_version!())
14 .about("Generate comparative benchmarking graphs")
15}
16pub fn process(_matches: &ArgMatches) {
17 let current_directory = std::env::current_dir().unwrap();
18 let results_directory = current_directory.join("benchmark_results");
19 if !results_directory.is_dir() {
20 eprintln!("Couldn't find the benchmark results directory");
21 return;
22 }
23
24 let graph_output_path = results_directory.join("graphs");
25 if graph_output_path.is_file() {
26 eprintln!("Delete the graphs benchmark_results/graphs file");
27 return;
28 }
29
30 let files = read_dir(&results_directory).unwrap();
31 let mut test_results = HashMap::new();
32 let file_name_re = Regex::new("(?P<test_name>.*)_(?P<commit_id>[^_]*)").unwrap();
33
34 if !graph_output_path.is_dir() {
35 let dir_builder = DirBuilder::new();
36 dir_builder.create(&graph_output_path).unwrap();
37 }
38 for f in files {
39 let path = f.unwrap().path();
40 if !path.is_file() {
41 continue;
42 }
43 let c = file_name_re
44 .captures(path.file_stem().unwrap().to_str().unwrap())
45 .unwrap();
46 let test_name = c["test_name"].to_owned();
47 let test_entry = test_results.entry(test_name);
48 let results = match test_entry {
49 Entry::Occupied(o) => o.into_mut(),
50 Entry::Vacant(o) => o.insert(vec![]),
51 };
52 results.push(path);
53 }
54 let commit_names = get_commit_names();
55 for (name, results) in test_results {
56 let mut figure = Figure::new();
57 figure.set_title(&name.replace('_', "\\_"));
58 let plot = figure.axes2d();
59 for path in results {
60 let file = File::open(&path).unwrap();
61 let measures: Measures = serde_json::from_reader(file).unwrap();
62 let caption = commit_names
63 .get(&measures.commit_id)
64 .cloned()
65 .unwrap_or_else(|| {
66 String::from_utf8(measures.commit_id.as_bytes()[0..7].to_owned()).unwrap()
67 });
68 plot.lines_points(&measures.x, &measures.y, &[PlotOption::Caption(&caption)]);
69 }
70
71 let path = graph_output_path.join(format!("{name}.png"));
72 figure.save_to_png(&path, 1920, 1080).unwrap();
73 }
74}
75
76fn get_commit_names() -> HashMap<String, String> {
77 let output = std::process::Command::new("git")
78 .arg("branch")
79 .arg("--format")
80 .arg("%(refname) %(objectname)")
81 .output()
82 .unwrap();
83 let re = Regex::new("refs/heads/(?P<branch_name>.*) (?P<commit_id>[^_\n\r]*)").unwrap();
84 let output = String::from_utf8(output.stdout).unwrap();
85 let mut result = HashMap::new();
86 for l in output.lines() {
87 let captures = re.captures(l).unwrap();
88 result.insert(
89 captures["commit_id"].to_owned(),
90 captures["branch_name"].to_owned(),
91 );
92 }
93 result
94}