in starlark/src/eval/runtime/heap_profile.rs [246:325]
fn write_summarized_heap_profile_to(mut file: impl Write, heap: &Heap) -> anyhow::Result<()> {
use summary::{FuncInfo, Info};
let mut ids = FunctionIds::default();
let root = ids.get_string("(root)".to_owned());
let start = Instant::now();
let mut info = Info {
ids,
info: Vec::new(),
last_changed: start,
call_stack: vec![(root, Duration::default(), start)],
};
info.ensure(root);
unsafe {
heap.for_each_ordered(|x| info.process(x));
}
// Just has root left on it
assert!(info.call_stack.len() == 1);
// Add a totals column
let total_id = info.ids.get_string("TOTALS".to_owned());
info.ensure(total_id);
let Info {
mut info, mut ids, ..
} = info;
let totals = FuncInfo::merge(info.iter());
let mut columns: Vec<(&'static str, usize)> =
totals.allocs.iter().map(|(k, v)| (*k, *v)).collect();
info[total_id.0] = totals;
let mut info = info.iter().enumerate().collect::<Vec<_>>();
columns.sort_by_key(|x| -(x.1 as isize));
info.sort_by_key(|x| -(x.1.time.as_nanos() as i128));
let mut csv = CsvWriter::new(
[
"Function",
"Time(s)",
"TimeRec(s)",
"Calls",
"Callers",
"TopCaller",
"TopCallerCount",
"Allocs",
]
.iter()
.copied()
.chain(columns.iter().map(|c| c.0)),
);
let blank = ids.get_string("".to_owned());
let un_ids = ids.invert();
for (rowname, info) in info {
let allocs = info.allocs.values().sum::<usize>();
let callers = info
.callers
.iter()
.max_by_key(|x| x.1)
.unwrap_or((&blank, &0));
assert!(
info.calls % 2 == 0,
"we enter calls twice, for drop and non_drop"
);
// We divide calls and time by two
// because we could calls twice: for drop and non-drop bumps.
csv.write_value(un_ids[rowname]);
csv.write_value(info.time / 2);
csv.write_value(info.time_rec / 2);
csv.write_value(info.calls / 2);
csv.write_value(info.callers.len());
csv.write_value(un_ids[callers.0.0]);
csv.write_value(callers.1);
csv.write_value(allocs);
for c in &columns {
csv.write_value(info.allocs.get(c.0).unwrap_or(&0));
}
csv.finish_row();
}
file.write_all(csv.finish().as_bytes())?;
Ok(())
}