Skip to content

Commit 72ffd85

Browse files
bors[bot]matklad
andauthored
Merge #5581
5581: Measure instructions in addition to time r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents c8573c4 + f22af66 commit 72ffd85

File tree

5 files changed

+125
-20
lines changed

5 files changed

+125
-20
lines changed

Cargo.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_prof/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ backtrace = { version = "0.3.44", optional = true }
1616
cfg-if = "0.1.10"
1717
libc = "0.2.73"
1818

19+
[target.'cfg(target_os = "linux")'.dependencies]
20+
perf-event = "0.4"
21+
1922
[features]
2023
cpu_profiler = []
2124

crates/ra_prof/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! A collection of tools for profiling rust-analyzer.
22
3+
mod stop_watch;
34
mod memory_usage;
45
#[cfg(feature = "cpu_profiler")]
56
mod google_cpu_profiler;
@@ -11,6 +12,7 @@ use std::cell::RefCell;
1112
pub use crate::{
1213
hprof::{init, init_from, profile},
1314
memory_usage::{Bytes, MemoryUsage},
15+
stop_watch::{StopWatch, StopWatchSpan},
1416
};
1517

1618
/// Prints backtrace to stderr, useful for debugging.

crates/ra_prof/src/stop_watch.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//! Like `std::time::Instant`, but also measures memory & CPU cycles.
2+
use std::{
3+
fmt,
4+
time::{Duration, Instant},
5+
};
6+
7+
use crate::MemoryUsage;
8+
9+
pub struct StopWatch {
10+
time: Instant,
11+
#[cfg(target_os = "linux")]
12+
counter: Option<perf_event::Counter>,
13+
memory: Option<MemoryUsage>,
14+
}
15+
16+
pub struct StopWatchSpan {
17+
pub time: Duration,
18+
pub instructions: Option<u64>,
19+
pub memory: Option<MemoryUsage>,
20+
}
21+
22+
impl StopWatch {
23+
pub fn start() -> StopWatch {
24+
#[cfg(target_os = "linux")]
25+
let counter = {
26+
let mut counter = perf_event::Builder::new().build().ok();
27+
if let Some(counter) = &mut counter {
28+
let _ = counter.enable();
29+
}
30+
counter
31+
};
32+
let time = Instant::now();
33+
StopWatch {
34+
time,
35+
#[cfg(target_os = "linux")]
36+
counter,
37+
memory: None,
38+
}
39+
}
40+
pub fn memory(mut self, yes: bool) -> StopWatch {
41+
if yes {
42+
self.memory = Some(MemoryUsage::current());
43+
}
44+
self
45+
}
46+
pub fn elapsed(&mut self) -> StopWatchSpan {
47+
let time = self.time.elapsed();
48+
49+
#[cfg(target_os = "linux")]
50+
let instructions = self.counter.as_mut().and_then(|it| it.read().ok());
51+
#[cfg(not(target_os = "linux"))]
52+
let instructions = None;
53+
54+
let memory = self.memory.map(|it| MemoryUsage::current() - it);
55+
StopWatchSpan { time, instructions, memory }
56+
}
57+
}
58+
59+
impl fmt::Display for StopWatchSpan {
60+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61+
write!(f, "{:.2?}", self.time)?;
62+
if let Some(mut instructions) = self.instructions {
63+
let mut prefix = "";
64+
if instructions > 10000 {
65+
instructions /= 1000;
66+
prefix = "k"
67+
}
68+
if instructions > 10000 {
69+
instructions /= 1000;
70+
prefix = "m"
71+
}
72+
write!(f, ", {}{}i", instructions, prefix)?;
73+
}
74+
if let Some(memory) = self.memory {
75+
write!(f, ", {}", memory)?;
76+
}
77+
Ok(())
78+
}
79+
}

crates/rust-analyzer/src/cli/analysis_stats.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use std::{
55
path::Path,
6-
time::{Instant, SystemTime, UNIX_EPOCH},
6+
time::{SystemTime, UNIX_EPOCH},
77
};
88

99
use hir::{
@@ -29,6 +29,7 @@ use crate::{
2929
},
3030
print_memory_usage,
3131
};
32+
use ra_prof::StopWatch;
3233

3334
/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
3435
struct Snap<DB>(DB);
@@ -54,11 +55,12 @@ pub fn analysis_stats(
5455
Rand32::new(seed)
5556
};
5657

57-
let db_load_time = Instant::now();
58+
let mut db_load_sw = StopWatch::start().memory(memory_usage);
5859
let (host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
5960
let db = host.raw_database();
60-
eprintln!("Database loaded {:?}", db_load_time.elapsed());
61-
let analysis_time = Instant::now();
61+
eprintln!("Database loaded {}", db_load_sw.elapsed());
62+
63+
let mut analysis_sw = StopWatch::start().memory(memory_usage);
6264
let mut num_crates = 0;
6365
let mut visited_modules = FxHashSet::default();
6466
let mut visit_queue = Vec::new();
@@ -110,20 +112,20 @@ pub fn analysis_stats(
110112
eprintln!("Total modules found: {}", visited_modules.len());
111113
eprintln!("Total declarations: {}", num_decls);
112114
eprintln!("Total functions: {}", funcs.len());
113-
let item_collection_memory = ra_prof::memory_usage();
114-
eprintln!("Item Collection: {:?}, {}", analysis_time.elapsed(), item_collection_memory);
115+
eprintln!("Item Collection: {}", analysis_sw.elapsed());
115116

116117
if randomize {
117118
shuffle(&mut rng, &mut funcs);
118119
}
119120

120121
let mut bar = match verbosity {
121122
Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
123+
_ if parallel => ProgressReport::hidden(),
122124
_ => ProgressReport::new(funcs.len() as u64),
123125
};
124126

125127
if parallel {
126-
let inference_time = Instant::now();
128+
let mut inference_sw = StopWatch::start().memory(memory_usage);
127129
let snap = Snap(db.snapshot());
128130
funcs
129131
.par_iter()
@@ -133,14 +135,10 @@ pub fn analysis_stats(
133135
snap.0.infer(f_id.into());
134136
})
135137
.count();
136-
eprintln!(
137-
"Parallel Inference: {:?}, {}",
138-
inference_time.elapsed(),
139-
ra_prof::memory_usage()
140-
);
138+
eprintln!("Parallel Inference: {}", inference_sw.elapsed());
141139
}
142140

143-
let inference_time = Instant::now();
141+
let mut inference_sw = StopWatch::start().memory(memory_usage);
144142
bar.tick();
145143
let mut num_exprs = 0;
146144
let mut num_exprs_unknown = 0;
@@ -291,14 +289,17 @@ pub fn analysis_stats(
291289
eprintln!("Type mismatches: {}", num_type_mismatches);
292290
report_metric("type mismatches", num_type_mismatches, "#");
293291

294-
let inference_time = inference_time.elapsed();
295-
let total_memory = ra_prof::memory_usage();
296-
eprintln!("Inference: {:?}, {}", inference_time, total_memory - item_collection_memory);
292+
eprintln!("Inference: {}", inference_sw.elapsed());
297293

298-
let analysis_time = analysis_time.elapsed();
299-
eprintln!("Total: {:?}, {}", analysis_time, total_memory);
300-
report_metric("total time", analysis_time.as_millis() as u64, "ms");
301-
report_metric("total memory", total_memory.allocated.megabytes() as u64, "MB");
294+
let total_span = analysis_sw.elapsed();
295+
eprintln!("Total: {}", total_span);
296+
report_metric("total time", total_span.time.as_millis() as u64, "ms");
297+
if let Some(instructions) = total_span.instructions {
298+
report_metric("total time", instructions, "#instr");
299+
}
300+
if let Some(memory) = total_span.memory {
301+
report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
302+
}
302303

303304
if memory_usage {
304305
print_memory_usage(host, vfs);

0 commit comments

Comments
 (0)