profile_inspect/output/
mod.rs1mod collapsed;
2mod json;
3mod markdown;
4mod speedscope;
5mod text;
6
7pub use collapsed::*;
8pub use json::*;
9pub use markdown::*;
10pub use speedscope::*;
11pub use text::*;
12
13use std::io::Write;
14
15use thiserror::Error;
16
17use crate::analysis::{CpuAnalysis, HeapAnalysis};
18use crate::ir::ProfileIR;
19
20#[derive(Debug, Error)]
22pub enum OutputError {
23 #[error("I/O error: {0}")]
24 Io(#[from] std::io::Error),
25
26 #[error("JSON serialization error: {0}")]
27 Json(#[from] serde_json::Error),
28}
29
30pub fn format_time_us(time_us: u64) -> String {
35 let ms = time_us as f64 / 1000.0;
36 format_time_ms(ms)
37}
38
39pub fn format_time_ms(ms: f64) -> String {
41 if ms < 1000.0 {
42 format!("{ms:.2} ms")
43 } else if ms < 60_000.0 {
44 format!("{:.2} s", ms / 1000.0)
45 } else {
46 format!("{:.2} min", ms / 60_000.0)
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum OutputFormat {
53 Markdown,
55 Text,
57 Json,
59 Speedscope,
61 Collapsed,
63}
64
65impl OutputFormat {
66 pub fn from_str(s: &str) -> Option<Self> {
68 match s.to_lowercase().as_str() {
69 "markdown" | "md" => Some(Self::Markdown),
70 "text" | "txt" => Some(Self::Text),
71 "json" => Some(Self::Json),
72 "speedscope" => Some(Self::Speedscope),
73 "collapsed" | "folded" => Some(Self::Collapsed),
74 _ => None,
75 }
76 }
77
78 pub fn extension(&self) -> &'static str {
80 match self {
81 Self::Markdown => "md",
82 Self::Text => "txt",
83 Self::Json => "json",
84 Self::Speedscope => "speedscope.json",
85 Self::Collapsed => "collapsed.txt",
86 }
87 }
88
89 pub fn default_filename(&self) -> &'static str {
91 match self {
92 Self::Markdown => "profile-analysis.md",
93 Self::Text => "profile-analysis.txt",
94 Self::Json => "profile-analysis.json",
95 Self::Speedscope => "profile.speedscope.json",
96 Self::Collapsed => "profile.collapsed.txt",
97 }
98 }
99}
100
101pub trait Formatter {
103 fn write_cpu_analysis(
105 &self,
106 profile: &ProfileIR,
107 analysis: &CpuAnalysis,
108 writer: &mut dyn Write,
109 ) -> Result<(), OutputError>;
110
111 fn write_heap_analysis(
113 &self,
114 profile: &ProfileIR,
115 analysis: &HeapAnalysis,
116 writer: &mut dyn Write,
117 ) -> Result<(), OutputError>;
118}
119
120pub fn get_formatter(format: OutputFormat) -> Box<dyn Formatter> {
122 match format {
123 OutputFormat::Markdown => Box::new(MarkdownFormatter),
124 OutputFormat::Text => Box::new(TextFormatter),
125 OutputFormat::Json => Box::new(JsonFormatter),
126 OutputFormat::Speedscope => Box::new(SpeedscopeFormatter),
127 OutputFormat::Collapsed => Box::new(CollapsedFormatter),
128 }
129}