profile_inspect/output/
collapsed.rs1use std::collections::HashMap;
2use std::io::Write;
3
4use crate::analysis::{CpuAnalysis, HeapAnalysis};
5use crate::ir::ProfileIR;
6
7use super::{Formatter, OutputError};
8
9pub struct CollapsedFormatter;
22
23impl Formatter for CollapsedFormatter {
24 fn write_cpu_analysis(
25 &self,
26 profile: &ProfileIR,
27 _analysis: &CpuAnalysis,
28 writer: &mut dyn Write,
29 ) -> Result<(), OutputError> {
30 let mut stack_weights: HashMap<String, u64> = HashMap::new();
32
33 for sample in &profile.samples {
34 if let Some(stack) = profile.get_stack(sample.stack_id) {
35 let stack_str: String = stack
37 .frames
38 .iter()
39 .filter_map(|fid| {
40 profile.get_frame(*fid).map(|f| {
41 let name = if f.name.is_empty() {
43 "(anonymous)".to_string()
44 } else {
45 f.name.replace(';', ":")
47 };
48
49 if let Some(ref file) = f.file {
51 let filename = file.rsplit('/').next().unwrap_or(file);
53 if let Some(line) = f.line {
54 format!("{name} ({filename}:{line})")
55 } else {
56 format!("{name} ({filename})")
57 }
58 } else {
59 name
60 }
61 })
62 })
63 .collect::<Vec<_>>()
64 .join(";");
65
66 if !stack_str.is_empty() {
67 *stack_weights.entry(stack_str).or_default() += sample.weight;
68 }
69 }
70 }
71
72 let mut stacks: Vec<_> = stack_weights.into_iter().collect();
74 stacks.sort_by(|a, b| a.0.cmp(&b.0));
75
76 for (stack, weight) in stacks {
78 writeln!(writer, "{stack} {weight}")?;
79 }
80
81 Ok(())
82 }
83
84 fn write_heap_analysis(
85 &self,
86 profile: &ProfileIR,
87 _analysis: &HeapAnalysis,
88 writer: &mut dyn Write,
89 ) -> Result<(), OutputError> {
90 let mut stack_weights: HashMap<String, u64> = HashMap::new();
92
93 for sample in &profile.samples {
94 if let Some(stack) = profile.get_stack(sample.stack_id) {
95 let stack_str: String = stack
96 .frames
97 .iter()
98 .filter_map(|fid| {
99 profile.get_frame(*fid).map(|f| {
100 let name = if f.name.is_empty() {
101 "(anonymous)".to_string()
102 } else {
103 f.name.replace(';', ":")
104 };
105
106 if let Some(ref file) = f.file {
107 let filename = file.rsplit('/').next().unwrap_or(file);
108 if let Some(line) = f.line {
109 format!("{name} ({filename}:{line})")
110 } else {
111 format!("{name} ({filename})")
112 }
113 } else {
114 name
115 }
116 })
117 })
118 .collect::<Vec<_>>()
119 .join(";");
120
121 if !stack_str.is_empty() {
122 *stack_weights.entry(stack_str).or_default() += sample.weight;
123 }
124 }
125 }
126
127 let mut stacks: Vec<_> = stack_weights.into_iter().collect();
128 stacks.sort_by(|a, b| a.0.cmp(&b.0));
129
130 for (stack, weight) in stacks {
131 writeln!(writer, "{stack} {weight}")?;
132 }
133
134 Ok(())
135 }
136}