Simplify profiler impl (bubble up Option and shorten code

This commit is contained in:
veetaha 2020-04-26 00:10:44 +03:00
parent fe99a29ad1
commit 24d18d92f6

View file

@ -30,8 +30,9 @@ pub fn init_from(spec: &str) {
pub type Label = &'static str; pub type Label = &'static str;
/// This function starts a profiling scope in the current execution stack with a given description. /// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop. /// 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 invoked multiple times at the execution stack. In this case the profiling information will be nested at the output. /// 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. /// Profiling information is being printed in the stderr.
/// ///
/// # Example /// # Example
@ -58,36 +59,35 @@ 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());
let enabled = PROFILING_ENABLED.load(Ordering::Relaxed)
&& PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)); if PROFILING_ENABLED.load(Ordering::Relaxed)
let label = if enabled { Some(label) } else { None }; && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label))
Profiler { label, detail: None } {
Profiler(Some(ProfilerImpl { label, detail: None }))
} else {
Profiler(None)
}
} }
pub struct Profiler { pub struct Profiler(Option<ProfilerImpl>);
label: Option<Label>,
struct ProfilerImpl {
label: Label,
detail: Option<String>, detail: Option<String>,
} }
impl Profiler { impl Profiler {
pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler { pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler {
if self.label.is_some() { if let Some(profiler) = &mut self.0 {
self.detail = Some(detail()) profiler.detail = Some(detail())
} }
self self
} }
} }
impl Drop for Profiler { impl Drop for ProfilerImpl {
fn drop(&mut self) { fn drop(&mut self) {
match self { PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take()));
Profiler { label: Some(label), detail } => {
PROFILE_STACK.with(|stack| {
stack.borrow_mut().pop(label, detail.take());
});
}
Profiler { label: None, .. } => (),
}
} }
} }
@ -179,21 +179,18 @@ impl ProfileStack {
pub fn pop(&mut self, label: Label, detail: Option<String>) { pub fn pop(&mut self, label: Label, detail: Option<String>) {
let start = self.starts.pop().unwrap(); let start = self.starts.pop().unwrap();
let duration = start.elapsed(); let duration = start.elapsed();
let level = self.starts.len();
self.messages.finish(Message { duration, label, detail }); self.messages.finish(Message { duration, label, detail });
if level == 0 { if self.starts.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
// `duration` is just a few nanos). // `duration` is just a few nanos).
if duration.as_millis() > longer_than.as_millis() { if duration.as_millis() > longer_than.as_millis() {
let stderr = stderr();
if let Some(root) = self.messages.root() { if let Some(root) = self.messages.root() {
print(&self.messages, root, 0, longer_than, &mut stderr.lock()); print(&self.messages, root, 0, longer_than, &mut stderr().lock());
} }
} }
self.messages.clear(); self.messages.clear();
assert!(self.starts.is_empty())
} }
} }
} }