use crate::Level;
use std::collections::HashMap;
use std::fmt::Display;
use std::sync::Mutex;
use std::sync::atomic::AtomicU64;
pub(crate) static TASK_ID: AtomicU64 = AtomicU64::new(0);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct TaskID(pub(crate) u64);
impl Display for TaskID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Debug)]
pub(crate) struct TaskMutable {
pub(crate) interval_statistics: HashMap<&'static str, crate::sys::Duration>,
pub(crate) interval_thresholds: HashMap<&'static str, crate::sys::Duration>,
}
#[derive(Debug)]
pub struct Task {
pub(crate) task_id: TaskID,
pub(crate) mutable: Mutex<TaskMutable>,
pub(crate) label: String,
pub(crate) completion_level: Level,
pub(crate) should_log_completion: bool,
}
impl Task {
pub(crate) fn new(label: String, completion_level: Level, should_log_completion: bool) -> Task {
Task {
task_id: TaskID(TASK_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed)),
mutable: Mutex::new(TaskMutable {
interval_statistics: HashMap::new(),
interval_thresholds: HashMap::new(),
}),
label,
completion_level,
should_log_completion,
}
}
#[inline]
pub(crate) fn add_task_interval(&self, key: &'static str, duration: crate::sys::Duration) {
let mut borrow = self.mutable.lock().unwrap();
borrow
.interval_statistics
.get_mut(key)
.map(|v| *v += duration)
.unwrap_or_else(|| {
borrow.interval_statistics.insert(key, duration);
});
}
#[inline]
pub(crate) fn add_task_interval_if(
&self,
key: &'static str,
duration: crate::sys::Duration,
threshold: crate::sys::Duration,
) {
let mut borrow = self.mutable.lock().unwrap();
borrow
.interval_statistics
.get_mut(key)
.map(|v| *v += duration)
.unwrap_or_else(|| {
borrow.interval_statistics.insert(key, duration);
});
borrow
.interval_thresholds
.get_mut(key)
.map(|v| *v += threshold)
.unwrap_or_else(|| {
borrow.interval_thresholds.insert(key, threshold);
});
}
}
impl Drop for Task {
fn drop(&mut self) {
let borrow = self.mutable.lock().unwrap();
if !borrow.interval_statistics.is_empty() {
let mut record = crate::log_record::LogRecord::new(Level::PerfWarn);
record.log_owned(format!("{} ", self.task_id.0));
record.log("PERFWARN: statistics[");
let mut first = true;
for (key, duration) in &borrow.interval_statistics {
if let Some(threshold) = borrow.interval_thresholds.get(key) {
if duration <= threshold {
continue;
}
}
if !first {
record.log(", ");
}
first = false;
record.log(key);
record.log_owned(format!(": {:?}", duration));
}
record.log("]");
if !first {
let global_loggers = crate::global_logger::global_loggers();
for logger in global_loggers {
logger.finish_log_record(record.clone());
}
}
}
if self.should_log_completion {
let mut record = crate::log_record::LogRecord::new(self.completion_level);
record.log_owned(format!("{} ", self.task_id.0));
record.log("Finished task `");
record.log(&self.label);
record.log("`");
let global_loggers = crate::global_logger::global_loggers();
for logger in global_loggers {
logger.finish_log_record(record.clone());
}
}
}
}