Skip to content

Commit 3cbcfcc

Browse files
authored
chore: improve explain perf to support flag inlined function (#19042)
* chore: post process frames after explain perf * ci: add a flag to allow skip trim debug info
1 parent a4fd094 commit 3cbcfcc

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ petgraph = { version = "0.6.2", features = ["serde-1"] }
425425
pin-project = "1"
426426
pin-project-lite = "0.2.9"
427427
poem = { version = "3.0", features = ["openssl-tls", "multipart", "compression", "cookie"] }
428-
pprof = { git = "https://github.com/datafuse-extras/pprof-rs", rev = "fe22b23", features = [
428+
pprof = { git = "https://github.com/datafuse-extras/pprof-rs", rev = "edecd74", features = [
429429
"flamegraph",
430430
"protobuf-codec",
431431
"protobuf",

src/common/base/src/runtime/perf/query_perf.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use databend_common_exception::Result;
1717
use log::debug;
1818
use pprof::ProfilerGuard;
1919
use pprof::ProfilerGuardBuilder;
20+
use regex::Regex;
2021

2122
use crate::runtime::ThreadTracker;
2223
use crate::runtime::TrackingGuard;
@@ -65,6 +66,7 @@ impl QueryPerf {
6566
pub fn dump(profiler_guard: &ProfilerGuard<'static>) -> Result<String> {
6667
let reporter = profiler_guard
6768
.report()
69+
.frames_post_processor(frames_post_processor())
6870
.build()
6971
.map_err(|_e| ErrorCode::Internal("Failed to report profiler data"))?;
7072
debug!("perf stop, begin to dump flamegraph");
@@ -126,6 +128,49 @@ impl QueryPerf {
126128
}
127129
}
128130

131+
const PPROF_TRACE_SYMBOL: &str =
132+
"<pprof::backtrace::backtrace_rs::Trace as pprof::backtrace::Trace>::trace";
133+
134+
fn frames_post_processor() -> impl Fn(&mut pprof::Frames) {
135+
// If pprof cannot get thread name, it will use thread id as fallback
136+
// this will make the flamegraph hard to read, so we rename such threads to "threads"
137+
let thread_rename = [(Regex::new(r"^\d+$").unwrap(), "threads")];
138+
139+
move |frames| {
140+
for (regex, name) in thread_rename.iter() {
141+
if regex.is_match(&frames.thread_name) {
142+
frames.thread_name = name.to_string();
143+
}
144+
}
145+
146+
// Remove frames introduced by pprof's own stack collection to keep user stacks clean.
147+
if let Some(pos) = frames.frames.iter().position(|frame| {
148+
frame
149+
.iter()
150+
.any(|symbol| symbol.name() == PPROF_TRACE_SYMBOL)
151+
}) {
152+
frames.frames.drain(..=pos);
153+
}
154+
155+
// Mark inlined functions with "(inlined)" suffix
156+
for inline_frames in frames.frames.iter_mut() {
157+
if inline_frames.len() <= 1 {
158+
continue;
159+
}
160+
161+
// Mark every symbol except the outermost one as inlined.
162+
let last_symbol_index = inline_frames.len() - 1;
163+
for symbol in inline_frames.iter_mut().take(last_symbol_index) {
164+
let symbol_name = symbol.name();
165+
if symbol_name.ends_with(" (inlined)") {
166+
continue;
167+
}
168+
symbol.name = Some(format!("{symbol_name} (inlined)").into_bytes());
169+
}
170+
}
171+
}
172+
}
173+
129174
#[cfg(test)]
130175
mod tests {
131176
use crate::runtime::QueryPerf;

0 commit comments

Comments
 (0)