Skip to content

Commit 391d7df

Browse files
committed
add command profiler
1 parent e804cd4 commit 391d7df

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

src/bootstrap/src/utils/exec.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,65 @@ pub struct CommandCacheKey {
7272
cwd: Option<PathBuf>,
7373
}
7474

75+
#[derive(Default, Clone)]
76+
pub struct CommandProfile {
77+
pub count: usize,
78+
pub total_duration: Duration,
79+
}
80+
81+
#[derive(Default)]
82+
pub struct CommandProfiler {
83+
stats: Mutex<HashMap<CommandCacheKey, CommandProfile>>,
84+
}
85+
86+
87+
impl CommandProfiler {
88+
pub fn record(&self, key: CommandCacheKey, duration: Duration) {
89+
let mut stats = self.stats.lock().unwrap();
90+
let entry = stats.entry(key).or_default();
91+
entry.count += 1;
92+
entry.total_duration += duration;
93+
}
94+
95+
pub fn report_slowest(&self, top_n: usize) {
96+
let stats = self.stats.lock().unwrap();
97+
let mut entries: Vec<_> = stats.iter().collect();
98+
entries.sort_by_key(|(_, stat)| std::cmp::Reverse(stat.total_duration));
99+
100+
println!("\nTop {top_n} slowest commands:");
101+
for (key, profile) in entries.into_iter().take(top_n) {
102+
println!(
103+
"- {:?} (count: {}, total: {:.2?}, avg: {:.2?})",
104+
key.program,
105+
profile.count,
106+
profile.total_duration,
107+
profile.total_duration / profile.count as u32
108+
);
109+
}
110+
}
111+
112+
pub fn to_json(&self) -> serde_json::Value {
113+
use serde_json::json;
114+
115+
let stats = self.stats.lock().unwrap();
116+
let entries: Vec<_> = stats
117+
.iter()
118+
.map(|(key, profile)| {
119+
json!({
120+
"program": key.program,
121+
"args": key.args,
122+
"envs": key.envs,
123+
"cwd": key.cwd,
124+
"count": profile.count,
125+
"total_duration_ms": profile.total_duration.as_millis(),
126+
})
127+
})
128+
.collect();
129+
130+
json!({ "commands": entries })
131+
}
132+
}
133+
75134
/// Wrapper around `std::process::Command`.
76135
///
77136
/// By default, the command will exit bootstrap if it fails.

0 commit comments

Comments
 (0)