//! 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; 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)); }