2019-08-17 07:29:57 -05:00
|
|
|
//! https://github.com/gperftools/gperftools
|
|
|
|
|
|
|
|
use std::{
|
|
|
|
ffi::CString,
|
|
|
|
os::raw::c_char,
|
|
|
|
path::Path,
|
|
|
|
sync::atomic::{AtomicUsize, Ordering},
|
|
|
|
};
|
|
|
|
|
|
|
|
#[link(name = "profiler")]
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
extern "C" {
|
|
|
|
fn ProfilerStart(fname: *const c_char) -> i32;
|
|
|
|
fn ProfilerStop();
|
|
|
|
}
|
|
|
|
|
|
|
|
const OFF: usize = 0;
|
|
|
|
const ON: usize = 1;
|
|
|
|
const PENDING: usize = 2;
|
|
|
|
|
2021-03-30 09:20:27 -05:00
|
|
|
fn transition(current: usize, new: usize) -> bool {
|
|
|
|
static STATE: AtomicUsize = AtomicUsize::new(OFF);
|
|
|
|
|
|
|
|
STATE.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn start(path: &Path) {
|
|
|
|
if !transition(OFF, PENDING) {
|
2019-08-17 07:29:57 -05:00
|
|
|
panic!("profiler already started");
|
|
|
|
}
|
|
|
|
let path = CString::new(path.display().to_string()).unwrap();
|
|
|
|
if unsafe { ProfilerStart(path.as_ptr()) } == 0 {
|
|
|
|
panic!("profiler failed to start")
|
|
|
|
}
|
2021-03-30 09:20:27 -05:00
|
|
|
assert!(transition(PENDING, ON));
|
2019-08-17 07:29:57 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 09:20:27 -05:00
|
|
|
pub(crate) fn stop() {
|
|
|
|
if !transition(ON, PENDING) {
|
2019-08-17 07:29:57 -05:00
|
|
|
panic!("profiler is not started")
|
|
|
|
}
|
|
|
|
unsafe { ProfilerStop() };
|
2021-03-30 09:20:27 -05:00
|
|
|
assert!(transition(PENDING, OFF));
|
2019-08-17 07:29:57 -05:00
|
|
|
}
|