use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Mode {
Heap,
AdHoc,
}
#[derive(Clone, Debug)]
struct Config {
mode: Mode,
file_name: Option<PathBuf>,
testing: bool,
#[allow(dead_code)]
trim_backtraces: Option<usize>,
}
impl Default for Config {
fn default() -> Self {
Self {
mode: Mode::Heap,
file_name: None,
testing: false,
trim_backtraces: None,
}
}
}
pub struct Profiler {
config: Config,
}
impl Profiler {
pub fn new_heap() -> Self {
Self::install(Config {
mode: Mode::Heap,
..Config::default()
})
}
pub fn new_ad_hoc() -> Self {
Self::install(Config {
mode: Mode::AdHoc,
..Config::default()
})
}
pub fn builder() -> ProfilerBuilder {
ProfilerBuilder::new()
}
fn install(config: Config) -> Self {
PROFILER_ACTIVE.store(true, Ordering::Release);
Self { config }
}
}
static PROFILER_ACTIVE: AtomicBool = AtomicBool::new(false);
impl Drop for Profiler {
fn drop(&mut self) {
PROFILER_ACTIVE.store(false, Ordering::Release);
if self.config.testing {
return;
}
let path = self.config.file_name.clone().unwrap_or_else(|| {
PathBuf::from(match self.config.mode {
Mode::Heap => "dhat-heap.json",
Mode::AdHoc => "dhat-ad-hoc.json",
})
});
match self.config.mode {
Mode::Heap => {
let _ = crate::dhat_json::write_dhat_json(&path);
}
Mode::AdHoc => {
let _ = super::ad_hoc_writer::write_ad_hoc(&path);
}
}
}
}
#[derive(Debug)]
pub struct ProfilerBuilder {
config: Config,
}
impl ProfilerBuilder {
fn new() -> Self {
Self {
config: Config::default(),
}
}
pub fn ad_hoc(mut self) -> Self {
self.config.mode = Mode::AdHoc;
self
}
pub fn testing(mut self) -> Self {
self.config.testing = true;
self
}
pub fn file_name<P: AsRef<Path>>(mut self, p: P) -> Self {
self.config.file_name = Some(p.as_ref().to_path_buf());
self
}
pub fn trim_backtraces(mut self, max_frames: Option<usize>) -> Self {
self.config.trim_backtraces = max_frames;
self
}
pub fn build(self) -> Profiler {
Profiler::install(self.config)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_defaults_to_heap_mode() {
let p = Profiler::builder().build();
assert_eq!(p.config.mode, Mode::Heap);
let _t = Profiler::builder().testing().build();
}
#[test]
fn builder_ad_hoc_switches_mode() {
let p = Profiler::builder().ad_hoc().testing().build();
assert_eq!(p.config.mode, Mode::AdHoc);
}
#[test]
fn builder_file_name_overrides_default() {
let p = Profiler::builder()
.file_name("custom.json")
.testing()
.build();
assert_eq!(
p.config.file_name.as_deref(),
Some(std::path::Path::new("custom.json"))
);
}
}