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}