Skip to content

Commit f83aebc

Browse files
authored
Capture Performance metrics (#108)
1 parent 8299d1d commit f83aebc

File tree

6 files changed

+99
-55
lines changed

6 files changed

+99
-55
lines changed

crates/pet-core/src/telemetry/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44
use inaccurate_python_info::InaccuratePythonEnvironmentInfo;
55
use missing_conda_info::MissingCondaEnvironments;
66
use missing_poetry_info::MissingPoetryEnvironments;
7+
use refresh_performance::RefreshPerformance;
78
use serde::{Deserialize, Serialize};
89

910
pub mod inaccurate_python_info;
1011
pub mod missing_conda_info;
1112
pub mod missing_poetry_info;
13+
pub mod refresh_performance;
1214

1315
pub type NumberOfCustomSearchPaths = u32;
1416

1517
#[derive(Serialize, Deserialize)]
1618
#[serde(rename_all = "camelCase")]
17-
#[derive(Debug, Clone, Copy)]
19+
#[derive(Debug, Clone)]
1820
pub enum TelemetryEvent {
1921
/// Total time taken to search for Global environments.
2022
GlobalEnvironmentsSearchCompleted(std::time::Duration),
@@ -34,6 +36,8 @@ pub enum TelemetryEvent {
3436
MissingCondaEnvironments(MissingCondaEnvironments),
3537
/// Sent when an environment is discovered by spawning poetry and not found otherwise.
3638
MissingPoetryEnvironments(MissingPoetryEnvironments),
39+
/// Telemetry with metrics for finding all environments as a result of refresh.
40+
RefreshPerformance(RefreshPerformance),
3741
}
3842

3943
pub fn get_telemetry_event_name(event: &TelemetryEvent) -> &'static str {
@@ -52,5 +56,6 @@ pub fn get_telemetry_event_name(event: &TelemetryEvent) -> &'static str {
5256
TelemetryEvent::InaccuratePythonEnvironmentInfo(_) => "InaccuratePythonEnvironmentInfo",
5357
TelemetryEvent::MissingCondaEnvironments(_) => "MissingCondaEnvironments",
5458
TelemetryEvent::MissingPoetryEnvironments(_) => "MissingPoetryEnvironments",
59+
TelemetryEvent::RefreshPerformance(_) => "RefreshPerformance",
5560
}
5661
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use std::collections::BTreeMap;
5+
6+
use serde::{Deserialize, Serialize};
7+
8+
/// Telemetry with metrics for finding all environments as a result of refresh.
9+
/// All durations are in milliseconds.
10+
#[derive(Serialize, Deserialize)]
11+
#[serde(rename_all = "camelCase")]
12+
#[derive(Debug, Clone)]
13+
pub struct RefreshPerformance {
14+
/// Total time taken to find all envs.
15+
pub total: u128,
16+
/// Breakdown of Global VirtualEnvs, Path, Workspace and the locators.
17+
pub breakdown: BTreeMap<String, u128>,
18+
/// Breakdown of each individual locators such as conda, pyenv, etc.
19+
pub locators: BTreeMap<String, u128>,
20+
}

crates/pet-reporter/src/jsonrpc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl Reporter for JsonRpcReporter {
2626
fn report_telemetry(&self, event: &TelemetryEvent) {
2727
let event = TelemetryData {
2828
event: get_telemetry_event_name(event).to_string(),
29-
data: *event,
29+
data: event.clone(),
3030
};
3131
trace!("Telemetry event {:?}", event.event);
3232
send_message("telemetry", Some(event))

crates/pet/src/find.rs

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,9 @@ use std::{sync::Arc, thread};
2424
use crate::locators::identify_python_environment_using_locators;
2525

2626
pub struct Summary {
27-
pub time: Duration,
28-
pub find_locators_times: BTreeMap<&'static str, Duration>,
29-
pub find_locators_time: Duration,
30-
pub find_path_time: Duration,
31-
pub find_global_virtual_envs_time: Duration,
32-
pub find_workspace_directories_time: Duration,
27+
pub total: Duration,
28+
pub locators: BTreeMap<&'static str, Duration>,
29+
pub breakdown: BTreeMap<&'static str, Duration>,
3330
}
3431

3532
#[derive(Debug, Clone, Deserialize, Serialize)]
@@ -49,12 +46,9 @@ pub fn find_and_report_envs(
4946
search_scope: Option<SearchScope>,
5047
) -> Arc<Mutex<Summary>> {
5148
let summary = Arc::new(Mutex::new(Summary {
52-
time: Duration::from_secs(0),
53-
find_locators_times: BTreeMap::new(),
54-
find_locators_time: Duration::from_secs(0),
55-
find_path_time: Duration::from_secs(0),
56-
find_global_virtual_envs_time: Duration::from_secs(0),
57-
find_workspace_directories_time: Duration::from_secs(0),
49+
total: Duration::from_secs(0),
50+
locators: BTreeMap::new(),
51+
breakdown: BTreeMap::new(),
5852
}));
5953
let start = std::time::Instant::now();
6054

@@ -88,13 +82,17 @@ pub fn find_and_report_envs(
8882
summary
8983
.lock()
9084
.unwrap()
91-
.find_locators_times
85+
.locators
9286
.insert(locator.get_name(), start.elapsed());
9387
});
9488
}
9589
});
9690
}
97-
summary.lock().unwrap().find_locators_time = start.elapsed();
91+
summary
92+
.lock()
93+
.unwrap()
94+
.breakdown
95+
.insert("Locators", start.elapsed());
9896
});
9997
// Step 2: Search in PATH variable
10098
s.spawn(|| {
@@ -115,7 +113,11 @@ pub fn find_and_report_envs(
115113
&global_env_search_paths,
116114
);
117115
}
118-
summary.lock().unwrap().find_path_time = start.elapsed();
116+
summary
117+
.lock()
118+
.unwrap()
119+
.breakdown
120+
.insert("Path", start.elapsed());
119121
});
120122
// Step 3: Search in some global locations for virtual envs.
121123
s.spawn(|| {
@@ -146,7 +148,11 @@ pub fn find_and_report_envs(
146148
&global_env_search_paths,
147149
);
148150
}
149-
summary.lock().unwrap().find_global_virtual_envs_time = start.elapsed();
151+
summary
152+
.lock()
153+
.unwrap()
154+
.breakdown
155+
.insert("GlobalVirtualEnvs", start.elapsed());
150156
});
151157
// Step 4: Find in workspace folders too.
152158
// This can be merged with step 2 as well, as we're only look for environments
@@ -176,10 +182,14 @@ pub fn find_and_report_envs(
176182
});
177183
}
178184
}
179-
summary.lock().unwrap().find_workspace_directories_time = start.elapsed();
185+
summary
186+
.lock()
187+
.unwrap()
188+
.breakdown
189+
.insert("Workspaces", start.elapsed());
180190
});
181191
});
182-
summary.lock().unwrap().time = start.elapsed();
192+
summary.lock().unwrap().total = start.elapsed();
183193

184194
summary
185195
}

crates/pet/src/jsonrpc.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ use pet::resolve::resolve_environment;
66
use pet_conda::Conda;
77
use pet_conda::CondaLocator;
88
use pet_core::python_environment::PythonEnvironment;
9+
use pet_core::telemetry::refresh_performance::RefreshPerformance;
10+
use pet_core::telemetry::TelemetryEvent;
911
use pet_core::{
1012
os_environment::{Environment, EnvironmentApi},
13+
reporter::Reporter,
1114
Configuration, Locator,
1215
};
1316
use pet_env_var_path::get_search_paths_from_env_variables;
@@ -21,14 +24,17 @@ use pet_reporter::collect;
2124
use pet_reporter::{cache::CacheReporter, jsonrpc};
2225
use pet_telemetry::report_inaccuracies_identified_after_resolving;
2326
use serde::{Deserialize, Serialize};
27+
use serde_json::json;
2428
use serde_json::{self, Value};
29+
use std::collections::BTreeMap;
2530
use std::sync::atomic::{AtomicBool, Ordering};
31+
use std::time::Duration;
2632
use std::{
2733
ops::Deref,
2834
path::PathBuf,
2935
sync::{Arc, RwLock},
3036
thread,
31-
time::{Duration, SystemTime},
37+
time::SystemTime,
3238
};
3339

3440
use crate::find::find_and_report_envs;
@@ -132,6 +138,10 @@ impl RefreshResult {
132138
}
133139

134140
pub fn handle_refresh(context: Arc<Context>, id: u32, params: Value) {
141+
let params = match params {
142+
Value::Null => json!({}),
143+
_ => params,
144+
};
135145
match serde_json::from_value::<RefreshOptions>(params.clone()) {
136146
Ok(refres_options) => {
137147
// Start in a new thread, we can have multiple requests.
@@ -148,25 +158,31 @@ pub fn handle_refresh(context: Arc<Context>, id: u32, params: Value) {
148158
refres_options.search_scope,
149159
);
150160
let summary = summary.lock().unwrap();
151-
for locator in summary.find_locators_times.iter() {
161+
for locator in summary.locators.iter() {
152162
info!("Locator {} took {:?}", locator.0, locator.1);
153163
}
154-
info!(
155-
"Environments found using locators in {:?}",
156-
summary.find_locators_time
157-
);
158-
info!("Environments in PATH found in {:?}", summary.find_path_time);
159-
info!(
160-
"Environments in global virtual env paths found in {:?}",
161-
summary.find_global_virtual_envs_time
162-
);
163-
info!(
164-
"Environments in workspace folders found in {:?}",
165-
summary.find_workspace_directories_time
166-
);
167-
trace!("Finished refreshing environments in {:?}", summary.time);
168-
send_reply(id, Some(RefreshResult::new(summary.time)));
164+
for item in summary.breakdown.iter() {
165+
info!("Locator {} took {:?}", item.0, item.1);
166+
}
167+
trace!("Finished refreshing environments in {:?}", summary.total);
168+
send_reply(id, Some(RefreshResult::new(summary.total)));
169169

170+
let perf = RefreshPerformance {
171+
total: summary.total.as_millis(),
172+
locators: summary
173+
.locators
174+
.clone()
175+
.iter()
176+
.map(|(k, v)| (k.to_string(), v.as_millis()))
177+
.collect::<BTreeMap<String, u128>>(),
178+
breakdown: summary
179+
.breakdown
180+
.clone()
181+
.iter()
182+
.map(|(k, v)| (k.to_string(), v.as_millis()))
183+
.collect::<BTreeMap<String, u128>>(),
184+
};
185+
reporter.report_telemetry(&TelemetryEvent::RefreshPerformance(perf));
170186
// Find an report missing envs for the first launch of this process.
171187
if MISSING_ENVS_REPORTED
172188
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)

crates/pet/src/lib.rs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -125,32 +125,25 @@ fn find_envs(
125125

126126
if options.print_summary {
127127
let summary = summary.lock().unwrap();
128-
if !summary.find_locators_times.is_empty() {
128+
if !summary.locators.is_empty() {
129129
println!();
130130
println!("Breakdown by each locator:");
131131
println!("--------------------------");
132-
for locator in summary.find_locators_times.iter() {
132+
for locator in summary.locators.iter() {
133133
println!("{:<20} : {:?}", locator.0, locator.1);
134134
}
135+
println!()
136+
}
137+
138+
if !summary.breakdown.is_empty() {
139+
println!("Breakdown for finding Environments:");
140+
println!("-----------------------------------");
141+
for item in summary.breakdown.iter() {
142+
println!("{:<20} : {:?}", item.0, item.1);
143+
}
135144
println!();
136145
}
137146

138-
println!("Breakdown for finding Environments:");
139-
println!("-----------------------------------");
140-
println!(
141-
"{:<20} : {:?}",
142-
"Using locators", summary.find_locators_time
143-
);
144-
println!("{:<20} : {:?}", "PATH Variable", summary.find_path_time);
145-
println!(
146-
"{:<20} : {:?}",
147-
"Global virtual envs", summary.find_global_virtual_envs_time
148-
);
149-
println!(
150-
"{:<20} : {:?}",
151-
"Workspace folders", summary.find_workspace_directories_time
152-
);
153-
println!();
154147
let summary = stdio_reporter.get_summary();
155148
if !summary.managers.is_empty() {
156149
println!("Managers:");

0 commit comments

Comments
 (0)