perf: Functionality for CI integration (#39297)

Nia created

Release Notes:

- N/A

Change summary

tooling/perf/src/lib.rs  |  1 -
tooling/perf/src/main.rs | 36 ++++++++++++++++++++++++++++++++----
2 files changed, 32 insertions(+), 5 deletions(-)

Detailed changes

tooling/perf/src/main.rs 🔗

@@ -35,6 +35,9 @@
 //! being created (unless no tests were run). These results can be automatically
 //! compared. To do so, run `cargo perf-compare new-ident old-ident`.
 //!
+//! To save the markdown output to a file instead, run `cargo perf-compare --save=$FILE
+//! new-ident old-ident`.
+//!
 //! NB: All files matching `.perf-runs/ident.*.json` will be considered when
 //! doing this comparison, so ensure there aren't leftover files in your `.perf-runs`
 //! directory that might match that!
@@ -91,7 +94,7 @@ impl OutputKind<'_> {
     /// Logs the output of a run as per the `OutputKind`.
     fn log(&self, output: &Output, t_bin: &str) {
         match self {
-            OutputKind::Markdown => print!("{output}"),
+            OutputKind::Markdown => println!("{output}"),
             OutputKind::Json(ident) => {
                 // We're going to be in tooling/perf/$whatever.
                 let wspace_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
@@ -215,8 +218,23 @@ fn parse_mdata(t_bin: &str, mdata_fn: &str) -> Result<TestMdata, FailKind> {
 
 /// Compares the perf results of two profiles as per the arguments passed in.
 fn compare_profiles(args: &[String]) {
-    let ident_new = args.first().expect("FATAL: missing identifier for new run");
-    let ident_old = args.get(1).expect("FATAL: missing identifier for old run");
+    let mut save_to = None;
+    let mut ident_idx = 0;
+    args.first().inspect(|a| {
+        if a.starts_with("--save") {
+            save_to = Some(
+                a.strip_prefix("--save=")
+                    .expect("FATAL: save param formatted incorrectly"),
+            );
+        }
+        ident_idx = 1;
+    });
+    let ident_new = args
+        .get(ident_idx)
+        .expect("FATAL: missing identifier for new run");
+    let ident_old = args
+        .get(ident_idx + 1)
+        .expect("FATAL: missing identifier for old run");
     let wspace_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
     let runs_dir = PathBuf::from(&wspace_dir)
         .join("..")
@@ -260,7 +278,17 @@ fn compare_profiles(args: &[String]) {
     }
 
     let res = outputs_new.compare_perf(outputs_old);
-    println!("{res}");
+    if let Some(filename) = save_to {
+        let mut file = std::fs::OpenOptions::new()
+            .create(true)
+            .write(true)
+            .truncate(true)
+            .open(filename)
+            .expect("FATAL: couldn't save run results to file");
+        file.write_all(format!("{res}").as_bytes()).unwrap();
+    } else {
+        println!("{res}");
+    }
 }
 
 /// Runs a test binary, filtering out tests which aren't marked for perf triage