parity-common/parity-util-mem/src/allocators.rs

146 lines
4.2 KiB
Rust

// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! default allocator management
//! Features are:
//! - windows:
//! - no features: default implementation from servo `heapsize` crate
//! - weealloc: default to `estimate_size`
//! - dlmalloc: default to `estimate_size`
//! - jemalloc: default windows allocator is used instead
//! - arch x86:
//! - no features: use default alloc
//! - jemalloc: use jemallocator crate
//! - weealloc: default to `estimate_size`
//! - dlmalloc: default to `estimate_size`
//! - arch wasm32:
//! - no features: default to `estimate_size`
//! - weealloc: default to `estimate_size`
//! - dlmalloc: default to `estimate_size`
//! - jemalloc: compile error
use malloc_size::{MallocSizeOfOps, VoidPtrToSizeFn, MallocSizeOf};
#[cfg(feature = "std")]
use malloc_size::MallocUnconditionalSizeOf;
#[cfg(feature = "std")]
use std::os::raw::c_void;
#[cfg(not(feature = "std"))]
use core::ffi::c_void;
#[cfg(not(feature = "std"))]
use alloc::collections::btree_set::BTreeSet;
mod usable_size {
use super::*;
cfg_if! {
if #[cfg(any(
target_arch = "wasm32",
feature = "estimate-heapsize",
feature = "weealloc-global",
feature = "dlmalloc-global",
))] {
// do not try system allocator
/// Warning this is for compatibility only.
/// This function does panic: `estimate-heapsize` feature needs to be activated
/// to avoid this function call.
pub unsafe extern "C" fn malloc_usable_size(_ptr: *const c_void) -> usize {
unreachable!("estimate heapsize only")
}
} else if #[cfg(target_os = "windows")] {
// default windows allocator
extern crate winapi;
use self::winapi::um::heapapi::{GetProcessHeap, HeapSize, HeapValidate};
/// Get the size of a heap block.
/// Call windows allocator through `winapi` crate
pub unsafe extern "C" fn malloc_usable_size(mut ptr: *const c_void) -> usize {
let heap = GetProcessHeap();
if HeapValidate(heap, 0, ptr) == 0 {
ptr = *(ptr as *const *const c_void).offset(-1);
}
HeapSize(heap, 0, ptr) as usize
}
} else if #[cfg(feature = "jemalloc-global")] {
/// Use of jemalloc usable size C function through jemallocator crate call.
pub unsafe extern "C" fn malloc_usable_size(ptr: *const c_void) -> usize {
jemallocator::usable_size(ptr)
}
} else {
// default allocator used
/// Macos, ios and android calls jemalloc.
/// Linux call system allocator (currently malloc).
extern "C" {
#[cfg_attr(any(prefixed_jemalloc, target_os = "macos", target_os = "ios", target_os = "android"), link_name = "je_malloc_usable_size")]
pub fn malloc_usable_size(ptr: *const c_void) -> usize;
}
}
}
/// No enclosing function defined.
#[inline]
pub fn new_enclosing_size_fn() -> Option<VoidPtrToSizeFn> {
None
}
}
/// Get a new instance of a MallocSizeOfOps
pub fn new_malloc_size_ops() -> MallocSizeOfOps {
MallocSizeOfOps::new(
usable_size::malloc_usable_size,
usable_size::new_enclosing_size_fn(),
None,
)
}
/// Extension methods for `MallocSizeOf` trait, do not implement
/// directly.
/// It allows getting heapsize without exposing `MallocSizeOfOps`
/// (a single default `MallocSizeOfOps` is used for each call).
pub trait MallocSizeOfExt: MallocSizeOf {
/// Method to launch a heapsize measurement with a
/// fresh state.
fn malloc_size_of(&self) -> usize {
let mut ops = new_malloc_size_ops();
<Self as MallocSizeOf>::size_of(self, &mut ops)
}
}
impl<T: MallocSizeOf> MallocSizeOfExt for T { }
#[cfg(feature = "std")]
impl<T: MallocSizeOf> MallocSizeOf for std::sync::Arc<T> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.unconditional_size_of(ops)
}
}