bonfida_benchviz/
lib.rs

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}