From 208b7bd7ba687fb570feb1b89219f14c63712ce8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 12 Aug 2020 16:32:36 +0200 Subject: Rename ra_prof -> profile --- Cargo.lock | 42 ++-- crates/profile/Cargo.toml | 27 +++ crates/profile/src/google_cpu_profiler.rs | 39 ++++ crates/profile/src/hprof.rs | 240 ++++++++++++++++++++ crates/profile/src/lib.rs | 109 +++++++++ crates/profile/src/memory_usage.rs | 75 +++++++ crates/profile/src/stop_watch.rs | 86 ++++++++ crates/profile/src/tree.rs | 84 +++++++ crates/ra_assists/Cargo.toml | 2 +- .../src/handlers/add_missing_impl_members.rs | 2 +- crates/ra_assists/src/handlers/auto_import.rs | 3 +- crates/ra_db/Cargo.toml | 2 +- crates/ra_db/src/lib.rs | 3 +- crates/ra_hir/Cargo.toml | 2 +- crates/ra_hir/src/code_model.rs | 3 +- crates/ra_hir/src/semantics.rs | 5 +- crates/ra_hir/src/semantics/source_to_def.rs | 5 +- crates/ra_hir_def/Cargo.toml | 2 +- crates/ra_hir_def/src/body.rs | 3 +- crates/ra_hir_def/src/data.rs | 3 +- crates/ra_hir_def/src/db.rs | 3 +- crates/ra_hir_def/src/find_path.rs | 5 +- crates/ra_hir_def/src/generics.rs | 3 +- crates/ra_hir_def/src/import_map.rs | 4 +- crates/ra_hir_def/src/item_tree.rs | 2 +- crates/ra_hir_def/src/lang_item.rs | 7 +- crates/ra_hir_def/src/nameres.rs | 3 +- crates/ra_hir_expand/Cargo.toml | 2 +- crates/ra_hir_expand/src/db.rs | 3 +- crates/ra_hir_ty/Cargo.toml | 2 +- crates/ra_hir_ty/src/db.rs | 3 +- crates/ra_hir_ty/src/diagnostics.rs | 3 +- crates/ra_hir_ty/src/infer.rs | 3 +- crates/ra_hir_ty/src/method_resolution.rs | 5 +- crates/ra_hir_ty/src/traits.rs | 3 +- crates/ra_hir_ty/src/traits/chalk.rs | 2 +- crates/ra_ide/Cargo.toml | 2 +- crates/ra_ide/src/diagnostics.rs | 3 +- crates/ra_ide/src/inlay_hints.rs | 3 +- crates/ra_ide/src/lib.rs | 2 +- crates/ra_ide/src/references.rs | 3 +- crates/ra_ide/src/status.rs | 2 +- crates/ra_ide/src/syntax_highlighting.rs | 3 +- crates/ra_ide_db/Cargo.toml | 2 +- crates/ra_ide_db/src/change.rs | 8 +- crates/ra_ide_db/src/defs.rs | 5 +- crates/ra_ide_db/src/imports_locator.rs | 5 +- crates/ra_ide_db/src/search.rs | 5 +- crates/ra_ide_db/src/symbol_index.rs | 5 +- crates/ra_prof/Cargo.toml | 27 --- crates/ra_prof/src/google_cpu_profiler.rs | 39 ---- crates/ra_prof/src/hprof.rs | 243 --------------------- crates/ra_prof/src/lib.rs | 109 --------- crates/ra_prof/src/memory_usage.rs | 75 ------- crates/ra_prof/src/stop_watch.rs | 86 -------- crates/ra_prof/src/tree.rs | 84 ------- crates/rust-analyzer/Cargo.toml | 2 +- crates/rust-analyzer/src/bin/main.rs | 2 +- crates/rust-analyzer/src/cli.rs | 3 +- crates/rust-analyzer/src/cli/analysis_bench.rs | 2 +- crates/rust-analyzer/src/cli/analysis_stats.rs | 2 +- crates/rust-analyzer/src/global_state.rs | 3 +- crates/rust-analyzer/src/handlers.rs | 77 ++++--- crates/rust-analyzer/src/lib.rs | 10 +- crates/rust-analyzer/src/main_loop.rs | 5 +- crates/rust-analyzer/src/reload.rs | 7 +- crates/rust-analyzer/tests/heavy_tests/support.rs | 2 +- xtask/tests/tidy.rs | 2 +- 68 files changed, 792 insertions(+), 826 deletions(-) create mode 100644 crates/profile/Cargo.toml create mode 100644 crates/profile/src/google_cpu_profiler.rs create mode 100644 crates/profile/src/hprof.rs create mode 100644 crates/profile/src/lib.rs create mode 100644 crates/profile/src/memory_usage.rs create mode 100644 crates/profile/src/stop_watch.rs create mode 100644 crates/profile/src/tree.rs delete mode 100644 crates/ra_prof/Cargo.toml delete mode 100644 crates/ra_prof/src/google_cpu_profiler.rs delete mode 100644 crates/ra_prof/src/hprof.rs delete mode 100644 crates/ra_prof/src/lib.rs delete mode 100644 crates/ra_prof/src/memory_usage.rs delete mode 100644 crates/ra_prof/src/stop_watch.rs delete mode 100644 crates/ra_prof/src/tree.rs diff --git a/Cargo.lock b/Cargo.lock index ab1698b11..c2a0457c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -894,6 +894,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "profile" +version = "0.0.0" +dependencies = [ + "arena", + "backtrace", + "cfg-if", + "libc", + "once_cell", + "perf-event", +] + [[package]] name = "quote" version = "1.0.7" @@ -909,11 +921,11 @@ version = "0.1.0" dependencies = [ "either", "itertools", + "profile", "ra_db", "ra_fmt", "ra_hir", "ra_ide_db", - "ra_prof", "ra_syntax", "ra_text_edit", "rustc-hash", @@ -935,8 +947,8 @@ dependencies = [ name = "ra_db" version = "0.1.0" dependencies = [ + "profile", "ra_cfg", - "ra_prof", "ra_syntax", "ra_tt", "rustc-hash", @@ -962,11 +974,11 @@ dependencies = [ "either", "itertools", "log", + "profile", "ra_db", "ra_hir_def", "ra_hir_expand", "ra_hir_ty", - "ra_prof", "ra_syntax", "rustc-hash", "stdx", @@ -986,11 +998,11 @@ dependencies = [ "itertools", "log", "once_cell", + "profile", "ra_cfg", "ra_db", "ra_hir_expand", "ra_mbe", - "ra_prof", "ra_syntax", "ra_tt", "rustc-hash", @@ -1006,10 +1018,10 @@ dependencies = [ "arena", "either", "log", + "profile", "ra_db", "ra_mbe", "ra_parser", - "ra_prof", "ra_syntax", "ra_tt", "rustc-hash", @@ -1029,10 +1041,10 @@ dependencies = [ "expect", "itertools", "log", + "profile", "ra_db", "ra_hir_def", "ra_hir_expand", - "ra_prof", "ra_syntax", "rustc-hash", "scoped-tls", @@ -1054,13 +1066,13 @@ dependencies = [ "itertools", "log", "oorandom", + "profile", "ra_assists", "ra_cfg", "ra_db", "ra_fmt", "ra_hir", "ra_ide_db", - "ra_prof", "ra_ssr", "ra_syntax", "ra_text_edit", @@ -1077,9 +1089,9 @@ dependencies = [ "fst", "log", "once_cell", + "profile", "ra_db", "ra_hir", - "ra_prof", "ra_syntax", "ra_text_edit", "rayon", @@ -1137,18 +1149,6 @@ dependencies = [ "test_utils", ] -[[package]] -name = "ra_prof" -version = "0.1.0" -dependencies = [ - "arena", - "backtrace", - "cfg-if", - "libc", - "once_cell", - "perf-event", -] - [[package]] name = "ra_project_model" version = "0.1.0" @@ -1314,6 +1314,7 @@ dependencies = [ "oorandom", "parking_lot", "pico-args", + "profile", "ra_cfg", "ra_db", "ra_hir", @@ -1323,7 +1324,6 @@ dependencies = [ "ra_ide_db", "ra_mbe", "ra_proc_macro_srv", - "ra_prof", "ra_project_model", "ra_ssr", "ra_syntax", diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml new file mode 100644 index 000000000..e271e3a56 --- /dev/null +++ b/crates/profile/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "profile" +version = "0.0.0" +license = "MIT OR Apache-2.0" +authors = ["rust-analyzer developers"] +edition = "2018" + +[lib] +doctest = false + +[dependencies] +once_cell = "1.3.1" +cfg-if = "0.1.10" +libc = "0.2.73" +backtrace = { version = "0.3.44", optional = true } + +arena = { path = "../arena" } + +[target.'cfg(target_os = "linux")'.dependencies] +perf-event = "0.4" + +[features] +cpu_profiler = [] + +# Uncomment to enable for the whole crate graph +# default = [ "backtrace" ] +# default = [ "cpu_profiler" ] diff --git a/crates/profile/src/google_cpu_profiler.rs b/crates/profile/src/google_cpu_profiler.rs new file mode 100644 index 000000000..db865c65b --- /dev/null +++ b/crates/profile/src/google_cpu_profiler.rs @@ -0,0 +1,39 @@ +//! https://github.com/gperftools/gperftools + +use std::{ + ffi::CString, + os::raw::c_char, + path::Path, + sync::atomic::{AtomicUsize, Ordering}, +}; + +#[link(name = "profiler")] +#[allow(non_snake_case)] +extern "C" { + fn ProfilerStart(fname: *const c_char) -> i32; + fn ProfilerStop(); +} + +static PROFILER_STATE: AtomicUsize = AtomicUsize::new(OFF); +const OFF: usize = 0; +const ON: usize = 1; +const PENDING: usize = 2; + +pub fn start(path: &Path) { + if PROFILER_STATE.compare_and_swap(OFF, PENDING, Ordering::SeqCst) != OFF { + panic!("profiler already started"); + } + let path = CString::new(path.display().to_string()).unwrap(); + if unsafe { ProfilerStart(path.as_ptr()) } == 0 { + panic!("profiler failed to start") + } + assert!(PROFILER_STATE.compare_and_swap(PENDING, ON, Ordering::SeqCst) == PENDING); +} + +pub fn stop() { + if PROFILER_STATE.compare_and_swap(ON, PENDING, Ordering::SeqCst) != ON { + panic!("profiler is not started") + } + unsafe { ProfilerStop() }; + assert!(PROFILER_STATE.compare_and_swap(PENDING, OFF, Ordering::SeqCst) == PENDING); +} diff --git a/crates/profile/src/hprof.rs b/crates/profile/src/hprof.rs new file mode 100644 index 000000000..934cc8e37 --- /dev/null +++ b/crates/profile/src/hprof.rs @@ -0,0 +1,240 @@ +//! Simple hierarchical profiler +use once_cell::sync::Lazy; +use std::{ + cell::RefCell, + collections::{BTreeMap, HashSet}, + io::{stderr, Write}, + sync::{ + atomic::{AtomicBool, Ordering}, + RwLock, + }, + time::{Duration, Instant}, +}; + +use crate::tree::{Idx, Tree}; + +/// Filtering syntax +/// env RA_PROFILE=* // dump everything +/// env RA_PROFILE=foo|bar|baz // enabled only selected entries +/// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms +pub fn init() { + let spec = std::env::var("RA_PROFILE").unwrap_or_default(); + init_from(&spec); +} + +pub fn init_from(spec: &str) { + let filter = if spec.is_empty() { Filter::disabled() } else { Filter::from_spec(spec) }; + filter.install(); +} + +pub type Label = &'static str; + +/// This function starts a profiling scope in the current execution stack with a given description. +/// It returns a `Profile` struct that measures elapsed time between this method invocation and `Profile` struct drop. +/// It supports nested profiling scopes in case when this function is invoked multiple times at the execution stack. +/// In this case the profiling information will be nested at the output. +/// Profiling information is being printed in the stderr. +/// +/// # Example +/// ``` +/// profile::init_from("profile1|profile2@2"); +/// profiling_function1(); +/// +/// fn profiling_function1() { +/// let _p = profile::span("profile1"); +/// profiling_function2(); +/// } +/// +/// fn profiling_function2() { +/// let _p = profile::span("profile2"); +/// } +/// ``` +/// This will print in the stderr the following: +/// ```text +/// 0ms - profile +/// 0ms - profile2 +/// ``` +pub fn span(label: Label) -> ProfileSpan { + assert!(!label.is_empty()); + + if PROFILING_ENABLED.load(Ordering::Relaxed) + && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)) + { + ProfileSpan(Some(ProfilerImpl { label, detail: None })) + } else { + ProfileSpan(None) + } +} + +pub struct ProfileSpan(Option); + +struct ProfilerImpl { + label: Label, + detail: Option, +} + +impl ProfileSpan { + pub fn detail(mut self, detail: impl FnOnce() -> String) -> ProfileSpan { + if let Some(profiler) = &mut self.0 { + profiler.detail = Some(detail()) + } + self + } +} + +impl Drop for ProfilerImpl { + fn drop(&mut self) { + PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take())); + } +} + +static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false); +static FILTER: Lazy> = Lazy::new(Default::default); +thread_local!(static PROFILE_STACK: RefCell = RefCell::new(ProfileStack::new())); + +#[derive(Default, Clone, Debug)] +struct Filter { + depth: usize, + allowed: HashSet, + longer_than: Duration, + version: usize, +} + +impl Filter { + fn disabled() -> Filter { + Filter::default() + } + + fn from_spec(mut spec: &str) -> Filter { + let longer_than = if let Some(idx) = spec.rfind('>') { + let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than"); + spec = &spec[..idx]; + Duration::from_millis(longer_than) + } else { + Duration::new(0, 0) + }; + + let depth = if let Some(idx) = spec.rfind('@') { + let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); + spec = &spec[..idx]; + depth + } else { + 999 + }; + let allowed = + if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() }; + Filter { depth, allowed, longer_than, version: 0 } + } + + fn install(mut self) { + PROFILING_ENABLED.store(self.depth > 0, Ordering::SeqCst); + let mut old = FILTER.write().unwrap(); + self.version = old.version + 1; + *old = self; + } +} + +struct ProfileStack { + starts: Vec, + filter: Filter, + messages: Tree, +} + +#[derive(Default)] +struct Message { + duration: Duration, + label: Label, + detail: Option, +} + +impl ProfileStack { + fn new() -> ProfileStack { + ProfileStack { starts: Vec::new(), messages: Tree::default(), filter: Default::default() } + } + + fn push(&mut self, label: Label) -> bool { + if self.starts.is_empty() { + if let Ok(f) = FILTER.try_read() { + if f.version > self.filter.version { + self.filter = f.clone(); + } + }; + } + if self.starts.len() > self.filter.depth { + return false; + } + let allowed = &self.filter.allowed; + if self.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) { + return false; + } + + self.starts.push(Instant::now()); + self.messages.start(); + true + } + + pub fn pop(&mut self, label: Label, detail: Option) { + let start = self.starts.pop().unwrap(); + let duration = start.elapsed(); + self.messages.finish(Message { duration, label, detail }); + if self.starts.is_empty() { + let longer_than = self.filter.longer_than; + // Convert to millis for comparison to avoid problems with rounding + // (otherwise we could print `0ms` despite user's `>0` filter when + // `duration` is just a few nanos). + if duration.as_millis() > longer_than.as_millis() { + if let Some(root) = self.messages.root() { + print(&self.messages, root, 0, longer_than, &mut stderr().lock()); + } + } + self.messages.clear(); + } + } +} + +fn print( + tree: &Tree, + curr: Idx, + level: u32, + longer_than: Duration, + out: &mut impl Write, +) { + let current_indent = " ".repeat(level as usize); + let detail = tree[curr].detail.as_ref().map(|it| format!(" @ {}", it)).unwrap_or_default(); + writeln!( + out, + "{}{:5}ms - {}{}", + current_indent, + tree[curr].duration.as_millis(), + tree[curr].label, + detail, + ) + .expect("printing profiling info"); + + let mut accounted_for = Duration::default(); + let mut short_children = BTreeMap::new(); // Use `BTreeMap` to get deterministic output. + for child in tree.children(curr) { + accounted_for += tree[child].duration; + + if tree[child].duration.as_millis() > longer_than.as_millis() { + print(tree, child, level + 1, longer_than, out) + } else { + let (total_duration, cnt) = + short_children.entry(tree[child].label).or_insert((Duration::default(), 0)); + *total_duration += tree[child].duration; + *cnt += 1; + } + } + + for (child_msg, (duration, count)) in short_children.iter() { + let millis = duration.as_millis(); + writeln!(out, " {}{:5}ms - {} ({} calls)", current_indent, millis, child_msg, count) + .expect("printing profiling info"); + } + + let unaccounted = tree[curr].duration - accounted_for; + if tree.children(curr).next().is_some() && unaccounted > longer_than { + writeln!(out, " {}{:5}ms - ???", current_indent, unaccounted.as_millis()) + .expect("printing profiling info"); + } +} diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs new file mode 100644 index 000000000..ab19271c7 --- /dev/null +++ b/crates/profile/src/lib.rs @@ -0,0 +1,109 @@ +//! A collection of tools for profiling rust-analyzer. + +mod stop_watch; +mod memory_usage; +#[cfg(feature = "cpu_profiler")] +mod google_cpu_profiler; +mod hprof; +mod tree; + +use std::cell::RefCell; + +pub use crate::{ + hprof::{init, init_from, span}, + memory_usage::{Bytes, MemoryUsage}, + stop_watch::{StopWatch, StopWatchSpan}, +}; + +/// Prints backtrace to stderr, useful for debugging. +#[cfg(feature = "backtrace")] +pub fn print_backtrace() { + let bt = backtrace::Backtrace::new(); + eprintln!("{:?}", bt); +} +#[cfg(not(feature = "backtrace"))] +pub fn print_backtrace() { + eprintln!( + r#"enable the backtrace feature: + profile = {{ path = "../profile", features = [ "backtrace"] }} +"# + ); +} + +thread_local!(static IN_SCOPE: RefCell = RefCell::new(false)); + +/// Allows to check if the current code is withing some dynamic scope, can be +/// useful during debugging to figure out why a function is called. +pub struct Scope { + prev: bool, +} + +impl Scope { + #[must_use] + pub fn enter() -> Scope { + let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true)); + Scope { prev } + } + pub fn is_active() -> bool { + IN_SCOPE.with(|slot| *slot.borrow()) + } +} + +impl Drop for Scope { + fn drop(&mut self) { + IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev); + } +} + +/// A wrapper around google_cpu_profiler. +/// +/// Usage: +/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro. +/// 2. Build with `cpu_profiler` feature. +/// 3. Tun the code, the *raw* output would be in the `./out.profile` file. +/// 4. Install pprof for visualization (https://github.com/google/pprof). +/// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000` +/// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. +/// +/// For example, here's how I run profiling on NixOS: +/// +/// ```bash +/// $ nix-shell -p gperftools --run \ +/// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null' +/// ``` +/// +/// See this diff for how to profile completions: +/// +/// https://github.com/rust-analyzer/rust-analyzer/pull/5306 +#[derive(Debug)] +pub struct CpuSpan { + _private: (), +} + +#[must_use] +pub fn cpu_span() -> CpuSpan { + #[cfg(feature = "cpu_profiler")] + { + google_cpu_profiler::start("./out.profile".as_ref()) + } + + #[cfg(not(feature = "cpu_profiler"))] + { + eprintln!("cpu_profiler feature is disabled") + } + + CpuSpan { _private: () } +} + +impl Drop for CpuSpan { + fn drop(&mut self) { + #[cfg(feature = "cpu_profiler")] + { + google_cpu_profiler::stop() + } + } +} + +pub fn memory_usage() -> MemoryUsage { + MemoryUsage::current() +} diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs new file mode 100644 index 000000000..83390212a --- /dev/null +++ b/crates/profile/src/memory_usage.rs @@ -0,0 +1,75 @@ +//! FIXME: write short doc here +use std::fmt; + +use cfg_if::cfg_if; + +#[derive(Copy, Clone)] +pub struct MemoryUsage { + pub allocated: Bytes, +} + +impl fmt::Display for MemoryUsage { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", self.allocated) + } +} + +impl std::ops::Sub for MemoryUsage { + type Output = MemoryUsage; + fn sub(self, rhs: MemoryUsage) -> MemoryUsage { + MemoryUsage { allocated: self.allocated - rhs.allocated } + } +} + +impl MemoryUsage { + pub fn current() -> MemoryUsage { + cfg_if! { + if #[cfg(all(target_os = "linux", target_env = "gnu"))] { + // Note: This is incredibly slow. + let alloc = unsafe { libc::mallinfo() }.uordblks as isize; + MemoryUsage { allocated: Bytes(alloc) } + } else { + MemoryUsage { allocated: Bytes(0) } + } + } + } +} + +#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] +pub struct Bytes(isize); + +impl Bytes { + pub fn megabytes(self) -> isize { + self.0 / 1024 / 1024 + } +} + +impl fmt::Display for Bytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bytes = self.0; + let mut value = bytes; + let mut suffix = "b"; + if value.abs() > 4096 { + value /= 1024; + suffix = "kb"; + if value.abs() > 4096 { + value /= 1024; + suffix = "mb"; + } + } + f.pad(&format!("{}{}", value, suffix)) + } +} + +impl std::ops::AddAssign for Bytes { + fn add_assign(&mut self, x: usize) { + self.0 += x as isize; + } +} + +impl std::ops::Sub for Bytes { + type Output = Bytes; + fn sub(self, rhs: Bytes) -> Bytes { + Bytes(self.0 - rhs.0) + } +} diff --git a/crates/profile/src/stop_watch.rs b/crates/profile/src/stop_watch.rs new file mode 100644 index 000000000..5e276190e --- /dev/null +++ b/crates/profile/src/stop_watch.rs @@ -0,0 +1,86 @@ +//! Like `std::time::Instant`, but also measures memory & CPU cycles. +use std::{ + fmt, + time::{Duration, Instant}, +}; + +use crate::MemoryUsage; + +pub struct StopWatch { + time: Instant, + #[cfg(target_os = "linux")] + counter: Option, + memory: Option, +} + +pub struct StopWatchSpan { + pub time: Duration, + pub instructions: Option, + pub memory: Option, +} + +impl StopWatch { + pub fn start() -> StopWatch { + #[cfg(target_os = "linux")] + let counter = { + let mut counter = perf_event::Builder::new() + .build() + .map_err(|err| eprintln!("Failed to create perf counter: {}", err)) + .ok(); + if let Some(counter) = &mut counter { + if let Err(err) = counter.enable() { + eprintln!("Failed to start perf counter: {}", err) + } + } + counter + }; + let time = Instant::now(); + StopWatch { + time, + #[cfg(target_os = "linux")] + counter, + memory: None, + } + } + pub fn memory(mut self, yes: bool) -> StopWatch { + if yes { + self.memory = Some(MemoryUsage::current()); + } + self + } + pub fn elapsed(&mut self) -> StopWatchSpan { + let time = self.time.elapsed(); + + #[cfg(target_os = "linux")] + let instructions = self.counter.as_mut().and_then(|it| { + it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok() + }); + #[cfg(not(target_os = "linux"))] + let instructions = None; + + let memory = self.memory.map(|it| MemoryUsage::current() - it); + StopWatchSpan { time, instructions, memory } + } +} + +impl fmt::Display for StopWatchSpan { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:.2?}", self.time)?; + if let Some(mut instructions) = self.instructions { + let mut prefix = ""; + if instructions > 10000 { + instructions /= 1000; + prefix = "k" + } + if instructions > 10000 { + instructions /= 1000; + prefix = "m" + } + write!(f, ", {}{}i", instructions, prefix)?; + } + if let Some(memory) = self.memory { + write!(f, ", {}", memory)?; + } + Ok(()) + } +} diff --git a/crates/profile/src/tree.rs b/crates/profile/src/tree.rs new file mode 100644 index 000000000..096f58511 --- /dev/null +++ b/crates/profile/src/tree.rs @@ -0,0 +1,84 @@ +//! A simple tree implementation which tries to not allocate all over the place. +use std::ops; + +use arena::Arena; + +#[derive(Default)] +pub struct Tree { + nodes: Arena>, + current_path: Vec<(Idx, Option>)>, +} + +pub type Idx = arena::Idx>; + +impl Tree { + pub fn start(&mut self) + where + T: Default, + { + let me = self.nodes.alloc(Node::new(T::default())); + if let Some((parent, last_child)) = self.current_path.last_mut() { + let slot = match *last_child { + Some(last_child) => &mut self.nodes[last_child].next_sibling, + None => &mut self.nodes[*parent].first_child, + }; + let prev = slot.replace(me); + assert!(prev.is_none()); + *last_child = Some(me); + } + + self.current_path.push((me, None)); + } + + pub fn finish(&mut self, data: T) { + let (me, _last_child) = self.current_path.pop().unwrap(); + self.nodes[me].data = data; + } + + pub fn root(&self) -> Option> { + self.nodes.iter().next().map(|(idx, _)| idx) + } + + pub fn children(&self, idx: Idx) -> impl Iterator> + '_ { + NodeIter { nodes: &self.nodes, next: self.nodes[idx].first_child } + } + pub fn clear(&mut self) { + self.nodes.clear(); + self.current_path.clear(); + } +} + +impl ops::Index> for Tree { + type Output = T; + fn index(&self, index: Idx) -> &T { + &self.nodes[index].data + } +} + +pub struct Node { + data: T, + first_child: Option>, + next_sibling: Option>, +} + +impl Node { + fn new(data: T) -> Node { + Node { data, first_child: None, next_sibling: None } + } +} + +struct NodeIter<'a, T> { + nodes: &'a Arena>, + next: Option>, +} + +impl<'a, T> Iterator for NodeIter<'a, T> { + type Item = Idx; + + fn next(&mut self) -> Option> { + self.next.map(|next| { + self.next = self.nodes[next].next_sibling; + next + }) + } +} diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index bd2905f08..6f5ace941 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml @@ -18,7 +18,7 @@ stdx = { path = "../stdx" } ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } ra_fmt = { path = "../ra_fmt" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } ra_db = { path = "../ra_db" } ra_ide_db = { path = "../ra_ide_db" } hir = { path = "../ra_hir", package = "ra_hir" } diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 95a750aee..dd1406228 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs @@ -110,7 +110,7 @@ fn add_missing_impl_members_inner( assist_id: &'static str, label: &'static str, ) -> Option<()> { - let _p = ra_prof::profile("add_missing_impl_members_inner"); + let _p = profile::span("add_missing_impl_members_inner"); let impl_def = ctx.find_node_at_offset::()?; let impl_item_list = impl_def.assoc_item_list()?; diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 01e7b7a44..6ec59ec4d 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs @@ -6,7 +6,6 @@ use hir::{ Type, }; use ra_ide_db::{imports_locator, RootDatabase}; -use ra_prof::profile; use ra_syntax::{ ast::{self, AstNode}, SyntaxNode, @@ -130,7 +129,7 @@ impl AutoImportAssets { } fn search_for_imports(&self, ctx: &AssistContext) -> BTreeSet { - let _p = profile("auto_import::search_for_imports"); + let _p = profile::span("auto_import::search_for_imports"); let db = ctx.db(); let current_crate = self.module_with_name_to_import.krate(); imports_locator::find_imports(&ctx.sema, current_crate, &self.get_search_query()) diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index fe73dc015..9cb9ba11c 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml @@ -14,7 +14,7 @@ rustc-hash = "1.1.0" ra_syntax = { path = "../ra_syntax" } ra_cfg = { path = "../ra_cfg" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } ra_tt = { path = "../ra_tt" } test_utils = { path = "../test_utils" } vfs = { path = "../vfs" } diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index f25be24fe..795d7d2b6 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -5,7 +5,6 @@ pub mod fixture; use std::{panic, sync::Arc}; -use ra_prof::profile; use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; use rustc_hash::FxHashSet; @@ -113,7 +112,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { } fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse { - let _p = profile("parse_query").detail(|| format!("{:?}", file_id)); + let _p = profile::span("parse_query").detail(|| format!("{:?}", file_id)); let text = db.file_text(file_id); SourceFile::parse(&*text) } diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index c260bb193..903406e84 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -19,7 +19,7 @@ itertools = "0.9.0" stdx = { path = "../stdx" } ra_syntax = { path = "../ra_syntax" } ra_db = { path = "../ra_db" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 0007d7fa8..5c0c6184a 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -31,7 +31,6 @@ use hir_ty::{ InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, }; use ra_db::{CrateId, Edition, FileId}; -use ra_prof::profile; use ra_syntax::{ ast::{self, AttrsOwner, NameOwner}, AstNode, @@ -304,7 +303,7 @@ impl Module { } pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { - let _p = profile("Module::diagnostics"); + let _p = profile::span("Module::diagnostics"); let crate_def_map = db.crate_def_map(self.id.krate); crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); for decl in self.declarations(db) { diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 36b688ccb..7e3ec6315 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -12,7 +12,6 @@ use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; use hir_ty::associated_type_shorthand_candidates; use itertools::Itertools; use ra_db::{FileId, FileRange}; -use ra_prof::profile; use ra_syntax::{ algo::{find_node_at_offset, skip_trivia_token}, ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize, @@ -334,7 +333,7 @@ impl<'db> SemanticsImpl<'db> { } fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { - let _p = profile("descend_into_macros"); + let _p = profile::span("descend_into_macros"); let parent = token.parent(); let parent = self.find_file(parent); let sa = self.analyze2(parent.as_ref(), None); @@ -523,7 +522,7 @@ impl<'db> SemanticsImpl<'db> { } fn analyze2(&self, src: InFile<&SyntaxNode>, offset: Option) -> SourceAnalyzer { - let _p = profile("Semantics::analyze2"); + let _p = profile::span("Semantics::analyze2"); let container = match self.with_ctx(|ctx| ctx.find_container(src)) { Some(it) => it, diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs index 863e8e5ff..a6ff8b0bf 100644 --- a/crates/ra_hir/src/semantics/source_to_def.rs +++ b/crates/ra_hir/src/semantics/source_to_def.rs @@ -10,7 +10,6 @@ use hir_def::{ }; use hir_expand::{name::AsName, AstId, MacroDefKind}; use ra_db::FileId; -use ra_prof::profile; use ra_syntax::{ ast::{self, NameOwner}, match_ast, AstNode, SyntaxNode, @@ -29,7 +28,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> { impl SourceToDefCtx<'_, '_> { pub(super) fn file_to_def(&mut self, file: FileId) -> Option { - let _p = profile("SourceBinder::to_module_def"); + let _p = profile::span("SourceBinder::to_module_def"); let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| { let crate_def_map = self.db.crate_def_map(crate_id); let local_id = crate_def_map.modules_for_file(file).next()?; @@ -39,7 +38,7 @@ impl SourceToDefCtx<'_, '_> { } pub(super) fn module_to_def(&mut self, src: InFile) -> Option { - let _p = profile("module_to_def"); + let _p = profile::span("module_to_def"); let parent_declaration = src .as_ref() .map(|it| it.syntax()) diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 6dd6fdde6..adfd8c7b7 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -25,7 +25,7 @@ stdx = { path = "../stdx" } arena = { path = "../arena" } ra_db = { path = "../ra_db" } ra_syntax = { path = "../ra_syntax" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } test_utils = { path = "../test_utils" } mbe = { path = "../ra_mbe", package = "ra_mbe" } diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index cb178655b..1deb1a837 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -11,7 +11,6 @@ use either::Either; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; use ra_cfg::CfgOptions; use ra_db::CrateId; -use ra_prof::profile; use ra_syntax::{ast, AstNode, AstPtr}; use rustc_hash::FxHashMap; use test_utils::mark; @@ -228,7 +227,7 @@ impl Body { db: &dyn DefDatabase, def: DefWithBodyId, ) -> (Arc, Arc) { - let _p = profile("body_with_source_map_query"); + let _p = profile::span("body_with_source_map_query"); let mut params = None; let (file_id, module, body) = match def { diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 88a8ef9bf..758c12f33 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use hir_expand::{name::Name, InFile}; -use ra_prof::profile; use ra_syntax::ast; use crate::{ @@ -133,7 +132,7 @@ pub struct ImplData { impl ImplData { pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc { - let _p = profile("impl_data_query"); + let _p = profile::span("impl_data_query"); let impl_loc = id.lookup(db); let item_tree = db.item_tree(impl_loc.id.file_id); diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 9c3ede2d7..1dd4197f8 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use hir_expand::{db::AstDatabase, HirFileId}; use ra_db::{salsa, CrateId, SourceDatabase, Upcast}; -use ra_prof::profile; use ra_syntax::SmolStr; use crate::{ @@ -116,6 +115,6 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { } fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc { - let _p = profile("crate_def_map:wait"); + let _p = profile::span("crate_def_map:wait"); db.crate_def_map_query(krate) } diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 06701a830..46e70eb48 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -1,7 +1,6 @@ //! An algorithm to find a path to refer to a certain item. use hir_expand::name::{known, AsName, Name}; -use ra_prof::profile; use rustc_hash::FxHashSet; use test_utils::mark; @@ -18,7 +17,7 @@ use crate::{ /// Find a path that can be used to refer to a certain item. This can depend on /// *from where* you're referring to the item, hence the `from` parameter. pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option { - let _p = profile("find_path"); + let _p = profile::span("find_path"); find_path_inner(db, item, from, MAX_PATH_LEN) } @@ -215,7 +214,7 @@ fn find_local_import_locations( item: ItemInNs, from: ModuleId, ) -> Vec<(ModuleId, Name)> { - let _p = profile("find_local_import_locations"); + let _p = profile::span("find_local_import_locations"); // `from` can import anything below `from` with visibility of at least `from`, and anything // above `from` with any visibility. That means we do not need to descend into private siblings diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 90daa46b4..0e06a0b12 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -11,7 +11,6 @@ use hir_expand::{ InFile, }; use ra_db::FileId; -use ra_prof::profile; use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; use crate::{ @@ -73,7 +72,7 @@ impl GenericParams { db: &dyn DefDatabase, def: GenericDefId, ) -> Arc { - let _p = profile("generic_params_query"); + let _p = profile::span("generic_params_query"); let generics = match def { GenericDefId::FunctionId(id) => { diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 9e4c30b1a..3a9eec887 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs @@ -56,7 +56,7 @@ pub struct ImportMap { impl ImportMap { pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { - let _p = ra_prof::profile("import_map_query"); + let _p = profile::span("import_map_query"); let def_map = db.crate_def_map(krate); let mut import_map = Self::default(); @@ -254,7 +254,7 @@ pub fn search_dependencies<'a>( krate: CrateId, query: Query, ) -> Vec { - let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query)); + let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query)); let graph = db.crate_graph(); let import_maps: Vec<_> = diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index fc05bb307..104966c7f 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -77,7 +77,7 @@ pub struct ItemTree { impl ItemTree { pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { - let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); + let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id)); let syntax = if let Some(node) = db.parse_or_expand(file_id) { node } else { diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs index 3516784b8..3631499bf 100644 --- a/crates/ra_hir_def/src/lang_item.rs +++ b/crates/ra_hir_def/src/lang_item.rs @@ -4,7 +4,6 @@ //! features, such as Fn family of traits. use std::sync::Arc; -use ra_prof::profile; use ra_syntax::SmolStr; use rustc_hash::FxHashMap; @@ -79,7 +78,7 @@ impl LangItems { /// Salsa query. This will look for lang items in a specific crate. pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { - let _p = profile("crate_lang_items_query"); + let _p = profile::span("crate_lang_items_query"); let mut lang_items = LangItems::default(); @@ -98,7 +97,7 @@ impl LangItems { db: &dyn DefDatabase, module: ModuleId, ) -> Option> { - let _p = profile("module_lang_items_query"); + let _p = profile::span("module_lang_items_query"); let mut lang_items = LangItems::default(); lang_items.collect_lang_items(db, module); if lang_items.items.is_empty() { @@ -115,7 +114,7 @@ impl LangItems { start_crate: CrateId, item: SmolStr, ) -> Option { - let _p = profile("lang_item_query"); + let _p = profile::span("lang_item_query"); let lang_items = db.crate_lang_items(start_crate); let start_crate_target = lang_items.items.get(&item); if let Some(target) = start_crate_target { diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index b4b97eb08..dc239997f 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -59,7 +59,6 @@ use std::sync::Arc; use arena::Arena; use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; use ra_db::{CrateId, Edition, FileId}; -use ra_prof::profile; use ra_syntax::ast; use rustc_hash::FxHashMap; use stdx::format_to; @@ -172,7 +171,7 @@ pub struct ModuleData { impl CrateDefMap { pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { - let _p = profile("crate_def_map_query").detail(|| { + let _p = profile::span("crate_def_map_query").detail(|| { db.crate_graph()[krate] .display_name .as_ref() diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index 808c36fd8..711a93c56 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml @@ -17,7 +17,7 @@ arena = { path = "../arena" } ra_db = { path = "../ra_db" } ra_syntax = { path = "../ra_syntax" } ra_parser = { path = "../ra_parser" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } tt = { path = "../ra_tt", package = "ra_tt" } mbe = { path = "../ra_mbe", package = "ra_mbe" } test_utils = { path = "../test_utils"} diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index f3b7cd492..f30528b3e 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -5,7 +5,6 @@ use std::sync::Arc; use mbe::{ExpandResult, MacroRules}; use ra_db::{salsa, SourceDatabase}; use ra_parser::FragmentKind; -use ra_prof::profile; use ra_syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; use crate::{ @@ -278,7 +277,7 @@ pub fn parse_macro_with_arg( macro_file: MacroFile, arg: Option>, ) -> Option<(Parse, Arc)> { - let _p = profile("parse_macro_query"); + let _p = profile::span("parse_macro_query"); let macro_call_id = macro_file.macro_call_id; let (tt, err) = if let Some(arg) = arg { diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index fc68eaa8f..380d5e601 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -22,7 +22,7 @@ hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } arena = { path = "../arena" } ra_db = { path = "../ra_db" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } ra_syntax = { path = "../ra_syntax" } test_utils = { path = "../test_utils" } diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index d396017bf..7a28673b1 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -8,7 +8,6 @@ use hir_def::{ TypeParamId, VariantId, }; use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; -use ra_prof::profile; use crate::{ method_resolution::{InherentImpls, TraitImpls}, @@ -123,7 +122,7 @@ pub trait HirDatabase: DefDatabase + Upcast { } fn infer_wait(db: &impl HirDatabase, def: DefWithBodyId) -> Arc { - let _p = profile("infer:wait").detail(|| match def { + let _p = profile::span("infer:wait").detail(|| match def { DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(), DefWithBodyId::StaticId(it) => { db.static_data(it).name.clone().unwrap_or_else(Name::missing).to_string() diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 7ab7f79db..55c02c1fe 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs @@ -8,7 +8,6 @@ use std::any::Any; use hir_def::DefWithBodyId; use hir_expand::diagnostics::{Diagnostic, DiagnosticSink}; use hir_expand::{name::Name, HirFileId, InFile}; -use ra_prof::profile; use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; use stdx::format_to; @@ -17,7 +16,7 @@ use crate::db::HirDatabase; pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { - let _p = profile("validate_body"); + let _p = profile::span("validate_body"); let infer = db.infer(owner); infer.add_diagnostics(db, owner, sink); let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink); diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index e003690b3..784ae1c3c 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -31,7 +31,6 @@ use hir_def::{ TypeAliasId, VariantId, }; use hir_expand::{diagnostics::DiagnosticSink, name::name}; -use ra_prof::profile; use ra_syntax::SmolStr; use rustc_hash::FxHashMap; use stdx::impl_from; @@ -64,7 +63,7 @@ mod coerce; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - let _p = profile("infer_query"); + let _p = profile::span("infer_query"); let resolver = def.resolver(db.upcast()); let mut ctx = InferenceContext::new(db, def, resolver); diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index fb4b30a13..3b3bee6a7 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -13,7 +13,6 @@ use hir_def::{ }; use hir_expand::name::Name; use ra_db::CrateId; -use ra_prof::profile; use rustc_hash::{FxHashMap, FxHashSet}; use super::Substs; @@ -109,7 +108,7 @@ pub struct TraitImpls { impl TraitImpls { pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = profile("trait_impls_in_crate_query"); + let _p = profile::span("trait_impls_in_crate_query"); let mut impls = Self { map: FxHashMap::default() }; let crate_def_map = db.crate_def_map(krate); @@ -135,7 +134,7 @@ impl TraitImpls { } pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = profile("trait_impls_in_deps_query"); + let _p = profile::span("trait_impls_in_deps_query"); let crate_graph = db.crate_graph(); let mut res = Self { map: FxHashMap::default() }; diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 3f6d2cf35..2576a9dfc 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -5,7 +5,6 @@ use chalk_ir::cast::Cast; use chalk_solve::Solver; use hir_def::{lang_item::LangItemTarget, TraitId}; use ra_db::CrateId; -use ra_prof::profile; use crate::{db::HirDatabase, DebruijnIndex, Substs}; @@ -125,7 +124,7 @@ pub(crate) fn trait_solve_query( krate: CrateId, goal: Canonical>, ) -> Option { - let _p = profile("trait_solve_query").detail(|| match &goal.value.value { + let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value { Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(), Obligation::Projection(_) => "projection".to_string(), }); diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 1c7065364..3b6af5c9a 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -410,7 +410,7 @@ pub(crate) fn impl_datum_query( krate: CrateId, impl_id: ImplId, ) -> Arc { - let _p = ra_prof::profile("impl_datum"); + let _p = profile::span("impl_datum"); debug!("impl_datum {:?}", impl_id); let impl_: hir_def::ImplId = from_chalk(db, impl_id); impl_def_datum(db, krate, impl_id, impl_) diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml index f4181c4eb..bbc9ba4e7 100644 --- a/crates/ra_ide/Cargo.toml +++ b/crates/ra_ide/Cargo.toml @@ -27,7 +27,7 @@ ra_db = { path = "../ra_db" } ra_ide_db = { path = "../ra_ide_db" } ra_cfg = { path = "../ra_cfg" } ra_fmt = { path = "../ra_fmt" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } test_utils = { path = "../test_utils" } ra_assists = { path = "../ra_assists" } ra_ssr = { path = "../ra_ssr" } diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 1046d7ab3..07bf133bd 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -10,7 +10,6 @@ use hir::{diagnostics::DiagnosticSinkBuilder, Semantics}; use itertools::Itertools; use ra_db::SourceDatabase; use ra_ide_db::RootDatabase; -use ra_prof::profile; use ra_syntax::{ ast::{self, AstNode}, SyntaxNode, TextRange, T, @@ -33,7 +32,7 @@ pub(crate) fn diagnostics( file_id: FileId, enable_experimental: bool, ) -> Vec { - let _p = profile("diagnostics"); + let _p = profile::span("diagnostics"); let sema = Semantics::new(db); let parse = db.parse(file_id); let mut res = Vec::new(); diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 1bacead63..920b04e8d 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs @@ -1,6 +1,5 @@ use hir::{Adt, Callable, HirDisplay, Semantics, Type}; use ra_ide_db::RootDatabase; -use ra_prof::profile; use ra_syntax::{ ast::{self, ArgListOwner, AstNode}, match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, @@ -64,7 +63,7 @@ pub(crate) fn inlay_hints( file_id: FileId, config: &InlayHintsConfig, ) -> Vec { - let _p = profile("inlay_hints"); + let _p = profile::span("inlay_hints"); let sema = Semantics::new(db); let file = sema.parse(file_id); diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 89fcb6f17..bfcf5d750 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -176,7 +176,7 @@ impl AnalysisHost { self.db.collect_garbage(); } /// NB: this clears the database - pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> { + pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes)> { self.db.per_query_memory_usage() } pub fn request_cancellation(&mut self) { diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 453985de3..c4eea3a45 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -17,7 +17,6 @@ use ra_ide_db::{ search::SearchScope, RootDatabase, }; -use ra_prof::profile; use ra_syntax::{ algo::find_node_at_offset, ast::{self, NameOwner}, @@ -90,7 +89,7 @@ pub(crate) fn find_all_refs( position: FilePosition, search_scope: Option, ) -> Option> { - let _p = profile("find_all_refs"); + let _p = profile::span("find_all_refs"); let syntax = sema.parse(position.file_id).syntax().clone(); let (opt_name, search_kind) = if let Some(name) = diff --git a/crates/ra_ide/src/status.rs b/crates/ra_ide/src/status.rs index 08e6f69cb..009bb662f 100644 --- a/crates/ra_ide/src/status.rs +++ b/crates/ra_ide/src/status.rs @@ -1,6 +1,7 @@ use std::{fmt, iter::FromIterator, sync::Arc}; use hir::MacroFile; +use profile::{memory_usage, Bytes}; use ra_db::{ salsa::debug::{DebugQueryTable, TableEntry}, FileTextQuery, SourceRootId, @@ -9,7 +10,6 @@ use ra_ide_db::{ symbol_index::{LibrarySymbolsQuery, SymbolIndex}, RootDatabase, }; -use ra_prof::{memory_usage, Bytes}; use ra_syntax::{ast, Parse, SyntaxNode}; use rustc_hash::FxHashMap; diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index c10e15db8..ebdf05127 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -9,7 +9,6 @@ use ra_ide_db::{ defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, RootDatabase, }; -use ra_prof::profile; use ra_syntax::{ ast::{self, HasFormatSpecifier}, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, @@ -46,7 +45,7 @@ pub(crate) fn highlight( range_to_highlight: Option, syntactic_name_ref_highlighting: bool, ) -> Vec { - let _p = profile("highlight"); + let _p = profile::span("highlight"); let sema = Semantics::new(db); // Determine the root based on the given range. diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml index 2716a38cc..92b8ef82a 100644 --- a/crates/ra_ide_db/Cargo.toml +++ b/crates/ra_ide_db/Cargo.toml @@ -24,7 +24,7 @@ stdx = { path = "../stdx" } ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } ra_db = { path = "../ra_db" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } test_utils = { path = "../test_utils" } # ra_ide should depend only on the top-level `hir` package. if you need diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index b13df8b85..7a4e04ca9 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs @@ -3,11 +3,11 @@ use std::{fmt, sync::Arc, time}; +use profile::{memory_usage, Bytes}; use ra_db::{ salsa::{Database, Durability, SweepStrategy}, CrateGraph, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, }; -use ra_prof::{memory_usage, profile, Bytes}; use rustc_hash::FxHashSet; use crate::{symbol_index::SymbolsDatabase, RootDatabase}; @@ -85,12 +85,12 @@ const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100); impl RootDatabase { pub fn request_cancellation(&mut self) { - let _p = profile("RootDatabase::request_cancellation"); + let _p = profile::span("RootDatabase::request_cancellation"); self.salsa_runtime_mut().synthetic_write(Durability::LOW); } pub fn apply_change(&mut self, change: AnalysisChange) { - let _p = profile("RootDatabase::apply_change"); + let _p = profile::span("RootDatabase::apply_change"); self.request_cancellation(); log::info!("apply_change {:?}", change); if let Some(roots) = change.roots { @@ -141,7 +141,7 @@ impl RootDatabase { return; } - let _p = profile("RootDatabase::collect_garbage"); + let _p = profile::span("RootDatabase::collect_garbage"); self.last_gc = crate::wasm_shims::Instant::now(); let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 9bb95277d..d46d1fe71 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs @@ -9,7 +9,6 @@ use hir::{ db::HirDatabase, Crate, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, }; -use ra_prof::profile; use ra_syntax::{ ast::{self, AstNode}, match_ast, SyntaxNode, @@ -110,7 +109,7 @@ impl NameClass { } pub fn classify_name(sema: &Semantics, name: &ast::Name) -> Option { - let _p = profile("classify_name"); + let _p = profile::span("classify_name"); let parent = name.syntax().parent()?; @@ -249,7 +248,7 @@ pub fn classify_name_ref( sema: &Semantics, name_ref: &ast::NameRef, ) -> Option { - let _p = profile("classify_name_ref"); + let _p = profile::span("classify_name_ref"); let parent = name_ref.syntax().parent()?; diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index 9e040973b..d510ce3b7 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs @@ -2,7 +2,6 @@ //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. use hir::{Crate, MacroDef, ModuleDef, Semantics}; -use ra_prof::profile; use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; use crate::{ @@ -18,7 +17,7 @@ pub fn find_imports<'a>( krate: Crate, name_to_import: &str, ) -> Vec> { - let _p = profile("search_for_imports"); + let _p = profile::span("search_for_imports"); let db = sema.db; // Query dependencies first. @@ -51,7 +50,7 @@ fn get_name_definition<'a>( sema: &Semantics<'a, RootDatabase>, import_candidate: &FileSymbol, ) -> Option { - let _p = profile("get_name_definition"); + let _p = profile::span("get_name_definition"); let file_id = import_candidate.file_id; let candidate_node = import_candidate.ptr.to_node(sema.parse(file_id).syntax()); diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs index 0b862b449..d90b830d0 100644 --- a/crates/ra_ide_db/src/search.rs +++ b/crates/ra_ide_db/src/search.rs @@ -9,7 +9,6 @@ use std::{convert::TryInto, mem}; use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility}; use once_cell::unsync::Lazy; use ra_db::{FileId, FileRange, SourceDatabaseExt}; -use ra_prof::profile; use ra_syntax::{ast, match_ast, AstNode, TextRange, TextSize}; use rustc_hash::FxHashMap; @@ -107,7 +106,7 @@ impl IntoIterator for SearchScope { impl Definition { fn search_scope(&self, db: &RootDatabase) -> SearchScope { - let _p = profile("search_scope"); + let _p = profile::span("search_scope"); let module = match self.module(db) { Some(it) => it, None => return SearchScope::empty(), @@ -187,7 +186,7 @@ impl Definition { sema: &Semantics, search_scope: Option, ) -> Vec { - let _p = profile("Definition::find_usages"); + let _p = profile::span("Definition::find_usages"); let search_scope = { let base = self.search_scope(sema.db); diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index 35a2c5be3..6ca8bb516 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs @@ -34,7 +34,6 @@ use ra_db::{ salsa::{self, ParallelDatabase}, CrateId, FileId, SourceDatabaseExt, SourceRootId, }; -use ra_prof::profile; use ra_syntax::{ ast::{self, NameOwner}, match_ast, AstNode, Parse, SmolStr, SourceFile, @@ -101,7 +100,7 @@ pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt { } fn library_symbols(db: &dyn SymbolsDatabase) -> Arc> { - let _p = profile("library_symbols"); + let _p = profile::span("library_symbols"); let roots = db.library_roots(); let res = roots @@ -162,7 +161,7 @@ impl Clone for Snap> { // | VS Code | kbd:[Ctrl+T] // |=== pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { - let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone()); + let _p = profile::span("world_symbols").detail(|| query.query.clone()); let tmp1; let tmp2; diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml deleted file mode 100644 index 9880c587f..000000000 --- a/crates/ra_prof/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -edition = "2018" -name = "ra_prof" -version = "0.1.0" -authors = ["rust-analyzer developers"] -publish = false -license = "MIT OR Apache-2.0" - -[lib] -doctest = false - -[dependencies] -arena = { path = "../arena" } -once_cell = "1.3.1" -backtrace = { version = "0.3.44", optional = true } -cfg-if = "0.1.10" -libc = "0.2.73" - -[target.'cfg(target_os = "linux")'.dependencies] -perf-event = "0.4" - -[features] -cpu_profiler = [] - -# Uncomment to enable for the whole crate graph -# default = [ "backtrace" ] -# default = [ "cpu_profiler" ] diff --git a/crates/ra_prof/src/google_cpu_profiler.rs b/crates/ra_prof/src/google_cpu_profiler.rs deleted file mode 100644 index db865c65b..000000000 --- a/crates/ra_prof/src/google_cpu_profiler.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! https://github.com/gperftools/gperftools - -use std::{ - ffi::CString, - os::raw::c_char, - path::Path, - sync::atomic::{AtomicUsize, Ordering}, -}; - -#[link(name = "profiler")] -#[allow(non_snake_case)] -extern "C" { - fn ProfilerStart(fname: *const c_char) -> i32; - fn ProfilerStop(); -} - -static PROFILER_STATE: AtomicUsize = AtomicUsize::new(OFF); -const OFF: usize = 0; -const ON: usize = 1; -const PENDING: usize = 2; - -pub fn start(path: &Path) { - if PROFILER_STATE.compare_and_swap(OFF, PENDING, Ordering::SeqCst) != OFF { - panic!("profiler already started"); - } - let path = CString::new(path.display().to_string()).unwrap(); - if unsafe { ProfilerStart(path.as_ptr()) } == 0 { - panic!("profiler failed to start") - } - assert!(PROFILER_STATE.compare_and_swap(PENDING, ON, Ordering::SeqCst) == PENDING); -} - -pub fn stop() { - if PROFILER_STATE.compare_and_swap(ON, PENDING, Ordering::SeqCst) != ON { - panic!("profiler is not started") - } - unsafe { ProfilerStop() }; - assert!(PROFILER_STATE.compare_and_swap(PENDING, OFF, Ordering::SeqCst) == PENDING); -} diff --git a/crates/ra_prof/src/hprof.rs b/crates/ra_prof/src/hprof.rs deleted file mode 100644 index a3f5321fb..000000000 --- a/crates/ra_prof/src/hprof.rs +++ /dev/null @@ -1,243 +0,0 @@ -//! Simple hierarchical profiler -use once_cell::sync::Lazy; -use std::{ - cell::RefCell, - collections::{BTreeMap, HashSet}, - io::{stderr, Write}, - sync::{ - atomic::{AtomicBool, Ordering}, - RwLock, - }, - time::{Duration, Instant}, -}; - -use crate::tree::{Idx, Tree}; - -/// Filtering syntax -/// env RA_PROFILE=* // dump everything -/// env RA_PROFILE=foo|bar|baz // enabled only selected entries -/// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms -pub fn init() { - let spec = std::env::var("RA_PROFILE").unwrap_or_default(); - init_from(&spec); -} - -pub fn init_from(spec: &str) { - let filter = if spec.is_empty() { Filter::disabled() } else { Filter::from_spec(spec) }; - filter.install(); -} - -pub type Label = &'static str; - -/// This function starts a profiling scope in the current execution stack with a given description. -/// It returns a `Profile` struct that measures elapsed time between this method invocation and `Profile` struct drop. -/// It supports nested profiling scopes in case when this function is invoked multiple times at the execution stack. -/// In this case the profiling information will be nested at the output. -/// Profiling information is being printed in the stderr. -/// -/// # Example -/// ``` -/// use ra_prof::{profile, set_filter, Filter}; -/// -/// let f = Filter::from_spec("profile1|profile2@2"); -/// set_filter(f); -/// profiling_function1(); -/// -/// fn profiling_function1() { -/// let _p = profile("profile1"); -/// profiling_function2(); -/// } -/// -/// fn profiling_function2() { -/// let _p = profile("profile2"); -/// } -/// ``` -/// This will print in the stderr the following: -/// ```text -/// 0ms - profile -/// 0ms - profile2 -/// ``` -pub fn profile(label: Label) -> Profiler { - assert!(!label.is_empty()); - - if PROFILING_ENABLED.load(Ordering::Relaxed) - && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)) - { - Profiler(Some(ProfilerImpl { label, detail: None })) - } else { - Profiler(None) - } -} - -pub struct Profiler(Option); - -struct ProfilerImpl { - label: Label, - detail: Option, -} - -impl Profiler { - pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler { - if let Some(profiler) = &mut self.0 { - profiler.detail = Some(detail()) - } - self - } -} - -impl Drop for ProfilerImpl { - fn drop(&mut self) { - PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take())); - } -} - -static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false); -static FILTER: Lazy> = Lazy::new(Default::default); -thread_local!(static PROFILE_STACK: RefCell = RefCell::new(ProfileStack::new())); - -#[derive(Default, Clone, Debug)] -struct Filter { - depth: usize, - allowed: HashSet, - longer_than: Duration, - version: usize, -} - -impl Filter { - fn disabled() -> Filter { - Filter::default() - } - - fn from_spec(mut spec: &str) -> Filter { - let longer_than = if let Some(idx) = spec.rfind('>') { - let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than"); - spec = &spec[..idx]; - Duration::from_millis(longer_than) - } else { - Duration::new(0, 0) - }; - - let depth = if let Some(idx) = spec.rfind('@') { - let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); - spec = &spec[..idx]; - depth - } else { - 999 - }; - let allowed = - if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() }; - Filter { depth, allowed, longer_than, version: 0 } - } - - fn install(mut self) { - PROFILING_ENABLED.store(self.depth > 0, Ordering::SeqCst); - let mut old = FILTER.write().unwrap(); - self.version = old.version + 1; - *old = self; - } -} - -struct ProfileStack { - starts: Vec, - filter: Filter, - messages: Tree, -} - -#[derive(Default)] -struct Message { - duration: Duration, - label: Label, - detail: Option, -} - -impl ProfileStack { - fn new() -> ProfileStack { - ProfileStack { starts: Vec::new(), messages: Tree::default(), filter: Default::default() } - } - - fn push(&mut self, label: Label) -> bool { - if self.starts.is_empty() { - if let Ok(f) = FILTER.try_read() { - if f.version > self.filter.version { - self.filter = f.clone(); - } - }; - } - if self.starts.len() > self.filter.depth { - return false; - } - let allowed = &self.filter.allowed; - if self.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) { - return false; - } - - self.starts.push(Instant::now()); - self.messages.start(); - true - } - - pub fn pop(&mut self, label: Label, detail: Option) { - let start = self.starts.pop().unwrap(); - let duration = start.elapsed(); - self.messages.finish(Message { duration, label, detail }); - if self.starts.is_empty() { - let longer_than = self.filter.longer_than; - // Convert to millis for comparison to avoid problems with rounding - // (otherwise we could print `0ms` despite user's `>0` filter when - // `duration` is just a few nanos). - if duration.as_millis() > longer_than.as_millis() { - if let Some(root) = self.messages.root() { - print(&self.messages, root, 0, longer_than, &mut stderr().lock()); - } - } - self.messages.clear(); - } - } -} - -fn print( - tree: &Tree, - curr: Idx, - level: u32, - longer_than: Duration, - out: &mut impl Write, -) { - let current_indent = " ".repeat(level as usize); - let detail = tree[curr].detail.as_ref().map(|it| format!(" @ {}", it)).unwrap_or_default(); - writeln!( - out, - "{}{:5}ms - {}{}", - current_indent, - tree[curr].duration.as_millis(), - tree[curr].label, - detail, - ) - .expect("printing profiling info"); - - let mut accounted_for = Duration::default(); - let mut short_children = BTreeMap::new(); // Use `BTreeMap` to get deterministic output. - for child in tree.children(curr) { - accounted_for += tree[child].duration; - - if tree[child].duration.as_millis() > longer_than.as_millis() { - print(tree, child, level + 1, longer_than, out) - } else { - let (total_duration, cnt) = - short_children.entry(tree[child].label).or_insert((Duration::default(), 0)); - *total_duration += tree[child].duration; - *cnt += 1; - } - } - - for (child_msg, (duration, count)) in short_children.iter() { - let millis = duration.as_millis(); - writeln!(out, " {}{:5}ms - {} ({} calls)", current_indent, millis, child_msg, count) - .expect("printing profiling info"); - } - - let unaccounted = tree[curr].duration - accounted_for; - if tree.children(curr).next().is_some() && unaccounted > longer_than { - writeln!(out, " {}{:5}ms - ???", current_indent, unaccounted.as_millis()) - .expect("printing profiling info"); - } -} diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs deleted file mode 100644 index eb50965ae..000000000 --- a/crates/ra_prof/src/lib.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! A collection of tools for profiling rust-analyzer. - -mod stop_watch; -mod memory_usage; -#[cfg(feature = "cpu_profiler")] -mod google_cpu_profiler; -mod hprof; -mod tree; - -use std::cell::RefCell; - -pub use crate::{ - hprof::{init, init_from, profile}, - memory_usage::{Bytes, MemoryUsage}, - stop_watch::{StopWatch, StopWatchSpan}, -}; - -/// Prints backtrace to stderr, useful for debugging. -#[cfg(feature = "backtrace")] -pub fn print_backtrace() { - let bt = backtrace::Backtrace::new(); - eprintln!("{:?}", bt); -} -#[cfg(not(feature = "backtrace"))] -pub fn print_backtrace() { - eprintln!( - r#"enable the backtrace feature: - ra_prof = {{ path = "../ra_prof", features = [ "backtrace"] }} -"# - ); -} - -thread_local!(static IN_SCOPE: RefCell = RefCell::new(false)); - -/// Allows to check if the current code is withing some dynamic scope, can be -/// useful during debugging to figure out why a function is called. -pub struct Scope { - prev: bool, -} - -impl Scope { - #[must_use] - pub fn enter() -> Scope { - let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true)); - Scope { prev } - } - pub fn is_active() -> bool { - IN_SCOPE.with(|slot| *slot.borrow()) - } -} - -impl Drop for Scope { - fn drop(&mut self) { - IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev); - } -} - -/// A wrapper around google_cpu_profiler. -/// -/// Usage: -/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro. -/// 2. Build with `cpu_profiler` feature. -/// 3. Tun the code, the *raw* output would be in the `./out.profile` file. -/// 4. Install pprof for visualization (https://github.com/google/pprof). -/// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000` -/// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. -/// -/// For example, here's how I run profiling on NixOS: -/// -/// ```bash -/// $ nix-shell -p gperftools --run \ -/// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null' -/// ``` -/// -/// See this diff for how to profile completions: -/// -/// https://github.com/rust-analyzer/rust-analyzer/pull/5306 -#[derive(Debug)] -pub struct CpuProfiler { - _private: (), -} - -#[must_use] -pub fn cpu_profiler() -> CpuProfiler { - #[cfg(feature = "cpu_profiler")] - { - google_cpu_profiler::start("./out.profile".as_ref()) - } - - #[cfg(not(feature = "cpu_profiler"))] - { - eprintln!("cpu_profiler feature is disabled") - } - - CpuProfiler { _private: () } -} - -impl Drop for CpuProfiler { - fn drop(&mut self) { - #[cfg(feature = "cpu_profiler")] - { - google_cpu_profiler::stop() - } - } -} - -pub fn memory_usage() -> MemoryUsage { - MemoryUsage::current() -} diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs deleted file mode 100644 index 83390212a..000000000 --- a/crates/ra_prof/src/memory_usage.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! FIXME: write short doc here -use std::fmt; - -use cfg_if::cfg_if; - -#[derive(Copy, Clone)] -pub struct MemoryUsage { - pub allocated: Bytes, -} - -impl fmt::Display for MemoryUsage { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}", self.allocated) - } -} - -impl std::ops::Sub for MemoryUsage { - type Output = MemoryUsage; - fn sub(self, rhs: MemoryUsage) -> MemoryUsage { - MemoryUsage { allocated: self.allocated - rhs.allocated } - } -} - -impl MemoryUsage { - pub fn current() -> MemoryUsage { - cfg_if! { - if #[cfg(all(target_os = "linux", target_env = "gnu"))] { - // Note: This is incredibly slow. - let alloc = unsafe { libc::mallinfo() }.uordblks as isize; - MemoryUsage { allocated: Bytes(alloc) } - } else { - MemoryUsage { allocated: Bytes(0) } - } - } - } -} - -#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] -pub struct Bytes(isize); - -impl Bytes { - pub fn megabytes(self) -> isize { - self.0 / 1024 / 1024 - } -} - -impl fmt::Display for Bytes { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let bytes = self.0; - let mut value = bytes; - let mut suffix = "b"; - if value.abs() > 4096 { - value /= 1024; - suffix = "kb"; - if value.abs() > 4096 { - value /= 1024; - suffix = "mb"; - } - } - f.pad(&format!("{}{}", value, suffix)) - } -} - -impl std::ops::AddAssign for Bytes { - fn add_assign(&mut self, x: usize) { - self.0 += x as isize; - } -} - -impl std::ops::Sub for Bytes { - type Output = Bytes; - fn sub(self, rhs: Bytes) -> Bytes { - Bytes(self.0 - rhs.0) - } -} diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs deleted file mode 100644 index 5e276190e..000000000 --- a/crates/ra_prof/src/stop_watch.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Like `std::time::Instant`, but also measures memory & CPU cycles. -use std::{ - fmt, - time::{Duration, Instant}, -}; - -use crate::MemoryUsage; - -pub struct StopWatch { - time: Instant, - #[cfg(target_os = "linux")] - counter: Option, - memory: Option, -} - -pub struct StopWatchSpan { - pub time: Duration, - pub instructions: Option, - pub memory: Option, -} - -impl StopWatch { - pub fn start() -> StopWatch { - #[cfg(target_os = "linux")] - let counter = { - let mut counter = perf_event::Builder::new() - .build() - .map_err(|err| eprintln!("Failed to create perf counter: {}", err)) - .ok(); - if let Some(counter) = &mut counter { - if let Err(err) = counter.enable() { - eprintln!("Failed to start perf counter: {}", err) - } - } - counter - }; - let time = Instant::now(); - StopWatch { - time, - #[cfg(target_os = "linux")] - counter, - memory: None, - } - } - pub fn memory(mut self, yes: bool) -> StopWatch { - if yes { - self.memory = Some(MemoryUsage::current()); - } - self - } - pub fn elapsed(&mut self) -> StopWatchSpan { - let time = self.time.elapsed(); - - #[cfg(target_os = "linux")] - let instructions = self.counter.as_mut().and_then(|it| { - it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok() - }); - #[cfg(not(target_os = "linux"))] - let instructions = None; - - let memory = self.memory.map(|it| MemoryUsage::current() - it); - StopWatchSpan { time, instructions, memory } - } -} - -impl fmt::Display for StopWatchSpan { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:.2?}", self.time)?; - if let Some(mut instructions) = self.instructions { - let mut prefix = ""; - if instructions > 10000 { - instructions /= 1000; - prefix = "k" - } - if instructions > 10000 { - instructions /= 1000; - prefix = "m" - } - write!(f, ", {}{}i", instructions, prefix)?; - } - if let Some(memory) = self.memory { - write!(f, ", {}", memory)?; - } - Ok(()) - } -} diff --git a/crates/ra_prof/src/tree.rs b/crates/ra_prof/src/tree.rs deleted file mode 100644 index 096f58511..000000000 --- a/crates/ra_prof/src/tree.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! A simple tree implementation which tries to not allocate all over the place. -use std::ops; - -use arena::Arena; - -#[derive(Default)] -pub struct Tree { - nodes: Arena>, - current_path: Vec<(Idx, Option>)>, -} - -pub type Idx = arena::Idx>; - -impl Tree { - pub fn start(&mut self) - where - T: Default, - { - let me = self.nodes.alloc(Node::new(T::default())); - if let Some((parent, last_child)) = self.current_path.last_mut() { - let slot = match *last_child { - Some(last_child) => &mut self.nodes[last_child].next_sibling, - None => &mut self.nodes[*parent].first_child, - }; - let prev = slot.replace(me); - assert!(prev.is_none()); - *last_child = Some(me); - } - - self.current_path.push((me, None)); - } - - pub fn finish(&mut self, data: T) { - let (me, _last_child) = self.current_path.pop().unwrap(); - self.nodes[me].data = data; - } - - pub fn root(&self) -> Option> { - self.nodes.iter().next().map(|(idx, _)| idx) - } - - pub fn children(&self, idx: Idx) -> impl Iterator> + '_ { - NodeIter { nodes: &self.nodes, next: self.nodes[idx].first_child } - } - pub fn clear(&mut self) { - self.nodes.clear(); - self.current_path.clear(); - } -} - -impl ops::Index> for Tree { - type Output = T; - fn index(&self, index: Idx) -> &T { - &self.nodes[index].data - } -} - -pub struct Node { - data: T, - first_child: Option>, - next_sibling: Option>, -} - -impl Node { - fn new(data: T) -> Node { - Node { data, first_child: None, next_sibling: None } - } -} - -struct NodeIter<'a, T> { - nodes: &'a Arena>, - next: Option>, -} - -impl<'a, T> Iterator for NodeIter<'a, T> { - type Item = Idx; - - fn next(&mut self) -> Option> { - self.next.map(|next| { - self.next = self.nodes[next].next_sibling; - next - }) - } -} diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 02c1371ac..6cbf43bb2 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -36,7 +36,7 @@ stdx = { path = "../stdx" } lsp-server = "0.3.3" flycheck = { path = "../flycheck" } ra_ide = { path = "../ra_ide" } -ra_prof = { path = "../ra_prof" } +profile = { path = "../profile" } ra_project_model = { path = "../ra_project_model" } ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index fc7f8b01d..9622d71c0 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -55,7 +55,7 @@ fn try_main() -> Result<()> { fn setup_logging() -> Result<()> { std::env::set_var("RUST_BACKTRACE", "short"); env_logger::try_init_from_env("RA_LOG")?; - ra_prof::init(); + profile::init(); Ok(()) } diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index 1034d11bd..46d70fcb2 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs @@ -11,7 +11,6 @@ use std::io::Read; use anyhow::Result; use ra_ide::Analysis; -use ra_prof::profile; use ra_syntax::{AstNode, SourceFile}; pub use analysis_bench::{BenchCmd, BenchWhat, Position}; @@ -38,7 +37,7 @@ impl Verbosity { } pub fn parse(no_dump: bool) -> Result<()> { - let _p = profile("parsing"); + let _p = profile::span("parsing"); let file = file()?; if !no_dump { println!("{:#?}", file.syntax()); diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index c54ee5f4d..bc5f77e1a 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs @@ -52,7 +52,7 @@ impl FromStr for Position { impl BenchCmd { pub fn run(self, verbosity: Verbosity) -> Result<()> { - ra_prof::init(); + profile::init(); let start = Instant::now(); eprint!("loading: "); diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 0d386841e..a30c1ec79 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -29,7 +29,7 @@ use crate::{ }, print_memory_usage, }; -use ra_prof::StopWatch; +use profile::StopWatch; /// Need to wrap Snapshot to provide `Clone` impl for `map_with` struct Snap(DB); diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 658a50d15..8c115c8a6 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -27,7 +27,6 @@ use crate::{ to_proto::url_from_abs_path, Result, }; -use ra_prof::profile; #[derive(Eq, PartialEq, Copy, Clone)] pub(crate) enum Status { @@ -135,7 +134,7 @@ impl GlobalState { } pub(crate) fn process_changes(&mut self) -> bool { - let _p = profile("GlobalState::process_changes"); + let _p = profile::span("GlobalState::process_changes"); let mut fs_changes = Vec::new(); let mut has_fs_changes = false; diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 785dd2a26..d9b75eed4 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -22,7 +22,6 @@ use ra_ide::{ FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit, }; -use ra_prof::profile; use ra_project_model::TargetKind; use ra_syntax::{algo, ast, AstNode, SyntaxKind, TextRange, TextSize}; use serde::{Deserialize, Serialize}; @@ -39,7 +38,7 @@ use crate::{ }; pub(crate) fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result { - let _p = profile("handle_analyzer_status"); + let _p = profile::span("handle_analyzer_status"); let mut buf = String::new(); if snap.workspaces.is_empty() { @@ -64,7 +63,7 @@ pub(crate) fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result } pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result { - let _p = profile("handle_memory_usage"); + let _p = profile::span("handle_memory_usage"); let mem = state.analysis_host.per_query_memory_usage(); let mut out = String::new(); @@ -78,7 +77,7 @@ pub(crate) fn handle_syntax_tree( snap: GlobalStateSnapshot, params: lsp_ext::SyntaxTreeParams, ) -> Result { - let _p = profile("handle_syntax_tree"); + let _p = profile::span("handle_syntax_tree"); let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(id)?; let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); @@ -90,7 +89,7 @@ pub(crate) fn handle_expand_macro( snap: GlobalStateSnapshot, params: lsp_ext::ExpandMacroParams, ) -> Result> { - let _p = profile("handle_expand_macro"); + let _p = profile::span("handle_expand_macro"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; let offset = from_proto::offset(&line_index, params.position); @@ -103,7 +102,7 @@ pub(crate) fn handle_selection_range( snap: GlobalStateSnapshot, params: lsp_types::SelectionRangeParams, ) -> Result>> { - let _p = profile("handle_selection_range"); + let _p = profile::span("handle_selection_range"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; let res: Result> = params @@ -146,7 +145,7 @@ pub(crate) fn handle_matching_brace( snap: GlobalStateSnapshot, params: lsp_ext::MatchingBraceParams, ) -> Result> { - let _p = profile("handle_matching_brace"); + let _p = profile::span("handle_matching_brace"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; let res = params @@ -168,7 +167,7 @@ pub(crate) fn handle_join_lines( snap: GlobalStateSnapshot, params: lsp_ext::JoinLinesParams, ) -> Result> { - let _p = profile("handle_join_lines"); + let _p = profile::span("handle_join_lines"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; let line_endings = snap.file_line_endings(file_id); @@ -191,7 +190,7 @@ pub(crate) fn handle_on_enter( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> Result>> { - let _p = profile("handle_on_enter"); + let _p = profile::span("handle_on_enter"); let position = from_proto::file_position(&snap, params)?; let edit = match snap.analysis.on_enter(position)? { None => return Ok(None), @@ -208,7 +207,7 @@ pub(crate) fn handle_on_type_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentOnTypeFormattingParams, ) -> Result>> { - let _p = profile("handle_on_type_formatting"); + let _p = profile::span("handle_on_type_formatting"); let mut position = from_proto::file_position(&snap, params.text_document_position)?; let line_index = snap.analysis.file_line_index(position.file_id)?; let line_endings = snap.file_line_endings(position.file_id); @@ -247,7 +246,7 @@ pub(crate) fn handle_document_symbol( snap: GlobalStateSnapshot, params: lsp_types::DocumentSymbolParams, ) -> Result> { - let _p = profile("handle_document_symbol"); + let _p = profile::span("handle_document_symbol"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; @@ -332,7 +331,7 @@ pub(crate) fn handle_workspace_symbol( snap: GlobalStateSnapshot, params: lsp_types::WorkspaceSymbolParams, ) -> Result>> { - let _p = profile("handle_workspace_symbol"); + let _p = profile::span("handle_workspace_symbol"); let all_symbols = params.query.contains('#'); let libs = params.query.contains('*'); let query = { @@ -380,7 +379,7 @@ pub(crate) fn handle_goto_definition( snap: GlobalStateSnapshot, params: lsp_types::GotoDefinitionParams, ) -> Result> { - let _p = profile("handle_goto_definition"); + let _p = profile::span("handle_goto_definition"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_definition(position)? { None => return Ok(None), @@ -395,7 +394,7 @@ pub(crate) fn handle_goto_implementation( snap: GlobalStateSnapshot, params: lsp_types::request::GotoImplementationParams, ) -> Result> { - let _p = profile("handle_goto_implementation"); + let _p = profile::span("handle_goto_implementation"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_implementation(position)? { None => return Ok(None), @@ -410,7 +409,7 @@ pub(crate) fn handle_goto_type_definition( snap: GlobalStateSnapshot, params: lsp_types::request::GotoTypeDefinitionParams, ) -> Result> { - let _p = profile("handle_goto_type_definition"); + let _p = profile::span("handle_goto_type_definition"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_type_definition(position)? { None => return Ok(None), @@ -425,7 +424,7 @@ pub(crate) fn handle_parent_module( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> Result> { - let _p = profile("handle_parent_module"); + let _p = profile::span("handle_parent_module"); let position = from_proto::file_position(&snap, params)?; let navs = snap.analysis.parent_module(position)?; let res = to_proto::goto_definition_response(&snap, None, navs)?; @@ -436,7 +435,7 @@ pub(crate) fn handle_runnables( snap: GlobalStateSnapshot, params: lsp_ext::RunnablesParams, ) -> Result> { - let _p = profile("handle_runnables"); + let _p = profile::span("handle_runnables"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; let offset = params.position.map(|it| from_proto::offset(&line_index, it)); @@ -513,7 +512,7 @@ pub(crate) fn handle_completion( snap: GlobalStateSnapshot, params: lsp_types::CompletionParams, ) -> Result> { - let _p = profile("handle_completion"); + let _p = profile::span("handle_completion"); let position = from_proto::file_position(&snap, params.text_document_position)?; let completion_triggered_after_single_colon = { let mut res = false; @@ -555,7 +554,7 @@ pub(crate) fn handle_folding_range( snap: GlobalStateSnapshot, params: FoldingRangeParams, ) -> Result>> { - let _p = profile("handle_folding_range"); + let _p = profile::span("handle_folding_range"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let folds = snap.analysis.folding_ranges(file_id)?; let text = snap.analysis.file_text(file_id)?; @@ -572,7 +571,7 @@ pub(crate) fn handle_signature_help( snap: GlobalStateSnapshot, params: lsp_types::SignatureHelpParams, ) -> Result> { - let _p = profile("handle_signature_help"); + let _p = profile::span("handle_signature_help"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let call_info = match snap.analysis.call_info(position)? { Some(it) => it, @@ -591,7 +590,7 @@ pub(crate) fn handle_hover( snap: GlobalStateSnapshot, params: lsp_types::HoverParams, ) -> Result> { - let _p = profile("handle_hover"); + let _p = profile::span("handle_hover"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let info = match snap.analysis.hover(position)? { None => return Ok(None), @@ -614,7 +613,7 @@ pub(crate) fn handle_prepare_rename( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, ) -> Result> { - let _p = profile("handle_prepare_rename"); + let _p = profile::span("handle_prepare_rename"); let position = from_proto::file_position(&snap, params)?; let optional_change = snap.analysis.rename(position, "dummy")?; @@ -632,7 +631,7 @@ pub(crate) fn handle_rename( snap: GlobalStateSnapshot, params: RenameParams, ) -> Result> { - let _p = profile("handle_rename"); + let _p = profile::span("handle_rename"); let position = from_proto::file_position(&snap, params.text_document_position)?; if params.new_name.is_empty() { @@ -656,7 +655,7 @@ pub(crate) fn handle_references( snap: GlobalStateSnapshot, params: lsp_types::ReferenceParams, ) -> Result>> { - let _p = profile("handle_references"); + let _p = profile::span("handle_references"); let position = from_proto::file_position(&snap, params.text_document_position)?; let refs = match snap.analysis.find_all_refs(position, None)? { @@ -683,7 +682,7 @@ pub(crate) fn handle_formatting( snap: GlobalStateSnapshot, params: DocumentFormattingParams, ) -> Result>> { - let _p = profile("handle_formatting"); + let _p = profile::span("handle_formatting"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let file = snap.analysis.file_text(file_id)?; let crate_ids = snap.analysis.crate_for(file_id)?; @@ -805,7 +804,7 @@ pub(crate) fn handle_code_action( mut snap: GlobalStateSnapshot, params: lsp_types::CodeActionParams, ) -> Result>> { - let _p = profile("handle_code_action"); + let _p = profile::span("handle_code_action"); // We intentionally don't support command-based actions, as those either // requires custom client-code anyway, or requires server-initiated edits. // Server initiated edits break causality, so we avoid those as well. @@ -847,7 +846,7 @@ pub(crate) fn handle_resolve_code_action( mut snap: GlobalStateSnapshot, params: lsp_ext::ResolveCodeActionParams, ) -> Result> { - let _p = profile("handle_resolve_code_action"); + let _p = profile::span("handle_resolve_code_action"); let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; let range = from_proto::text_range(&line_index, params.code_action_params.range); @@ -871,7 +870,7 @@ pub(crate) fn handle_code_lens( snap: GlobalStateSnapshot, params: lsp_types::CodeLensParams, ) -> Result>> { - let _p = profile("handle_code_lens"); + let _p = profile::span("handle_code_lens"); let mut lenses: Vec = Default::default(); if snap.config.lens.none() { @@ -957,7 +956,7 @@ pub(crate) fn handle_code_lens_resolve( snap: GlobalStateSnapshot, code_lens: CodeLens, ) -> Result { - let _p = profile("handle_code_lens_resolve"); + let _p = profile::span("handle_code_lens_resolve"); let data = code_lens.data.unwrap(); let resolve = from_json::>("CodeLensResolveData", data)?; match resolve { @@ -994,7 +993,7 @@ pub(crate) fn handle_document_highlight( snap: GlobalStateSnapshot, params: lsp_types::DocumentHighlightParams, ) -> Result>> { - let _p = profile("handle_document_highlight"); + let _p = profile::span("handle_document_highlight"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let line_index = snap.analysis.file_line_index(position.file_id)?; @@ -1021,7 +1020,7 @@ pub(crate) fn handle_ssr( snap: GlobalStateSnapshot, params: lsp_ext::SsrParams, ) -> Result { - let _p = profile("handle_ssr"); + let _p = profile::span("handle_ssr"); let selections = params .selections .iter() @@ -1041,7 +1040,7 @@ pub(crate) fn publish_diagnostics( snap: &GlobalStateSnapshot, file_id: FileId, ) -> Result> { - let _p = profile("publish_diagnostics"); + let _p = profile::span("publish_diagnostics"); let line_index = snap.analysis.file_line_index(file_id)?; let diagnostics: Vec = snap .analysis @@ -1064,7 +1063,7 @@ pub(crate) fn handle_inlay_hints( snap: GlobalStateSnapshot, params: InlayHintsParams, ) -> Result> { - let _p = profile("handle_inlay_hints"); + let _p = profile::span("handle_inlay_hints"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.analysis.file_line_index(file_id)?; Ok(snap @@ -1079,7 +1078,7 @@ pub(crate) fn handle_call_hierarchy_prepare( snap: GlobalStateSnapshot, params: CallHierarchyPrepareParams, ) -> Result>> { - let _p = profile("handle_call_hierarchy_prepare"); + let _p = profile::span("handle_call_hierarchy_prepare"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.call_hierarchy(position)? { @@ -1101,7 +1100,7 @@ pub(crate) fn handle_call_hierarchy_incoming( snap: GlobalStateSnapshot, params: CallHierarchyIncomingCallsParams, ) -> Result>> { - let _p = profile("handle_call_hierarchy_incoming"); + let _p = profile::span("handle_call_hierarchy_incoming"); let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); @@ -1136,7 +1135,7 @@ pub(crate) fn handle_call_hierarchy_outgoing( snap: GlobalStateSnapshot, params: CallHierarchyOutgoingCallsParams, ) -> Result>> { - let _p = profile("handle_call_hierarchy_outgoing"); + let _p = profile::span("handle_call_hierarchy_outgoing"); let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); @@ -1171,7 +1170,7 @@ pub(crate) fn handle_semantic_tokens( snap: GlobalStateSnapshot, params: SemanticTokensParams, ) -> Result> { - let _p = profile("handle_semantic_tokens"); + let _p = profile::span("handle_semantic_tokens"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let text = snap.analysis.file_text(file_id)?; @@ -1190,7 +1189,7 @@ pub(crate) fn handle_semantic_tokens_edits( snap: GlobalStateSnapshot, params: SemanticTokensEditsParams, ) -> Result> { - let _p = profile("handle_semantic_tokens_edits"); + let _p = profile::span("handle_semantic_tokens_edits"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let text = snap.analysis.file_text(file_id)?; @@ -1220,7 +1219,7 @@ pub(crate) fn handle_semantic_tokens_range( snap: GlobalStateSnapshot, params: SemanticTokensRangeParams, ) -> Result> { - let _p = profile("handle_semantic_tokens_range"); + let _p = profile::span("handle_semantic_tokens_range"); let frange = from_proto::file_range(&snap, params.text_document, params.range)?; let text = snap.analysis.file_text(frange.file_id)?; diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index ed37992cd..8d2e76cc2 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -74,16 +74,16 @@ impl std::error::Error for LspError {} fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) { let mut mem = host.per_query_memory_usage(); - let before = ra_prof::memory_usage(); + let before = profile::memory_usage(); drop(vfs); - let vfs = before.allocated - ra_prof::memory_usage().allocated; + let vfs = before.allocated - profile::memory_usage().allocated; mem.push(("VFS".into(), vfs)); - let before = ra_prof::memory_usage(); + let before = profile::memory_usage(); drop(host); - mem.push(("Unaccounted".into(), before.allocated - ra_prof::memory_usage().allocated)); + mem.push(("Unaccounted".into(), before.allocated - profile::memory_usage().allocated)); - mem.push(("Remaining".into(), ra_prof::memory_usage().allocated)); + mem.push(("Remaining".into(), profile::memory_usage().allocated)); for (name, bytes) in mem { eprintln!("{:>8} {}", bytes, name); diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index e6cf46df2..32962b088 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -10,7 +10,6 @@ use lsp_server::{Connection, Notification, Request, Response}; use lsp_types::notification::Notification as _; use ra_db::VfsPath; use ra_ide::{Canceled, FileId}; -use ra_prof::profile; use crate::{ config::Config, @@ -173,7 +172,7 @@ impl GlobalState { fn handle_event(&mut self, event: Event) -> Result<()> { let loop_start = Instant::now(); // NOTE: don't count blocking select! call as a loop-turn time - let _p = profile("GlobalState::handle_event"); + let _p = profile::span("GlobalState::handle_event"); log::info!("handle_event({:?})", event); let queue_count = self.task_pool.handle.len(); @@ -204,7 +203,7 @@ impl GlobalState { self.analysis_host.maybe_collect_garbage(); } Event::Vfs(mut task) => { - let _p = profile("GlobalState::handle_event/vfs"); + let _p = profile::span("GlobalState::handle_event/vfs"); loop { match task { vfs::loader::Message::Loaded { files } => { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 1907f2f13..f74f2c02c 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -4,7 +4,6 @@ use std::{mem, sync::Arc}; use flycheck::FlycheckHandle; use ra_db::{CrateGraph, SourceRoot, VfsPath}; use ra_ide::AnalysisChange; -use ra_prof::profile; use ra_project_model::{ProcMacroClient, ProjectWorkspace}; use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; @@ -17,7 +16,7 @@ use crate::{ impl GlobalState { pub(crate) fn update_configuration(&mut self, config: Config) { - let _p = profile("GlobalState::update_configuration"); + let _p = profile::span("GlobalState::update_configuration"); let old_config = mem::replace(&mut self.config, config); if self.config.lru_capacity != old_config.lru_capacity { self.analysis_host.update_lru_capacity(old_config.lru_capacity); @@ -115,7 +114,7 @@ impl GlobalState { }); } pub(crate) fn switch_workspaces(&mut self, workspaces: Vec>) { - let _p = profile("GlobalState::switch_workspaces"); + let _p = profile::span("GlobalState::switch_workspaces"); log::info!("reloading projects: {:?}", self.config.linked_projects); let mut has_errors = false; @@ -300,7 +299,7 @@ pub(crate) struct SourceRootConfig { impl SourceRootConfig { pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec { - let _p = profile("SourceRootConfig::partition"); + let _p = profile::span("SourceRootConfig::partition"); self.fsc .partition(vfs) .into_iter() diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index f242c8165..15866fbb1 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs @@ -62,7 +62,7 @@ impl<'a> Project<'a> { static INIT: Once = Once::new(); INIT.call_once(|| { env_logger::builder().is_test(true).try_init().unwrap(); - ra_prof::init_from(crate::PROFILE); + profile::init_from(crate::PROFILE); }); for entry in Fixture::parse(self.fixture) { diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs index 4ff72865e..7384205db 100644 --- a/xtask/tests/tidy.rs +++ b/xtask/tests/tidy.rs @@ -197,7 +197,7 @@ impl TidyDocs { "ra_ide", "ra_mbe", "ra_parser", - "ra_prof", + "profile", "ra_project_model", "ra_syntax", "ra_tt", -- cgit v1.2.3