aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-04-14 23:21:12 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-04-14 23:21:12 +0100
commit546d9be2a7bf7b3942c125f922a01321aea6ad26 (patch)
tree7323905a2e0efe7fefb029c8d049987df6a6462f /crates
parente1a2649aff0a9387fb14646a56cb652061bc42ec (diff)
parent247ac265f1e7f2d812e6f9174d48ceef45465b91 (diff)
Merge #1146
1146: Moar profiling r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide_api/Cargo.toml1
-rw-r--r--crates/ra_ide_api/src/change.rs2
-rw-r--r--crates/ra_lsp_server/src/main.rs19
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs3
-rw-r--r--crates/ra_prof/src/lib.rs93
5 files changed, 77 insertions, 41 deletions
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml
index 45bab4e28..333706c1a 100644
--- a/crates/ra_ide_api/Cargo.toml
+++ b/crates/ra_ide_api/Cargo.toml
@@ -23,6 +23,7 @@ ra_syntax = { path = "../ra_syntax" }
23ra_text_edit = { path = "../ra_text_edit" } 23ra_text_edit = { path = "../ra_text_edit" }
24ra_db = { path = "../ra_db" } 24ra_db = { path = "../ra_db" }
25ra_fmt = { path = "../ra_fmt" } 25ra_fmt = { path = "../ra_fmt" }
26ra_prof = { path = "../ra_prof" }
26hir = { path = "../ra_hir", package = "ra_hir" } 27hir = { path = "../ra_hir", package = "ra_hir" }
27test_utils = { path = "../test_utils" } 28test_utils = { path = "../test_utils" }
28ra_assists = { path = "../ra_assists" } 29ra_assists = { path = "../ra_assists" }
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index a4a086931..5bfdbe7e9 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -9,6 +9,7 @@ use ra_db::{
9 salsa::{Database, SweepStrategy}, 9 salsa::{Database, SweepStrategy},
10}; 10};
11use ra_syntax::SourceFile; 11use ra_syntax::SourceFile;
12use ra_prof::profile;
12use relative_path::RelativePathBuf; 13use relative_path::RelativePathBuf;
13use rayon::prelude::*; 14use rayon::prelude::*;
14 15
@@ -153,6 +154,7 @@ const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
153 154
154impl RootDatabase { 155impl RootDatabase {
155 pub(crate) fn apply_change(&mut self, change: AnalysisChange) { 156 pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
157 let _p = profile("RootDatabase::apply_change");
156 log::info!("apply_change {:?}", change); 158 log::info!("apply_change {:?}", change);
157 if !change.new_roots.is_empty() { 159 if !change.new_roots.is_empty() {
158 let mut local_roots = Vec::clone(&self.local_roots()); 160 let mut local_roots = Vec::clone(&self.local_roots());
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index 82f52a6e8..b0b70df5c 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -6,21 +6,16 @@ use ra_lsp_server::{Result, InitializationOptions};
6use ra_prof; 6use ra_prof;
7 7
8fn main() -> Result<()> { 8fn main() -> Result<()> {
9 ::std::env::set_var("RUST_BACKTRACE", "short"); 9 std::env::set_var("RUST_BACKTRACE", "short");
10 let logger = Logger::with_env_or_str("error").duplicate_to_stderr(Duplicate::All); 10 let logger = Logger::with_env_or_str("error").duplicate_to_stderr(Duplicate::All);
11 match ::std::env::var("RA_INTERNAL_MODE") { 11 match std::env::var("RA_LOG_DIR") {
12 Ok(ref v) if v == "1" => logger.log_to_file().directory("log").start()?, 12 Ok(ref v) if v == "1" => logger.log_to_file().directory("log").start()?,
13 _ => logger.start()?, 13 _ => logger.start()?,
14 }; 14 };
15 let prof_depth = match ::std::env::var("RA_PROFILE_DEPTH") { 15 ra_prof::set_filter(match std::env::var("RA_PROFILE") {
16 Ok(ref d) => d.parse()?, 16 Ok(spec) => ra_prof::Filter::from_spec(&spec),
17 _ => 0, 17 Err(_) => ra_prof::Filter::disabled(),
18 }; 18 });
19 let profile_allowed = match ::std::env::var("RA_PROFILE") {
20 Ok(ref p) => p.split(";").map(String::from).collect(),
21 _ => Vec::new(),
22 };
23 ra_prof::set_filter(ra_prof::Filter::new(prof_depth, profile_allowed));
24 log::info!("lifecycle: server started"); 19 log::info!("lifecycle: server started");
25 match ::std::panic::catch_unwind(main_inner) { 20 match ::std::panic::catch_unwind(main_inner) {
26 Ok(res) => { 21 Ok(res) => {
@@ -36,7 +31,7 @@ fn main() -> Result<()> {
36 31
37fn main_inner() -> Result<()> { 32fn main_inner() -> Result<()> {
38 let (receiver, sender, threads) = stdio_transport(); 33 let (receiver, sender, threads) = stdio_transport();
39 let cwd = ::std::env::current_dir()?; 34 let cwd = std::env::current_dir()?;
40 run_server(ra_lsp_server::server_capabilities(), receiver, sender, |params, r, s| { 35 run_server(ra_lsp_server::server_capabilities(), receiver, sender, |params, r, s| {
41 let root = params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); 36 let root = params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
42 37
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 41d1f759f..eb8a53545 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -12,6 +12,7 @@ use ra_ide_api::{
12 AssistId, 12 AssistId,
13}; 13};
14use ra_syntax::{AstNode, SyntaxKind, TextUnit}; 14use ra_syntax::{AstNode, SyntaxKind, TextUnit};
15use ra_prof::profile;
15use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
16use serde::{Serialize, Deserialize}; 17use serde::{Serialize, Deserialize};
17use serde_json::to_value; 18use serde_json::to_value;
@@ -328,6 +329,7 @@ pub fn handle_completion(
328 world: ServerWorld, 329 world: ServerWorld,
329 params: req::CompletionParams, 330 params: req::CompletionParams,
330) -> Result<Option<req::CompletionResponse>> { 331) -> Result<Option<req::CompletionResponse>> {
332 let _p = profile("handle_completion");
331 let position = { 333 let position = {
332 let file_id = params.text_document.try_conv_with(&world)?; 334 let file_id = params.text_document.try_conv_with(&world)?;
333 let line_index = world.analysis().file_line_index(file_id); 335 let line_index = world.analysis().file_line_index(file_id);
@@ -564,6 +566,7 @@ pub fn handle_code_action(
564 world: ServerWorld, 566 world: ServerWorld,
565 params: req::CodeActionParams, 567 params: req::CodeActionParams,
566) -> Result<Option<CodeActionResponse>> { 568) -> Result<Option<CodeActionResponse>> {
569 let _p = profile("handle_code_action");
567 let file_id = params.text_document.try_conv_with(&world)?; 570 let file_id = params.text_document.try_conv_with(&world)?;
568 let line_index = world.analysis().file_line_index(file_id); 571 let line_index = world.analysis().file_line_index(file_id);
569 let range = params.range.conv_with(&line_index); 572 let range = params.range.conv_with(&line_index);
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index 1cc8e361d..402c719b1 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -6,7 +6,7 @@ use std::iter::repeat;
6use std::collections::{HashSet}; 6use std::collections::{HashSet};
7use std::default::Default; 7use std::default::Default;
8use std::iter::FromIterator; 8use std::iter::FromIterator;
9use std::sync::RwLock; 9use std::sync::{RwLock, atomic::{AtomicBool, Ordering}};
10use lazy_static::lazy_static; 10use lazy_static::lazy_static;
11 11
12/// Set profiling filter. It specifies descriptions allowed to profile. 12/// Set profiling filter. It specifies descriptions allowed to profile.
@@ -15,18 +15,20 @@ use lazy_static::lazy_static;
15/// 15///
16/// #Example 16/// #Example
17/// ``` 17/// ```
18/// use ra_prof::set_filter; 18/// use ra_prof::{set_filter, Filter};
19/// use ra_prof::Filter; 19/// let f = Filter::from_spec("profile1|profile2@2");
20/// let max_depth = 2;
21/// let allowed = vec!["profile1".to_string(), "profile2".to_string()];
22/// let f = Filter::new( max_depth, allowed );
23/// set_filter(f); 20/// set_filter(f);
24/// ``` 21/// ```
25///
26pub fn set_filter(f: Filter) { 22pub fn set_filter(f: Filter) {
23 PROFILING_ENABLED.store(f.depth > 0, Ordering::SeqCst);
27 let set = HashSet::from_iter(f.allowed.iter().cloned()); 24 let set = HashSet::from_iter(f.allowed.iter().cloned());
28 let mut old = FILTER.write().unwrap(); 25 let mut old = FILTER.write().unwrap();
29 let filter_data = FilterData { depth: f.depth, allowed: set, version: old.version + 1 }; 26 let filter_data = FilterData {
27 depth: f.depth,
28 allowed: set,
29 longer_than: f.longer_than,
30 version: old.version + 1,
31 };
30 *old = filter_data; 32 *old = filter_data;
31} 33}
32 34
@@ -37,12 +39,9 @@ pub fn set_filter(f: Filter) {
37/// 39///
38/// #Example 40/// #Example
39/// ``` 41/// ```
40/// use ra_prof::profile; 42/// use ra_prof::{profile, set_filter, Filter};
41/// use ra_prof::set_filter;
42/// use ra_prof::Filter;
43/// 43///
44/// let allowed = vec!["profile1".to_string(), "profile2".to_string()]; 44/// let f = Filter::from_spec("profile1|profile2@2");
45/// let f = Filter::new(2, allowed);
46/// set_filter(f); 45/// set_filter(f);
47/// profiling_function1(); 46/// profiling_function1();
48/// 47///
@@ -60,8 +59,12 @@ pub fn set_filter(f: Filter) {
60/// 0ms - profile 59/// 0ms - profile
61/// 0ms - profile2 60/// 0ms - profile2
62/// ``` 61/// ```
63///
64pub fn profile(desc: &str) -> Profiler { 62pub fn profile(desc: &str) -> Profiler {
63 assert!(!desc.is_empty());
64 if !PROFILING_ENABLED.load(Ordering::Relaxed) {
65 return Profiler { desc: None };
66 }
67
65 PROFILE_STACK.with(|stack| { 68 PROFILE_STACK.with(|stack| {
66 let mut stack = stack.borrow_mut(); 69 let mut stack = stack.borrow_mut();
67 if stack.starts.len() == 0 { 70 if stack.starts.len() == 0 {
@@ -74,14 +77,14 @@ pub fn profile(desc: &str) -> Profiler {
74 Err(_) => (), 77 Err(_) => (),
75 }; 78 };
76 } 79 }
77 let desc_str = desc.to_string(); 80
78 if desc_str.is_empty() { 81 if stack.starts.len() > stack.filter_data.depth {
79 Profiler { desc: None } 82 return Profiler { desc: None };
80 } else if stack.starts.len() < stack.filter_data.depth 83 }
81 && stack.filter_data.allowed.contains(&desc_str) 84
82 { 85 if stack.filter_data.allowed.is_empty() || stack.filter_data.allowed.contains(desc) {
83 stack.starts.push(Instant::now()); 86 stack.starts.push(Instant::now());
84 Profiler { desc: Some(desc_str) } 87 Profiler { desc: Some(desc.to_string()) }
85 } else { 88 } else {
86 Profiler { desc: None } 89 Profiler { desc: None }
87 } 90 }
@@ -95,11 +98,41 @@ pub struct Profiler {
95pub struct Filter { 98pub struct Filter {
96 depth: usize, 99 depth: usize,
97 allowed: Vec<String>, 100 allowed: Vec<String>,
101 longer_than: Duration,
98} 102}
99 103
100impl Filter { 104impl Filter {
101 pub fn new(depth: usize, allowed: Vec<String>) -> Filter { 105 // Filtering syntax
102 Filter { depth, allowed } 106 // env RA_PROFILE=* // dump everything
107 // env RA_PROFILE=foo|bar|baz // enabled only selected entries
108 // env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms
109 pub fn from_spec(mut spec: &str) -> Filter {
110 let longer_than = if let Some(idx) = spec.rfind(">") {
111 let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than");
112 spec = &spec[..idx];
113 Duration::from_millis(longer_than)
114 } else {
115 Duration::new(0, 0)
116 };
117
118 let depth = if let Some(idx) = spec.rfind("@") {
119 let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
120 spec = &spec[..idx];
121 depth
122 } else {
123 999
124 };
125 let allowed =
126 if spec == "*" { Vec::new() } else { spec.split("|").map(String::from).collect() };
127 Filter::new(depth, allowed, longer_than)
128 }
129
130 pub fn disabled() -> Filter {
131 Filter::new(0, Vec::new(), Duration::new(0, 0))
132 }
133
134 pub fn new(depth: usize, allowed: Vec<String>, longer_than: Duration) -> Filter {
135 Filter { depth, allowed, longer_than }
103 } 136 }
104} 137}
105 138
@@ -126,8 +159,11 @@ struct FilterData {
126 depth: usize, 159 depth: usize,
127 version: usize, 160 version: usize,
128 allowed: HashSet<String>, 161 allowed: HashSet<String>,
162 longer_than: Duration,
129} 163}
130 164
165static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);
166
131lazy_static! { 167lazy_static! {
132 static ref FILTER: RwLock<FilterData> = RwLock::new(Default::default()); 168 static ref FILTER: RwLock<FilterData> = RwLock::new(Default::default());
133} 169}
@@ -147,7 +183,9 @@ impl Drop for Profiler {
147 stack.messages.push(Message { level, duration, message }); 183 stack.messages.push(Message { level, duration, message });
148 if level == 0 { 184 if level == 0 {
149 let stdout = stderr(); 185 let stdout = stderr();
150 print(0, &stack.messages, &mut stdout.lock()); 186 if duration >= stack.filter_data.longer_than {
187 print(0, &stack.messages, &mut stdout.lock());
188 }
151 stack.messages.clear(); 189 stack.messages.clear();
152 } 190 }
153 }); 191 });
@@ -174,15 +212,12 @@ fn print(lvl: usize, msgs: &[Message], out: &mut impl Write) {
174 212
175#[cfg(test)] 213#[cfg(test)]
176mod tests { 214mod tests {
177 215 use super::*;
178 use super::profile;
179 use super::set_filter;
180 use super::Filter;
181 216
182 #[test] 217 #[test]
183 fn test_basic_profile() { 218 fn test_basic_profile() {
184 let s = vec!["profile1".to_string(), "profile2".to_string()]; 219 let s = vec!["profile1".to_string(), "profile2".to_string()];
185 let f = Filter::new(2, s); 220 let f = Filter::new(2, s, Duration::new(0, 0));
186 set_filter(f); 221 set_filter(f);
187 profiling_function1(); 222 profiling_function1();
188 } 223 }