aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_prof/src/memory_usage.rs6
-rw-r--r--crates/rust-analyzer/src/cli.rs7
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs59
-rw-r--r--crates/rust-analyzer/src/lib.rs2
-rw-r--r--xtask/src/metrics.rs55
-rw-r--r--xtask/src/not_bash.rs3
6 files changed, 102 insertions, 30 deletions
diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs
index ee79ec3ee..745345fac 100644
--- a/crates/ra_prof/src/memory_usage.rs
+++ b/crates/ra_prof/src/memory_usage.rs
@@ -31,6 +31,12 @@ impl fmt::Display for MemoryUsage {
31#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] 31#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
32pub struct Bytes(usize); 32pub struct Bytes(usize);
33 33
34impl Bytes {
35 pub fn megabytes(self) -> usize {
36 self.0 / 1024 / 1024
37 }
38}
39
34impl fmt::Display for Bytes { 40impl fmt::Display for Bytes {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 let bytes = self.0; 42 let bytes = self.0;
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index 753001949..a9b9c8923 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -74,3 +74,10 @@ fn read_stdin() -> Result<String> {
74 std::io::stdin().read_to_string(&mut buff)?; 74 std::io::stdin().read_to_string(&mut buff)?;
75 Ok(buff) 75 Ok(buff)
76} 76}
77
78fn report_metric(metric: &str, value: u64, unit: &str) {
79 if std::env::var("RA_METRICS").is_err() {
80 return;
81 }
82 println!("METRIC:{}:{}:{}", metric, value, unit)
83}
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index ddb3db6c3..10327ebb9 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -3,26 +3,27 @@
3 3
4use std::{path::Path, time::Instant}; 4use std::{path::Path, time::Instant};
5 5
6use itertools::Itertools;
7use rand::{seq::SliceRandom, thread_rng};
8use rayon::prelude::*;
9use rustc_hash::FxHashSet;
10
11use hir::{ 6use hir::{
12 db::{AstDatabase, DefDatabase, HirDatabase}, 7 db::{AstDatabase, DefDatabase, HirDatabase},
13 original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef, 8 original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
14}; 9};
15use hir_def::FunctionId; 10use hir_def::FunctionId;
16use hir_ty::{Ty, TypeWalk}; 11use hir_ty::{Ty, TypeWalk};
12use itertools::Itertools;
17use ra_db::{ 13use ra_db::{
18 salsa::{self, ParallelDatabase}, 14 salsa::{self, ParallelDatabase},
19 SourceDatabaseExt, 15 SourceDatabaseExt,
20}; 16};
21use ra_syntax::AstNode; 17use ra_syntax::AstNode;
18use rand::{seq::SliceRandom, thread_rng};
19use rayon::prelude::*;
20use rustc_hash::FxHashSet;
22use stdx::format_to; 21use stdx::format_to;
23 22
24use crate::{ 23use crate::{
25 cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity}, 24 cli::{
25 load_cargo::load_cargo, progress_report::ProgressReport, report_metric, Result, Verbosity,
26 },
26 print_memory_usage, 27 print_memory_usage,
27}; 28};
28 29
@@ -48,7 +49,7 @@ pub fn analysis_stats(
48 let db_load_time = Instant::now(); 49 let db_load_time = Instant::now();
49 let (host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?; 50 let (host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
50 let db = host.raw_database(); 51 let db = host.raw_database();
51 println!("Database loaded {:?}", db_load_time.elapsed()); 52 eprintln!("Database loaded {:?}", db_load_time.elapsed());
52 let analysis_time = Instant::now(); 53 let analysis_time = Instant::now();
53 let mut num_crates = 0; 54 let mut num_crates = 0;
54 let mut visited_modules = FxHashSet::default(); 55 let mut visited_modules = FxHashSet::default();
@@ -74,7 +75,7 @@ pub fn analysis_stats(
74 visit_queue.shuffle(&mut thread_rng()); 75 visit_queue.shuffle(&mut thread_rng());
75 } 76 }
76 77
77 println!("Crates in this dir: {}", num_crates); 78 eprintln!("Crates in this dir: {}", num_crates);
78 let mut num_decls = 0; 79 let mut num_decls = 0;
79 let mut funcs = Vec::new(); 80 let mut funcs = Vec::new();
80 while let Some(module) = visit_queue.pop() { 81 while let Some(module) = visit_queue.pop() {
@@ -98,10 +99,15 @@ pub fn analysis_stats(
98 } 99 }
99 } 100 }
100 } 101 }
101 println!("Total modules found: {}", visited_modules.len()); 102 eprintln!("Total modules found: {}", visited_modules.len());
102 println!("Total declarations: {}", num_decls); 103 eprintln!("Total declarations: {}", num_decls);
103 println!("Total functions: {}", funcs.len()); 104 eprintln!("Total functions: {}", funcs.len());
104 println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); 105 let item_collection_memory = ra_prof::memory_usage();
106 eprintln!(
107 "Item Collection: {:?}, {}",
108 analysis_time.elapsed(),
109 item_collection_memory.allocated
110 );
105 111
106 if randomize { 112 if randomize {
107 funcs.shuffle(&mut thread_rng()); 113 funcs.shuffle(&mut thread_rng());
@@ -123,7 +129,11 @@ pub fn analysis_stats(
123 snap.0.infer(f_id.into()); 129 snap.0.infer(f_id.into());
124 }) 130 })
125 .count(); 131 .count();
126 println!("Parallel Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage()); 132 eprintln!(
133 "Parallel Inference: {:?}, {}",
134 inference_time.elapsed(),
135 ra_prof::memory_usage().allocated
136 );
127 } 137 }
128 138
129 let inference_time = Instant::now(); 139 let inference_time = Instant::now();
@@ -260,20 +270,31 @@ pub fn analysis_stats(
260 bar.inc(1); 270 bar.inc(1);
261 } 271 }
262 bar.finish_and_clear(); 272 bar.finish_and_clear();
263 println!("Total expressions: {}", num_exprs); 273 eprintln!("Total expressions: {}", num_exprs);
264 println!( 274 eprintln!(
265 "Expressions of unknown type: {} ({}%)", 275 "Expressions of unknown type: {} ({}%)",
266 num_exprs_unknown, 276 num_exprs_unknown,
267 if num_exprs > 0 { num_exprs_unknown * 100 / num_exprs } else { 100 } 277 if num_exprs > 0 { num_exprs_unknown * 100 / num_exprs } else { 100 }
268 ); 278 );
269 println!( 279 eprintln!(
270 "Expressions of partially unknown type: {} ({}%)", 280 "Expressions of partially unknown type: {} ({}%)",
271 num_exprs_partially_unknown, 281 num_exprs_partially_unknown,
272 if num_exprs > 0 { num_exprs_partially_unknown * 100 / num_exprs } else { 100 } 282 if num_exprs > 0 { num_exprs_partially_unknown * 100 / num_exprs } else { 100 }
273 ); 283 );
274 println!("Type mismatches: {}", num_type_mismatches); 284 eprintln!("Type mismatches: {}", num_type_mismatches);
275 println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage()); 285
276 println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); 286 let inference_time = inference_time.elapsed();
287 let total_memory = ra_prof::memory_usage();
288 eprintln!(
289 "Inference: {:?}, {}",
290 inference_time,
291 total_memory.allocated - item_collection_memory.allocated
292 );
293
294 let analysis_time = analysis_time.elapsed();
295 eprintln!("Total: {:?}, {}", analysis_time, total_memory);
296 report_metric("total time", analysis_time.as_millis() as u64, "ms");
297 report_metric("total memory", total_memory.allocated.megabytes() as u64, "MB");
277 298
278 if memory_usage { 299 if memory_usage {
279 print_memory_usage(host, vfs); 300 print_memory_usage(host, vfs);
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index c4284556e..ed37992cd 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -86,6 +86,6 @@ fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) {
86 mem.push(("Remaining".into(), ra_prof::memory_usage().allocated)); 86 mem.push(("Remaining".into(), ra_prof::memory_usage().allocated));
87 87
88 for (name, bytes) in mem { 88 for (name, bytes) in mem {
89 println!("{:>8} {}", bytes, name); 89 eprintln!("{:>8} {}", bytes, name);
90 } 90 }
91} 91}
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs
index 6c042d695..9ac3fa51d 100644
--- a/xtask/src/metrics.rs
+++ b/xtask/src/metrics.rs
@@ -3,14 +3,15 @@ use std::{
3 env, 3 env,
4 fmt::{self, Write as _}, 4 fmt::{self, Write as _},
5 io::Write as _, 5 io::Write as _,
6 path::Path,
6 time::{Instant, SystemTime, UNIX_EPOCH}, 7 time::{Instant, SystemTime, UNIX_EPOCH},
7}; 8};
8 9
9use anyhow::{bail, format_err, Result}; 10use anyhow::{bail, format_err, Result};
10 11
11use crate::not_bash::{fs2, pushd, rm_rf, run}; 12use crate::not_bash::{fs2, pushd, pushenv, rm_rf, run};
12 13
13type Unit = &'static str; 14type Unit = String;
14 15
15pub struct MetricsCmd { 16pub struct MetricsCmd {
16 pub dry_run: bool, 17 pub dry_run: bool,
@@ -22,9 +23,21 @@ impl MetricsCmd {
22 if !self.dry_run { 23 if !self.dry_run {
23 rm_rf("./target/release")?; 24 rm_rf("./target/release")?;
24 } 25 }
26 if !Path::new("./target/rustc-perf").exists() {
27 fs2::create_dir_all("./target/rustc-perf")?;
28 run!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")?;
29 }
30 {
31 let _d = pushd("./target/rustc-perf");
32 run!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033")?;
33 }
34
35 let _env = pushenv("RA_METRICS", "1");
25 36
26 metrics.measure_build()?; 37 metrics.measure_build()?;
27 metrics.measure_analysis_stats_self()?; 38 metrics.measure_analysis_stats_self()?;
39 metrics.measure_analysis_stats("ripgrep")?;
40 metrics.measure_analysis_stats("webrender")?;
28 41
29 if !self.dry_run { 42 if !self.dry_run {
30 let _d = pushd("target"); 43 let _d = pushd("target");
@@ -46,23 +59,47 @@ impl MetricsCmd {
46 59
47impl Metrics { 60impl Metrics {
48 fn measure_build(&mut self) -> Result<()> { 61 fn measure_build(&mut self) -> Result<()> {
62 eprintln!("\nMeasuring build");
49 run!("cargo fetch")?; 63 run!("cargo fetch")?;
50 64
51 let time = Instant::now(); 65 let time = Instant::now();
52 run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?; 66 run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?;
53 let time = time.elapsed(); 67 let time = time.elapsed();
54 self.report("build", time.as_millis() as u64, "ms"); 68 self.report("build", time.as_millis() as u64, "ms".into());
55 Ok(()) 69 Ok(())
56 } 70 }
57 fn measure_analysis_stats_self(&mut self) -> Result<()> { 71 fn measure_analysis_stats_self(&mut self) -> Result<()> {
58 let time = Instant::now(); 72 self.measure_analysis_stats_path("self", &".")
59 run!("./target/release/rust-analyzer analysis-stats .")?; 73 }
60 let time = time.elapsed(); 74 fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> {
61 self.report("analysis-stats/self", time.as_millis() as u64, "ms"); 75 self.measure_analysis_stats_path(
76 bench,
77 &format!("./target/rustc-perf/collector/benchmarks/{}", bench),
78 )
79 }
80 fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
81 eprintln!("\nMeasuring analysis-stats/{}", name);
82 let output = run!("./target/release/rust-analyzer analysis-stats --quiet {}", path)?;
83 for (metric, value, unit) in parse_metrics(&output) {
84 self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
85 }
62 Ok(()) 86 Ok(())
63 } 87 }
64} 88}
65 89
90fn parse_metrics(output: &str) -> Vec<(&str, u64, &str)> {
91 output
92 .lines()
93 .filter_map(|it| {
94 let entry = it.split(':').collect::<Vec<_>>();
95 match entry.as_slice() {
96 ["METRIC", name, value, unit] => Some((*name, value.parse().unwrap(), *unit)),
97 _ => None,
98 }
99 })
100 .collect()
101}
102
66#[derive(Debug)] 103#[derive(Debug)]
67struct Metrics { 104struct Metrics {
68 host: Host, 105 host: Host,
@@ -111,11 +148,11 @@ impl Metrics {
111 json.field("metrics"); 148 json.field("metrics");
112 json.begin_object(); 149 json.begin_object();
113 { 150 {
114 for (k, &(value, unit)) in &self.metrics { 151 for (k, (value, unit)) in &self.metrics {
115 json.field(k); 152 json.field(k);
116 json.begin_array(); 153 json.begin_array();
117 { 154 {
118 json.number(value as f64); 155 json.number(*value as f64);
119 json.string(unit); 156 json.string(unit);
120 } 157 }
121 json.end_array(); 158 json.end_array();
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs
index 0f3a56b25..ef811e5bf 100644
--- a/xtask/src/not_bash.rs
+++ b/xtask/src/not_bash.rs
@@ -186,7 +186,8 @@ impl Env {
186 fn pushd(&mut self, dir: PathBuf) { 186 fn pushd(&mut self, dir: PathBuf) {
187 let dir = self.cwd().join(dir); 187 let dir = self.cwd().join(dir);
188 self.pushd_stack.push(dir); 188 self.pushd_stack.push(dir);
189 env::set_current_dir(self.cwd()).unwrap(); 189 env::set_current_dir(self.cwd())
190 .unwrap_or_else(|err| panic!("Failed to set cwd to {}: {}", self.cwd().display(), err));
190 } 191 }
191 fn popd(&mut self) { 192 fn popd(&mut self) {
192 self.pushd_stack.pop().unwrap(); 193 self.pushd_stack.pop().unwrap();