diff options
-rw-r--r-- | Cargo.lock | 20 | ||||
-rw-r--r-- | crates/ra_prof/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_prof/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_prof/src/stop_watch.rs | 79 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/analysis_stats.rs | 41 |
5 files changed, 125 insertions, 20 deletions
diff --git a/Cargo.lock b/Cargo.lock index 3e685b7f1..e63dcc530 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -841,6 +841,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
841 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" | 841 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" |
842 | 842 | ||
843 | [[package]] | 843 | [[package]] |
844 | name = "perf-event" | ||
845 | version = "0.4.3" | ||
846 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
847 | checksum = "0cb38a2f363560fb3cfcb47f28848b245a41c7e0d63e0b190918b712b6bf6803" | ||
848 | dependencies = [ | ||
849 | "libc", | ||
850 | "perf-event-open-sys", | ||
851 | ] | ||
852 | |||
853 | [[package]] | ||
854 | name = "perf-event-open-sys" | ||
855 | version = "0.3.1" | ||
856 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
857 | checksum = "95db63e37862bc1b842135d2234ef9418f222cc660c6752f45e7cf9ddfb97f96" | ||
858 | dependencies = [ | ||
859 | "libc", | ||
860 | ] | ||
861 | |||
862 | [[package]] | ||
844 | name = "petgraph" | 863 | name = "petgraph" |
845 | version = "0.5.1" | 864 | version = "0.5.1" |
846 | source = "registry+https://github.com/rust-lang/crates.io-index" | 865 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1126,6 +1145,7 @@ dependencies = [ | |||
1126 | "cfg-if", | 1145 | "cfg-if", |
1127 | "libc", | 1146 | "libc", |
1128 | "once_cell", | 1147 | "once_cell", |
1148 | "perf-event", | ||
1129 | "ra_arena", | 1149 | "ra_arena", |
1130 | ] | 1150 | ] |
1131 | 1151 | ||
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml index 6c214501e..c82b9f76d 100644 --- a/crates/ra_prof/Cargo.toml +++ b/crates/ra_prof/Cargo.toml | |||
@@ -16,6 +16,9 @@ backtrace = { version = "0.3.44", optional = true } | |||
16 | cfg-if = "0.1.10" | 16 | cfg-if = "0.1.10" |
17 | libc = "0.2.73" | 17 | libc = "0.2.73" |
18 | 18 | ||
19 | [target.'cfg(target_os = "linux")'.dependencies] | ||
20 | perf-event = "0.4" | ||
21 | |||
19 | [features] | 22 | [features] |
20 | cpu_profiler = [] | 23 | cpu_profiler = [] |
21 | 24 | ||
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs index ba5609703..eb50965ae 100644 --- a/crates/ra_prof/src/lib.rs +++ b/crates/ra_prof/src/lib.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! A collection of tools for profiling rust-analyzer. | 1 | //! A collection of tools for profiling rust-analyzer. |
2 | 2 | ||
3 | mod stop_watch; | ||
3 | mod memory_usage; | 4 | mod memory_usage; |
4 | #[cfg(feature = "cpu_profiler")] | 5 | #[cfg(feature = "cpu_profiler")] |
5 | mod google_cpu_profiler; | 6 | mod google_cpu_profiler; |
@@ -11,6 +12,7 @@ use std::cell::RefCell; | |||
11 | pub use crate::{ | 12 | pub use crate::{ |
12 | hprof::{init, init_from, profile}, | 13 | hprof::{init, init_from, profile}, |
13 | memory_usage::{Bytes, MemoryUsage}, | 14 | memory_usage::{Bytes, MemoryUsage}, |
15 | stop_watch::{StopWatch, StopWatchSpan}, | ||
14 | }; | 16 | }; |
15 | 17 | ||
16 | /// Prints backtrace to stderr, useful for debugging. | 18 | /// Prints backtrace to stderr, useful for debugging. |
diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs new file mode 100644 index 000000000..8b8ec25a5 --- /dev/null +++ b/crates/ra_prof/src/stop_watch.rs | |||
@@ -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 | } | ||
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index cf0d82b62..73ec3204b 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | use std::{ | 4 | use std::{ |
5 | path::Path, | 5 | path::Path, |
6 | time::{Instant, SystemTime, UNIX_EPOCH}, | 6 | time::{SystemTime, UNIX_EPOCH}, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use hir::{ | 9 | use hir::{ |
@@ -29,6 +29,7 @@ use crate::{ | |||
29 | }, | 29 | }, |
30 | print_memory_usage, | 30 | print_memory_usage, |
31 | }; | 31 | }; |
32 | use ra_prof::StopWatch; | ||
32 | 33 | ||
33 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | 34 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` |
34 | struct Snap<DB>(DB); | 35 | struct Snap<DB>(DB); |
@@ -54,11 +55,12 @@ pub fn analysis_stats( | |||
54 | Rand32::new(seed) | 55 | Rand32::new(seed) |
55 | }; | 56 | }; |
56 | 57 | ||
57 | let db_load_time = Instant::now(); | 58 | let mut db_load_sw = StopWatch::start().memory(memory_usage); |
58 | let (host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?; | 59 | let (host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?; |
59 | let db = host.raw_database(); | 60 | let db = host.raw_database(); |
60 | eprintln!("Database loaded {:?}", db_load_time.elapsed()); | 61 | eprintln!("Database loaded {}", db_load_sw.elapsed()); |
61 | let analysis_time = Instant::now(); | 62 | |
63 | let mut analysis_sw = StopWatch::start().memory(memory_usage); | ||
62 | let mut num_crates = 0; | 64 | let mut num_crates = 0; |
63 | let mut visited_modules = FxHashSet::default(); | 65 | let mut visited_modules = FxHashSet::default(); |
64 | let mut visit_queue = Vec::new(); | 66 | let mut visit_queue = Vec::new(); |
@@ -110,8 +112,7 @@ pub fn analysis_stats( | |||
110 | eprintln!("Total modules found: {}", visited_modules.len()); | 112 | eprintln!("Total modules found: {}", visited_modules.len()); |
111 | eprintln!("Total declarations: {}", num_decls); | 113 | eprintln!("Total declarations: {}", num_decls); |
112 | eprintln!("Total functions: {}", funcs.len()); | 114 | eprintln!("Total functions: {}", funcs.len()); |
113 | let item_collection_memory = ra_prof::memory_usage(); | 115 | eprintln!("Item Collection: {}", analysis_sw.elapsed()); |
114 | eprintln!("Item Collection: {:?}, {}", analysis_time.elapsed(), item_collection_memory); | ||
115 | 116 | ||
116 | if randomize { | 117 | if randomize { |
117 | shuffle(&mut rng, &mut funcs); | 118 | shuffle(&mut rng, &mut funcs); |
@@ -119,11 +120,12 @@ pub fn analysis_stats( | |||
119 | 120 | ||
120 | let mut bar = match verbosity { | 121 | let mut bar = match verbosity { |
121 | Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), | 122 | Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), |
123 | _ if parallel => ProgressReport::hidden(), | ||
122 | _ => ProgressReport::new(funcs.len() as u64), | 124 | _ => ProgressReport::new(funcs.len() as u64), |
123 | }; | 125 | }; |
124 | 126 | ||
125 | if parallel { | 127 | if parallel { |
126 | let inference_time = Instant::now(); | 128 | let mut inference_sw = StopWatch::start().memory(memory_usage); |
127 | let snap = Snap(db.snapshot()); | 129 | let snap = Snap(db.snapshot()); |
128 | funcs | 130 | funcs |
129 | .par_iter() | 131 | .par_iter() |
@@ -133,14 +135,10 @@ pub fn analysis_stats( | |||
133 | snap.0.infer(f_id.into()); | 135 | snap.0.infer(f_id.into()); |
134 | }) | 136 | }) |
135 | .count(); | 137 | .count(); |
136 | eprintln!( | 138 | eprintln!("Parallel Inference: {}", inference_sw.elapsed()); |
137 | "Parallel Inference: {:?}, {}", | ||
138 | inference_time.elapsed(), | ||
139 | ra_prof::memory_usage() | ||
140 | ); | ||
141 | } | 139 | } |
142 | 140 | ||
143 | let inference_time = Instant::now(); | 141 | let mut inference_sw = StopWatch::start().memory(memory_usage); |
144 | bar.tick(); | 142 | bar.tick(); |
145 | let mut num_exprs = 0; | 143 | let mut num_exprs = 0; |
146 | let mut num_exprs_unknown = 0; | 144 | let mut num_exprs_unknown = 0; |
@@ -291,14 +289,17 @@ pub fn analysis_stats( | |||
291 | eprintln!("Type mismatches: {}", num_type_mismatches); | 289 | eprintln!("Type mismatches: {}", num_type_mismatches); |
292 | report_metric("type mismatches", num_type_mismatches, "#"); | 290 | report_metric("type mismatches", num_type_mismatches, "#"); |
293 | 291 | ||
294 | let inference_time = inference_time.elapsed(); | 292 | eprintln!("Inference: {}", inference_sw.elapsed()); |
295 | let total_memory = ra_prof::memory_usage(); | ||
296 | eprintln!("Inference: {:?}, {}", inference_time, total_memory - item_collection_memory); | ||
297 | 293 | ||
298 | let analysis_time = analysis_time.elapsed(); | 294 | let total_span = analysis_sw.elapsed(); |
299 | eprintln!("Total: {:?}, {}", analysis_time, total_memory); | 295 | eprintln!("Total: {}", total_span); |
300 | report_metric("total time", analysis_time.as_millis() as u64, "ms"); | 296 | report_metric("total time", total_span.time.as_millis() as u64, "ms"); |
301 | report_metric("total memory", total_memory.allocated.megabytes() as u64, "MB"); | 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 | } | ||
302 | 303 | ||
303 | if memory_usage { | 304 | if memory_usage { |
304 | print_memory_usage(host, vfs); | 305 | print_memory_usage(host, vfs); |