use crate::Level;
use crate::context::Context;
use crate::global_logger::global_loggers;
use crate::log_record::LogRecord;
use std::sync::atomic::{AtomicU64, Ordering};
static PROFILE_ID_COUNTER: AtomicU64 = AtomicU64::new(1);
#[derive(Debug)]
pub struct PerfwarnInterval {
label: &'static str,
start: crate::sys::Instant,
scale: f32,
}
impl PerfwarnInterval {
#[inline]
pub fn new(label: &'static str, time: crate::sys::Instant) -> Self {
Self {
label,
start: time,
scale: 1.0,
}
}
#[inline]
#[doc(hidden)]
pub fn log_timestamp(&self, record: &mut LogRecord) {
let time = crate::sys::Instant::now();
let duration = time.duration_since(self.start);
record.log_owned(format!("[{:?}] ", duration));
}
pub fn scale(&mut self, scale: f32) {
self.scale = scale;
}
}
impl Drop for PerfwarnInterval {
fn drop(&mut self) {
let end_time = crate::sys::Instant::now();
let duration = end_time.duration_since(self.start);
let ctx = Context::current();
ctx._add_task_interval(self.label, duration);
let mut record = LogRecord::new(Level::PerfWarn);
let ctx = Context::current();
ctx._log_prelude(&mut record);
record.log("PERWARN: END ");
record.log_time_since(end_time);
record.log(self.label);
record.log(" ");
let scaled_duration = duration.mul_f32(self.scale);
record.log_owned(format!("[interval took {:?}] ", scaled_duration));
let global_loggers = global_loggers();
for logger in global_loggers {
logger.finish_log_record(record.clone());
}
}
}
#[cfg(test)]
mod tests {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn assert_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<super::PerfwarnInterval>();
assert_send_sync::<super::PerfwarnIntervalIf>();
assert_send_sync::<super::ProfileInterval>();
}
}
#[derive(Debug)]
pub struct PerfwarnIntervalIf {
label: &'static str,
start: crate::sys::Instant,
threshold: crate::sys::Duration,
record: crate::log_record::LogRecord,
}
impl PerfwarnIntervalIf {
#[inline]
pub fn new(
label: &'static str,
time: crate::sys::Instant,
threshold: crate::sys::Duration,
record: crate::log_record::LogRecord,
) -> Self {
Self {
label,
start: time,
threshold,
record,
}
}
}
impl Drop for PerfwarnIntervalIf {
fn drop(&mut self) {
let end_time = crate::sys::Instant::now();
let duration = end_time.duration_since(self.start);
let ctx = Context::current();
ctx._add_task_interval_if(self.label, duration, self.threshold);
if duration > self.threshold {
let mut insert_idx = 0;
let mut found = false;
for (i, part) in self.record.parts.iter().enumerate() {
if part == "PERFWARN: " {
insert_idx = i + 3;
found = true;
break;
}
}
if found && insert_idx <= self.record.parts.len() {
let mut temp_record = crate::log_record::LogRecord::new(Level::PerfWarn);
temp_record.log_time_since(end_time);
let timestamp = temp_record.parts.pop().unwrap();
self.record.parts.insert(insert_idx, timestamp);
}
self.record.log(" is SLOW: ");
self.record
.log_owned(format!("[interval took {:?}] ", duration));
let global_loggers = global_loggers();
for logger in global_loggers {
logger.finish_log_record(self.record.clone());
}
}
}
}
#[inline]
pub fn next_profile_id() -> u64 {
PROFILE_ID_COUNTER.fetch_add(1, Ordering::Relaxed)
}
#[derive(Debug)]
pub struct ProfileInterval {
id: u64,
label: &'static str,
start: crate::sys::Instant,
}
impl ProfileInterval {
#[inline]
pub fn new(id: u64, label: &'static str, time: crate::sys::Instant) -> Self {
Self {
id,
label,
start: time,
}
}
#[inline]
pub fn id(&self) -> u64 {
self.id
}
}
impl Drop for ProfileInterval {
fn drop(&mut self) {
let end_time = crate::sys::Instant::now();
let duration = end_time.duration_since(self.start);
let mut record = LogRecord::new(Level::Profile);
let ctx = Context::current();
ctx._log_prelude(&mut record);
record.log_owned(format!("PROFILE: END [id={}] ", self.id));
record.log_owned(format!("[elapsed: {:?}] ", duration));
record.log(self.label);
let global_loggers = global_loggers();
for logger in global_loggers {
logger.finish_log_record(record.clone());
}
}
}