Allow specifying additional info on call to profile

This commit is contained in:
Aleksey Kladov 2020-03-06 17:23:08 +01:00
parent 59f91f2f9b
commit b33b843f40
3 changed files with 52 additions and 21 deletions

View file

@ -16,6 +16,7 @@ use crate::{
Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
TyDefId, TypeCtor, ValueTyDefId, TyDefId, TypeCtor, ValueTyDefId,
}; };
use hir_expand::name::Name;
#[salsa::query_group(HirDatabaseStorage)] #[salsa::query_group(HirDatabaseStorage)]
#[salsa::requires(salsa::Database)] #[salsa::requires(salsa::Database)]
@ -111,7 +112,15 @@ pub trait HirDatabase: DefDatabase {
} }
fn infer(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { fn infer(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
let _p = profile("wait_infer"); let _p = profile("wait_infer").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()
}
DefWithBodyId::ConstId(it) => {
db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
}
});
db.do_infer(def) db.do_infer(def)
} }

View file

@ -221,7 +221,10 @@ pub(crate) fn trait_solve_query(
krate: CrateId, krate: CrateId,
goal: Canonical<InEnvironment<Obligation>>, goal: Canonical<InEnvironment<Obligation>>,
) -> Option<Solution> { ) -> Option<Solution> {
let _p = profile("trait_solve_query"); let _p = profile("trait_solve_query").detail(|| match &goal.value.value {
Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(),
Obligation::Projection(_) => "projection".to_string(),
});
log::debug!("trait_solve_query({})", goal.value.value.display(db)); log::debug!("trait_solve_query({})", goal.value.value.display(db));
if let Obligation::Projection(pred) = &goal.value.value { if let Obligation::Projection(pred) = &goal.value.value {

View file

@ -88,7 +88,7 @@ pub type Label = &'static str;
pub fn profile(label: Label) -> Profiler { pub fn profile(label: Label) -> Profiler {
assert!(!label.is_empty()); assert!(!label.is_empty());
if !PROFILING_ENABLED.load(Ordering::Relaxed) { if !PROFILING_ENABLED.load(Ordering::Relaxed) {
return Profiler { label: None }; return Profiler { label: None, detail: None };
} }
PROFILE_STACK.with(|stack| { PROFILE_STACK.with(|stack| {
@ -101,15 +101,15 @@ pub fn profile(label: Label) -> Profiler {
}; };
} }
if stack.starts.len() > stack.filter_data.depth { if stack.starts.len() > stack.filter_data.depth {
return Profiler { label: None }; return Profiler { label: None, detail: None };
} }
let allowed = &stack.filter_data.allowed; let allowed = &stack.filter_data.allowed;
if stack.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) { if stack.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) {
return Profiler { label: None }; return Profiler { label: None, detail: None };
} }
stack.starts.push(Instant::now()); stack.starts.push(Instant::now());
Profiler { label: Some(label) } Profiler { label: Some(label), detail: None }
}) })
} }
@ -130,6 +130,16 @@ pub fn print_time(label: Label) -> impl Drop {
pub struct Profiler { pub struct Profiler {
label: Option<Label>, label: Option<Label>,
detail: Option<String>,
}
impl Profiler {
pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler {
if self.label.is_some() {
self.detail = Some(detail())
}
self
}
} }
pub struct Filter { pub struct Filter {
@ -183,6 +193,7 @@ struct Message {
level: usize, level: usize,
duration: Duration, duration: Duration,
label: Label, label: Label,
detail: Option<String>,
} }
impl ProfileStack { impl ProfileStack {
@ -208,13 +219,13 @@ thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(Profile
impl Drop for Profiler { impl Drop for Profiler {
fn drop(&mut self) { fn drop(&mut self) {
match self { match self {
Profiler { label: Some(label) } => { Profiler { label: Some(label), detail } => {
PROFILE_STACK.with(|stack| { PROFILE_STACK.with(|stack| {
let mut stack = stack.borrow_mut(); let mut stack = stack.borrow_mut();
let start = stack.starts.pop().unwrap(); let start = stack.starts.pop().unwrap();
let duration = start.elapsed(); let duration = start.elapsed();
let level = stack.starts.len(); let level = stack.starts.len();
stack.messages.push(Message { level, duration, label }); stack.messages.push(Message { level, duration, label, detail: detail.take() });
if level == 0 { if level == 0 {
let stdout = stderr(); let stdout = stderr();
let longer_than = stack.filter_data.longer_than; let longer_than = stack.filter_data.longer_than;
@ -228,7 +239,7 @@ impl Drop for Profiler {
} }
}); });
} }
Profiler { label: None } => (), Profiler { label: None, .. } => (),
} }
} }
} }
@ -251,8 +262,16 @@ fn print_for_idx(
) { ) {
let current = &msgs[current_idx]; let current = &msgs[current_idx];
let current_indent = " ".repeat(current.level); let current_indent = " ".repeat(current.level);
writeln!(out, "{}{:5}ms - {}", current_indent, current.duration.as_millis(), current.label) let detail = current.detail.as_ref().map(|it| format!(" @ {}", it)).unwrap_or_default();
.expect("printing profiling info"); writeln!(
out,
"{}{:5}ms - {}{}",
current_indent,
current.duration.as_millis(),
current.label,
detail,
)
.expect("printing profiling info");
let longer_than_millis = longer_than.as_millis(); let longer_than_millis = longer_than.as_millis();
let children_indices = &children_map[current_idx]; let children_indices = &children_map[current_idx];
@ -417,9 +436,9 @@ mod tests {
fn test_longer_than() { fn test_longer_than() {
let mut result = vec![]; let mut result = vec![];
let msgs = vec![ let msgs = vec![
Message { level: 1, duration: Duration::from_nanos(3), label: "bar" }, Message { level: 1, duration: Duration::from_nanos(3), label: "bar", detail: None },
Message { level: 1, duration: Duration::from_nanos(2), label: "bar" }, Message { level: 1, duration: Duration::from_nanos(2), label: "bar", detail: None },
Message { level: 0, duration: Duration::from_millis(1), label: "foo" }, Message { level: 0, duration: Duration::from_millis(1), label: "foo", detail: None },
]; ];
print(&msgs, Duration::from_millis(0), &mut result); print(&msgs, Duration::from_millis(0), &mut result);
// The calls to `bar` are so short that they'll be rounded to 0ms and should get collapsed // The calls to `bar` are so short that they'll be rounded to 0ms and should get collapsed
@ -434,8 +453,8 @@ mod tests {
fn test_unaccounted_for_topmost() { fn test_unaccounted_for_topmost() {
let mut result = vec![]; let mut result = vec![];
let msgs = vec![ let msgs = vec![
Message { level: 1, duration: Duration::from_millis(2), label: "bar" }, Message { level: 1, duration: Duration::from_millis(2), label: "bar", detail: None },
Message { level: 0, duration: Duration::from_millis(5), label: "foo" }, Message { level: 0, duration: Duration::from_millis(5), label: "foo", detail: None },
]; ];
print(&msgs, Duration::from_millis(0), &mut result); print(&msgs, Duration::from_millis(0), &mut result);
assert_eq!( assert_eq!(
@ -453,11 +472,11 @@ mod tests {
fn test_unaccounted_for_multiple_levels() { fn test_unaccounted_for_multiple_levels() {
let mut result = vec![]; let mut result = vec![];
let msgs = vec![ let msgs = vec![
Message { level: 2, duration: Duration::from_millis(3), label: "baz" }, Message { level: 2, duration: Duration::from_millis(3), label: "baz", detail: None },
Message { level: 1, duration: Duration::from_millis(5), label: "bar" }, Message { level: 1, duration: Duration::from_millis(5), label: "bar", detail: None },
Message { level: 2, duration: Duration::from_millis(2), label: "baz" }, Message { level: 2, duration: Duration::from_millis(2), label: "baz", detail: None },
Message { level: 1, duration: Duration::from_millis(4), label: "bar" }, Message { level: 1, duration: Duration::from_millis(4), label: "bar", detail: None },
Message { level: 0, duration: Duration::from_millis(9), label: "foo" }, Message { level: 0, duration: Duration::from_millis(9), label: "foo", detail: None },
]; ];
print(&msgs, Duration::from_millis(0), &mut result); print(&msgs, Duration::from_millis(0), &mut result);
assert_eq!( assert_eq!(