Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/interpreter/clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,35 @@ impl ClickHouse {
.await;
}

/// Return jemalloc flamegraph in pyspy format.
/// It is the same format as TSV, but with ' ' delimiter between symbols and weight.
pub async fn get_jemalloc_flamegraph(&self, selected_host: Option<&String>) -> Result<Columns> {
let dbtable = self.get_table_name("system", "jemalloc_profile");
let host_filter = if let Some(host) = selected_host {
if !host.is_empty() && self.options.cluster.is_some() {
format!("AND hostName() = '{}'", host.replace('\'', "''"))
} else {
String::new()
}
} else {
String::new()
};
return self
.execute(&format!(
r#"
WITH splitByChar(' ', line) AS parts
SELECT
arrayStringConcat(arraySlice(parts, 1, -1), ' ') AS symbols,
parts[-1]::UInt64 AS bytes
FROM {}
WHERE 1 {}
SETTINGS jemalloc_profile_output_format='collapsed'
"#,
dbtable, host_filter,
))
.await;
}

pub async fn get_live_query_flamegraph(
&self,
query_ids: &Option<Vec<String>>,
Expand Down
17 changes: 17 additions & 0 deletions src/interpreter/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub enum Event {
TextLog(&'static str, TextLogArguments),
// [bool (true - show in TUI, false - share via pastila), type, start, end]
ServerFlameGraph(bool, TraceType, DateTime<Local>, DateTime<Local>),
// [bool (true - show in TUI, false - share via pastila)]
JemallocFlameGraph(bool),
// (type, bool (true - show in TUI, false - open in browser), start time, end time, [query_ids])
QueryFlameGraph(
TraceType,
Expand Down Expand Up @@ -86,6 +88,7 @@ impl Event {
Event::LastQueryLog(..) => "LastQueryLog".to_string(),
Event::TextLog(..) => "TextLog".to_string(),
Event::ServerFlameGraph(..) => "ServerFlameGraph".to_string(),
Event::JemallocFlameGraph(..) => "JemallocFlameGraph".to_string(),
Event::QueryFlameGraph(..) => "QueryFlameGraph".to_string(),
Event::LiveQueryFlameGraph(..) => "LiveQueryFlameGraph".to_string(),
Event::Summary => "Summary".to_string(),
Expand Down Expand Up @@ -428,6 +431,20 @@ async fn process_event(context: ContextArc, event: Event, need_clear: &mut bool)
.await?;
*need_clear = true;
}
Event::JemallocFlameGraph(tui) => {
let flamegraph_block = clickhouse
.get_jemalloc_flamegraph(selected_host.as_ref())
.await?;
render_or_share_flamegraph(
tui,
cb_sink,
flamegraph_block,
pastila_clickhouse_host,
pastila_url,
)
.await?;
*need_clear = true;
}
Event::QueryFlameGraph(trace_type, tui, start, end, query_ids) => {
let flamegraph_block = clickhouse
.get_flamegraph(
Expand Down
10 changes: 10 additions & 0 deletions src/view/navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub trait Navigation {
fn show_actions(&mut self);
fn show_fuzzy_actions(&mut self);
fn show_server_flamegraph(&mut self, tui: bool, trace_type: Option<TraceType>);
fn show_jemalloc_flamegraph(&mut self, tui: bool);
fn show_host_filter_dialog(&mut self);

fn drop_main_view(&mut self);
Expand Down Expand Up @@ -270,6 +271,8 @@ impl Navigation for Cursive {
context.add_global_action_without_shortcut(self, "Share Server MemoryAllocatedWithoutCheck Flamegraph", |siv| siv.show_server_flamegraph(false, Some(TraceType::MemoryAllocatedWithoutCheck)));
context.add_global_action_without_shortcut(self, "Share Server Events Flamegraph", |siv| siv.show_server_flamegraph(false, Some(TraceType::ProfileEvent)));
context.add_global_action_without_shortcut(self, "Share Server Live Flamegraph", |siv| siv.show_server_flamegraph(false, None));
context.add_global_action_without_shortcut(self, "Jemalloc", |siv| siv.show_jemalloc_flamegraph(true));
context.add_global_action_without_shortcut(self, "Share Jemalloc", |siv| siv.show_jemalloc_flamegraph(false));

// If logging is done to file, console is always empty
if context.options.service.log.is_none() {
Expand Down Expand Up @@ -587,6 +590,13 @@ impl Navigation for Cursive {
}
}

fn show_jemalloc_flamegraph(&mut self, tui: bool) {
let mut context = self.user_data::<ContextArc>().unwrap().lock().unwrap();
context
.worker
.send(true, WorkerEvent::JemallocFlameGraph(tui));
}

fn show_host_filter_dialog(&mut self) {
let context_arc = self.user_data::<ContextArc>().unwrap().clone();
let context = context_arc.lock().unwrap();
Expand Down
Loading