Skip to content

Commit d06ec2f

Browse files
authored
fix: Correct tutorial 12 profile folded stack format (#202)
- Reorder stack processing to place kernel frames at bottom and user frames on top - Match expected flamegraph.pl input format - Simplify output to standard folded format: "comm;stack1;stack2 count" - Remove timestamp and CPU metadata
1 parent bb994bf commit d06ec2f

File tree

1 file changed

+49
-44
lines changed

1 file changed

+49
-44
lines changed

src/12-profile/src/event.rs

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::mem;
2-
use std::time::{SystemTime, UNIX_EPOCH};
31
use blazesym::symbolize;
42
use nix::sys::sysinfo;
3+
use std::mem;
4+
use std::time::{SystemTime, UNIX_EPOCH};
55

66
pub const MAX_STACK_DEPTH: usize = 128;
77
pub const TASK_COMM_LEN: usize = 16;
@@ -35,7 +35,7 @@ impl EventHandler {
3535
pub fn new(format: OutputFormat) -> Self {
3636
// Get system uptime to calculate boot time
3737
let boot_time_ns = Self::get_boot_time_ns();
38-
38+
3939
Self {
4040
symbolizer: symbolize::Symbolizer::new(),
4141
format,
@@ -49,11 +49,11 @@ impl EventHandler {
4949
.duration_since(UNIX_EPOCH)
5050
.expect("System time before Unix epoch");
5151
let now_ns = now.as_nanos() as u64;
52-
52+
5353
// Get system uptime in nanoseconds
5454
let info = sysinfo::sysinfo().expect("Failed to get sysinfo");
5555
let uptime_ns = (info.uptime().as_secs_f64() * 1_000_000_000.0) as u64;
56-
56+
5757
// Boot time = current time - uptime
5858
now_ns - uptime_ns
5959
}
@@ -104,8 +104,10 @@ impl EventHandler {
104104
let unix_timestamp_ns = event.timestamp + self.boot_time_ns;
105105
let timestamp_sec = unix_timestamp_ns / 1_000_000_000;
106106
let timestamp_nsec = unix_timestamp_ns % 1_000_000_000;
107-
println!("[{}.{:09}] COMM: {} (pid={}) @ CPU {}",
108-
timestamp_sec, timestamp_nsec, comm, event.pid, event.cpu_id);
107+
println!(
108+
"[{}.{:09}] COMM: {} (pid={}) @ CPU {}",
109+
timestamp_sec, timestamp_nsec, comm, event.pid, event.cpu_id
110+
);
109111

110112
if event.kstack_size > 0 {
111113
println!("Kernel:");
@@ -128,48 +130,43 @@ impl EventHandler {
128130

129131
fn handle_folded_extended(&self, event: &StacktraceEvent) {
130132
let comm = Self::get_comm_str(&event.comm);
131-
let tid = event.pid; // For single-threaded processes, TID = PID
132-
133+
133134
let mut stack_frames = Vec::new();
134135

135-
// Process user stack (if present)
136+
// Process kernel stack first (bottom of stack, closer to root)
137+
if event.kstack_size > 0 {
138+
let kstack = Self::get_stack_slice(&event.kstack, event.kstack_size);
139+
let kernel_frames = symbolize_stack_to_vec(&self.symbolizer, kstack, 0);
140+
141+
// Add kernel frames with [k] suffix (from bottom to top)
142+
for frame in kernel_frames.iter() {
143+
stack_frames.push(format!("{}_[k]", frame));
144+
}
145+
}
146+
147+
// Process user stack (on top of kernel stack)
136148
if event.ustack_size > 0 {
137149
let ustack = Self::get_stack_slice(&event.ustack, event.ustack_size);
138150
let user_frames = symbolize_stack_to_vec(&self.symbolizer, ustack, event.pid);
139-
140-
// Add user frames in reverse order (top to bottom)
141-
for frame in user_frames.iter().rev() {
151+
152+
// Add user frames (from bottom to top)
153+
for frame in user_frames.iter() {
142154
stack_frames.push(frame.clone());
143155
}
144156
}
145157

146-
// Process kernel stack (if present)
147-
if event.kstack_size > 0 {
148-
let kstack = Self::get_stack_slice(&event.kstack, event.kstack_size);
149-
let kernel_frames = symbolize_stack_to_vec(&self.symbolizer, kstack, 0);
150-
151-
// Add kernel frames with [k] suffix in reverse order (top to bottom)
152-
for frame in kernel_frames.iter().rev() {
153-
stack_frames.push(format!("{}_[k]", frame));
154-
}
158+
// If no frames, skip this event
159+
if stack_frames.is_empty() {
160+
return;
155161
}
156162

157-
// Format: timestamp_ns comm pid tid cpu stack1;stack2;stack3
158-
// Convert kernel timestamp to Unix timestamp
159-
let unix_timestamp_ns = event.timestamp + self.boot_time_ns;
160-
println!(
161-
"{} {} {} {} {} {}",
162-
unix_timestamp_ns,
163-
comm,
164-
event.pid,
165-
tid,
166-
event.cpu_id,
167-
stack_frames.join(";")
168-
);
163+
// Format for flamegraph.pl folded format:
164+
// comm;stack_frame1;stack_frame2;stack_frame3 count
165+
// The count is 1 for each sample
166+
println!("{};{} 1", comm, stack_frames.join(";"));
169167
}
170168
}
171169

172-
173170
fn print_frame(
174171
name: &str,
175172
addr_info: Option<(blazesym::Addr, blazesym::Addr, usize)>,
@@ -217,7 +214,11 @@ fn convert_stack_addresses(stack: &[u64]) -> Vec<blazesym::Addr> {
217214
.collect::<Vec<_>>()
218215
} else {
219216
// For same-sized types, still need to return owned data for consistency
220-
stack.iter().copied().map(|addr| addr as blazesym::Addr).collect()
217+
stack
218+
.iter()
219+
.copied()
220+
.map(|addr| addr as blazesym::Addr)
221+
.collect()
221222
}
222223
}
223224

@@ -242,26 +243,30 @@ fn get_symbolize_source(pid: u32) -> symbolize::source::Source<'static> {
242243
}
243244

244245
// Symbolize stack and return as vector of strings for folded format
245-
fn symbolize_stack_to_vec(symbolizer: &symbolize::Symbolizer, stack: &[u64], pid: u32) -> Vec<String> {
246+
fn symbolize_stack_to_vec(
247+
symbolizer: &symbolize::Symbolizer,
248+
stack: &[u64],
249+
pid: u32,
250+
) -> Vec<String> {
246251
let converted = convert_stack_addresses(stack);
247252
let stack_addrs = get_stack_slice(stack, &converted);
248253
let src = get_symbolize_source(pid);
249-
254+
250255
let syms = match symbolizer.symbolize(&src, symbolize::Input::AbsAddr(stack_addrs)) {
251256
Ok(syms) => syms,
252257
Err(_) => {
253258
// Return addresses if symbolization fails
254-
return stack_addrs.iter().map(|addr| format!("{:#x}", addr)).collect();
259+
return stack_addrs
260+
.iter()
261+
.map(|addr| format!("{:#x}", addr))
262+
.collect();
255263
}
256264
};
257265

258266
let mut result = Vec::new();
259267
for (addr, sym) in stack_addrs.iter().copied().zip(syms) {
260268
match sym {
261-
symbolize::Symbolized::Sym(symbolize::Sym {
262-
name,
263-
..
264-
}) => {
269+
symbolize::Symbolized::Sym(symbolize::Sym { name, .. }) => {
265270
result.push(name.to_string());
266271
}
267272
symbolize::Symbolized::Unknown(..) => {
@@ -306,4 +311,4 @@ fn show_stack_trace(stack: &[u64], symbolizer: &symbolize::Symbolizer, pid: u32)
306311
}
307312
}
308313
}
309-
}
314+
}

0 commit comments

Comments
 (0)