pyroscope_rbspy_oncpu/ui/
output.rs1use std::io::Write;
2
3use crate::core::types::{StackFrame, StackTrace};
4use crate::ui::{callgrind, flamegraph, pprof, speedscope, summary};
5
6use anyhow::Result;
7
8pub trait Outputter {
9 fn record(&mut self, stack: &StackTrace) -> Result<()>;
10 fn complete(&mut self, write: &mut dyn Write) -> Result<()>;
11}
12
13pub struct Flamegraph {
15 stats: flamegraph::Stats,
16 min_width: f64,
17}
18
19impl Outputter for Flamegraph {
20 fn record(&mut self, stack: &StackTrace) -> Result<()> {
21 self.stats.record(&stack.trace)
22 }
23
24 fn complete(&mut self, write: &mut dyn Write) -> Result<()> {
25 self.stats.write_flamegraph(write, self.min_width)
26 }
27}
28
29impl Flamegraph {
30 pub fn new(min_width: f64) -> Flamegraph {
31 Flamegraph {
32 min_width,
33 stats: Default::default(),
34 }
35 }
36}
37
38#[derive(Default)]
41pub struct Collapsed(pub flamegraph::Stats);
42
43impl Outputter for Collapsed {
44 fn record(&mut self, stack: &StackTrace) -> Result<()> {
45 self.0.record(&stack.trace)
46 }
47
48 fn complete(&mut self, mut write: &mut dyn Write) -> Result<()> {
49 self.0.write_collapsed(&mut write)
50 }
51}
52
53pub struct Callgrind(pub callgrind::Stats);
54
55impl Outputter for Callgrind {
56 fn record(&mut self, stack: &StackTrace) -> Result<()> {
57 self.0.add(&filter_unknown(&stack.trace));
58 Ok(())
59 }
60
61 fn complete(&mut self, mut write: &mut dyn Write) -> Result<()> {
62 self.0.finish();
63 self.0.write(&mut write)
64 }
65}
66
67pub struct Summary(pub summary::Stats);
68
69impl Outputter for Summary {
70 fn record(&mut self, stack: &StackTrace) -> Result<()> {
71 self.0.add_function_name(&filter_unknown(&stack.trace));
72 Ok(())
73 }
74
75 fn complete(&mut self, mut write: &mut dyn Write) -> Result<()> {
76 self.0.write(&mut write)
77 }
78}
79
80pub struct SummaryLine(pub summary::Stats);
81
82impl Outputter for SummaryLine {
83 fn record(&mut self, stack: &StackTrace) -> Result<()> {
84 self.0.add_lineno(&filter_unknown(&stack.trace));
85 Ok(())
86 }
87
88 fn complete(&mut self, mut write: &mut dyn Write) -> Result<()> {
89 self.0.write(&mut write)
90 }
91}
92
93pub struct Speedscope(pub speedscope::Stats);
94
95impl Outputter for Speedscope {
96 fn record(&mut self, stack: &StackTrace) -> Result<()> {
97 self.0.record(&stack)
98 }
99
100 fn complete(&mut self, write: &mut dyn Write) -> Result<()> {
101 self.0.write(write)
102 }
103}
104
105pub struct Pprof(pub pprof::Stats);
106
107impl Outputter for Pprof {
108 fn record(&mut self, stack: &StackTrace) -> Result<()> {
109 self.0.record(stack)
110 }
111
112 fn complete(&mut self, write: &mut dyn Write) -> Result<()> {
113 self.0.write(write)
114 }
115}
116
117fn filter_unknown(trace: &[StackFrame]) -> Vec<StackFrame> {
120 let unknown = StackFrame::unknown_c_function();
121 let vec: Vec<StackFrame> = trace.iter().filter(|&x| x != &unknown).cloned().collect();
122 if vec.is_empty() {
123 vec![unknown]
124 } else {
125 vec
126 }
127}