Skip to content

Commit 27738ea

Browse files
author
Paolo Tranquilli
committed
Rust: reorganize perf diagnostics
1 parent 556774e commit 27738ea

File tree

6 files changed

+136
-128
lines changed

6 files changed

+136
-128
lines changed

rust/extractor/src/diagnostics.rs

Lines changed: 75 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use anyhow::Context;
33
use chrono::{DateTime, Utc};
44
use log::{debug, info};
55
use ra_ap_project_model::ProjectManifest;
6+
use serde::ser::SerializeMap;
67
use serde::Serialize;
8+
use std::collections::HashMap;
79
use std::fmt::Display;
810
use std::fs::File;
911
use std::path::{Path, PathBuf};
@@ -72,27 +74,29 @@ pub struct Diagnostics<T> {
7274
attributes: T,
7375
}
7476

75-
#[derive(Debug, Clone, Serialize)]
77+
#[derive(Default, Debug, Clone, Copy, Serialize, PartialEq, Eq, Hash)]
7678
#[serde(rename_all = "camelCase")]
77-
enum ExtractionStepTarget {
78-
LoadManifest(PathBuf),
79-
FetchFile(PathBuf),
80-
Parse(PathBuf),
81-
Extract(PathBuf),
79+
enum ExtractionStepKind {
80+
#[default]
81+
LoadManifest,
82+
LoadSource,
83+
Parse,
84+
Extract,
8285
}
8386

8487
#[derive(Debug, Clone, Serialize)]
8588
#[serde(rename_all = "camelCase")]
8689
pub struct ExtractionStep {
87-
#[serde(flatten)]
88-
target: ExtractionStepTarget,
90+
action: ExtractionStepKind,
91+
file: PathBuf,
8992
ms: u128,
9093
}
9194

9295
impl ExtractionStep {
93-
fn new(start: Instant, target: ExtractionStepTarget) -> Self {
96+
fn new(start: Instant, action: ExtractionStepKind, file: PathBuf) -> Self {
9497
let ret = ExtractionStep {
95-
target,
98+
action,
99+
file,
96100
ms: start.elapsed().as_millis(),
97101
};
98102
debug!("{ret:?}");
@@ -102,70 +106,84 @@ impl ExtractionStep {
102106
pub fn load_manifest(start: Instant, target: &ProjectManifest) -> Self {
103107
Self::new(
104108
start,
105-
ExtractionStepTarget::LoadManifest(PathBuf::from(target.manifest_path())),
109+
ExtractionStepKind::LoadManifest,
110+
PathBuf::from(target.manifest_path()),
106111
)
107112
}
108113

109114
pub fn parse(start: Instant, target: &Path) -> Self {
110-
Self::new(start, ExtractionStepTarget::Parse(PathBuf::from(target)))
115+
Self::new(start, ExtractionStepKind::Parse, PathBuf::from(target))
111116
}
112117

113118
pub fn extract(start: Instant, target: &Path) -> Self {
114-
Self::new(start, ExtractionStepTarget::Extract(PathBuf::from(target)))
119+
Self::new(start, ExtractionStepKind::Extract, PathBuf::from(target))
115120
}
116121

117-
pub fn fetch_file(start: Instant, target: &Path) -> Self {
118-
Self::new(
119-
start,
120-
ExtractionStepTarget::FetchFile(PathBuf::from(target)),
121-
)
122+
pub fn load_source(start: Instant, target: &Path) -> Self {
123+
Self::new(start, ExtractionStepKind::LoadSource, PathBuf::from(target))
122124
}
123125
}
124126

125-
#[derive(Debug, Default, Clone, Serialize)]
126-
#[serde(rename_all = "camelCase")]
127-
struct HumanReadableDuration {
128-
ms: u128,
129-
pretty: String,
127+
#[derive(Debug, Default, Clone)]
128+
struct HumanReadableDuration(u128);
129+
130+
impl Serialize for HumanReadableDuration {
131+
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
132+
let mut map = serializer.serialize_map(Some(2))?;
133+
map.serialize_entry("ms", &self.0)?;
134+
map.serialize_entry("pretty", &self.pretty())?;
135+
map.end()
136+
}
130137
}
131138

132139
impl HumanReadableDuration {
133-
pub fn new(ms: u128) -> Self {
134-
let seconds = ms / 1000;
135-
let minutes = seconds / 60;
140+
pub fn add(&mut self, other: u128) {
141+
self.0 += other;
142+
}
143+
144+
pub fn pretty(&self) -> String {
145+
let milliseconds = self.0 % 1000;
146+
let mut seconds = self.0 / 1000;
147+
if seconds < 60 {
148+
return format!("{seconds}.{milliseconds:03}s");
149+
}
150+
let mut minutes = seconds / 60;
151+
seconds %= 60;
152+
if minutes < 60 {
153+
return format!("{minutes}min{seconds:02}.{milliseconds:03}s");
154+
}
136155
let hours = minutes / 60;
137-
let pretty = format!(
138-
"{hours}:{minutes:02}:{seconds:02}.{milliseconds:03}",
139-
minutes = minutes % 60,
140-
seconds = seconds % 60,
141-
milliseconds = ms % 1000,
142-
);
143-
Self { ms, pretty }
156+
minutes %= 60;
157+
format!("{hours}h{minutes:02}min{seconds:02}.{milliseconds:03}s")
144158
}
145159
}
146160

147161
impl From<u128> for HumanReadableDuration {
148162
fn from(val: u128) -> Self {
149-
HumanReadableDuration::new(val)
163+
HumanReadableDuration(val)
150164
}
151165
}
152166

153167
impl Display for HumanReadableDuration {
154168
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
155-
write!(f, "{}ms ({})", self.ms, self.pretty)
169+
f.write_str(&self.pretty())
156170
}
157171
}
158172

173+
#[derive(Debug, Default, Clone, Serialize)]
174+
#[serde(rename_all = "camelCase")]
175+
struct DurationsSummary {
176+
#[serde(flatten)]
177+
durations: HashMap<ExtractionStepKind, HumanReadableDuration>,
178+
total: HumanReadableDuration,
179+
}
180+
159181
#[derive(Debug, Default, Clone, Serialize)]
160182
#[serde(rename_all = "camelCase")]
161183
struct ExtractionSummary {
162184
number_of_manifests: usize,
163185
number_of_files: usize,
164-
total_load_duration: HumanReadableDuration,
165-
total_fetch_file_duration: HumanReadableDuration,
166-
total_parse_duration: HumanReadableDuration,
167-
total_extract_duration: HumanReadableDuration,
168-
total_duration: HumanReadableDuration,
186+
durations: DurationsSummary,
169187
}
170188

171189
#[derive(Debug, Default, Clone, Serialize)]
@@ -180,46 +198,32 @@ type ExtractionDiagnostics = Diagnostics<ExtractionAttributes>;
180198
fn summary(start: Instant, steps: &[ExtractionStep]) -> ExtractionSummary {
181199
let mut number_of_manifests = 0;
182200
let mut number_of_files = 0;
183-
let mut total_load_duration = 0;
184-
let mut total_parse_duration = 0;
185-
let mut total_extract_duration = 0;
186-
let mut total_fetch_file_duration: u128 = 0;
201+
let mut durations = HashMap::new();
187202
for step in steps {
188-
match &step.target {
189-
ExtractionStepTarget::LoadManifest(_) => {
203+
match &step.action {
204+
ExtractionStepKind::LoadManifest => {
190205
number_of_manifests += 1;
191-
total_load_duration += step.ms;
192206
}
193-
ExtractionStepTarget::FetchFile(_) => {
207+
ExtractionStepKind::Parse => {
194208
number_of_files += 1;
195-
total_fetch_file_duration += step.ms;
196-
}
197-
ExtractionStepTarget::Parse(_) => {
198-
total_parse_duration += step.ms;
199-
}
200-
ExtractionStepTarget::Extract(_) => {
201-
total_extract_duration += step.ms;
202209
}
210+
_ => {}
203211
}
212+
durations
213+
.entry(step.action)
214+
.or_insert(HumanReadableDuration(0))
215+
.add(step.ms);
204216
}
205-
let ret = ExtractionSummary {
217+
let total = start.elapsed().as_millis().into();
218+
for (key, value) in &durations {
219+
info!("total duration ({key:?}): {value}");
220+
}
221+
info!("total duration: {total}");
222+
ExtractionSummary {
206223
number_of_manifests,
207224
number_of_files,
208-
total_load_duration: total_load_duration.into(),
209-
total_fetch_file_duration: total_fetch_file_duration.into(),
210-
total_parse_duration: total_parse_duration.into(),
211-
total_extract_duration: total_extract_duration.into(),
212-
total_duration: start.elapsed().as_millis().into(),
213-
};
214-
info!("total loadimg duration: {}", ret.total_load_duration);
215-
info!(
216-
"total file fetching duration: {}",
217-
ret.total_fetch_file_duration
218-
);
219-
info!("total parsing duration: {}", ret.total_parse_duration);
220-
info!("total extracting duration: {}", ret.total_extract_duration);
221-
info!("total duration: {}", ret.total_duration);
222-
ret
225+
durations: DurationsSummary { durations, total },
226+
}
223227
}
224228

225229
pub fn emit_extraction_diagnostics(

rust/extractor/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<'a> Extractor<'a> {
118118
ret
119119
}
120120

121-
pub fn fetch_file(
121+
pub fn load_source(
122122
&mut self,
123123
file: &Path,
124124
semantics: &Semantics<'_, RootDatabase>,
@@ -131,7 +131,7 @@ impl<'a> Extractor<'a> {
131131
if semantics.file_to_module_def(id).is_none() {
132132
return Err("not included as a module".to_string());
133133
}
134-
self.steps.push(ExtractionStep::fetch_file(before, file));
134+
self.steps.push(ExtractionStep::load_source(before, file));
135135
Ok(())
136136
}
137137

@@ -189,7 +189,7 @@ fn main() -> anyhow::Result<()> {
189189
if let Some((ref db, ref vfs)) = extractor.load_manifest(manifest, &cargo_config) {
190190
let semantics = Semantics::new(db);
191191
for file in files {
192-
match extractor.fetch_file(file, &semantics, vfs) {
192+
match extractor.load_source(file, &semantics, vfs) {
193193
Ok(()) => extractor.extract_with_semantics(file, &semantics, vfs),
194194
Err(reason) => extractor.extract_without_semantics(file, &reason),
195195
};

rust/ql/integration-tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ def manifests(cwd):
1717
@pytest.fixture
1818
def rust_check_diagnostics(check_diagnostics):
1919
check_diagnostics.replacements += [
20-
(r'"ms"\s*:\s*[0-9]+', '"ms": "REDACTED"'),
21-
(r'"pretty"\s*:\s*"[0-9]+:[0-9]{2}:[0-9]{2}.[0-9]{3}"', '"pretty": "REDACTED"'),
20+
(r'"ms"\s*:\s*[0-9]+', '"ms": "__REDACTED__"'),
21+
(r'"pretty"\s*:\s*"[^"]*"', '"pretty": "__REDACTED__"'),
2222
]
2323
check_diagnostics.skip += [
2424
"attributes.steps", # the order of the steps is not stable

rust/ql/integration-tests/hello-project/diagnostics.expected

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,24 @@
44
"numberOfFiles": 4,
55
"numberOfManifests": 1,
66
"totalDuration": {
7-
"ms": "REDACTED",
8-
"pretty": "REDACTED"
7+
"ms": "__REDACTED__",
8+
"pretty": "__REDACTED__"
99
},
1010
"totalExtractDuration": {
11-
"ms": "REDACTED",
12-
"pretty": "REDACTED"
11+
"ms": "__REDACTED__",
12+
"pretty": "__REDACTED__"
1313
},
1414
"totalFetchFileDuration": {
15-
"ms": "REDACTED",
16-
"pretty": "REDACTED"
15+
"ms": "__REDACTED__",
16+
"pretty": "__REDACTED__"
1717
},
1818
"totalLoadDuration": {
19-
"ms": "REDACTED",
20-
"pretty": "REDACTED"
19+
"ms": "__REDACTED__",
20+
"pretty": "__REDACTED__"
2121
},
2222
"totalParseDuration": {
23-
"ms": "REDACTED",
24-
"pretty": "REDACTED"
23+
"ms": "__REDACTED__",
24+
"pretty": "__REDACTED__"
2525
}
2626
}
2727
},

rust/ql/integration-tests/hello-workspace/diagnostics.cargo.expected

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
{
22
"attributes": {
33
"summary": {
4-
"numberOfFiles": 4,
5-
"numberOfManifests": 2,
6-
"totalDuration": {
7-
"ms": "REDACTED",
8-
"pretty": "REDACTED"
9-
},
10-
"totalExtractDuration": {
11-
"ms": "REDACTED",
12-
"pretty": "REDACTED"
13-
},
14-
"totalFetchFileDuration": {
15-
"ms": "REDACTED",
16-
"pretty": "REDACTED"
4+
"durations": {
5+
"extract": {
6+
"ms": "__REDACTED__",
7+
"pretty": "__REDACTED__"
8+
},
9+
"loadManifest": {
10+
"ms": "__REDACTED__",
11+
"pretty": "__REDACTED__"
12+
},
13+
"loadSource": {
14+
"ms": "__REDACTED__",
15+
"pretty": "__REDACTED__"
16+
},
17+
"parse": {
18+
"ms": "__REDACTED__",
19+
"pretty": "__REDACTED__"
20+
},
21+
"total": {
22+
"ms": "__REDACTED__",
23+
"pretty": "__REDACTED__"
24+
}
1725
},
18-
"totalLoadDuration": {
19-
"ms": "REDACTED",
20-
"pretty": "REDACTED"
21-
},
22-
"totalParseDuration": {
23-
"ms": "REDACTED",
24-
"pretty": "REDACTED"
25-
}
26+
"numberOfFiles": 4,
27+
"numberOfManifests": 2
2628
}
2729
},
2830
"severity": "note",

0 commit comments

Comments
 (0)