aboutsummaryrefslogtreecommitdiff
path: root/crates/profile/src/google_cpu_profiler.rs
blob: db865c65be17e80716c93cbbbe9c870e506ae79c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//! 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();
}

static PROFILER_STATE: AtomicUsize = AtomicUsize::new(OFF);
const OFF: usize = 0;
const ON: usize = 1;
const PENDING: usize = 2;

pub fn start(path: &Path) {
    if PROFILER_STATE.compare_and_swap(OFF, PENDING, Ordering::SeqCst) != OFF {
        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!(PROFILER_STATE.compare_and_swap(PENDING, ON, Ordering::SeqCst) == PENDING);
}

pub fn stop() {
    if PROFILER_STATE.compare_and_swap(ON, PENDING, Ordering::SeqCst) != ON {
        panic!("profiler is not started")
    }
    unsafe { ProfilerStop() };
    assert!(PROFILER_STATE.compare_and_swap(PENDING, OFF, Ordering::SeqCst) == PENDING);
}