alloc: Allow disabling jemalloc

This commit is contained in:
Alex Crichton 2014-06-13 23:23:31 -07:00
parent 7613c9dd59
commit 4cd932f94e
4 changed files with 208 additions and 48 deletions

2
configure vendored
View File

@ -421,6 +421,7 @@ opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
opt rpath 1 "build rpaths into rustc itself"
opt nightly 0 "build nightly packages"
opt verify-install 1 "verify installed binaries work"
opt jemalloc 1 "build liballoc with jemalloc"
valopt prefix "/usr/local" "set installation prefix"
valopt local-rust-root "/usr/local" "set prefix for local rust binary"
valopt llvm-root "" "set LLVM root"
@ -1167,6 +1168,7 @@ putvar CFG_MANDIR
putvar CFG_DISABLE_INJECT_STD_VERSION
putvar CFG_JEMALLOC_ROOT
putvar CFG_LIBUV_ROOT
putvar CFG_DISABLE_JEMALLOC
# Avoid spurious warnings from clang by feeding it original source on
# ccache-miss rather than preprocessed input.

View File

@ -306,6 +306,8 @@ $$(JEMALLOC_LOCAL_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
EXTRA_CFLAGS="$$(CFG_CFLAGS_$(1)) $$(CFG_JEMALLOC_CFLAGS_$(1)) -g1"
$$(Q)$$(MAKE) -C "$$(JEMALLOC_BUILD_DIR_$(1))" build_lib_static
ifeq ($$(CFG_DISABLE_JEMALLOC),)
RUSTFLAGS_alloc := --cfg jemalloc
ifeq ($(1),$$(CFG_BUILD))
ifneq ($$(CFG_JEMALLOC_ROOT),)
$$(JEMALLOC_LIB_$(1)): $$(CFG_JEMALLOC_ROOT)/libjemalloc_pic.a
@ -319,6 +321,10 @@ else
$$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_LOCAL_$(1))
$$(Q)cp $$< $$@
endif
else
$$(JEMALLOC_LIB_$(1)): $$(MKFILE_DEPS)
$$(Q)touch $$@
endif
################################################################################
# compiler-rt

View File

@ -84,6 +84,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
-L "$$(RT_OUTPUT_DIR_$(2))" \
-L "$$(LLVM_LIBDIR_$(2))" \
-L "$$(dir $$(LLVM_STDCPP_LOCATION_$(2)))" \
$$(RUSTFLAGS_$(4)) \
--out-dir $$(@D) $$<
@touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES,\

View File

@ -12,36 +12,9 @@
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
// and `nonnull`
use core::intrinsics::{abort, cttz32};
use core::option::{None, Option};
use core::ptr::{RawPtr, mut_null, null};
use libc::{c_char, c_int, c_void, size_t};
#[cfg(not(test))] use core::raw;
#[cfg(not(test))] use util;
#[link(name = "jemalloc", kind = "static")]
extern {
fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
flags: c_int) -> size_t;
fn je_dallocx(ptr: *mut c_void, flags: c_int);
fn je_nallocx(size: size_t, flags: c_int) -> size_t;
fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void, *c_char)>,
cbopaque: *mut c_void,
opts: *c_char);
}
// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
#[cfg(not(windows), not(target_os = "android"))]
#[link(name = "pthread")]
extern {}
// MALLOCX_ALIGN(a) macro
#[inline(always)]
fn mallocx_align(a: uint) -> c_int { unsafe { cttz32(a as u32) as c_int } }
/// Return a pointer to `size` bytes of memory.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
@ -49,11 +22,7 @@ fn mallocx_align(a: uint) -> c_int { unsafe { cttz32(a as u32) as c_int } }
/// size on the platform.
#[inline]
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
let ptr = je_mallocx(size as size_t, mallocx_align(align)) as *mut u8;
if ptr.is_null() {
abort()
}
ptr
imp::allocate(size, align)
}
/// Extend or shrink the allocation referenced by `ptr` to `size` bytes of
@ -67,15 +36,9 @@ pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
/// create the allocation referenced by `ptr`. The `old_size` parameter may also
/// be the value returned by `usable_size` for the requested size.
#[inline]
#[allow(unused_variable)] // for the parameter names in the documentation
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
old_size: uint) -> *mut u8 {
let ptr = je_rallocx(ptr as *mut c_void, size as size_t,
mallocx_align(align)) as *mut u8;
if ptr.is_null() {
abort()
}
ptr
imp::reallocate(ptr, size, align, old_size)
}
/// Extend or shrink the allocation referenced by `ptr` to `size` bytes of
@ -92,11 +55,9 @@ pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
#[inline]
#[allow(unused_variable)] // for the parameter names in the documentation
pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
old_size: uint) -> bool {
je_xallocx(ptr as *mut c_void, size as size_t, 0,
mallocx_align(align)) == size as size_t
imp::reallocate_inplace(ptr, size, align, old_size)
}
/// Deallocate the memory referenced by `ptr`.
@ -107,16 +68,15 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
/// create the allocation referenced by `ptr`. The `size` parameter may also be
/// the value returned by `usable_size` for the requested size.
#[inline]
#[allow(unused_variable)] // for the parameter names in the documentation
pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
je_dallocx(ptr as *mut c_void, mallocx_align(align))
imp::deallocate(ptr, size, align)
}
/// Return the usable size of an allocation created with the specified the
/// `size` and `align`.
#[inline]
pub fn usable_size(size: uint, align: uint) -> uint {
unsafe { je_nallocx(size as size_t, mallocx_align(align)) as uint }
imp::usable_size(size, align)
}
/// Print implementation-defined allocator statistics.
@ -125,9 +85,7 @@ pub fn usable_size(size: uint, align: uint) -> uint {
/// during the call.
#[unstable]
pub fn stats_print() {
unsafe {
je_malloc_stats_print(None, mut_null(), null())
}
imp::stats_print();
}
// The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size
@ -170,6 +128,199 @@ unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint,
alloc as *mut u8
}
#[cfg(jemalloc)]
mod imp {
use core::intrinsics::abort;
use core::option::{None, Option};
use core::ptr::{RawPtr, mut_null, null};
use core::num::Bitwise;
use libc::{c_char, c_int, c_void, size_t};
#[link(name = "jemalloc", kind = "static")]
extern {
fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
fn je_rallocx(ptr: *mut c_void, size: size_t,
flags: c_int) -> *mut c_void;
fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
flags: c_int) -> size_t;
fn je_dallocx(ptr: *mut c_void, flags: c_int);
fn je_nallocx(size: size_t, flags: c_int) -> size_t;
fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void, *c_char)>,
cbopaque: *mut c_void,
opts: *c_char);
}
// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
#[cfg(not(windows), not(target_os = "android"))]
#[link(name = "pthread")]
extern {}
// MALLOCX_ALIGN(a) macro
#[inline(always)]
fn mallocx_align(a: uint) -> c_int { a.trailing_zeros() as c_int }
#[inline]
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
let ptr = je_mallocx(size as size_t, mallocx_align(align)) as *mut u8;
if ptr.is_null() {
abort()
}
ptr
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
_old_size: uint) -> *mut u8 {
let ptr = je_rallocx(ptr as *mut c_void, size as size_t,
mallocx_align(align)) as *mut u8;
if ptr.is_null() {
abort()
}
ptr
}
#[inline]
pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
_old_size: uint) -> bool {
je_xallocx(ptr as *mut c_void, size as size_t, 0,
mallocx_align(align)) == size as size_t
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
je_dallocx(ptr as *mut c_void, mallocx_align(align))
}
#[inline]
pub fn usable_size(size: uint, align: uint) -> uint {
unsafe { je_nallocx(size as size_t, mallocx_align(align)) as uint }
}
pub fn stats_print() {
unsafe {
je_malloc_stats_print(None, mut_null(), null())
}
}
}
#[cfg(not(jemalloc), unix)]
mod imp {
use core::mem;
use core::ptr;
use libc;
use libc_heap;
extern {
fn posix_memalign(memptr: *mut *mut libc::c_void,
align: libc::size_t,
size: libc::size_t) -> libc::c_int;
}
#[inline]
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
// The posix_memalign manpage states
//
// alignment [...] must be a power of and a multiple of
// sizeof(void *)
//
// The `align` parameter to this function is the *minimum* alignment for
// a block of memory, so we special case everything under `*uint` to
// just pass it to malloc, which is guaranteed to align to at least the
// size of `*uint`.
if align < mem::size_of::<*uint>() {
libc_heap::malloc_raw(size)
} else {
let mut out = 0 as *mut libc::c_void;
let ret = posix_memalign(&mut out,
align as libc::size_t,
size as libc::size_t);
if ret != 0 {
::oom();
}
out as *mut u8
}
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
old_size: uint) -> *mut u8 {
let new_ptr = allocate(size, align);
ptr::copy_memory(new_ptr, ptr as *u8, old_size);
deallocate(ptr, old_size, align);
return new_ptr;
}
#[inline]
pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint,
_old_size: uint) -> bool {
false
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
libc::free(ptr as *mut libc::c_void)
}
#[inline]
pub fn usable_size(size: uint, _align: uint) -> uint {
size
}
pub fn stats_print() {
}
}
#[cfg(not(jemalloc), windows)]
mod imp {
use libc::{c_void, size_t};
use core::ptr::RawPtr;
extern {
fn _aligned_malloc(size: size_t, align: size_t) -> *mut c_void;
fn _aligned_realloc(block: *mut c_void, size: size_t,
align: size_t) -> *mut c_void;
fn _aligned_free(ptr: *mut c_void);
}
#[inline]
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
let ptr = _aligned_malloc(size as size_t, align as size_t);
if ptr.is_null() {
::oom();
}
ptr as *mut u8
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
_old_size: uint) -> *mut u8 {
let ptr = _aligned_realloc(ptr as *mut c_void, size as size_t,
align as size_t);
if ptr.is_null() {
::oom();
}
ptr as *mut u8
}
#[inline]
pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint,
_old_size: uint) -> bool {
false
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
_aligned_free(ptr as *mut c_void)
}
#[inline]
pub fn usable_size(size: uint, _align: uint) -> uint {
size
}
pub fn stats_print() {}
}
#[cfg(test)]
mod bench {
extern crate test;