| //! 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)] | |
| unsafe extern "C" { | |
| fn ProfilerStart(fname: *const c_char) -> i32; | |
| fn ProfilerStop(); | |
| } | |
| const OFF: usize = 0; | |
| const ON: usize = 1; | |
| const PENDING: usize = 2; | |
| 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) { | |
| 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") | |
| } | |
| assert!(transition(PENDING, ON)); | |
| } | |
| pub(crate) fn stop() { | |
| if !transition(ON, PENDING) { | |
| panic!("profiler is not started") | |
| } | |
| unsafe { ProfilerStop() }; | |
| assert!(transition(PENDING, OFF)); | |
| } |