summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-01-14 02:50:39 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-01-14 02:50:39 -0500
commited9d1b4ee5241554030b67424faf5cc40e1634c7 (patch)
tree33bc9e0b9f83cf37cd8642f051b880881e1a3a7d
parente47626633192b6b1e16d87587753d0dd6d683cab (diff)
More improvementsHEADmaster
- Better printing out of header and columns, we now align to terminal size - Don't panic on broken pipe - Print out more info when testing first/last commits Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs94
2 files changed, 70 insertions, 25 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 1cd4414..5815e14 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,4 +13,5 @@ nom = "7.1.2"
pager = "0.16.1"
serde = "1.0.152"
serde_derive = "1.0.152"
+termsize = "0.1.6"
toml = "0.5.10"
diff --git a/src/main.rs b/src/main.rs
index a51c03a..4328808 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
use std::collections::HashMap;
-use std::collections::HashSet;
+use std::collections::BTreeSet;
use std::io;
use std::io::Write;
use std::error::Error;
@@ -14,12 +14,8 @@ use toml;
const RESULTS: &str = "perf-results.toml";
+/* Results for each test, for a particular commit */
type DataPoints = HashMap<String, f32>;
-type DataPointsDeltas = HashMap<String, (f32, f32)>;
-
-fn dps_to_dpdeltas(d: &DataPoints) -> DataPointsDeltas {
- d.iter().map(|x| (x.0.clone(), (*x.1, 0.0)) ).collect()
-}
struct TestResult {
commit: String,
@@ -29,6 +25,13 @@ struct TestResult {
type TestResultsVec = Vec<TestResult>;
+/* Test results and delta (ratio) from previous commit */
+type DataPointsDeltas = HashMap<String, (f32, f32)>;
+
+fn dps_to_dpdeltas(d: &DataPoints) -> DataPointsDeltas {
+ d.iter().map(|x| (x.0.clone(), (*x.1, 0.0)) ).collect()
+}
+
struct TestResultDeltas {
commit: String,
commitmsg: String,
@@ -39,6 +42,7 @@ type TestResultsDeltasVec = Vec<TestResultDeltas>;
#[derive(Serialize, Deserialize)]
struct TestResultsMap {
+ #[serde(flatten)]
d: HashMap<String, DataPoints>,
}
@@ -101,12 +105,24 @@ fn results_merge(r1: &mut TestResultsVec, r2: &TestResultsMap) {
fn pick_commit_to_test(results: &TestResultsVec, test: &str) -> Option<usize> {
let i = results.first().unwrap();
if i.data_points.get(test).is_none() {
- return Some(0);
+ let idx = 0;
+
+ println!("Testing first commit");
+ println!("{} {} {:89}", idx,
+ results[idx].commit[..10].yellow(),
+ results[idx].commitmsg);
+ return Some(idx);
}
let i = results.last().unwrap();
if i.data_points.get(test).is_none() {
- return Some(results.len() - 1);
+ let idx = results.len() - 1;
+
+ println!("Testing last commit");
+ println!("{} {} {:89}", idx,
+ results[idx].commit[..10].yellow(),
+ results[idx].commitmsg);
+ return Some(idx);
}
let mut last_idx: usize = 0;
@@ -169,7 +185,7 @@ fn parse_test_output(output: &str) -> Option<f32> {
None
}
-fn run_tests(repo: &git2::Repository, range: &str, test: &str) {
+fn cmd_run(repo: &git2::Repository, range: &str, test: &str) {
let mut results = results_new(&repo, range).unwrap();
let mut existing = results_read(RESULTS).unwrap_or(TestResultsMap { d: HashMap::new() });
@@ -280,30 +296,53 @@ fn results_to_results_with_deltas(results: TestResultsVec) -> TestResultsDeltasV
results
}
-fn list_tests(repo: &git2::Repository, head: &Option<String>) {
+fn cmd_log(repo: &git2::Repository, head: &Option<String>) -> io::Result<()> {
+ /* We use write! to stdout instead of print! to avoid panicing on a broken pipe: */
+ let mut stdout = io::stdout();
+
colored::control::set_override(ShouldColorize::from_env().should_colorize());
Pager::with_pager("less -FRX").setup();
- let results = results_read(RESULTS).unwrap();
+ let results = results_read(RESULTS);
+ if results.is_err() {
+ eprintln!("No results found");
+ std::process::exit(1);
+ }
+ let results = results.unwrap();
+
let log = log_with_results(repo, head, &results).unwrap();
let log = results_to_results_with_deltas(log);
- let mut columns = HashSet::new();
+ let mut columns = BTreeSet::new();
for r in log.iter() {
for e in r.data_points.iter() {
columns.insert(e.0);
}
}
- print!("{:100}", "");
- for e in columns.iter() {
- print!("{:20}", e);
+ let term_cols = termsize::get().map(|x| x.cols);
+ let msg_width = if let Some(term_cols) = term_cols {
+ term_cols as usize - 11 - columns.len() * 20
+ } else {
+ 89
+ };
+
+ for (i, e) in columns.iter().enumerate() {
+ if i != 0 && e.len() >= 20 {
+ writeln!(stdout, "")?;
+ }
+
+ if i == 0 || e.len() >= 20 {
+ write!(stdout, "{:>1$}", e, msg_width + 11 + (i + 1) * 20)?;
+ } else {
+ write!(stdout, "{:>1$}", e, 20)?;
+ }
}
- println!("");
+ writeln!(stdout, "")?;
for i in log.iter() {
- print!("{} {:89}", &i.commit[..10].yellow(), i.commitmsg);
+ write!(stdout, "{} {:1$.*}", &i.commit[..10].yellow(), msg_width, i.commitmsg)?;
for e in columns.iter() {
if let Some(v) = i.data_points.get(e.clone()) {
@@ -314,17 +353,22 @@ fn list_tests(repo: &git2::Repository, head: &Option<String>) {
f.normal()
};
- print!("{}", f);
+ write!(stdout, "{}", f)?;
} else {
- print!("{:20}", "");
+ write!(stdout, "{:20}", "")?;
}
}
- println!("");
+ writeln!(stdout, "")?;
}
+
+ Ok(())
}
#[derive(Parser)]
-#[command(author, version, about, long_about = None)]
+#[command(name = "bisect-perf-regressions")]
+#[command(author = "Kent Overstreet <kent.overstreet@linux.dev>")]
+#[command(version = "0.1")]
+#[command(about = "Bisect performance regressions and provide results in a git log view")]
struct Args {
#[command(subcommand)]
command: Option<Commands>,
@@ -336,7 +380,7 @@ enum Commands {
range: String,
test: String,
},
- List {
+ Log {
head: Option<String>
},
}
@@ -346,10 +390,10 @@ fn main() {
let repo = git2::Repository::open(".").unwrap();
match &args.command {
- Some(Commands::List { head } )
- => list_tests(&repo, head),
+ Some(Commands::Log { head } )
+ => { cmd_log(&repo, head).ok(); },
Some(Commands::Run { range, test} )
- => run_tests(&repo, range, test),
+ => cmd_run(&repo, range, test),
None
=> {}
}