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