1use std::os::raw::c_void;
9
10#[cfg(not(feature = "allocation-tracking"))]
11#[global_allocator]
12static ALLOC: Allocator = Allocator;
13
14#[cfg(feature = "allocation-tracking")]
15#[global_allocator]
16static ALLOC: crate::tracking::AccountingAlloc<Allocator> =
17 crate::tracking::AccountingAlloc::with_allocator(Allocator);
18
19#[cfg(feature = "allocation-tracking")]
20mod tracking;
21
22pub fn is_tracking_unmeasured() -> bool {
23 cfg!(feature = "allocation-tracking")
24}
25
26pub fn dump_unmeasured(_writer: impl std::io::Write) {
27 #[cfg(feature = "allocation-tracking")]
28 ALLOC.dump_unmeasured_allocations(_writer);
29}
30
31pub struct HeapReport {
32 pub path: &'static str,
33 pub size: Option<usize>,
34}
35
36pub use crate::platform::*;
37
38type EnclosingSizeFn = unsafe extern "C" fn(*const c_void) -> usize;
39
40#[cfg(feature = "allocation-tracking")]
45unsafe extern "C" fn enclosing_size_impl(ptr: *const c_void) -> usize {
46 let (adjusted, size) = crate::ALLOC.enclosing_size(ptr);
47 if size != 0 {
48 crate::ALLOC.note_allocation(adjusted, size);
49 }
50 size
51}
52
53#[expect(non_upper_case_globals)]
54#[cfg(feature = "allocation-tracking")]
55pub static enclosing_size: Option<EnclosingSizeFn> = Some(crate::enclosing_size_impl);
56
57#[expect(non_upper_case_globals)]
58#[cfg(not(feature = "allocation-tracking"))]
59pub static enclosing_size: Option<EnclosingSizeFn> = None;
60
61#[cfg(not(any(windows, feature = "use-system-allocator", target_env = "ohos")))]
62mod platform {
63 use std::ffi::CStr;
64 use std::mem::size_of_val;
65 use std::os::raw::c_void;
66 use std::ptr;
67
68 use tikv_jemalloc_sys::mallctl;
69 pub use tikv_jemallocator::Jemalloc as Allocator;
70
71 pub fn heap_reports() -> Vec<crate::HeapReport> {
72 vec![
73 crate::HeapReport {
74 path: "jemalloc-heap-allocated",
75 size: jemalloc_stat(c"stats.allocated"),
76 },
77 crate::HeapReport {
78 path: "jemalloc-heap-active",
79 size: jemalloc_stat(c"stats.active"),
80 },
81 crate::HeapReport {
82 path: "jemalloc-heap-mapped",
83 size: jemalloc_stat(c"stats.mapped"),
84 },
85 ]
86 }
87
88 fn jemalloc_stat(value_name: &CStr) -> Option<usize> {
89 let epoch_c_name = c"epoch";
93 let mut epoch: u64 = 0;
94 let epoch_ptr = &raw mut epoch;
95 let mut epoch_len = size_of_val(&epoch);
96
97 let mut value: usize = 0;
98 let value_ptr = &raw mut value;
99 let mut value_len = size_of_val(&value);
100
101 let rv = unsafe {
104 mallctl(
105 epoch_c_name.as_ptr(),
106 epoch_ptr.cast(),
107 &mut epoch_len,
108 epoch_ptr.cast(),
109 epoch_len,
110 )
111 };
112 if rv != 0 {
113 return None;
114 }
115
116 let rv = unsafe {
117 mallctl(
118 value_name.as_ptr(),
119 value_ptr.cast(),
120 &mut value_len,
121 ptr::null_mut(),
122 0,
123 )
124 };
125 if rv != 0 {
126 return None;
127 }
128
129 Some(value)
130 }
131
132 pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
138 let size = unsafe { tikv_jemallocator::usable_size(ptr) };
139 #[cfg(feature = "allocation-tracking")]
140 crate::ALLOC.note_allocation(ptr, size);
141 size
142 }
143
144 pub mod libc_compat {
146 pub use tikv_jemalloc_sys::{free, malloc, realloc};
147 }
148}
149
150#[cfg(all(
151 not(windows),
152 any(feature = "use-system-allocator", target_env = "ohos")
153))]
154mod platform {
155 pub use std::alloc::System as Allocator;
156 use std::os::raw::c_void;
157
158 pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
164 #[cfg(target_vendor = "apple")]
165 unsafe {
166 let size = libc::malloc_size(ptr);
167 #[cfg(feature = "allocation-tracking")]
168 crate::ALLOC.note_allocation(ptr, size);
169 size
170 }
171
172 #[cfg(not(target_vendor = "apple"))]
173 unsafe {
174 let size = libc::malloc_usable_size(ptr as *mut _);
175 #[cfg(feature = "allocation-tracking")]
176 crate::ALLOC.note_allocation(ptr, size);
177 size
178 }
179 }
180
181 pub mod libc_compat {
182 pub use libc::{free, malloc, realloc};
183 }
184
185 pub fn heap_reports() -> Vec<crate::HeapReport> {
186 Vec::new()
187 }
188}
189
190#[cfg(windows)]
191mod platform {
192 pub use std::alloc::System as Allocator;
193 use std::os::raw::c_void;
194
195 use windows_sys::Win32::Foundation::FALSE;
196 use windows_sys::Win32::System::Memory::{GetProcessHeap, HeapSize, HeapValidate};
197
198 pub unsafe extern "C" fn usable_size(mut ptr: *const c_void) -> usize {
204 unsafe {
205 let heap = GetProcessHeap();
206
207 if HeapValidate(heap, 0, ptr) == FALSE {
208 ptr = *(ptr as *const *const c_void).offset(-1)
209 }
210
211 let size = HeapSize(heap, 0, ptr) as usize;
212 #[cfg(feature = "allocation-tracking")]
213 crate::ALLOC.note_allocation(ptr, size);
214 size
215 }
216 }
217
218 pub fn heap_reports() -> Vec<crate::HeapReport> {
219 Vec::new()
220 }
221}