tetsy_util_mem/
allocators.rs

1// Copyright 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! default allocator management
10//! Features are:
11//! - windows:
12//!	 - no features: default implementation from servo `heapsize` crate
13//!	 - weealloc: default to `estimate_size`
14//!	 - dlmalloc: default to `estimate_size`
15//!	 - jemalloc: default windows allocator is used instead
16//!	 - mimalloc: use mimallocator crate
17//! - arch x86:
18//!	 - no features: use default alloc
19//!	 - jemalloc: use jemallocator crate
20//!	 - weealloc: default to `estimate_size`
21//!	 - dlmalloc: default to `estimate_size`
22//!	 - mimalloc: use mimallocator crate
23//! - arch x86/macos:
24//!	 - no features: use default alloc, requires using `estimate_size`
25//!	 - jemalloc: use jemallocator crate
26//!	 - weealloc: default to `estimate_size`
27//!	 - dlmalloc: default to `estimate_size`
28//!	 - mimalloc: use mimallocator crate
29//! - arch wasm32:
30//!	 - no features: default to `estimate_size`
31//!	 - weealloc: default to `estimate_size`
32//!	 - dlmalloc: default to `estimate_size`
33//!	 - jemalloc: compile error
34//!	 - mimalloc: compile error (until https://github.com/microsoft/mimalloc/pull/32 is merged)
35
36#[cfg(feature = "std")]
37use crate::malloc_size::MallocUnconditionalSizeOf;
38use crate::malloc_size::{MallocSizeOf, MallocSizeOfOps, VoidPtrToSizeFn};
39#[cfg(not(feature = "std"))]
40use core::ffi::c_void;
41#[cfg(feature = "std")]
42use std::os::raw::c_void;
43
44mod usable_size {
45
46	use super::*;
47
48	cfg_if::cfg_if! {
49
50		if #[cfg(any(
51			target_arch = "wasm32",
52			feature = "estimate-heapsize",
53			feature = "weealloc-global",
54			feature = "dlmalloc-global",
55		))] {
56
57			// do not try system allocator
58
59			/// Warning this is for compatibility only.
60			/// This function does panic: `estimate-heapsize` feature needs to be activated
61			/// to avoid this function call.
62			pub unsafe extern "C" fn malloc_usable_size(_ptr: *const c_void) -> usize {
63				unreachable!("estimate heapsize only")
64			}
65
66		} else if #[cfg(target_os = "windows")] {
67
68			use winapi::um::heapapi::{GetProcessHeap, HeapSize, HeapValidate};
69			use winapi::ctypes::c_void as winapi_c_void;
70
71			/// Get the size of a heap block.
72			/// Call windows allocator through `winapi` crate
73			pub unsafe extern "C" fn malloc_usable_size(mut ptr: *const c_void) -> usize {
74
75				let heap = GetProcessHeap();
76
77				if HeapValidate(heap, 0, ptr as *const winapi_c_void) == 0 {
78					ptr = *(ptr as *const *const c_void).offset(-1);
79				}
80
81				HeapSize(heap, 0, ptr as *const winapi_c_void) as usize
82			}
83
84		} else if #[cfg(feature = "jemalloc-global")] {
85
86			/// Use of jemalloc usable size C function through jemallocator crate call.
87			pub unsafe extern "C" fn malloc_usable_size(ptr: *const c_void) -> usize {
88				jemallocator::usable_size(ptr)
89			}
90
91		} else if #[cfg(feature = "mimalloc-global")] {
92
93			/// Use of mimalloc usable size C function through mimalloc_sys crate call.
94			pub unsafe extern "C" fn malloc_usable_size(ptr: *const c_void) -> usize {
95				// mimalloc doesn't actually mutate the value ptr points to,
96				// but requires a mut pointer in the API
97				libmimalloc_sys::mi_usable_size(ptr as *mut _)
98			}
99
100		} else if #[cfg(any(target_os = "linux", target_os = "android"))] {
101
102			/// Linux call system allocator (currently malloc).
103			extern "C" {
104				pub fn malloc_usable_size(ptr: *const c_void) -> usize;
105			}
106
107		} else {
108			// default allocator for non linux or windows system use estimate
109			pub unsafe extern "C" fn malloc_usable_size(_ptr: *const c_void) -> usize {
110				unreachable!("estimate heapsize or feature allocator needed")
111			}
112
113		}
114
115	}
116
117	/// No enclosing function defined.
118	#[inline]
119	pub fn new_enclosing_size_fn() -> Option<VoidPtrToSizeFn> {
120		None
121	}
122}
123
124/// Get a new instance of a MallocSizeOfOps
125pub fn new_malloc_size_ops() -> MallocSizeOfOps {
126	MallocSizeOfOps::new(usable_size::malloc_usable_size, usable_size::new_enclosing_size_fn(), None)
127}
128
129/// Extension methods for `MallocSizeOf` trait, do not implement
130/// directly.
131/// It allows getting heapsize without exposing `MallocSizeOfOps`
132/// (a single default `MallocSizeOfOps` is used for each call).
133pub trait MallocSizeOfExt: MallocSizeOf {
134	/// Method to launch a heapsize measurement with a
135	/// fresh state.
136	fn malloc_size_of(&self) -> usize {
137		let mut ops = new_malloc_size_ops();
138		<Self as MallocSizeOf>::size_of(self, &mut ops)
139	}
140}
141
142impl<T: MallocSizeOf> MallocSizeOfExt for T {}
143
144#[cfg(feature = "std")]
145impl<T: MallocSizeOf> MallocSizeOf for std::sync::Arc<T> {
146	fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
147		self.unconditional_size_of(ops)
148	}
149}