1use std::path::Path;
2use std::path::PathBuf;
3
4use profile_bee_common::StackInfo;
5
6pub struct FrameCount {
11 pub frames: Vec<StackFrameInfo>,
12 pub count: u64,
13}
14
15#[derive(Debug, Default, Clone, Eq, PartialEq)]
21pub struct StackFrameInfo {
22 pub pid: usize,
23 pub cmd: String,
24
25 pub address: u64,
27 pub object_path: Option<PathBuf>,
29
30 pub symbol: Option<String>,
32
33 pub source: Option<String>,
35
36 pub cpu_id: Option<u32>,
37
38 pub ns: Option<u64>,
40}
41
42impl StackFrameInfo {
43 pub fn prepare(meta: &StackInfo) -> Self {
45 Self {
46 pid: meta.tgid as usize,
47 cmd: meta.get_cmd(),
48 ..Default::default()
50 }
51 }
52
53 pub fn process_only(meta: &StackInfo) -> Self {
55 let cmd = meta.get_cmd();
56 let with_pid = false;
57
58 let sym = if with_pid {
59 format!("{} ({})", cmd, meta.tgid)
60 } else {
61 cmd.to_owned()
62 };
63
64 Self {
65 pid: meta.tgid as usize,
66 cmd,
67 symbol: Some(sym),
68 ..Default::default()
69 }
70 }
71
72 pub fn new(address: u64, object_path: Option<PathBuf>) -> Self {
73 Self {
74 address,
75 object_path,
76 ..Default::default()
77 }
78 }
79
80 pub fn address(&self) -> u64 {
82 self.address
83 }
84
85 pub fn object_path(&self) -> Option<&Path> {
87 self.object_path.as_deref()
88 }
89
90 pub fn fmt(&self) -> String {
91 format!(
92 "{:#x}\t{}\t{}\t{}",
93 self.address(),
94 self.cmd,
95 self.fmt_object(),
96 self.fmt_symbol()
97 )
98 }
99
100 pub fn fmt_symbol(&self) -> String {
101 format!(
102 "{}{}",
103 self.symbol.as_deref().unwrap_or(
104 format!("{}+{:#x}", self.fmt_object(), self.address).as_str()
106 ),
107 self.fmt_source()
108 )
109 }
110
111 pub fn fmt_object(&self) -> &str {
112 self.object_path()
113 .and_then(|v| v.file_name())
114 .and_then(|v| v.to_str())
115 .unwrap_or(&self.cmd)
116 }
117
118 fn fmt_shorter_source(&self, count: usize) -> Option<String> {
119 StackFrameInfo::fmt_shorter(self.source.as_deref(), count)
120 }
121
122 fn fmt_shorter(op: Option<&str>, count: usize) -> Option<String> {
125 op.map(|v| {
126 v.split('/')
127 .rev()
128 .take(count)
129 .map(|v| v.to_string())
130 .collect::<Vec<String>>()
131 .into_iter()
132 .rev()
133 .collect::<Vec<String>>()
134 .join("/")
135 })
136 }
137
138 pub fn fmt_source(&self) -> String {
139 let short = self.fmt_shorter_source(4);
140
141 if short.is_some() {
142 format!(" ({})", short.unwrap())
143 } else {
144 "".to_string()
145 }
146 }
147}
148
149pub trait StackInfoExt {
150 fn get_cmd(&self) -> String;
151 fn get_cpu_id(&self) -> Option<u32>;
152}
153
154impl StackInfoExt for StackInfo {
155 fn get_cmd(&self) -> String {
156 str_from_u8_nul_utf8(&self.cmd).unwrap().to_owned()
157 }
158
159 fn get_cpu_id(&self) -> Option<u32> {
160 if self.cpu == u32::MAX {
161 return None;
162 }
163
164 Some(self.cpu)
165 }
166}
167
168pub fn str_from_u8_nul_utf8(utf8_src: &[u8]) -> core::result::Result<&str, std::str::Utf8Error> {
169 let nul_range_end = utf8_src
170 .iter()
171 .position(|&c| c == b'\0')
172 .unwrap_or(utf8_src.len()); ::std::str::from_utf8(&utf8_src[0..nul_range_end])
174}