trace_tools/util/
flamegrapher.rs1use crate::error::{Error, FlamegrapherErrorKind};
5
6use std::{
7 fs::File,
8 io::{BufReader, BufWriter},
9 path::{Path, PathBuf},
10};
11
12#[derive(Default)]
15pub struct Flamegrapher {
16 stack_filename: Option<PathBuf>,
17 graph_filename: Option<PathBuf>,
18}
19
20impl Flamegrapher {
21 pub fn new() -> Self {
23 Self::default()
24 }
25
26 pub fn with_stack_file<P: AsRef<Path>>(mut self, stack_filename: P) -> Result<Self, Error> {
32 let stack_filename = stack_filename.as_ref().to_path_buf();
33
34 if !stack_filename.exists() {
35 return Err(Error::Flamegrapher(FlamegrapherErrorKind::StackFileNotFound(
36 stack_filename,
37 )));
38 }
39
40 self.stack_filename = Some(stack_filename);
41 Ok(self)
42 }
43
44 pub fn with_graph_file<P: AsRef<Path>>(mut self, graph_filename: P) -> Result<Self, Error> {
52 let graph_filename = graph_filename.as_ref().with_extension("svg");
53
54 match graph_filename.parent() {
55 Some(directory) if !directory.is_dir() => {
56 return Err(Error::Flamegrapher(FlamegrapherErrorKind::GraphFileInvalid(
57 graph_filename,
58 )));
59 }
60 _ => {}
61 }
62
63 self.graph_filename = Some(graph_filename);
64 Ok(self)
65 }
66
67 pub fn write_flamegraph(&self) -> Result<(), Error> {
76 let stack_filename = self
77 .stack_filename
78 .as_ref()
79 .ok_or_else(|| Error::Flamegrapher(FlamegrapherErrorKind::MissingField("stack_filename".to_string())))?;
80
81 let graph_filename = self
82 .graph_filename
83 .as_ref()
84 .ok_or_else(|| Error::Flamegrapher(FlamegrapherErrorKind::MissingField("graph_filename".to_string())))?;
85
86 let stack_file = File::open(stack_filename).map_err(|err| Error::Flamegrapher(err.into()))?;
87 let reader = BufReader::new(stack_file);
88
89 let graph_file = File::create(graph_filename).map_err(|err| Error::Flamegrapher(err.into()))?;
90 let writer = BufWriter::new(graph_file);
91
92 let mut graph_options = inferno::flamegraph::Options::default();
93 inferno::flamegraph::from_reader(&mut graph_options, reader, writer)
94 .map_err(|err| Error::Flamegrapher(FlamegrapherErrorKind::Inferno(Box::new(err))))?;
95
96 Ok(())
97 }
98}