use alloc::{string::String, vec::Vec};
use miden_core::operations::Operation;
use super::OpHistogramProc;
use crate::profiling::instrument::Instrument;
fn section<'a>(report: &'a str, name: &str) -> &'a str {
let marker = format!("procedure: {name}\n");
let start = report.find(&marker).expect("section exists") + marker.len();
match report[start..].find("procedure: ") {
Some(rel) => &report[start..start + rel],
None => &report[start..],
}
}
fn count_for(section: &str, label: &str) -> Option<u64> {
section
.lines()
.find(|line| line.split_whitespace().next() == Some(label))
.map(parse_count_from_line)
}
fn sum_total_cycles(report: &str) -> u64 {
report
.lines()
.filter(|line| line.split_whitespace().next() == Some("total_cycles"))
.map(parse_count_from_line)
.sum()
}
fn parse_count_from_line(line: &str) -> u64 {
line.split_whitespace()
.last()
.and_then(|count| count.parse().ok())
.expect("report line ends with the count")
}
#[test]
fn op_histogram_proc_reports_per_procedure_histograms() {
let mut hist = OpHistogramProc::default();
hist.on_operation_execution_cycle(Operation::Add, Some("main"));
hist.on_operation_execution_cycle(Operation::Add, Some("main"));
hist.on_operation_execution_cycle(Operation::Noop, Some("sum"));
hist.on_operation_execution_cycle(Operation::Mul, Some("sum"));
let mut buf = Vec::new();
hist.write_report_to(&mut buf).unwrap();
let report = String::from_utf8(buf).unwrap();
let main = section(&report, "main");
assert_eq!(count_for(main, "total_cycles"), Some(2));
assert_eq!(count_for(main, "add"), Some(2));
assert_eq!(count_for(main, "noop"), None);
let sum = section(&report, "sum");
assert_eq!(count_for(sum, "total_cycles"), Some(2));
assert_eq!(count_for(sum, "noop"), Some(1));
assert_eq!(count_for(sum, "mul"), Some(1));
assert_eq!(sum_total_cycles(&report), 4);
}
#[test]
fn op_histogram_proc_sorts_by_total_cycles() {
let mut hist = OpHistogramProc::default();
hist.on_operation_execution_cycle(Operation::Add, Some("z"));
hist.on_operation_execution_cycle(Operation::Add, Some("z"));
hist.on_operation_execution_cycle(Operation::Add, Some("z"));
hist.on_operation_execution_cycle(Operation::Noop, Some("a"));
let mut buf = Vec::new();
hist.write_report_to(&mut buf).unwrap();
let report = String::from_utf8(buf).unwrap();
let z_pos = report.find("procedure: z").unwrap();
let a_pos = report.find("procedure: a").unwrap();
assert!(z_pos < a_pos, "histogram with more cycles must be printed first:\n{report}");
assert_eq!(sum_total_cycles(&report), 4);
}
#[test]
fn op_histogram_proc_collects_unattributed_ops_separately() {
let mut hist = OpHistogramProc::default();
hist.on_operation_execution_cycle(Operation::Add, None);
hist.on_operation_execution_cycle(Operation::Add, None);
hist.on_operation_execution_cycle(Operation::Noop, Some("main"));
let mut buf = Vec::new();
hist.write_report_to(&mut buf).unwrap();
let report = String::from_utf8(buf).unwrap();
let unknown = section(&report, "<unknown>");
assert_eq!(count_for(unknown, "total_cycles"), Some(2));
assert_eq!(count_for(unknown, "add"), Some(2));
assert_eq!(count_for(unknown, "noop"), None);
let main = section(&report, "main");
assert_eq!(count_for(main, "noop"), Some(1));
assert_eq!(count_for(main, "add"), None);
assert_eq!(sum_total_cycles(&report), 3);
}