mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
internal: track missing .check_cancelled
This commit is contained in:
parent
2381a54c2f
commit
483a5bc9c8
3 changed files with 81 additions and 11 deletions
|
@ -59,6 +59,8 @@ pub trait CheckCanceled {
|
||||||
Self: Sized + panic::RefUnwindSafe,
|
Self: Sized + panic::RefUnwindSafe,
|
||||||
F: FnOnce(&Self) -> T + panic::UnwindSafe,
|
F: FnOnce(&Self) -> T + panic::UnwindSafe,
|
||||||
{
|
{
|
||||||
|
// Uncomment to debug missing cancellations.
|
||||||
|
// let _span = profile::heartbeat_span();
|
||||||
panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
|
panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
|
||||||
Ok(canceled) => *canceled,
|
Ok(canceled) => *canceled,
|
||||||
Err(payload) => panic::resume_unwind(payload),
|
Err(payload) => panic::resume_unwind(payload),
|
||||||
|
@ -68,6 +70,7 @@ pub trait CheckCanceled {
|
||||||
|
|
||||||
impl<T: salsa::Database> CheckCanceled for T {
|
impl<T: salsa::Database> CheckCanceled for T {
|
||||||
fn check_canceled(&self) {
|
fn check_canceled(&self) {
|
||||||
|
// profile::heartbeat();
|
||||||
if self.salsa_runtime().is_current_revision_canceled() {
|
if self.salsa_runtime().is_current_revision_canceled() {
|
||||||
Canceled::throw()
|
Canceled::throw()
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,20 @@ pub fn span(label: Label) -> ProfileSpan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn heartbeat_span() -> HeartbeatSpan {
|
||||||
|
let enabled = PROFILING_ENABLED.load(Ordering::Relaxed);
|
||||||
|
HeartbeatSpan::new(enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn heartbeat() {
|
||||||
|
let enabled = PROFILING_ENABLED.load(Ordering::Relaxed);
|
||||||
|
if enabled {
|
||||||
|
with_profile_stack(|it| it.heartbeat(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ProfileSpan(Option<ProfilerImpl>);
|
pub struct ProfileSpan(Option<ProfilerImpl>);
|
||||||
|
|
||||||
struct ProfilerImpl {
|
struct ProfilerImpl {
|
||||||
|
@ -92,6 +106,28 @@ impl Drop for ProfilerImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct HeartbeatSpan {
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeartbeatSpan {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(enabled: bool) -> Self {
|
||||||
|
if enabled {
|
||||||
|
with_profile_stack(|it| it.heartbeats(true))
|
||||||
|
}
|
||||||
|
Self { enabled }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for HeartbeatSpan {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.enabled {
|
||||||
|
with_profile_stack(|it| it.heartbeats(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);
|
static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||||
static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default);
|
static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default);
|
||||||
|
|
||||||
|
@ -105,6 +141,7 @@ struct Filter {
|
||||||
depth: usize,
|
depth: usize,
|
||||||
allowed: HashSet<String>,
|
allowed: HashSet<String>,
|
||||||
longer_than: Duration,
|
longer_than: Duration,
|
||||||
|
heartbeat_longer_than: Duration,
|
||||||
version: usize,
|
version: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +158,7 @@ impl Filter {
|
||||||
} else {
|
} else {
|
||||||
Duration::new(0, 0)
|
Duration::new(0, 0)
|
||||||
};
|
};
|
||||||
|
let heartbeat_longer_than = longer_than;
|
||||||
|
|
||||||
let depth = if let Some(idx) = spec.rfind('@') {
|
let depth = if let Some(idx) = spec.rfind('@') {
|
||||||
let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
|
let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
|
||||||
|
@ -131,7 +169,7 @@ impl Filter {
|
||||||
};
|
};
|
||||||
let allowed =
|
let allowed =
|
||||||
if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() };
|
if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() };
|
||||||
Filter { depth, allowed, longer_than, version: 0 }
|
Filter { depth, allowed, longer_than, heartbeat_longer_than, version: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install(mut self) {
|
fn install(mut self) {
|
||||||
|
@ -143,9 +181,15 @@ impl Filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProfileStack {
|
struct ProfileStack {
|
||||||
starts: Vec<Instant>,
|
frames: Vec<Frame>,
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
messages: Tree<Message>,
|
messages: Tree<Message>,
|
||||||
|
heartbeats: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Frame {
|
||||||
|
t: Instant,
|
||||||
|
heartbeats: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -157,35 +201,49 @@ struct Message {
|
||||||
|
|
||||||
impl ProfileStack {
|
impl ProfileStack {
|
||||||
fn new() -> ProfileStack {
|
fn new() -> ProfileStack {
|
||||||
ProfileStack { starts: Vec::new(), messages: Tree::default(), filter: Default::default() }
|
ProfileStack {
|
||||||
|
frames: Vec::new(),
|
||||||
|
messages: Tree::default(),
|
||||||
|
filter: Default::default(),
|
||||||
|
heartbeats: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, label: Label) -> bool {
|
fn push(&mut self, label: Label) -> bool {
|
||||||
if self.starts.is_empty() {
|
if self.frames.is_empty() {
|
||||||
if let Ok(f) = FILTER.try_read() {
|
if let Ok(f) = FILTER.try_read() {
|
||||||
if f.version > self.filter.version {
|
if f.version > self.filter.version {
|
||||||
self.filter = f.clone();
|
self.filter = f.clone();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if self.starts.len() > self.filter.depth {
|
if self.frames.len() > self.filter.depth {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let allowed = &self.filter.allowed;
|
let allowed = &self.filter.allowed;
|
||||||
if self.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) {
|
if self.frames.is_empty() && !allowed.is_empty() && !allowed.contains(label) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.starts.push(Instant::now());
|
self.frames.push(Frame { t: Instant::now(), heartbeats: 0 });
|
||||||
self.messages.start();
|
self.messages.start();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self, label: Label, detail: Option<String>) {
|
fn pop(&mut self, label: Label, detail: Option<String>) {
|
||||||
let start = self.starts.pop().unwrap();
|
let frame = self.frames.pop().unwrap();
|
||||||
let duration = start.elapsed();
|
let duration = frame.t.elapsed();
|
||||||
|
|
||||||
|
if self.heartbeats {
|
||||||
|
self.heartbeat(frame.heartbeats);
|
||||||
|
let avg_span = duration / (frame.heartbeats + 1);
|
||||||
|
if avg_span > self.filter.heartbeat_longer_than {
|
||||||
|
eprintln!("Too few heartbeats {} ({}/{:?})?", label, frame.heartbeats, duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.messages.finish(Message { duration, label, detail });
|
self.messages.finish(Message { duration, label, detail });
|
||||||
if self.starts.is_empty() {
|
if self.frames.is_empty() {
|
||||||
let longer_than = self.filter.longer_than;
|
let longer_than = self.filter.longer_than;
|
||||||
// Convert to millis for comparison to avoid problems with rounding
|
// Convert to millis for comparison to avoid problems with rounding
|
||||||
// (otherwise we could print `0ms` despite user's `>0` filter when
|
// (otherwise we could print `0ms` despite user's `>0` filter when
|
||||||
|
@ -198,6 +256,15 @@ impl ProfileStack {
|
||||||
self.messages.clear();
|
self.messages.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn heartbeats(&mut self, yes: bool) {
|
||||||
|
self.heartbeats = yes;
|
||||||
|
}
|
||||||
|
fn heartbeat(&mut self, n: u32) {
|
||||||
|
if let Some(frame) = self.frames.last_mut() {
|
||||||
|
frame.heartbeats += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print(
|
fn print(
|
||||||
|
|
|
@ -10,7 +10,7 @@ mod tree;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
hprof::{init, init_from, span},
|
hprof::{heartbeat, heartbeat_span, init, init_from, span},
|
||||||
memory_usage::{Bytes, MemoryUsage},
|
memory_usage::{Bytes, MemoryUsage},
|
||||||
stop_watch::{StopWatch, StopWatchSpan},
|
stop_watch::{StopWatch, StopWatchSpan},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue