1#![no_std]
34
35extern crate alloc;
36
37#[cfg(any(feature = "heap", feature = "cpu"))]
39mod profiling;
40
41#[cfg(feature = "cpu")]
43pub use profiling::{start_cpu_profiling, stop_cpu_profiling};
44
45#[cfg(not(feature = "cpu"))]
47#[inline]
48pub fn start_cpu_profiling(_freq_hz: u32) {}
49
50#[cfg(not(feature = "cpu"))]
51#[inline]
52pub fn stop_cpu_profiling() {}
53
54pub struct ProfilingAllocator<const CPU_FREQ: u32 = 99>;
65
66impl<const CPU_FREQ: u32> ProfilingAllocator<CPU_FREQ> {
67 pub const fn new() -> Self {
68 Self
69 }
70}
71
72impl<const CPU_FREQ: u32> Default for ProfilingAllocator<CPU_FREQ> {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78pub type HeapProfiler = ProfilingAllocator<99>;
80
81#[cfg(not(feature = "heap"))]
82mod disabled {
83 use super::ProfilingAllocator;
84 use core::alloc::{GlobalAlloc, Layout};
85
86 unsafe impl<const CPU_FREQ: u32> GlobalAlloc for ProfilingAllocator<CPU_FREQ> {
87 #[inline]
88 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
89 unsafe { libc::malloc(layout.size()) as *mut u8 }
90 }
91
92 #[inline]
93 unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
94 unsafe { libc::free(ptr as *mut libc::c_void) }
95 }
96
97 #[inline]
98 unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 {
99 unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
100 }
101
102 #[inline]
103 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
104 unsafe { libc::calloc(1, layout.size()) as *mut u8 }
105 }
106 }
107}
108
109#[cfg(feature = "heap")]
110mod enabled {
111 use super::ProfilingAllocator;
112 #[cfg(feature = "cpu")]
113 use super::profiling::start_cpu_profiling;
114 use super::profiling::{record_alloc, record_dealloc};
115 use core::alloc::{GlobalAlloc, Layout};
116 use core::sync::atomic::{AtomicBool, Ordering};
117
118 static CPU_INITIALIZED: AtomicBool = AtomicBool::new(false);
119
120 #[inline]
121 fn maybe_init_cpu<const FREQ: u32>() {
122 #[cfg(feature = "cpu")]
123 {
124 if FREQ > 0 && !CPU_INITIALIZED.swap(true, Ordering::SeqCst) {
125 start_cpu_profiling(FREQ);
126 }
127 }
128 }
129
130 unsafe impl<const CPU_FREQ: u32> GlobalAlloc for ProfilingAllocator<CPU_FREQ> {
131 #[inline(never)]
134 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
135 maybe_init_cpu::<CPU_FREQ>();
136 let ptr = unsafe { libc::malloc(layout.size()) as *mut u8 };
137 if !ptr.is_null() {
138 record_alloc(ptr, layout.size());
139 }
140 ptr
141 }
142
143 #[inline(never)]
144 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
145 record_dealloc(ptr, layout.size());
146 unsafe { libc::free(ptr as *mut libc::c_void) }
147 }
148
149 #[inline(never)]
150 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
151 record_dealloc(ptr, layout.size());
152 let new_ptr = unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 };
153 if !new_ptr.is_null() {
154 record_alloc(new_ptr, new_size);
155 }
156 new_ptr
157 }
158
159 #[inline(never)]
160 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
161 maybe_init_cpu::<CPU_FREQ>();
162 let ptr = unsafe { libc::calloc(1, layout.size()) as *mut u8 };
163 if !ptr.is_null() {
164 record_alloc(ptr, layout.size());
165 }
166 ptr
167 }
168 }
169}
170
171#[macro_export]
194#[cfg(feature = "heap")]
195macro_rules! profiler {
196 () => {
197 $crate::profiler!(cpu = 99);
198 };
199 (cpu = $freq:expr) => {
200 #[global_allocator]
201 static __RSPROF_ALLOC: $crate::ProfilingAllocator<$freq> =
202 $crate::ProfilingAllocator::<$freq>::new();
203 };
204}
205
206#[macro_export]
208#[cfg(not(feature = "heap"))]
209macro_rules! profiler {
210 () => {};
211 (cpu = $freq:expr) => {};
212}