From 49a6daaa8386f321d23f57fb5f3ae365abf82a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 12 Dec 2023 08:18:10 +0100 Subject: [PATCH] perf(lsp): collect counts and durations of all requests (#21540) In addition to collecting details per-request metrics of the last 3000 request this commit adds aggregate metrics for all requests. --- cli/lsp/language_server.rs | 20 ++++++++++++++++++-- cli/lsp/performance.rs | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 9b531cc409..2d3864e0ab 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -3807,14 +3807,30 @@ impl Inner { .join("\n - ") ) .unwrap(); + contents - .push_str("\n## Performance\n\n|Name|Duration|Count|\n|---|---|---|\n"); + .push_str("\n## Performance (last 3 000 entries)\n\n|Name|Count|Duration|\n|---|---|---|\n"); let mut averages = self.performance.averages_as_f64(); averages.sort_by(|a, b| a.0.cmp(&b.0)); for (name, count, average_duration) in averages { - writeln!(contents, "|{}|{}ms|{}|", name, average_duration, count) + writeln!(contents, "|{}|{}|{}ms|", name, count, average_duration) .unwrap(); } + + contents.push_str( + "\n## Performance (total)\n\n|Name|Count|Duration|\n|---|---|---|\n", + ); + let mut measurements_by_type = self.performance.measurements_by_type(); + measurements_by_type.sort_by(|a, b| a.0.cmp(&b.0)); + for (name, total_count, total_duration) in measurements_by_type { + writeln!( + contents, + "|{}|{}|{:.3}ms|", + name, total_count, total_duration + ) + .unwrap(); + } + Some(contents) } else { let asset_or_doc = self.get_maybe_asset_or_document(&specifier); diff --git a/cli/lsp/performance.rs b/cli/lsp/performance.rs index 610e180670..abcba8c4c7 100644 --- a/cli/lsp/performance.rs +++ b/cli/lsp/performance.rs @@ -79,6 +79,8 @@ impl From for PerformanceMeasure { #[derive(Debug)] pub struct Performance { counts: Mutex>, + measurements_by_type: + Mutex>, max_size: usize, measures: Mutex>, } @@ -87,6 +89,7 @@ impl Default for Performance { fn default() -> Self { Self { counts: Default::default(), + measurements_by_type: Default::default(), max_size: 3_000, measures: Default::default(), } @@ -137,6 +140,14 @@ impl Performance { .collect() } + pub fn measurements_by_type(&self) -> Vec<(String, u32, f64)> { + let measurements_by_type = self.measurements_by_type.lock(); + measurements_by_type + .iter() + .map(|(name, (count, duration))| (name.to_string(), *count, *duration)) + .collect::>() + } + pub fn averages_as_f64(&self) -> Vec<(String, u32, f64)> { let mut averages: HashMap> = HashMap::new(); for measure in self.measures.lock().iter() { @@ -164,6 +175,13 @@ impl Performance { let mut counts = self.counts.lock(); let count = counts.entry(name.to_string()).or_insert(0); *count += 1; + { + let mut measurements_by_type = self.measurements_by_type.lock(); + let measurement = measurements_by_type + .entry(name.to_string()) + .or_insert((0, 0.0)); + measurement.0 += 1; + } let msg = if let Some(args) = maybe_args { json!({ "type": "mark", @@ -218,6 +236,13 @@ impl Performance { }) ); let duration = measure.duration; + { + let mut measurements_by_type = self.measurements_by_type.lock(); + let measurement = measurements_by_type + .entry(measure.name.to_string()) + .or_insert((0, 0.0)); + measurement.1 += duration.as_micros() as f64 / 1000.0; + } let mut measures = self.measures.lock(); measures.push_front(measure); while measures.len() > self.max_size {