From 44494e235a0558c531173fe25ede4f164ea2e4ef Mon Sep 17 00:00:00 2001 From: David Barsky Date: Tue, 30 Jan 2024 18:13:29 -0500 Subject: [PATCH] internal: teach hprof to record `tracing` fields --- crates/rust-analyzer/src/tracing/hprof.rs | 68 +++++++++++++++++------ 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/crates/rust-analyzer/src/tracing/hprof.rs b/crates/rust-analyzer/src/tracing/hprof.rs index f37262a17a..c99b551df8 100644 --- a/crates/rust-analyzer/src/tracing/hprof.rs +++ b/crates/rust-analyzer/src/tracing/hprof.rs @@ -32,7 +32,8 @@ //! ``` use std::{ - fmt, mem, + fmt::Write, + mem, time::{Duration, Instant}, }; @@ -99,21 +100,37 @@ impl SpanTree { struct Data { start: Instant, children: Vec, + fields: String, } impl Data { fn new(attrs: &Attributes<'_>) -> Self { - let mut span = Self { start: Instant::now(), children: Vec::new() }; - attrs.record(&mut span); - span + let mut data = Self { start: Instant::now(), children: Vec::new(), fields: String::new() }; + + let mut visitor = DataVisitor { string: &mut data.fields }; + attrs.record(&mut visitor); + data } + fn into_node(self, name: &'static str) -> Node { - Node { name, count: 1, duration: self.start.elapsed(), children: self.children } + Node { + name, + fields: self.fields, + count: 1, + duration: self.start.elapsed(), + children: self.children, + } } } -impl Visit for Data { - fn record_debug(&mut self, _field: &Field, _value: &dyn fmt::Debug) {} +pub struct DataVisitor<'a> { + string: &'a mut String, +} + +impl<'a> Visit for DataVisitor<'a> { + fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) { + write!(self.string, "{} = {:?} ", field.name(), value).unwrap(); + } } impl Layer for SpanTree @@ -151,6 +168,7 @@ where #[derive(Default)] struct Node { name: &'static str, + fields: String, count: u32, duration: Duration, children: Vec, @@ -163,16 +181,22 @@ impl Node { fn go(&self, level: usize, filter: &WriteFilter) { if self.duration > filter.longer_than && level < filter.depth { - let duration = format!("{:3.2?}", self.duration); - let count = if self.count > 1 { self.count.to_string() } else { String::new() }; - eprintln!( - "{:width$} {:<9} {:<6} {}", - "", - duration, - count, - self.name, - width = level * 2 - ); + let duration = ms(self.duration); + let current_indent = level * 2; + + let mut out = String::new(); + let _ = write!(out, "{:current_indent$} {duration} {:<6}", "", self.name); + + if !self.fields.is_empty() { + let _ = write!(out, " @ {}", self.fields); + } + + if self.count > 1 { + let _ = write!(out, " ({} calls)", self.count); + } + + eprintln!("{}", out); + for child in &self.children { child.go(level + 1, filter) } @@ -236,3 +260,13 @@ impl WriteFilter { (WriteFilter { depth, longer_than }, allowed) } } + +#[allow(non_camel_case_types)] +struct ms(Duration); + +impl std::fmt::Display for ms { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let n = self.0.as_millis(); + write!(f, "{n:5}ms") + } +}