summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs b/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs
new file mode 100644
index 000000000..cae6caeaa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/profile/src/google_cpu_profiler.rs
@@ -0,0 +1,44 @@
+//! 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));
+}