From cfeee53389559466dddf4f25b993082432f1ed53 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 16 Mar 2020 16:44:29 -0700 Subject: [PATCH 01/42] remove accidental include file --- include/mimalloc-internal-tld.h | 722 -------------------------------- 1 file changed, 722 deletions(-) delete mode 100644 include/mimalloc-internal-tld.h diff --git a/include/mimalloc-internal-tld.h b/include/mimalloc-internal-tld.h deleted file mode 100644 index ce67b0c7..00000000 --- a/include/mimalloc-internal-tld.h +++ /dev/null @@ -1,722 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2019, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ -#pragma once -#ifndef MIMALLOC_INTERNAL_TLD_H -#define MIMALLOC_INTERNAL_TLD_H - -#include "mimalloc-types.h" -#include "mimalloc-internal.h" - -#define MI_TLD_DECL 1 // thread local declaration -#define MI_TLD_PTHREAD 2 // ptrhead_get/setspecific -#define MI_TLD_DECL_GUARD 3 // thread local + recursion guard at initial load -#define MI_TLD_PTHREAD_GUARD 4 // ptrhead_get/setspecific + recursion guard at initial load -#define MI_TLD_SLOT 5 // steal slot from OS thread local predefined slots -#define MI_TLD_PTHREAD_SLOT 6 // steal slot from pthread structure (usually `retval`) - - -#if !defined(MI_TLD) -#if defined(_MSC_VER) || defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) - // on windows and linux/freeBSD/netBSD (with initial-exec) a __thread always works without recursion into malloc - #define MI_TLD MI_TLD_DECL -#elif !defined(MI_MIMALLOC_OVERRIDE) - // if not overriding, __thread declarations should be fine (use MI_TLD_PTHREAD if your OS does not have __thread) - #define MI_TLD MI_TLD_DECL -#elif // defined(MI_MALLOC_OVERRIDE) - // if overriding, some BSD variants allocate when accessing a thread local the first time - #if defined(__APPLE__) - #define MI_TLD MI_TLD_SLOT - #define MI_TLD_SLOT_NUM 89 // seems unused? (__PTK_FRAMEWORK_OLDGC_KEY9) see - // possibly unused ones are 9, 29, __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4 (94), __PTK_FRAMEWORK_GC_KEY9 (112) and __PTK_FRAMEWORK_OLDGC_KEY9 (89) - // #define MI_TLD MI_TLD_PTHREAD_SLOT - // #define MI_TLD_PTHREAD_SLOT_OFS (2*sizeof(void*) + sizeof(long) + 2*sizeof(void*) /*TAILQ*/) // offset `tl_exit_value` - #elif defined(__OpenBSD__) - #define MI_TLD MI_TLD_PTHREAD_SLOT - #define MI_TLD_PTHREAD_SLOT_OFS (6*sizeof(int) + 1*sizeof(void*)) // offset `retval` - #elif defined(__DragonFly__) - #define MI_TLD MI_TLD_PTHREAD_SLOT - #define MI_TLD_PTHREAD_SLOT_OFS (4 + 1*sizeof(void*)) // offset `uniqueid` (also used by gdb?) - #endif - #endif -#endif - -#if (MI_DEBUG>0) -#define mi_trace_message(...) _mi_trace_message(__VA_ARGS__) -#else -#define mi_trace_message(...) -#endif - -#define MI_CACHE_LINE 64 -#if defined(_MSC_VER) -#pragma warning(disable:4127) // suppress constant conditional warning (due to MI_SECURE paths) -#define mi_decl_noinline __declspec(noinline) -#define mi_decl_thread __declspec(thread) -#define mi_decl_cache_align __declspec(align(MI_CACHE_LINE)) -#elif (defined(__GNUC__) && (__GNUC__>=3)) // includes clang and icc -#define mi_decl_noinline __attribute__((noinline)) -#define mi_decl_thread __thread -#define mi_decl_cache_align __attribute__((aligned(MI_CACHE_LINE))) -#else -#define mi_decl_noinline -#define mi_decl_thread __thread // hope for the best :-) -#define mi_decl_cache_align -#endif - - -// "options.c" -void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message); -void _mi_fprintf(mi_output_fun* out, void* arg, const char* fmt, ...); -void _mi_warning_message(const char* fmt, ...); -void _mi_verbose_message(const char* fmt, ...); -void _mi_trace_message(const char* fmt, ...); -void _mi_options_init(void); -void _mi_error_message(int err, const char* fmt, ...); - -// random.c -void _mi_random_init(mi_random_ctx_t* ctx); -void _mi_random_split(mi_random_ctx_t* ctx, mi_random_ctx_t* new_ctx); -uintptr_t _mi_random_next(mi_random_ctx_t* ctx); -uintptr_t _mi_heap_random_next(mi_heap_t* heap); -uintptr_t _os_random_weak(uintptr_t extra_seed); -static inline uintptr_t _mi_random_shuffle(uintptr_t x); - -// init.c -extern mi_stats_t _mi_stats_main; -extern const mi_page_t _mi_page_empty; -bool _mi_is_main_thread(void); -bool _mi_preloading(); // true while the C runtime is not ready - -// os.c -size_t _mi_os_page_size(void); -void _mi_os_init(void); // called from process init -void* _mi_os_alloc(size_t size, mi_stats_t* stats); // to allocate thread local data -void _mi_os_free(void* p, size_t size, mi_stats_t* stats); // to free thread local data -size_t _mi_os_good_alloc_size(size_t size); - -// memory.c -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, size_t* id, mi_os_tld_t* tld); -void _mi_mem_free(void* p, size_t size, size_t id, bool fully_committed, bool any_reset, mi_os_tld_t* tld); - -bool _mi_mem_reset(void* p, size_t size, mi_os_tld_t* tld); -bool _mi_mem_unreset(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld); -bool _mi_mem_commit(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld); -bool _mi_mem_protect(void* addr, size_t size); -bool _mi_mem_unprotect(void* addr, size_t size); - -void _mi_mem_collect(mi_os_tld_t* tld); - -// "segment.c" -mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_wsize, mi_segments_tld_t* tld, mi_os_tld_t* os_tld); -void _mi_segment_page_free(mi_page_t* page, bool force, mi_segments_tld_t* tld); -void _mi_segment_page_abandon(mi_page_t* page, mi_segments_tld_t* tld); -uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t block_size, size_t* page_size, size_t* pre_size); // page start for any page -void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block_t* block); - -void _mi_segment_thread_collect(mi_segments_tld_t* tld); -void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld); -void _mi_abandoned_await_readers(void); - - - -// "page.c" -void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc; - -void _mi_page_retire(mi_page_t* page); // free the page if there are no other pages with many free blocks -void _mi_page_unfull(mi_page_t* page); -void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force); // free the page -void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq); // abandon the page, to be picked up by another thread... -void _mi_heap_delayed_free(mi_heap_t* heap); -void _mi_heap_collect_retired(mi_heap_t* heap, bool force); - -void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never); -size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append); -void _mi_deferred_free(mi_heap_t* heap, bool force); - -void _mi_page_free_collect(mi_page_t* page,bool force); -void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page); // callback from segments - -size_t _mi_bin_size(uint8_t bin); // for stats -uint8_t _mi_bin(size_t size); // for stats -uint8_t _mi_bsr(uintptr_t x); // bit-scan-right, used on BSD in "os.c" - -// "heap.c" -void _mi_heap_destroy_pages(mi_heap_t* heap); -void _mi_heap_collect_abandon(mi_heap_t* heap); -void _mi_heap_set_default_direct(mi_heap_t* heap); - -// "stats.c" -void _mi_stats_done(mi_stats_t* stats); - -mi_msecs_t _mi_clock_now(void); -mi_msecs_t _mi_clock_end(mi_msecs_t start); -mi_msecs_t _mi_clock_start(void); - -// "alloc.c" -void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept; // called from `_mi_malloc_generic` -void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero); -void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero); -mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* page, const void* p); -bool _mi_free_delayed_block(mi_block_t* block); -void _mi_block_zero_init(const mi_page_t* page, void* p, size_t size); - -#if MI_DEBUG>1 -bool _mi_page_is_valid(mi_page_t* page); -#endif - - -// ------------------------------------------------------ -// Branches -// ------------------------------------------------------ - -#if defined(__GNUC__) || defined(__clang__) -#define mi_unlikely(x) __builtin_expect((x),0) -#define mi_likely(x) __builtin_expect((x),1) -#else -#define mi_unlikely(x) (x) -#define mi_likely(x) (x) -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - - -/* ----------------------------------------------------------- - Error codes passed to `_mi_fatal_error` - All are recoverable but EFAULT is a serious error and aborts by default in secure mode. - For portability define undefined error codes using common Unix codes: - ------------------------------------------------------------ */ -#include -#ifndef EAGAIN // double free -#define EAGAIN (11) -#endif -#ifndef ENOMEM // out of memory -#define ENOMEM (12) -#endif -#ifndef EFAULT // corrupted free-list or meta-data -#define EFAULT (14) -#endif -#ifndef EINVAL // trying to free an invalid pointer -#define EINVAL (22) -#endif -#ifndef EOVERFLOW // count*size overflow -#define EOVERFLOW (75) -#endif - - -/* ----------------------------------------------------------- - Inlined definitions ------------------------------------------------------------ */ -#define UNUSED(x) (void)(x) -#if (MI_DEBUG>0) -#define UNUSED_RELEASE(x) -#else -#define UNUSED_RELEASE(x) UNUSED(x) -#endif - -#define MI_INIT4(x) x(),x(),x(),x() -#define MI_INIT8(x) MI_INIT4(x),MI_INIT4(x) -#define MI_INIT16(x) MI_INIT8(x),MI_INIT8(x) -#define MI_INIT32(x) MI_INIT16(x),MI_INIT16(x) -#define MI_INIT64(x) MI_INIT32(x),MI_INIT32(x) -#define MI_INIT128(x) MI_INIT64(x),MI_INIT64(x) -#define MI_INIT256(x) MI_INIT128(x),MI_INIT128(x) - - -// Is `x` a power of two? (0 is considered a power of two) -static inline bool _mi_is_power_of_two(uintptr_t x) { - return ((x & (x - 1)) == 0); -} - -// Align upwards -static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) { - mi_assert_internal(alignment != 0); - uintptr_t mask = alignment - 1; - if ((alignment & mask) == 0) { // power of two? - return ((sz + mask) & ~mask); - } - else { - return (((sz + mask)/alignment)*alignment); - } -} - -// Divide upwards: `s <= _mi_divide_up(s,d)*d < s+d`. -static inline uintptr_t _mi_divide_up(uintptr_t size, size_t divider) { - mi_assert_internal(divider != 0); - return (divider == 0 ? size : ((size + divider - 1) / divider)); -} - -// Is memory zero initialized? -static inline bool mi_mem_is_zero(void* p, size_t size) { - for (size_t i = 0; i < size; i++) { - if (((uint8_t*)p)[i] != 0) return false; - } - return true; -} - -// Align a byte size to a size in _machine words_, -// i.e. byte size == `wsize*sizeof(void*)`. -static inline size_t _mi_wsize_from_size(size_t size) { - mi_assert_internal(size <= SIZE_MAX - sizeof(uintptr_t)); - return (size + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); -} - - -// Overflow detecting multiply -static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { -#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5 -#include // UINT_MAX, ULONG_MAX -#if (SIZE_MAX == UINT_MAX) - return __builtin_umul_overflow(count, size, total); -#elif (SIZE_MAX == ULONG_MAX) - return __builtin_umull_overflow(count, size, total); -#else - return __builtin_umulll_overflow(count, size, total); -#endif -#else /* __builtin_umul_overflow is unavailable */ - #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) - *total = count * size; - return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW) - && size > 0 && (SIZE_MAX / size) < count); -#endif -} - -// Safe multiply `count*size` into `total`; return `true` on overflow. -static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* total) { - if (count==1) { // quick check for the case where count is one (common for C++ allocators) - *total = size; - return false; - } - else if (mi_unlikely(mi_mul_overflow(count, size, total))) { - _mi_error_message(EOVERFLOW, "allocation request too large (%zu * %zu bytes)\n", count, size); - *total = SIZE_MAX; - return true; - } - else return false; -} - - -/* ----------------------------------------------------------- - The thread local default heap ------------------------------------------------------------ */ - -extern const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value of the thread local default heap -extern mi_heap_t _mi_heap_main; // statically allocated main backing heap -extern bool _mi_process_is_initialized; - -#if defined(MI_TLS_OSX_FAST) -#define MI_TLS_OSX_OFFSET (MI_TLS_OSX_SLOT*sizeof(void*)) -static inline void* mi_tls_osx_fast_get(void) { - void* ret; - __asm__("mov %%gs:%1, %0" : "=r" (ret) : "m" (*(void**)(MI_TLS_OSX_OFFSET))); - return ret; -} -static inline void mi_tls_osx_fast_set(void* value) { - __asm__("movq %1,%%gs:%0" : "=m" (*(void**)(MI_TLS_OSX_OFFSET)) : "rn" (value)); -} -#elif defined(MI_TLS_PTHREADS) -extern pthread_key_t _mi_heap_default_key; -#else -extern mi_decl_thread mi_heap_t* _mi_heap_default; // default heap to allocate from -#endif - - -static inline mi_heap_t* mi_get_default_heap(void) { -#if defined(MI_TLS_OSX_FAST) - // Use a fixed slot in the TSD on MacOSX to avoid recursion (since the loader calls malloc). - // We use slot 94 (__PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4) - // which seems unused except for the more recent Webkit - // Use with care. - mi_heap_t* heap = (mi_heap_t*)mi_tls_osx_fast_get(); - return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap); -#elif defined(MI_TLS_PTHREADS) - // Use pthreads for TLS; this is used on macOSX with interpose as the loader calls `malloc` - // to allocate TLS storage leading to recursive calls if __thread declared variables are accessed. - // Using pthreads allows us to initialize without recursive calls. (performance seems still quite good). - mi_heap_t* heap = (mi_unlikely(_mi_heap_default_key == (pthread_key_t)(-1)) ? (mi_heap_t*)&_mi_heap_empty : (mi_heap_t*)pthread_getspecific(_mi_heap_default_key)); - return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap); -#else - #if defined(MI_TLS_RECURSE_GUARD) - // On some BSD platforms, like openBSD, the dynamic loader calls `malloc` - // to initialize thread local data (before our module is loaded). - // To avoid recursion, we need to avoid accessing the thread local `_mi_default_heap` - // until our module is loaded and use the statically allocated main heap until that time. - // TODO: patch ourselves dynamically to avoid this check every time? - // if (mi_unlikely(!_mi_process_is_initialized)) return &_mi_heap_main; - #endif - return _mi_heap_default; -#endif -} - -static inline bool mi_heap_is_default(const mi_heap_t* heap) { - return (heap == mi_get_default_heap()); -} - -static inline bool mi_heap_is_backing(const mi_heap_t* heap) { - return (heap->tld->heap_backing == heap); -} - -static inline bool mi_heap_is_initialized(mi_heap_t* heap) { - mi_assert_internal(heap != NULL); - return (heap != &_mi_heap_empty); -} - -static inline uintptr_t _mi_ptr_cookie(const void* p) { - mi_assert_internal(_mi_heap_main.cookie != 0); - return ((uintptr_t)p ^ _mi_heap_main.cookie); -} - -/* ----------------------------------------------------------- - Pages ------------------------------------------------------------ */ - -static inline mi_page_t* _mi_heap_get_free_small_page(mi_heap_t* heap, size_t size) { - mi_assert_internal(size <= (MI_SMALL_SIZE_MAX + MI_PADDING_SIZE)); - const size_t idx = _mi_wsize_from_size(size); - mi_assert_internal(idx < MI_PAGES_DIRECT); - return heap->pages_free_direct[idx]; -} - -// Get the page belonging to a certain size class -static inline mi_page_t* _mi_get_free_small_page(size_t size) { - return _mi_heap_get_free_small_page(mi_get_default_heap(), size); -} - -// Segment that contains the pointer -static inline mi_segment_t* _mi_ptr_segment(const void* p) { - // mi_assert_internal(p != NULL); - return (mi_segment_t*)((uintptr_t)p & ~MI_SEGMENT_MASK); -} - -// Segment belonging to a page -static inline mi_segment_t* _mi_page_segment(const mi_page_t* page) { - mi_segment_t* segment = _mi_ptr_segment(page); - mi_assert_internal(segment == NULL || page == &segment->pages[page->segment_idx]); - return segment; -} - -// used internally -static inline uintptr_t _mi_segment_page_idx_of(const mi_segment_t* segment, const void* p) { - // if (segment->page_size > MI_SEGMENT_SIZE) return &segment->pages[0]; // huge pages - ptrdiff_t diff = (uint8_t*)p - (uint8_t*)segment; - mi_assert_internal(diff >= 0 && (size_t)diff < MI_SEGMENT_SIZE); - uintptr_t idx = (uintptr_t)diff >> segment->page_shift; - mi_assert_internal(idx < segment->capacity); - mi_assert_internal(segment->page_kind <= MI_PAGE_MEDIUM || idx == 0); - return idx; -} - -// Get the page containing the pointer -static inline mi_page_t* _mi_segment_page_of(const mi_segment_t* segment, const void* p) { - uintptr_t idx = _mi_segment_page_idx_of(segment, p); - return &((mi_segment_t*)segment)->pages[idx]; -} - -// Quick page start for initialized pages -static inline uint8_t* _mi_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t* page_size) { - const size_t bsize = page->xblock_size; - mi_assert_internal(bsize > 0 && (bsize%sizeof(void*)) == 0); - return _mi_segment_page_start(segment, page, bsize, page_size, NULL); -} - -// Get the page containing the pointer -static inline mi_page_t* _mi_ptr_page(void* p) { - return _mi_segment_page_of(_mi_ptr_segment(p), p); -} - -// Get the block size of a page (special cased for huge objects) -static inline size_t mi_page_block_size(const mi_page_t* page) { - const size_t bsize = page->xblock_size; - mi_assert_internal(bsize > 0); - if (mi_likely(bsize < MI_HUGE_BLOCK_SIZE)) { - return bsize; - } - else { - size_t psize; - _mi_segment_page_start(_mi_page_segment(page), page, bsize, &psize, NULL); - return psize; - } -} - -// Get the usable block size of a page without fixed padding. -// This may still include internal padding due to alignment and rounding up size classes. -static inline size_t mi_page_usable_block_size(const mi_page_t* page) { - return mi_page_block_size(page) - MI_PADDING_SIZE; -} - - -// Thread free access -static inline mi_block_t* mi_page_thread_free(const mi_page_t* page) { - return (mi_block_t*)(mi_atomic_read_relaxed(&page->xthread_free) & ~3); -} - -static inline mi_delayed_t mi_page_thread_free_flag(const mi_page_t* page) { - return (mi_delayed_t)(mi_atomic_read_relaxed(&page->xthread_free) & 3); -} - -// Heap access -static inline mi_heap_t* mi_page_heap(const mi_page_t* page) { - return (mi_heap_t*)(mi_atomic_read_relaxed(&page->xheap)); -} - -static inline void mi_page_set_heap(mi_page_t* page, mi_heap_t* heap) { - mi_assert_internal(mi_page_thread_free_flag(page) != MI_DELAYED_FREEING); - mi_atomic_write(&page->xheap,(uintptr_t)heap); -} - -// Thread free flag helpers -static inline mi_block_t* mi_tf_block(mi_thread_free_t tf) { - return (mi_block_t*)(tf & ~0x03); -} -static inline mi_delayed_t mi_tf_delayed(mi_thread_free_t tf) { - return (mi_delayed_t)(tf & 0x03); -} -static inline mi_thread_free_t mi_tf_make(mi_block_t* block, mi_delayed_t delayed) { - return (mi_thread_free_t)((uintptr_t)block | (uintptr_t)delayed); -} -static inline mi_thread_free_t mi_tf_set_delayed(mi_thread_free_t tf, mi_delayed_t delayed) { - return mi_tf_make(mi_tf_block(tf),delayed); -} -static inline mi_thread_free_t mi_tf_set_block(mi_thread_free_t tf, mi_block_t* block) { - return mi_tf_make(block, mi_tf_delayed(tf)); -} - -// are all blocks in a page freed? -// note: needs up-to-date used count, (as the `xthread_free` list may not be empty). see `_mi_page_collect_free`. -static inline bool mi_page_all_free(const mi_page_t* page) { - mi_assert_internal(page != NULL); - return (page->used == 0); -} - -// are there any available blocks? -static inline bool mi_page_has_any_available(const mi_page_t* page) { - mi_assert_internal(page != NULL && page->reserved > 0); - return (page->used < page->reserved || (mi_page_thread_free(page) != NULL)); -} - -// are there immediately available blocks, i.e. blocks available on the free list. -static inline bool mi_page_immediate_available(const mi_page_t* page) { - mi_assert_internal(page != NULL); - return (page->free != NULL); -} - -// is more than 7/8th of a page in use? -static inline bool mi_page_mostly_used(const mi_page_t* page) { - if (page==NULL) return true; - uint16_t frac = page->reserved / 8U; - return (page->reserved - page->used <= frac); -} - -static inline mi_page_queue_t* mi_page_queue(const mi_heap_t* heap, size_t size) { - return &((mi_heap_t*)heap)->pages[_mi_bin(size)]; -} - - - -//----------------------------------------------------------- -// Page flags -//----------------------------------------------------------- -static inline bool mi_page_is_in_full(const mi_page_t* page) { - return page->flags.x.in_full; -} - -static inline void mi_page_set_in_full(mi_page_t* page, bool in_full) { - page->flags.x.in_full = in_full; -} - -static inline bool mi_page_has_aligned(const mi_page_t* page) { - return page->flags.x.has_aligned; -} - -static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { - page->flags.x.has_aligned = has_aligned; -} - - -/* ------------------------------------------------------------------- -Encoding/Decoding the free list next pointers - -This is to protect against buffer overflow exploits where the -free list is mutated. Many hardened allocators xor the next pointer `p` -with a secret key `k1`, as `p^k1`. This prevents overwriting with known -values but might be still too weak: if the attacker can guess -the pointer `p` this can reveal `k1` (since `p^k1^p == k1`). -Moreover, if multiple blocks can be read as well, the attacker can -xor both as `(p1^k1) ^ (p2^k1) == p1^p2` which may reveal a lot -about the pointers (and subsequently `k1`). - -Instead mimalloc uses an extra key `k2` and encodes as `((p^k2)<<> (MI_INTPTR_BITS - shift))); -} -static inline uintptr_t mi_rotr(uintptr_t x, uintptr_t shift) { - shift %= MI_INTPTR_BITS; - return ((x >> shift) | (x << (MI_INTPTR_BITS - shift))); -} - -static inline void* mi_ptr_decode(const void* null, const mi_encoded_t x, const uintptr_t* keys) { - void* p = (void*)(mi_rotr(x - keys[0], keys[0]) ^ keys[1]); - return (mi_unlikely(p==null) ? NULL : p); -} - -static inline mi_encoded_t mi_ptr_encode(const void* null, const void* p, const uintptr_t* keys) { - uintptr_t x = (uintptr_t)(mi_unlikely(p==NULL) ? null : p); - return mi_rotl(x ^ keys[1], keys[0]) + keys[0]; -} - -static inline mi_block_t* mi_block_nextx( const void* null, const mi_block_t* block, const uintptr_t* keys ) { - #ifdef MI_ENCODE_FREELIST - return (mi_block_t*)mi_ptr_decode(null, block->next, keys); - #else - UNUSED(keys); UNUSED(null); - return (mi_block_t*)block->next; - #endif -} - -static inline void mi_block_set_nextx(const void* null, mi_block_t* block, const mi_block_t* next, const uintptr_t* keys) { - #ifdef MI_ENCODE_FREELIST - block->next = mi_ptr_encode(null, next, keys); - #else - UNUSED(keys); UNUSED(null); - block->next = (mi_encoded_t)next; - #endif -} - -static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* block) { - #ifdef MI_ENCODE_FREELIST - mi_block_t* next = mi_block_nextx(page,block,page->keys); - // check for free list corruption: is `next` at least in the same page? - // TODO: check if `next` is `page->block_size` aligned? - if (mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next))) { - _mi_error_message(EFAULT, "corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next); - next = NULL; - } - return next; - #else - UNUSED(page); - return mi_block_nextx(page,block,NULL); - #endif -} - -static inline void mi_block_set_next(const mi_page_t* page, mi_block_t* block, const mi_block_t* next) { - #ifdef MI_ENCODE_FREELIST - mi_block_set_nextx(page,block,next, page->keys); - #else - UNUSED(page); - mi_block_set_nextx(page,block,next,NULL); - #endif -} - -// ------------------------------------------------------------------- -// Fast "random" shuffle -// ------------------------------------------------------------------- - -static inline uintptr_t _mi_random_shuffle(uintptr_t x) { - if (x==0) { x = 17; } // ensure we don't get stuck in generating zeros -#if (MI_INTPTR_SIZE==8) - // by Sebastiano Vigna, see: - x ^= x >> 30; - x *= 0xbf58476d1ce4e5b9UL; - x ^= x >> 27; - x *= 0x94d049bb133111ebUL; - x ^= x >> 31; -#elif (MI_INTPTR_SIZE==4) - // by Chris Wellons, see: - x ^= x >> 16; - x *= 0x7feb352dUL; - x ^= x >> 15; - x *= 0x846ca68bUL; - x ^= x >> 16; -#endif - return x; -} - -// ------------------------------------------------------------------- -// Optimize numa node access for the common case (= one node) -// ------------------------------------------------------------------- - -int _mi_os_numa_node_get(mi_os_tld_t* tld); -size_t _mi_os_numa_node_count_get(void); - -extern size_t _mi_numa_node_count; -static inline int _mi_os_numa_node(mi_os_tld_t* tld) { - if (mi_likely(_mi_numa_node_count == 1)) return 0; - else return _mi_os_numa_node_get(tld); -} -static inline size_t _mi_os_numa_node_count(void) { - if (mi_likely(_mi_numa_node_count>0)) return _mi_numa_node_count; - else return _mi_os_numa_node_count_get(); -} - - -// ------------------------------------------------------------------- -// Getting the thread id should be performant -// as it is called in the fast path of `_mi_free`, -// so we specialize for various platforms. -// ------------------------------------------------------------------- -#if defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -#include -static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept { - // Windows: works on Intel and ARM in both 32- and 64-bit - return (uintptr_t)NtCurrentTeb(); -} -#elif (defined(__GNUC__) || defined(__clang__)) && \ - (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)) -// TLS register on x86 is in the FS or GS register -// see: https://akkadia.org/drepper/tls.pdf -static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept { - uintptr_t tid; - #if defined(__i386__) - __asm__("movl %%gs:0, %0" : "=r" (tid) : : ); // 32-bit always uses GS - #elif defined(__MACH__) - __asm__("movq %%gs:0, %0" : "=r" (tid) : : ); // x86_64 macOS uses GS - #elif defined(__x86_64__) - __asm__("movq %%fs:0, %0" : "=r" (tid) : : ); // x86_64 Linux, BSD uses FS - #elif defined(__arm__) - asm volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid)); - #elif defined(__aarch64__) - asm volatile ("mrs %0, tpidr_el0" : "=r" (tid)); - #endif - return tid; -} -#else -// otherwise use standard C -static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept { - return (uintptr_t)&_mi_heap_default; -} -#endif - - -#endif From c0b06949cbf5a6c19fdd79cade0936e51b501bf2 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 20 Mar 2020 17:38:14 +0000 Subject: [PATCH 02/42] 32 bits build fix proposal. --- src/os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/os.c b/src/os.c index 89fd349b..3a1c4c6a 100644 --- a/src/os.c +++ b/src/os.c @@ -905,6 +905,7 @@ static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) } #else static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) { + UNUSED(addr); UNUSED(size); UNUSED(numa_node); return NULL; } #endif @@ -940,6 +941,7 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { } #else static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { + UNUSED(pages); if (total_size != NULL) *total_size = 0; return NULL; } From 414acd49aba5647db777cb6010b5f2118acb6ef6 Mon Sep 17 00:00:00 2001 From: Cormac Relf Date: Mon, 6 Apr 2020 21:05:44 +1000 Subject: [PATCH 03/42] Add test to exercise mi_usable_size on aligned allocations --- test/test-api.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-api.c b/test/test-api.c index 166cfca6..e5827a93 100644 --- a/test/test-api.c +++ b/test/test-api.c @@ -152,6 +152,9 @@ int main() { } result = ok; }); + CHECK_BODY("malloc-aligned5", { + void* p = mi_malloc_aligned(4097,4096); size_t usable = mi_usable_size(p); result = usable >= 4097 && usable < 10000; mi_free(p); + }); CHECK_BODY("malloc-aligned-at1", { void* p = mi_malloc_aligned_at(48,32,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 32 == 0); mi_free(p); }); From 0047b271f7aff49e49f205c3d609f41bf4061160 Mon Sep 17 00:00:00 2001 From: Cormac Relf Date: Mon, 6 Apr 2020 21:05:44 +1000 Subject: [PATCH 04/42] Call mi_page_usable_size_of with unaligned block rather than start of aligned memory --- src/alloc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index b1c4cd34..baa36225 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -472,15 +472,16 @@ size_t mi_usable_size(const void* p) mi_attr_noexcept { if (p==NULL) return 0; const mi_segment_t* const segment = _mi_ptr_segment(p); const mi_page_t* const page = _mi_segment_page_of(segment, p); - const mi_block_t* const block = (const mi_block_t*)p; - const size_t size = mi_page_usable_size_of(page, block); + const mi_block_t* block = (const mi_block_t*)p; if (mi_unlikely(mi_page_has_aligned(page))) { - ptrdiff_t const adjust = (uint8_t*)p - (uint8_t*)_mi_page_ptr_unalign(segment,page,p); + block = _mi_page_ptr_unalign(segment, page, p); + size_t size = mi_page_usable_size_of(page, block); + ptrdiff_t const adjust = (uint8_t*)p - (uint8_t*)block; mi_assert_internal(adjust >= 0 && (size_t)adjust <= size); return (size - adjust); } else { - return size; + return mi_page_usable_size_of(page, block); } } From c7e9cfd3ed934addee49f97a65a8d9f622291179 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 08:32:25 -0700 Subject: [PATCH 05/42] add test case for issue #212 --- test/main-override.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index 18d49df3..b0c9fdf0 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -20,16 +20,18 @@ static void msleep(unsigned long msecs) { Sleep(msecs); } static void msleep(unsigned long msecs) { usleep(msecs * 1000UL); } #endif -void heap_no_delete(); -void heap_late_free(); -void padding_shrink(); +void heap_thread_free_large(); // issue #212 +void heap_no_delete(); // issue #202 +void heap_late_free(); // issue #204 +void padding_shrink(); // issue #209 void various_tests(); int main() { mi_stats_reset(); // ignore earlier allocations - // heap_no_delete(); // issue #202 - // heap_late_free(); // issue #204 - padding_shrink(); // issue #209 + heap_thread_free_large(); + heap_no_delete(); + heap_late_free(); + padding_shrink(); various_tests(); mi_stats_print(NULL); return 0; @@ -157,3 +159,17 @@ void padding_shrink(void) t1.join(); mi_free(shared_p); } + + +// Issue #221 +void heap_thread_free_large_worker() { + mi_free(shared_p); +} + +void heap_thread_free_large() { + for (int i = 0; i < 100; i++) { + shared_p = mi_malloc(2*1024*1024 + 1); + auto t1 = std::thread(heap_thread_free_large_worker); + t1.join(); + } +} From faa83a1c47394e0ff0fd5c41de4a54e064c0de61 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 09:19:26 -0700 Subject: [PATCH 06/42] fix issue number: 212 to #221 --- test/main-override.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index b0c9fdf0..fdd79d2d 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -20,7 +20,7 @@ static void msleep(unsigned long msecs) { Sleep(msecs); } static void msleep(unsigned long msecs) { usleep(msecs * 1000UL); } #endif -void heap_thread_free_large(); // issue #212 +void heap_thread_free_large(); // issue #221 void heap_no_delete(); // issue #202 void heap_late_free(); // issue #204 void padding_shrink(); // issue #209 From 50bfacdb71503181e58a2e3ca3f1db14eb390632 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 09:53:29 -0700 Subject: [PATCH 07/42] fix mingw compilation by using export definitions (issue #217) --- include/mimalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 85f25ffb..e6f68b66 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -34,7 +34,7 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_decl_nodiscard #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__MINGW32__) #if !defined(MI_SHARED_LIB) #define mi_decl_export #elif defined(MI_SHARED_LIB_EXPORT) From 0f3bd05fd5a9471ddb9f7fe42b40a561b7e3650b Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 10:03:30 -0700 Subject: [PATCH 08/42] fix mingw compilation for numa awareness (issue #217) --- src/os.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/os.c b/src/os.c index 3a1c4c6a..512df5be 100644 --- a/src/os.c +++ b/src/os.c @@ -1015,6 +1015,11 @@ void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* stats) { Support NUMA aware allocation -----------------------------------------------------------------------------*/ #ifdef WIN32 +#ifdef __MINGW32__ // until mingw updates its headers +typedef struct _PROCESSOR_NUMBER { WORD Group; BYTE Number; BYTE Reserved; } PROCESSOR_NUMBER, *PPROCESSOR_NUMBER; +WINBASEAPI VOID WINAPI GetCurrentProcessorNumberEx(_Out_ PPROCESSOR_NUMBER ProcNumber); +WINBASEAPI BOOL WINAPI GetNumaProcessorNodeEx(_In_ PPROCESSOR_NUMBER Processor, _Out_ PUSHORT NodeNumber); +#endif static size_t mi_os_numa_nodex() { PROCESSOR_NUMBER pnum; USHORT numa_node = 0; From 0a3e5bb69980f29373337e564a80d77de1b80af0 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 10:56:53 -0700 Subject: [PATCH 09/42] further fixes to compile on mingw without warnings (issue #217) --- ide/vs2019/mimalloc-override.vcxproj | 2 +- include/mimalloc.h | 13 +++++++++---- src/os.c | 2 ++ test/main-override.cpp | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj index 17b6f4c0..a0e79fb0 100644 --- a/ide/vs2019/mimalloc-override.vcxproj +++ b/ide/vs2019/mimalloc-override.vcxproj @@ -254,4 +254,4 @@ - + \ No newline at end of file diff --git a/include/mimalloc.h b/include/mimalloc.h index e6f68b66..b99b668a 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -42,13 +42,18 @@ terms of the MIT license. A copy of the license can be found in the file #else #define mi_decl_export __declspec(dllimport) #endif - #if (_MSC_VER >= 1900) && !defined(__EDG__) - #define mi_decl_restrict __declspec(allocator) __declspec(restrict) + #if defined(__MINGW32__) + #define mi_decl_restrict + #define mi_attr_malloc __attribute__((malloc)) #else - #define mi_decl_restrict __declspec(restrict) + #if (_MSC_VER >= 1900) && !defined(__EDG__) + #define mi_decl_restrict __declspec(allocator) __declspec(restrict) + #else + #define mi_decl_restrict __declspec(restrict) + #endif + #define mi_attr_malloc #endif #define mi_cdecl __cdecl - #define mi_attr_malloc #define mi_attr_alloc_size(s) #define mi_attr_alloc_size2(s1,s2) #define mi_attr_alloc_align(p) diff --git a/src/os.c b/src/os.c index 512df5be..1765a941 100644 --- a/src/os.c +++ b/src/os.c @@ -866,6 +866,8 @@ static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) params[0].ULong = (unsigned)numa_node; return (*pVirtualAlloc2)(GetCurrentProcess(), addr, size, flags, PAGE_READWRITE, params, 1); } + #else + UNUSED(numa_node); #endif // otherwise use regular virtual alloc on older windows return VirtualAlloc(addr, size, flags, PAGE_READWRITE); diff --git a/test/main-override.cpp b/test/main-override.cpp index fdd79d2d..734e4c94 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -168,7 +168,7 @@ void heap_thread_free_large_worker() { void heap_thread_free_large() { for (int i = 0; i < 100; i++) { - shared_p = mi_malloc(2*1024*1024 + 1); + shared_p = mi_malloc_aligned(2*1024*1024 + 1, 8); auto t1 = std::thread(heap_thread_free_large_worker); t1.join(); } From 34d3b8c47f607ad6ef918d159d98dac13399aa9c Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 11:25:25 -0700 Subject: [PATCH 10/42] add version check for mingw compilation and add FlsAlloc definitions if required --- src/init.c | 6 ++++++ src/os.c | 14 +++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/init.c b/src/init.c index 2e94935c..e95ff674 100644 --- a/src/init.c +++ b/src/init.c @@ -286,6 +286,12 @@ static void _mi_thread_done(mi_heap_t* default_heap); // use thread local storage keys to detect thread ending #include #include + #if (_WIN32_WINNT < 0x600) // before Windows Vista + WINBASEAPI DWORD WINAPI FlsAlloc( _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback ); + WINBASEAPI PVOID WINAPI FlsGetValue( _In_ DWORD dwFlsIndex ); + WINBASEAPI BOOL WINAPI FlsSetValue( _In_ DWORD dwFlsIndex, _In_opt_ PVOID lpFlsData ); + WINBASEAPI BOOL WINAPI FlsFree(_In_ DWORD dwFlsIndex); + #endif static DWORD mi_fls_key = (DWORD)(-1); static void NTAPI mi_fls_done(PVOID value) { if (value!=NULL) _mi_thread_done((mi_heap_t*)value); diff --git a/src/os.c b/src/os.c index 1765a941..12ba9442 100644 --- a/src/os.c +++ b/src/os.c @@ -823,7 +823,7 @@ and possibly associated with a specific NUMA node. (use `numa_node>=0`) -----------------------------------------------------------------------------*/ #define MI_HUGE_OS_PAGE_SIZE (GiB) -#if defined(WIN32) && (MI_INTPTR_SIZE >= 8) +#if defined(_WIN32) && (MI_INTPTR_SIZE >= 8) static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) { mi_assert_internal(size%GiB == 0); @@ -1016,12 +1016,12 @@ void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* stats) { /* ---------------------------------------------------------------------------- Support NUMA aware allocation -----------------------------------------------------------------------------*/ -#ifdef WIN32 -#ifdef __MINGW32__ // until mingw updates its headers -typedef struct _PROCESSOR_NUMBER { WORD Group; BYTE Number; BYTE Reserved; } PROCESSOR_NUMBER, *PPROCESSOR_NUMBER; -WINBASEAPI VOID WINAPI GetCurrentProcessorNumberEx(_Out_ PPROCESSOR_NUMBER ProcNumber); -WINBASEAPI BOOL WINAPI GetNumaProcessorNodeEx(_In_ PPROCESSOR_NUMBER Processor, _Out_ PUSHORT NodeNumber); -#endif +#ifdef _WIN32 + #if (_WIN32_WINNT < 0x601) // before Win7 + typedef struct _PROCESSOR_NUMBER { WORD Group; BYTE Number; BYTE Reserved; } PROCESSOR_NUMBER, *PPROCESSOR_NUMBER; + WINBASEAPI VOID WINAPI GetCurrentProcessorNumberEx(_Out_ PPROCESSOR_NUMBER ProcNumber); + WINBASEAPI BOOL WINAPI GetNumaProcessorNodeEx(_In_ PPROCESSOR_NUMBER Processor, _Out_ PUSHORT NodeNumber); + #endif static size_t mi_os_numa_nodex() { PROCESSOR_NUMBER pnum; USHORT numa_node = 0; From 84b9b8878ef2e85926000508939be4e65090c17f Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 11:49:32 -0700 Subject: [PATCH 11/42] possible fix for issue #221 --- src/segment.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/segment.c b/src/segment.c index 9eab7548..55410f59 100644 --- a/src/segment.c +++ b/src/segment.c @@ -1298,16 +1298,16 @@ void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block page->used--; page->is_zero = false; mi_assert(page->used == 0); - mi_segments_tld_t* tld = &heap->tld->segments; + mi_tld_t* tld = heap->tld; const size_t bsize = mi_page_usable_block_size(page); if (bsize > MI_HUGE_OBJ_SIZE_MAX) { - _mi_stat_decrease(&tld->stats->giant, bsize); + _mi_stat_decrease(&tld->stats.giant, bsize); } else { - _mi_stat_decrease(&tld->stats->huge, bsize); + _mi_stat_decrease(&tld->stats.huge, bsize); } - mi_segments_track_size((long)segment->segment_size, tld); - _mi_segment_page_free(page, true, tld); + mi_segments_track_size((long)segment->segment_size, &tld->segments); + _mi_segment_page_free(page, true, &tld->segments); } } From afc4f79a6948e87b984a8e6cdc465f45ea6c10a0 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 12:15:12 -0700 Subject: [PATCH 12/42] fix for ensuring heap initialization with static linking on windows on huge allocations (issues #221) --- ide/vs2019/mimalloc-override-test.vcxproj | 6 +++--- src/segment.c | 2 +- test/main-override.cpp | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ide/vs2019/mimalloc-override-test.vcxproj b/ide/vs2019/mimalloc-override-test.vcxproj index a2497a19..7a9202f1 100644 --- a/ide/vs2019/mimalloc-override-test.vcxproj +++ b/ide/vs2019/mimalloc-override-test.vcxproj @@ -176,14 +176,14 @@ + + + {abb5eae7-b3e6-432e-b636-333449892ea7} - - - diff --git a/src/segment.c b/src/segment.c index 55410f59..8aa838a2 100644 --- a/src/segment.c +++ b/src/segment.c @@ -1290,7 +1290,7 @@ void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block mi_assert_internal(mi_atomic_read_relaxed(&segment->thread_id)==0); // claim it and free - mi_heap_t* heap = mi_get_default_heap(); + mi_heap_t* heap = mi_heap_get_default(); // issue #221; don't use the internal get_default_heap as we need to ensure the thread is initialized. // paranoia: if this it the last reference, the cas should always succeed if (mi_atomic_cas_strong(&segment->thread_id, heap->thread_id, 0)) { mi_block_set_next(page, block, page->free); diff --git a/test/main-override.cpp b/test/main-override.cpp index 734e4c94..eda32ae4 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -29,10 +29,12 @@ void various_tests(); int main() { mi_stats_reset(); // ignore earlier allocations heap_thread_free_large(); + /* heap_no_delete(); heap_late_free(); padding_shrink(); various_tests(); + */ mi_stats_print(NULL); return 0; } From 69a0846478131810c85d6df903c5cf36aee858c7 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 7 Apr 2020 10:01:18 -0700 Subject: [PATCH 13/42] add MI_PADDING flag to cmake to supress use of padding in debug mode --- CMakeLists.txt | 6 ++++++ include/mimalloc-types.h | 4 ++-- src/alloc.c | 4 ++-- src/init.c | 4 ++-- test/main-override-static.c | 2 +- test/main-override.cpp | 2 -- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0893007..61303345 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macO option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) option(MI_BUILD_TESTS "Build test executables" ON) option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) +option(MI_PADDING "Enable padding to detect heap block overflow (only in debug mode)" ON) include("cmake/mimalloc-config-version.cmake") @@ -99,6 +100,11 @@ if(MI_DEBUG_FULL MATCHES "ON") list(APPEND mi_defines MI_DEBUG=3) # full invariant checking endif() +if(MI_PADDING MATCHES "OFF") + message(STATUS "Disable padding of heap blocks in debug mode (MI_PADDING=OFF)") + list(APPEND mi_defines MI_PADDING=0) +endif() + if(MI_USE_CXX MATCHES "ON") message(STATUS "Use the C++ compiler to compile (MI_USE_CXX=ON)") set_source_files_properties(${mi_sources} PROPERTIES LANGUAGE CXX ) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 28606668..7e50a2bc 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -57,7 +57,7 @@ terms of the MIT license. A copy of the license can be found in the file // Encoded free lists allow detection of corrupted free lists // and can detect buffer overflows, modify after free, and double `free`s. -#if (MI_SECURE>=3 || MI_DEBUG>=1 || defined(MI_PADDING)) +#if (MI_SECURE>=3 || MI_DEBUG>=1 || MI_PADDING > 0) #define MI_ENCODE_FREELIST 1 #endif @@ -303,7 +303,7 @@ typedef struct mi_random_cxt_s { // In debug mode there is a padding stucture at the end of the blocks to check for buffer overflows -#if defined(MI_PADDING) +#if (MI_PADDING) typedef struct mi_padding_s { uint32_t canary; // encoded block value to check validity of the padding (in case of overflow) uint32_t delta; // padding bytes before the block. (mi_usable_size(p) - delta == exact allocated bytes) diff --git a/src/alloc.c b/src/alloc.c index 9b441499..d7b8219e 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -44,7 +44,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz mi_heap_stat_increase(heap, normal[bin], 1); } #endif -#if defined(MI_PADDING) && defined(MI_ENCODE_FREELIST) +#if (MI_PADDING > 0) && defined(MI_ENCODE_FREELIST) mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + mi_page_usable_block_size(page)); ptrdiff_t delta = ((uint8_t*)padding - (uint8_t*)block - (size - MI_PADDING_SIZE)); mi_assert_internal(delta >= 0 && mi_page_usable_block_size(page) >= (size - MI_PADDING_SIZE + delta)); @@ -203,7 +203,7 @@ static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block // Check for heap block overflow by setting up padding at the end of the block // --------------------------------------------------------------------------- -#if defined(MI_PADDING) && defined(MI_ENCODE_FREELIST) +#if (MI_PADDING>0) && defined(MI_ENCODE_FREELIST) static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* block, size_t* delta, size_t* bsize) { *bsize = mi_page_usable_block_size(page); const mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + *bsize); diff --git a/src/init.c b/src/init.c index e95ff674..6b62e888 100644 --- a/src/init.c +++ b/src/init.c @@ -32,9 +32,9 @@ const mi_page_t _mi_page_empty = { #define MI_PAGE_EMPTY() ((mi_page_t*)&_mi_page_empty) -#if defined(MI_PADDING) && (MI_INTPTR_SIZE >= 8) +#if (MI_PADDING>0) && (MI_INTPTR_SIZE >= 8) #define MI_SMALL_PAGES_EMPTY { MI_INIT128(MI_PAGE_EMPTY), MI_PAGE_EMPTY(), MI_PAGE_EMPTY() } -#elif defined(MI_PADDING) +#elif (MI_PADDING>0) #define MI_SMALL_PAGES_EMPTY { MI_INIT128(MI_PAGE_EMPTY), MI_PAGE_EMPTY(), MI_PAGE_EMPTY(), MI_PAGE_EMPTY() } #else #define MI_SMALL_PAGES_EMPTY { MI_INIT128(MI_PAGE_EMPTY), MI_PAGE_EMPTY() } diff --git a/test/main-override-static.c b/test/main-override-static.c index 950392d0..9243fd21 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -19,7 +19,7 @@ int main() { // double_free1(); // double_free2(); // corrupt_free(); - // block_overflow1(); + block_overflow1(); void* p1 = malloc(78); void* p2 = malloc(24); diff --git a/test/main-override.cpp b/test/main-override.cpp index eda32ae4..734e4c94 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -29,12 +29,10 @@ void various_tests(); int main() { mi_stats_reset(); // ignore earlier allocations heap_thread_free_large(); - /* heap_no_delete(); heap_late_free(); padding_shrink(); various_tests(); - */ mi_stats_print(NULL); return 0; } From 6f03be2d3acd66ae6925ddc3cce4b14032ec5d51 Mon Sep 17 00:00:00 2001 From: Jiaye Wu Date: Tue, 14 Apr 2020 12:54:35 +0800 Subject: [PATCH 14/42] Fix Windows builds on Azure Pipelines Currently, all Windows builds are using `Debug|x64` configuration. For example, you can see the CTest steps with Release build cost 20+ seconds, which means it is using the debug binary. --- azure-pipelines.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6c7bad96..954ec15d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,12 +18,15 @@ jobs: Debug: BuildType: debug cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + MSBuildConfiguration: Debug Release: BuildType: release cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + MSBuildConfiguration: Release Secure: BuildType: secure cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON + MSBuildConfiguration: Release steps: - task: CMake@1 inputs: @@ -32,6 +35,7 @@ jobs: - task: MSBuild@1 inputs: solution: $(BuildType)/libmimalloc.sln + configuration: '$(MSBuildConfiguration)' - script: | cd $(BuildType) ctest From 6c5039bad1879efc87495d762b8c99e56b7a6588 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 14 Apr 2020 14:20:56 +0100 Subject: [PATCH 15/42] Android build fix proposal. malloc_usable_size has different signature on this platform. thread and real time apis are part of bionic. --- CMakeLists.txt | 10 ++++++---- src/alloc-override.c | 4 ++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61303345..508934dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,10 +146,12 @@ endif() if(WIN32) list(APPEND mi_libraries psapi shell32 user32 bcrypt) else() - list(APPEND mi_libraries pthread) - find_library(LIBRT rt) - if(LIBRT) - list(APPEND mi_libraries ${LIBRT}) + if(NOT ${CC} MATCHES "android") + list(APPEND mi_libraries pthread) + find_library(LIBRT rt) + if(LIBRT) + list(APPEND mi_libraries ${LIBRT}) + endif() endif() endif() diff --git a/src/alloc-override.c b/src/alloc-override.c index c0e7bc2b..569e60ef 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -165,7 +165,11 @@ extern "C" { void* reallocf(void* p, size_t newsize) MI_FORWARD2(mi_reallocf,p,newsize); size_t malloc_size(void* p) MI_FORWARD1(mi_usable_size,p); +#if !defined(__ANDROID__) size_t malloc_usable_size(void *p) MI_FORWARD1(mi_usable_size,p); +#else +size_t malloc_usable_size(const void *p) MI_FORWARD1(mi_usable_size,p); +#endif void cfree(void* p) MI_FORWARD0(mi_free, p); // no forwarding here due to aliasing/name mangling issues From 1116c0df2ea85bd03b4cfe38b2bd11afda090784 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 14 Apr 2020 17:42:30 -0700 Subject: [PATCH 16/42] fix strnlen do not search beyond n characters, issue #228 --- src/alloc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index d7b8219e..90a1f461 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -649,12 +649,13 @@ mi_decl_restrict char* mi_strdup(const char* s) mi_attr_noexcept { // `strndup` using mi_malloc mi_decl_restrict char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n) mi_attr_noexcept { if (s == NULL) return NULL; - size_t m = strlen(s); - if (n > m) n = m; - char* t = (char*)mi_heap_malloc(heap, n+1); + const char* end = (const char*)memchr(s, 0, n); // find end of string in the first `n` characters (returns NULL if not found) + const size_t m = (end != NULL ? (end - s) : n); // `m` is the minimum of `n` or the end-of-string + mi_assert_internal(m <= n); + char* t = (char*)mi_heap_malloc(heap, m+1); if (t == NULL) return NULL; - memcpy(t, s, n); - t[n] = 0; + memcpy(t, s, m); + t[m] = 0; return t; } From 80aeb1bd1d6f22094744bb61bfcfdae5b266f14d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 15 Apr 2020 05:34:07 +0100 Subject: [PATCH 17/42] Fix compiler detection --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 508934dc..e37b5083 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,7 +146,7 @@ endif() if(WIN32) list(APPEND mi_libraries psapi shell32 user32 bcrypt) else() - if(NOT ${CC} MATCHES "android") + if(NOT ${CMAKE_C_COMPILER} MATCHES "android") list(APPEND mi_libraries pthread) find_library(LIBRT rt) if(LIBRT) From 211038c4e5436cea5b3d99e7e90e419396310512 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 15 Apr 2020 11:55:54 -0700 Subject: [PATCH 18/42] (possible) fix for overriding of aligned_alloc on systems that define it as static inline. issue #219 --- src/alloc-override.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/alloc-override.c b/src/alloc-override.c index 569e60ef..e2fb1ba5 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -177,9 +177,16 @@ void* valloc(size_t size) { return mi_valloc(s void* pvalloc(size_t size) { return mi_pvalloc(size); } void* reallocarray(void* p, size_t count, size_t size) { return mi_reallocarray(p, count, size); } void* memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); } -void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } int posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p, alignment, size); } +// on some glibc `aligned_alloc` is declared `static inline` so we cannot override it (e.g. Conda). +// In those cases it will use `memalign`, `posix_memalign`, or `_aligned_malloc` so we override that instead. +#if _GLIBCXX_HAVE__ALIGNED_MALLOC +void* _aligned_malloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } +#else +void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } +#endif + #if defined(__GLIBC__) && defined(__linux__) // forward __libc interface (needed for glibc-based Linux distributions) void* __libc_malloc(size_t size) MI_FORWARD1(mi_malloc,size); From 77acf5a8685e82f6f2a20d37bb7f51789c9adcfd Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Apr 2020 09:27:43 -0700 Subject: [PATCH 19/42] more careful overriding of aligned_alloc for compilation on Conda (#219) --- src/alloc-override.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/alloc-override.c b/src/alloc-override.c index e2fb1ba5..0e908f42 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -163,30 +163,31 @@ extern "C" { // Posix & Unix functions definitions // ------------------------------------------------------ +void cfree(void* p) MI_FORWARD0(mi_free, p); void* reallocf(void* p, size_t newsize) MI_FORWARD2(mi_reallocf,p,newsize); size_t malloc_size(void* p) MI_FORWARD1(mi_usable_size,p); #if !defined(__ANDROID__) size_t malloc_usable_size(void *p) MI_FORWARD1(mi_usable_size,p); #else -size_t malloc_usable_size(const void *p) MI_FORWARD1(mi_usable_size,p); +size_t malloc_usable_size(const void *p) MI_FORWARD1(mi_usable_size,p); #endif -void cfree(void* p) MI_FORWARD0(mi_free, p); // no forwarding here due to aliasing/name mangling issues -void* valloc(size_t size) { return mi_valloc(size); } -void* pvalloc(size_t size) { return mi_pvalloc(size); } -void* reallocarray(void* p, size_t count, size_t size) { return mi_reallocarray(p, count, size); } -void* memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); } -int posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p, alignment, size); } +void* valloc(size_t size) { return mi_valloc(size); } +void* pvalloc(size_t size) { return mi_pvalloc(size); } +void* reallocarray(void* p, size_t count, size_t size) { return mi_reallocarray(p, count, size); } +void* memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); } +int posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p, alignment, size); } +void* _aligned_malloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } -// on some glibc `aligned_alloc` is declared `static inline` so we cannot override it (e.g. Conda). -// In those cases it will use `memalign`, `posix_memalign`, or `_aligned_malloc` so we override that instead. -#if _GLIBCXX_HAVE__ALIGNED_MALLOC -void* _aligned_malloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } -#else +// on some glibc `aligned_alloc` is declared `static inline` so we cannot override it (e.g. Conda). This happens +// when _GLIBCXX_HAVE_ALIGNED_ALLOC is not defined. However, in those cases it will use `memalign`, `posix_memalign`, +// or `_aligned_malloc` and we can avoid overriding it ourselves. +#if _GLIBCXX_HAVE_ALIGNED_ALLOC void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } #endif + #if defined(__GLIBC__) && defined(__linux__) // forward __libc interface (needed for glibc-based Linux distributions) void* __libc_malloc(size_t size) MI_FORWARD1(mi_malloc,size); @@ -195,10 +196,10 @@ void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(a void __libc_free(void* p) MI_FORWARD0(mi_free,p); void __libc_cfree(void* p) MI_FORWARD0(mi_free,p); - void* __libc_valloc(size_t size) { return mi_valloc(size); } - void* __libc_pvalloc(size_t size) { return mi_pvalloc(size); } - void* __libc_memalign(size_t alignment, size_t size) { return mi_memalign(alignment,size); } - int __posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p,alignment,size); } + void* __libc_valloc(size_t size) { return mi_valloc(size); } + void* __libc_pvalloc(size_t size) { return mi_pvalloc(size); } + void* __libc_memalign(size_t alignment, size_t size) { return mi_memalign(alignment,size); } + int __posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p,alignment,size); } #endif #ifdef __cplusplus From 093db6af247c603460b670faade912993b28eea3 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Apr 2020 09:33:19 -0700 Subject: [PATCH 20/42] possible fix for memory instability on Win7 (#230) --- src/os.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/os.c b/src/os.c index 12ba9442..1c7e03c8 100644 --- a/src/os.c +++ b/src/os.c @@ -212,10 +212,12 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment void* p = VirtualAlloc(hint, size, flags, PAGE_READWRITE); if (p != NULL) return p; DWORD err = GetLastError(); - if (err != ERROR_INVALID_ADDRESS) { // if linked with multiple instances, we may have tried to allocate at an already allocated area + if (err != ERROR_INVALID_ADDRESS && // If linked with multiple instances, we may have tried to allocate at an already allocated area (#210) + err != ERROR_INVALID_PARAMETER) { // Windows7 instability (#230) return NULL; } - } + // fall through + } #endif #if defined(MEM_EXTENDED_PARAMETER_TYPE_BITS) // on modern Windows try use VirtualAlloc2 for aligned allocation @@ -228,6 +230,7 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment return (*pVirtualAlloc2)(GetCurrentProcess(), addr, size, flags, PAGE_READWRITE, ¶m, 1); } #endif + // last resort return VirtualAlloc(addr, size, flags, PAGE_READWRITE); } From 8e584cf3d96023d6f696cc69bfbe4f26cd2f4fb4 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Apr 2020 09:50:35 -0700 Subject: [PATCH 21/42] update readme to caution against using fork with huge/large OS pages (#229) --- readme.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/readme.md b/readme.md index 423c91b9..7f34eb7f 100644 --- a/readme.md +++ b/readme.md @@ -208,11 +208,12 @@ or via environment variables. - `MIMALLOC_SHOW_STATS=1`: show statistics when the program terminates. - `MIMALLOC_VERBOSE=1`: show verbose messages. - `MIMALLOC_SHOW_ERRORS=1`: show error and warning messages. -- `MIMALLOC_PAGE_RESET=1`: reset (or purge) OS pages when not in use. This can reduce - memory fragmentation in long running (server) programs. If performance is impacted, - `MIMALLOC_RESET_DELAY=` can be set higher (100ms by default) to make the page - reset occur less frequently. -- `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages when available; for some workloads this can significantly +- `MIMALLOC_PAGE_RESET=0`: by default, mimalloc will reset (or purge) OS pages when not in use to signal to the OS + that the underlying physical memory can be reused. This can reduce memory fragmentation in long running (server) + programs. By setting it to `0` no such page resets will be done which can improve performance for programs that are not long + running. As an alternative, the `MIMALLOC_RESET_DELAY=` can be set higher (100ms by default) to make the page + reset occur less frequently instead of turning it off completely. +- `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages (2MiB) when available; for some workloads this can significantly improve performance. Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs to explicitly allow large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that @@ -223,16 +224,21 @@ or via environment variables. turned off by default on Windows as it looks not good in the task manager. However, turning it on has no real drawbacks and may improve performance by a little. --> -- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB huge OS pages. This reserves the huge pages at - startup and can give quite a (latency) performance improvement on long running workloads. Usually it is better to not use +- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB _huge_ OS pages. This reserves the huge pages at + startup and sometimes this can give a large (latency) performance improvement on big workloads. + Usually it is better to not use `MIMALLOC_LARGE_OS_PAGES` in combination with this setting. Just like large OS pages, use with care as reserving contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at startup only once). Note that we usually need to explicitly enable huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). With huge OS pages, it may be beneficial to set the setting - `MIMALLOC_EAGER_COMMIT_DELAY=N` (with usually `N` as 1) to delay the initial `N` segments + `MIMALLOC_EAGER_COMMIT_DELAY=N` (`N` is 1 by default) to delay the initial `N` segments (of 4MiB) of a thread to not allocate in the huge OS pages; this prevents threads that are short lived and allocate just a little to take up space in the huge OS page area (which cannot be reset). +Use caution when using `fork` in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write +for all pages in the original process including the huge OS pages. When any memory is now written in that area, the +OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in big increments. + [linux-huge]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/tuning_and_optimizing_red_hat_enterprise_linux_for_oracle_9i_and_10g_databases/sect-oracle_9i_and_10g_tuning_guide-large_memory_optimization_big_pages_and_huge_pages-configuring_huge_pages_in_red_hat_enterprise_linux_4_or_5 [windows-huge]: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows?view=sql-server-2017 From b0150ba705af13e6095943bd6b91e61b478987a2 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Apr 2020 09:56:55 -0700 Subject: [PATCH 22/42] more notes on windows overriding --- readme.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 7f34eb7f..2a3f5891 100644 --- a/readme.md +++ b/readme.md @@ -286,9 +286,13 @@ the [shell](https://stackoverflow.com/questions/43941322/dyld-insert-libraries-i ### Override on Windows -Overriding on Windows is robust but requires that you link your program explicitly with +Overriding on Windows is robust and has the +particular advantage to be able to redirect all malloc/free calls that go through +the (dynamic) C runtime allocator, including those from other DLL's or libraries. + +The overriding on Windows requires that you link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -Moreover, you need to ensure the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) is available +Also, the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) must be available in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc (in `mimalloc-override.dll`). @@ -303,8 +307,9 @@ is also recommended to also override the `new`/`delete` operations (by including The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully redirected. -(Note: in principle, it is possible to patch existing executables -that are linked with the dynamic C runtime (`ucrtbase.dll`) by just putting the `mimalloc-override.dll` into the import table (and putting `mimalloc-redirect.dll` in the same folder) +(Note: in principle, it is possible to even patch existing executables without any recompilation +if they are linked with the dynamic C runtime (`ucrtbase.dll`) -- just put the `mimalloc-override.dll` +into the import table (and put `mimalloc-redirect.dll` in the same folder) Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)). From cbebd4e15c806d842d4383255704af24d94c0f73 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 20 Apr 2020 11:37:59 -0700 Subject: [PATCH 23/42] Add thank you notes --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme.md b/readme.md index 423c91b9..939cd3b5 100644 --- a/readme.md +++ b/readme.md @@ -75,6 +75,11 @@ free list encoding](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af * 2019-09-01, `v1.0.8`: pre-release 8: more robust windows dynamic overriding, initial huge page support. * 2019-08-10, `v1.0.6`: pre-release 6: various performance improvements. +Special thanks to: + +* Jason Gibson (@jasongibson) for exhaustive testing on large workloads and server environments and finding complex bugs in (early versions of) `mimalloc`. +* Manuel Pöter (@mpoeter) and Sam Gross (@colesbury) for finding an ABA concurrency issue in abandoned segment reclamation. + # Building ## Windows From 45a6161cf312edf605eaf8cf93287269436ed0fe Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Apr 2020 11:54:28 -0700 Subject: [PATCH 24/42] update logo to just use paths in svg --- doc/mimalloc-logo.svg | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/doc/mimalloc-logo.svg b/doc/mimalloc-logo.svg index 7b6231bd..672c7e41 100644 --- a/doc/mimalloc-logo.svg +++ b/doc/mimalloc-logo.svg @@ -36,15 +36,15 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="23.706667" - inkscape:cx="34.419045" + inkscape:cx="24.864771" inkscape:cy="35.79485" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" inkscape:window-width="3840" - inkscape:window-height="2160" - inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-height="2050" + inkscape:window-x="-12" + inkscape:window-y="-12" inkscape:window-maximized="1" inkscape:snap-object-midpoints="false" inkscape:snap-bbox="false" @@ -126,17 +126,15 @@ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.28797817px;font-family:RoutedGothicEx;-inkscape-font-specification:'RoutedGothicEx, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28599727" id="path6525" /> - m + id="text848"> + + From bb6afb7efd0d00d0777b05f7fe44c54cca5f39d7 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Apr 2020 12:00:39 -0700 Subject: [PATCH 25/42] update documentation --- doc/mimalloc-doc.h | 48 ++++++++++++++----------- docs/annotated.html | 2 +- docs/bench.html | 2 +- docs/build.html | 2 +- docs/classes.html | 2 +- docs/environment.html | 10 +++--- docs/functions.html | 2 +- docs/functions_vars.html | 2 +- docs/group__aligned.html | 2 +- docs/group__analysis.html | 2 +- docs/group__cpp.html | 2 +- docs/group__extended.html | 2 +- docs/group__heap.html | 2 +- docs/group__malloc.html | 2 +- docs/group__options.html | 2 +- docs/group__posix.html | 2 +- docs/group__typed.html | 4 +-- docs/group__zeroinit.html | 2 +- docs/index.html | 6 ++-- docs/mimalloc-doc_8h_source.html | 62 ++++++++++++++++---------------- docs/mimalloc-logo.svg | 26 +++++++------- docs/modules.html | 2 +- docs/overrides.html | 11 +++--- docs/pages.html | 2 +- docs/using.html | 2 +- 25 files changed, 106 insertions(+), 97 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 3f24a623..67f4fe95 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -1009,28 +1009,31 @@ or via environment variables. - `MIMALLOC_SHOW_STATS=1`: show statistics when the program terminates. - `MIMALLOC_VERBOSE=1`: show verbose messages. - `MIMALLOC_SHOW_ERRORS=1`: show error and warning messages. -- `MIMALLOC_PAGE_RESET=1`: reset (or purge) OS pages when not in use. This can reduce - memory fragmentation in long running (server) programs. If performance is impacted, - `MIMALLOC_RESET_DELAY=`_msecs_ can be set higher (100ms by default) to make the page - reset occur less frequently. -- `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages when available; for some workloads this can significantly +- `MIMALLOC_PAGE_RESET=0`: by default, mimalloc will reset (or purge) OS pages when not in use to signal to the OS + that the underlying physical memory can be reused. This can reduce memory fragmentation in long running (server) + programs. By setting it to `0` no such page resets will be done which can improve performance for programs that are not long + running. As an alternative, the `MIMALLOC_RESET_DELAY=` can be set higher (100ms by default) to make the page + reset occur less frequently instead of turning it off completely. +- `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages (2MiB) when available; for some workloads this can significantly improve performance. Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs to explicitly allow large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead when possible). -- `MIMALLOC_EAGER_REGION_COMMIT=1`: on Windows, commit large (256MiB) regions eagerly. On Windows, these regions - show in the working set even though usually just a small part is committed to physical memory. This is why it - turned off by default on Windows as it looks not good in the task manager. However, in reality it is always better - to turn it on as it improves performance and has no other drawbacks. -- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB huge OS pages. This reserves the huge pages at - startup and can give quite a performance improvement on long running workloads. Usually it is better to not use +- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB _huge_ OS pages. This reserves the huge pages at + startup and sometimes this can give a large (latency) performance improvement on big workloads. + Usually it is better to not use `MIMALLOC_LARGE_OS_PAGES` in combination with this setting. Just like large OS pages, use with care as reserving - contiguous physical memory can take a long time when memory is fragmented. + contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at + startup only once). Note that we usually need to explicitly enable huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). With huge OS pages, it may be beneficial to set the setting - `MIMALLOC_EAGER_COMMIT_DELAY=N` (with usually `N` as 1) to delay the initial `N` segments + `MIMALLOC_EAGER_COMMIT_DELAY=N` (`N` is 1 by default) to delay the initial `N` segments (of 4MiB) of a thread to not allocate in the huge OS pages; this prevents threads that are short lived and allocate just a little to take up space in the huge OS page area (which cannot be reset). +Use caution when using `fork` in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write +for all pages in the original process including the huge OS pages. When any memory is now written in that area, the +OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in big increments. + [linux-huge]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/tuning_and_optimizing_red_hat_enterprise_linux_for_oracle_9i_and_10g_databases/sect-oracle_9i_and_10g_tuning_guide-large_memory_optimization_big_pages_and_huge_pages-configuring_huge_pages_in_red_hat_enterprise_linux_4_or_5 [windows-huge]: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows?view=sql-server-2017 @@ -1074,14 +1077,18 @@ resolved to the _mimalloc_ library. Note that certain security restrictions may apply when doing this from the [shell](https://stackoverflow.com/questions/43941322/dyld-insert-libraries-ignored-when-calling-application-through-bash). -Note: unfortunately, at this time, dynamic overriding on macOS seems broken but it is actively worked on to fix this -(see issue [`#50`](https://github.com/microsoft/mimalloc/issues/50)). +(Note: macOS support for dynamic overriding is recent, please report any issues.) + ### Windows -Overriding on Windows is robust but requires that you link your program explicitly with +Overriding on Windows is robust and has the +particular advantage to be able to redirect all malloc/free calls that go through +the (dynamic) C runtime allocator, including those from other DLL's or libraries. + +The overriding on Windows requires that you link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -Moreover, you need to ensure the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) is available +Also, the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) must be available in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc (in `mimalloc-override.dll`). @@ -1090,14 +1097,15 @@ To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the `main` function, like `mi_version()` (or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project for an example on how to use this. For best performance on Windows with C++, it -is highly recommended to also override the `new`/`delete` operations (by including +is also recommended to also override the `new`/`delete` operations (by including [`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) a single(!) source file in your project). The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully redirected. -(Note: in principle, it is possible to patch existing executables -that are linked with the dynamic C runtime (`ucrtbase.dll`) by just putting the `mimalloc-override.dll` into the import table (and putting `mimalloc-redirect.dll` in the same folder) +(Note: in principle, it is possible to even patch existing executables without any recompilation +if they are linked with the dynamic C runtime (`ucrtbase.dll`) -- just put the `mimalloc-override.dll` +into the import table (and put `mimalloc-redirect.dll` in the same folder) Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)). diff --git a/docs/annotated.html b/docs/annotated.html index 5120b803..feba2438 100644 --- a/docs/annotated.html +++ b/docs/annotated.html @@ -37,7 +37,7 @@ Logo
mi-malloc -  1.4 +  1.6
diff --git a/docs/bench.html b/docs/bench.html index 6b289c04..f39fade6 100644 --- a/docs/bench.html +++ b/docs/bench.html @@ -37,7 +37,7 @@ Logo
mi-malloc -  1.4 +  1.6
diff --git a/docs/build.html b/docs/build.html index 755aad88..2bd06f13 100644 --- a/docs/build.html +++ b/docs/build.html @@ -37,7 +37,7 @@ Logo
mi-malloc -  1.4 +  1.6
diff --git a/docs/classes.html b/docs/classes.html index de960fb6..e74a0a24 100644 --- a/docs/classes.html +++ b/docs/classes.html @@ -37,7 +37,7 @@ Logo
mi-malloc -  1.4 +  1.6
diff --git a/docs/environment.html b/docs/environment.html index 1063654e..87d67e4a 100644 --- a/docs/environment.html +++ b/docs/environment.html @@ -37,7 +37,7 @@ Logo
mi-malloc -  1.4 +  1.6
@@ -107,11 +107,11 @@ $(document).ready(function(){initNavTree('environment.html','');});
  • MIMALLOC_SHOW_STATS=1: show statistics when the program terminates.
  • MIMALLOC_VERBOSE=1: show verbose messages.
  • MIMALLOC_SHOW_ERRORS=1: show error and warning messages.
  • -
  • MIMALLOC_PAGE_RESET=1: reset (or purge) OS pages when not in use. This can reduce memory fragmentation in long running (server) programs. If performance is impacted, MIMALLOC_RESET_DELAY=_msecs_ can be set higher (100ms by default) to make the page reset occur less frequently.
  • -
  • MIMALLOC_LARGE_OS_PAGES=1: use large OS pages when available; for some workloads this can significantly improve performance. Use MIMALLOC_VERBOSE to check if the large OS pages are enabled – usually one needs to explicitly allow large OS pages (as on Windows and Linux). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that can have fragmented memory (for that reason, we generally recommend to use MIMALLOC_RESERVE_HUGE_OS_PAGES instead when possible).
  • -
  • MIMALLOC_EAGER_REGION_COMMIT=1: on Windows, commit large (256MiB) regions eagerly. On Windows, these regions show in the working set even though usually just a small part is committed to physical memory. This is why it turned off by default on Windows as it looks not good in the task manager. However, in reality it is always better to turn it on as it improves performance and has no other drawbacks.
  • -
  • MIMALLOC_RESERVE_HUGE_OS_PAGES=N: where N is the number of 1GiB huge OS pages. This reserves the huge pages at startup and can give quite a performance improvement on long running workloads. Usually it is better to not use MIMALLOC_LARGE_OS_PAGES in combination with this setting. Just like large OS pages, use with care as reserving contiguous physical memory can take a long time when memory is fragmented. Note that we usually need to explicitly enable huge OS pages (as on Windows and Linux)). With huge OS pages, it may be beneficial to set the setting MIMALLOC_EAGER_COMMIT_DELAY=N (with usually N as 1) to delay the initial N segments of a thread to not allocate in the huge OS pages; this prevents threads that are short lived and allocate just a little to take up space in the huge OS page area (which cannot be reset).
  • +
  • MIMALLOC_PAGE_RESET=0: by default, mimalloc will reset (or purge) OS pages when not in use to signal to the OS that the underlying physical memory can be reused. This can reduce memory fragmentation in long running (server) programs. By setting it to 0 no such page resets will be done which can improve performance for programs that are not long running. As an alternative, the MIMALLOC_RESET_DELAY=<msecs> can be set higher (100ms by default) to make the page reset occur less frequently instead of turning it off completely.
  • +
  • MIMALLOC_LARGE_OS_PAGES=1: use large OS pages (2MiB) when available; for some workloads this can significantly improve performance. Use MIMALLOC_VERBOSE to check if the large OS pages are enabled – usually one needs to explicitly allow large OS pages (as on Windows and Linux). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that can have fragmented memory (for that reason, we generally recommend to use MIMALLOC_RESERVE_HUGE_OS_PAGES instead when possible).
  • +
  • MIMALLOC_RESERVE_HUGE_OS_PAGES=N: where N is the number of 1GiB huge OS pages. This reserves the huge pages at startup and sometimes this can give a large (latency) performance improvement on big workloads. Usually it is better to not use MIMALLOC_LARGE_OS_PAGES in combination with this setting. Just like large OS pages, use with care as reserving contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at startup only once). Note that we usually need to explicitly enable huge OS pages (as on Windows and Linux)). With huge OS pages, it may be beneficial to set the setting MIMALLOC_EAGER_COMMIT_DELAY=N (N is 1 by default) to delay the initial N segments (of 4MiB) of a thread to not allocate in the huge OS pages; this prevents threads that are short lived and allocate just a little to take up space in the huge OS page area (which cannot be reset).
  • +

    Use caution when using fork in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write for all pages in the original process including the huge OS pages. When any memory is now written in that area, the OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in big increments.

    diff --git a/docs/functions.html b/docs/functions.html index 43e116ed..62021210 100644 --- a/docs/functions.html +++ b/docs/functions.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/functions_vars.html b/docs/functions_vars.html index 060a18d2..7d41d10e 100644 --- a/docs/functions_vars.html +++ b/docs/functions_vars.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__aligned.html b/docs/group__aligned.html index 88c10eb4..a3eaacf0 100644 --- a/docs/group__aligned.html +++ b/docs/group__aligned.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__analysis.html b/docs/group__analysis.html index b8d644aa..2487c240 100644 --- a/docs/group__analysis.html +++ b/docs/group__analysis.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__cpp.html b/docs/group__cpp.html index caf758a8..88c75888 100644 --- a/docs/group__cpp.html +++ b/docs/group__cpp.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__extended.html b/docs/group__extended.html index 9e2a2efc..325d62bf 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__heap.html b/docs/group__heap.html index 0973279a..1a38c936 100644 --- a/docs/group__heap.html +++ b/docs/group__heap.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__malloc.html b/docs/group__malloc.html index bee7b4eb..224c4b08 100644 --- a/docs/group__malloc.html +++ b/docs/group__malloc.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__options.html b/docs/group__options.html index 71c7ba24..5e45d7bd 100644 --- a/docs/group__options.html +++ b/docs/group__options.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__posix.html b/docs/group__posix.html index 1aea8dc8..fe3a88e1 100644 --- a/docs/group__posix.html +++ b/docs/group__posix.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/group__typed.html b/docs/group__typed.html index cf5ac5d1..5cbfbd6b 100644 --- a/docs/group__typed.html +++ b/docs/group__typed.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    @@ -146,7 +146,7 @@ Macros

    Detailed Description

    Typed allocation macros.

    -

    Macro Definition Documentation

    +

    For example:

    int* p = mi_malloc_tp(int)

    Macro Definition Documentation

    ◆ mi_calloc_tp

    diff --git a/docs/group__zeroinit.html b/docs/group__zeroinit.html index 28983138..3c04a5a6 100644 --- a/docs/group__zeroinit.html +++ b/docs/group__zeroinit.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/index.html b/docs/index.html index 0efc9c09..ce9c983d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    @@ -127,7 +127,9 @@ $(document).ready(function(){initNavTree('index.html','');});
  • Heap Allocation
  • Typed Macros
  • Heap Introspection
  • -
  • Runtime Options
  • +
  • Runtime Options
  • +
  • Posix
  • +
  • C++ wrappers
  • diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index f70ae81f..09c03b9b 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    @@ -102,7 +102,7 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
    mimalloc-doc.h
    -
    1 /* ----------------------------------------------------------------------------
    2 Copyright (c) 2018, Microsoft Research, Daan Leijen
    3 This is free software; you can redistribute it and/or modify it under the
    4 terms of the MIT license. A copy of the license can be found in the file
    5 "LICENSE" at the root of this distribution.
    6 -----------------------------------------------------------------------------*/
    7 
    8 #error "documentation file only!"
    9 
    10 
    81 
    85 
    89 void mi_free(void* p);
    90 
    95 void* mi_malloc(size_t size);
    96 
    101 void* mi_zalloc(size_t size);
    102 
    112 void* mi_calloc(size_t count, size_t size);
    113 
    126 void* mi_realloc(void* p, size_t newsize);
    127 
    138 void* mi_recalloc(void* p, size_t count, size_t size);
    139 
    153 void* mi_expand(void* p, size_t newsize);
    154 
    164 void* mi_mallocn(size_t count, size_t size);
    165 
    175 void* mi_reallocn(void* p, size_t count, size_t size);
    176 
    193 void* mi_reallocf(void* p, size_t newsize);
    194 
    195 
    204 char* mi_strdup(const char* s);
    205 
    215 char* mi_strndup(const char* s, size_t n);
    216 
    229 char* mi_realpath(const char* fname, char* resolved_name);
    230 
    232 
    233 // ------------------------------------------------------
    234 // Extended functionality
    235 // ------------------------------------------------------
    236 
    240 
    243 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
    244 
    252 void* mi_malloc_small(size_t size);
    253 
    261 void* mi_zalloc_small(size_t size);
    262 
    277 size_t mi_usable_size(void* p);
    278 
    288 size_t mi_good_size(size_t size);
    289 
    297 void mi_collect(bool force);
    298 
    303 void mi_stats_print(void* out);
    304 
    310 void mi_stats_print(mi_output_fun* out, void* arg);
    311 
    313 void mi_stats_reset(void);
    314 
    316 void mi_stats_merge(void);
    317 
    321 void mi_thread_init(void);
    322 
    327 void mi_thread_done(void);
    328 
    334 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
    335 
    342 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    343 
    359 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    360 
    366 typedef void (mi_output_fun)(const char* msg, void* arg);
    367 
    374 void mi_register_output(mi_output_fun* out, void* arg);
    375 
    381 typedef void (mi_error_fun)(int err, void* arg);
    382 
    398 void mi_register_error(mi_error_fun* errfun, void* arg);
    399 
    404 bool mi_is_in_heap_region(const void* p);
    405 
    406 
    419 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    420 
    433 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    434 
    435 
    440 bool mi_is_redirected();
    441 
    442 
    444 
    445 // ------------------------------------------------------
    446 // Aligned allocation
    447 // ------------------------------------------------------
    448 
    454 
    467 void* mi_malloc_aligned(size_t size, size_t alignment);
    468 void* mi_zalloc_aligned(size_t size, size_t alignment);
    469 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    470 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    471 
    482 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    483 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    484 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    485 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    486 
    488 
    494 
    499 struct mi_heap_s;
    500 
    505 typedef struct mi_heap_s mi_heap_t;
    506 
    509 
    517 void mi_heap_delete(mi_heap_t* heap);
    518 
    526 void mi_heap_destroy(mi_heap_t* heap);
    527 
    532 
    536 
    543 
    545 void mi_heap_collect(mi_heap_t* heap, bool force);
    546 
    549 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    550 
    554 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    555 
    558 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    559 
    562 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    563 
    566 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    567 
    570 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    571 
    574 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    575 
    578 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    579 
    580 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    581 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    582 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    583 
    584 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    585 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    586 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    587 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    588 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    589 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    590 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    591 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    592 
    594 
    595 
    604 
    605 void* mi_rezalloc(void* p, size_t newsize);
    606 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    607 
    608 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    609 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    610 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    611 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    612 
    613 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    614 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    615 
    616 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    617 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    618 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    619 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    620 
    622 
    628 
    640 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    641 
    643 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    644 
    646 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    647 
    649 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    650 
    652 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    653 
    655 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    656 
    658 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    659 
    661 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    662 
    664 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    665 
    667 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    668 
    670 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    671 
    673 
    679 
    686 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    687 
    696 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    697 
    705 bool mi_check_owned(const void* p);
    706 
    709 typedef struct mi_heap_area_s {
    710  void* blocks;
    711  size_t reserved;
    712  size_t committed;
    713  size_t used;
    714  size_t block_size;
    716 
    724 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    725 
    737 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    738 
    740 
    746 
    748 typedef enum mi_option_e {
    749  // stable options
    753  // the following options are experimental
    767 } mi_option_t;
    768 
    769 
    770 bool mi_option_enabled(mi_option_t option);
    771 void mi_option_enable(mi_option_t option, bool enable);
    772 void mi_option_enable_default(mi_option_t option, bool enable);
    773 
    774 long mi_option_get(mi_option_t option);
    775 void mi_option_set(mi_option_t option, long value);
    776 void mi_option_set_default(mi_option_t option, long value);
    777 
    778 
    780 
    787 
    788 void* mi_recalloc(void* p, size_t count, size_t size);
    789 size_t mi_malloc_size(const void* p);
    790 size_t mi_malloc_usable_size(const void *p);
    791 
    793 void mi_cfree(void* p);
    794 
    795 int mi_posix_memalign(void** p, size_t alignment, size_t size);
    796 int mi__posix_memalign(void** p, size_t alignment, size_t size);
    797 void* mi_memalign(size_t alignment, size_t size);
    798 void* mi_valloc(size_t size);
    799 
    800 void* mi_pvalloc(size_t size);
    801 void* mi_aligned_alloc(size_t alignment, size_t size);
    802 void* mi_reallocarray(void* p, size_t count, size_t size);
    803 
    804 void mi_free_size(void* p, size_t size);
    805 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    806 void mi_free_aligned(void* p, size_t alignment);
    807 
    809 
    822 
    824 void* mi_new(std::size_t n) noexcept(false);
    825 
    827 void* mi_new_n(size_t count, size_t size) noexcept(false);
    828 
    830 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    831 
    833 void* mi_new_nothrow(size_t n);
    834 
    836 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    837 
    839 void* mi_new_realloc(void* p, size_t newsize);
    840 
    842 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    843 
    851 template<class T> struct mi_stl_allocator { }
    852 
    854 
    void mi_option_enable_default(mi_option_t option, bool enable)
    +
    1 /* ----------------------------------------------------------------------------
    2 Copyright (c) 2018, Microsoft Research, Daan Leijen
    3 This is free software; you can redistribute it and/or modify it under the
    4 terms of the MIT license. A copy of the license can be found in the file
    5 "LICENSE" at the root of this distribution.
    6 -----------------------------------------------------------------------------*/
    7 
    8 #error "documentation file only!"
    9 
    10 
    83 
    87 
    91 void mi_free(void* p);
    92 
    97 void* mi_malloc(size_t size);
    98 
    103 void* mi_zalloc(size_t size);
    104 
    114 void* mi_calloc(size_t count, size_t size);
    115 
    128 void* mi_realloc(void* p, size_t newsize);
    129 
    140 void* mi_recalloc(void* p, size_t count, size_t size);
    141 
    155 void* mi_expand(void* p, size_t newsize);
    156 
    166 void* mi_mallocn(size_t count, size_t size);
    167 
    177 void* mi_reallocn(void* p, size_t count, size_t size);
    178 
    195 void* mi_reallocf(void* p, size_t newsize);
    196 
    197 
    206 char* mi_strdup(const char* s);
    207 
    217 char* mi_strndup(const char* s, size_t n);
    218 
    231 char* mi_realpath(const char* fname, char* resolved_name);
    232 
    234 
    235 // ------------------------------------------------------
    236 // Extended functionality
    237 // ------------------------------------------------------
    238 
    242 
    245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
    246 
    254 void* mi_malloc_small(size_t size);
    255 
    263 void* mi_zalloc_small(size_t size);
    264 
    279 size_t mi_usable_size(void* p);
    280 
    290 size_t mi_good_size(size_t size);
    291 
    299 void mi_collect(bool force);
    300 
    305 void mi_stats_print(void* out);
    306 
    312 void mi_stats_print(mi_output_fun* out, void* arg);
    313 
    315 void mi_stats_reset(void);
    316 
    318 void mi_stats_merge(void);
    319 
    323 void mi_thread_init(void);
    324 
    329 void mi_thread_done(void);
    330 
    336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
    337 
    344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    345 
    361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    362 
    368 typedef void (mi_output_fun)(const char* msg, void* arg);
    369 
    376 void mi_register_output(mi_output_fun* out, void* arg);
    377 
    383 typedef void (mi_error_fun)(int err, void* arg);
    384 
    400 void mi_register_error(mi_error_fun* errfun, void* arg);
    401 
    406 bool mi_is_in_heap_region(const void* p);
    407 
    408 
    421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    422 
    435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    436 
    437 
    442 bool mi_is_redirected();
    443 
    444 
    446 
    447 // ------------------------------------------------------
    448 // Aligned allocation
    449 // ------------------------------------------------------
    450 
    456 
    469 void* mi_malloc_aligned(size_t size, size_t alignment);
    470 void* mi_zalloc_aligned(size_t size, size_t alignment);
    471 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    472 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    473 
    484 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    485 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    486 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    487 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    488 
    490 
    496 
    501 struct mi_heap_s;
    502 
    507 typedef struct mi_heap_s mi_heap_t;
    508 
    511 
    519 void mi_heap_delete(mi_heap_t* heap);
    520 
    528 void mi_heap_destroy(mi_heap_t* heap);
    529 
    534 
    538 
    545 
    547 void mi_heap_collect(mi_heap_t* heap, bool force);
    548 
    551 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    552 
    556 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    557 
    560 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    561 
    564 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    565 
    568 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    569 
    572 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    573 
    576 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    577 
    580 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    581 
    582 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    583 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    584 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    585 
    586 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    587 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    588 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    589 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    590 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    591 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    592 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    593 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    594 
    596 
    597 
    606 
    607 void* mi_rezalloc(void* p, size_t newsize);
    608 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    609 
    610 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    611 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    612 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    613 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    614 
    615 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    616 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    617 
    618 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    619 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    620 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    621 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    622 
    624 
    633 
    645 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    646 
    648 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    649 
    651 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    652 
    654 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    655 
    657 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    658 
    660 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    661 
    663 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    664 
    666 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    667 
    669 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    670 
    672 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    673 
    675 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    676 
    678 
    684 
    691 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    692 
    701 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    702 
    710 bool mi_check_owned(const void* p);
    711 
    714 typedef struct mi_heap_area_s {
    715  void* blocks;
    716  size_t reserved;
    717  size_t committed;
    718  size_t used;
    719  size_t block_size;
    721 
    729 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    730 
    742 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    743 
    745 
    751 
    753 typedef enum mi_option_e {
    754  // stable options
    758  // the following options are experimental
    772 } mi_option_t;
    773 
    774 
    775 bool mi_option_enabled(mi_option_t option);
    776 void mi_option_enable(mi_option_t option, bool enable);
    777 void mi_option_enable_default(mi_option_t option, bool enable);
    778 
    779 long mi_option_get(mi_option_t option);
    780 void mi_option_set(mi_option_t option, long value);
    781 void mi_option_set_default(mi_option_t option, long value);
    782 
    783 
    785 
    792 
    793 void* mi_recalloc(void* p, size_t count, size_t size);
    794 size_t mi_malloc_size(const void* p);
    795 size_t mi_malloc_usable_size(const void *p);
    796 
    798 void mi_cfree(void* p);
    799 
    800 int mi_posix_memalign(void** p, size_t alignment, size_t size);
    801 int mi__posix_memalign(void** p, size_t alignment, size_t size);
    802 void* mi_memalign(size_t alignment, size_t size);
    803 void* mi_valloc(size_t size);
    804 
    805 void* mi_pvalloc(size_t size);
    806 void* mi_aligned_alloc(size_t alignment, size_t size);
    807 void* mi_reallocarray(void* p, size_t count, size_t size);
    808 
    809 void mi_free_size(void* p, size_t size);
    810 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    811 void mi_free_aligned(void* p, size_t alignment);
    812 
    814 
    827 
    829 void* mi_new(std::size_t n) noexcept(false);
    830 
    832 void* mi_new_n(size_t count, size_t size) noexcept(false);
    833 
    835 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    836 
    838 void* mi_new_nothrow(size_t n);
    839 
    841 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    842 
    844 void* mi_new_realloc(void* p, size_t newsize);
    845 
    847 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    848 
    856 template<class T> struct mi_stl_allocator { }
    857 
    859 
    void mi_option_enable_default(mi_option_t option, bool enable)
    size_t mi_usable_size(void *p)
    Return the available bytes in a memory block.
    void * mi_new_nothrow(size_t n)
    like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
    void * mi_reallocn(void *p, size_t count, size_t size)
    Re-allocate memory to count elements of size bytes.
    @@ -118,17 +118,17 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
    void mi_stats_merge(void)
    Merge thread local statistics with the main statistics and reset.
    void * mi_new_n(size_t count, size_t size) noexcept(false)
    like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    void mi_option_set_default(mi_option_t option, long value)
    -
    void() mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition: mimalloc-doc.h:381
    +
    void() mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition: mimalloc-doc.h:383
    void * mi_rezalloc(void *p, size_t newsize)
    -
    Eagerly commit segments (4MiB) (enabled by default).
    Definition: mimalloc-doc.h:754
    +
    Eagerly commit segments (4MiB) (enabled by default).
    Definition: mimalloc-doc.h:759
    void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
    Allocate zero-initialized in a specific heap.
    void mi_option_set(mi_option_t option, long value)
    -
    Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
    Definition: mimalloc-doc.h:755
    +
    Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
    Definition: mimalloc-doc.h:760
    void mi_cfree(void *p)
    Just as free but also checks if the pointer p belongs to our heap.
    void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
    -
    Definition: mimalloc-doc.h:766
    +
    Definition: mimalloc-doc.h:771
    void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    -
    void * blocks
    start of the area containing heap blocks
    Definition: mimalloc-doc.h:710
    +
    void * blocks
    start of the area containing heap blocks
    Definition: mimalloc-doc.h:715
    void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
    int mi__posix_memalign(void **p, size_t alignment, size_t size)
    void mi_free(void *p)
    Free previously allocated memory.
    @@ -144,37 +144,37 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
    void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    void * mi_zalloc(size_t size)
    Allocate zero-initialized size bytes.
    void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
    -
    The number of segments per thread to keep cached.
    Definition: mimalloc-doc.h:758
    +
    The number of segments per thread to keep cached.
    Definition: mimalloc-doc.h:763
    void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
    Allocate count zero-initialized elements in a specific heap.
    void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
    bool mi_is_redirected()
    Is the C runtime malloc API redirected?
    -
    size_t block_size
    size in bytes of one block
    Definition: mimalloc-doc.h:714
    +
    size_t block_size
    size in bytes of one block
    Definition: mimalloc-doc.h:719
    void * mi_reallocarray(void *p, size_t count, size_t size)
    int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs)
    Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most t...
    -
    void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition: mimalloc-doc.h:342
    +
    void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition: mimalloc-doc.h:344
    bool mi_is_in_heap_region(const void *p)
    Is a pointer part of our heap?
    void mi_option_enable(mi_option_t option, bool enable)
    void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
    like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc e...
    void * mi_realloc(void *p, size_t newsize)
    Re-allocate memory to newsize bytes.
    -
    The number of huge OS pages (1GiB in size) to reserve at the start of the program.
    Definition: mimalloc-doc.h:757
    +
    The number of huge OS pages (1GiB in size) to reserve at the start of the program.
    Definition: mimalloc-doc.h:762
    void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
    void mi_free_size_aligned(void *p, size_t size, size_t alignment)
    void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    -
    Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
    Definition: mimalloc-doc.h:759
    +
    Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
    Definition: mimalloc-doc.h:764
    void mi_thread_done(void)
    Uninitialize mimalloc on a thread.
    bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
    Visit all areas and blocks in a heap.
    -
    Pretend there are at most N NUMA nodes.
    Definition: mimalloc-doc.h:762
    +
    Pretend there are at most N NUMA nodes.
    Definition: mimalloc-doc.h:767
    void * mi_malloc(size_t size)
    Allocate size bytes.
    bool mi_option_enabled(mi_option_t option)
    void mi_register_error(mi_error_fun *errfun, void *arg)
    Register an error callback function.
    -
    Experimental.
    Definition: mimalloc-doc.h:763
    +
    Experimental.
    Definition: mimalloc-doc.h:768
    char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
    Duplicate a string of at most length n in a specific heap.
    -
    bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
    Visitor function passed to mi_heap_visit_blocks()
    Definition: mimalloc-doc.h:724
    +
    bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
    Visitor function passed to mi_heap_visit_blocks()
    Definition: mimalloc-doc.h:729
    void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
    void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    char * mi_realpath(const char *fname, char *resolved_name)
    Resolve a file path name.
    -
    Print error messages to stderr.
    Definition: mimalloc-doc.h:751
    -
    Experimental.
    Definition: mimalloc-doc.h:760
    +
    Print error messages to stderr.
    Definition: mimalloc-doc.h:756
    +
    Experimental.
    Definition: mimalloc-doc.h:765
    void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    void * mi_new_aligned_nothrow(size_t n, size_t alignment)
    like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
    void * mi_memalign(size_t alignment, size_t size)
    @@ -182,11 +182,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
    bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
    Does a heap contain a pointer to a previously allocated block?
    void mi_heap_collect(mi_heap_t *heap, bool force)
    Release outstanding resources in a specific heap.
    void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    -
    Print verbose messages to stderr.
    Definition: mimalloc-doc.h:752
    +
    Print verbose messages to stderr.
    Definition: mimalloc-doc.h:757
    void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
    void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
    Allocate size bytes aligned by alignment at a specified offset.
    void mi_heap_delete(mi_heap_t *heap)
    Delete a previously allocated heap.
    -
    OS tag to assign to mimalloc'd memory.
    Definition: mimalloc-doc.h:765
    +
    OS tag to assign to mimalloc'd memory.
    Definition: mimalloc-doc.h:770
    mi_heap_t * mi_heap_get_default()
    Get the default heap that is used for mi_malloc() et al.
    int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs)
    Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs ...
    void * mi_aligned_alloc(size_t alignment, size_t size)
    @@ -194,30 +194,30 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
    void mi_thread_init(void)
    Initialize mimalloc on a thread.
    size_t mi_good_size(size_t size)
    Return the used allocation size.
    void mi_stats_print(void *out)
    Print the main statistics.
    -
    Experimental.
    Definition: mimalloc-doc.h:764
    +
    Experimental.
    Definition: mimalloc-doc.h:769
    void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
    void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
    Allocate count elements in a specific heap.
    -
    An area of heap space contains blocks of a single size.
    Definition: mimalloc-doc.h:709
    +
    An area of heap space contains blocks of a single size.
    Definition: mimalloc-doc.h:714
    void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
    Print out heap statistics for this thread.
    -
    Print statistics to stderr when the program is done.
    Definition: mimalloc-doc.h:750
    +
    Print statistics to stderr when the program is done.
    Definition: mimalloc-doc.h:755
    void * mi_zalloc_aligned(size_t size, size_t alignment)
    -
    size_t reserved
    bytes reserved for this area
    Definition: mimalloc-doc.h:711
    -
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition: mimalloc-doc.h:505
    -
    size_t used
    bytes in use by allocated blocks
    Definition: mimalloc-doc.h:713
    +
    size_t reserved
    bytes reserved for this area
    Definition: mimalloc-doc.h:716
    +
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition: mimalloc-doc.h:507
    +
    size_t used
    bytes in use by allocated blocks
    Definition: mimalloc-doc.h:718
    void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
    Register a deferred free function.
    void mi_free_size(void *p, size_t size)
    void mi_collect(bool force)
    Eagerly free memory.
    void * mi_new_reallocn(void *p, size_t newcount, size_t size)
    like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc excepti...
    void mi_heap_destroy(mi_heap_t *heap)
    Destroy a heap, freeing all its still allocated blocks.
    void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
    -
    Use large OS pages (2MiB in size) if possible.
    Definition: mimalloc-doc.h:756
    +
    Use large OS pages (2MiB in size) if possible.
    Definition: mimalloc-doc.h:761
    void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
    void mi_register_output(mi_output_fun *out, void *arg)
    Register an output function.
    -
    std::allocator implementation for mimalloc for use in STL containers.
    Definition: mimalloc-doc.h:851
    +
    std::allocator implementation for mimalloc for use in STL containers.
    Definition: mimalloc-doc.h:856
    void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
    Allocate a small object in a specific heap.
    void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
    size_t mi_malloc_usable_size(const void *p)
    -
    void() mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition: mimalloc-doc.h:366
    +
    void() mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition: mimalloc-doc.h:368
    char * mi_strdup(const char *s)
    Allocate and duplicate a string.
    void * mi_heap_realloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    void * mi_reallocf(void *p, size_t newsize)
    Re-allocate memory to newsize bytes,.
    @@ -230,11 +230,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
    mi_heap_t * mi_heap_get_backing()
    Get the backing heap.
    void mi_free_aligned(void *p, size_t alignment)
    void * mi_new(std::size_t n) noexcept(false)
    like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception...
    -
    Delay in milli-seconds before resetting a page (100ms by default)
    Definition: mimalloc-doc.h:761
    +
    Delay in milli-seconds before resetting a page (100ms by default)
    Definition: mimalloc-doc.h:766
    mi_heap_t * mi_heap_new()
    Create a new heap that can be used for allocation.
    void * mi_heap_malloc(mi_heap_t *heap, size_t size)
    Allocate in a specific heap.
    -
    size_t committed
    current committed bytes of this area
    Definition: mimalloc-doc.h:712
    -
    mi_option_t
    Runtime options.
    Definition: mimalloc-doc.h:748
    +
    size_t committed
    current committed bytes of this area
    Definition: mimalloc-doc.h:717
    +
    mi_option_t
    Runtime options.
    Definition: mimalloc-doc.h:753
    bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
    Check safely if any pointer is part of a heap.
    mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
    Set the default heap to use for mi_malloc() et al.
    diff --git a/docs/mimalloc-logo.svg b/docs/mimalloc-logo.svg index 7b6231bd..672c7e41 100644 --- a/docs/mimalloc-logo.svg +++ b/docs/mimalloc-logo.svg @@ -36,15 +36,15 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="23.706667" - inkscape:cx="34.419045" + inkscape:cx="24.864771" inkscape:cy="35.79485" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" inkscape:window-width="3840" - inkscape:window-height="2160" - inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-height="2050" + inkscape:window-x="-12" + inkscape:window-y="-12" inkscape:window-maximized="1" inkscape:snap-object-midpoints="false" inkscape:snap-bbox="false" @@ -126,17 +126,15 @@ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.28797817px;font-family:RoutedGothicEx;-inkscape-font-specification:'RoutedGothicEx, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28599727" id="path6525" /> - m + id="text848"> + + diff --git a/docs/modules.html b/docs/modules.html index 91bf17e8..9858d6ad 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/overrides.html b/docs/overrides.html index 3b5d9bd3..2a6c51e9 100644 --- a/docs/overrides.html +++ b/docs/overrides.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    @@ -116,12 +116,13 @@ $(document).ready(function(){initNavTree('overrides.html','');});
  • env DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram
  • Note that certain security restrictions may apply when doing this from the shell.

    -

    Note: unfortunately, at this time, dynamic overriding on macOS seems broken but it is actively worked on to fix this (see issue #50).

    +

    (Note: macOS support for dynamic overriding is recent, please report any issues.)

    Windows

    -

    Overriding on Windows is robust but requires that you link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the /MD or /MDd switch). Moreover, you need to ensure the mimalloc-redirect.dll (or mimalloc-redirect32.dll) is available in the same folder as the main mimalloc-override.dll at runtime (as it is a dependency). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc (in mimalloc-override.dll).

    -

    To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the main function, like mi_version() (or use the /INCLUDE:mi_version switch on the linker). See the mimalloc-override-test project for an example on how to use this. For best performance on Windows with C++, it is highly recommended to also override the new/delete operations (by including mimalloc-new-delete.h a single(!) source file in your project).

    +

    Overriding on Windows is robust and has the particular advantage to be able to redirect all malloc/free calls that go through the (dynamic) C runtime allocator, including those from other DLL's or libraries.

    +

    The overriding on Windows requires that you link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the /MD or /MDd switch). Also, the mimalloc-redirect.dll (or mimalloc-redirect32.dll) must be available in the same folder as the main mimalloc-override.dll at runtime (as it is a dependency). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc (in mimalloc-override.dll).

    +

    To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the main function, like mi_version() (or use the /INCLUDE:mi_version switch on the linker). See the mimalloc-override-test project for an example on how to use this. For best performance on Windows with C++, it is also recommended to also override the new/delete operations (by including mimalloc-new-delete.h a single(!) source file in your project).

    The environment variable MIMALLOC_DISABLE_REDIRECT=1 can be used to disable dynamic overriding at run-time. Use MIMALLOC_VERBOSE=1 to check if mimalloc was successfully redirected.

    -

    (Note: in principle, it is possible to patch existing executables that are linked with the dynamic C runtime (ucrtbase.dll) by just putting the mimalloc-override.dll into the import table (and putting mimalloc-redirect.dll in the same folder) Such patching can be done for example with CFF Explorer).

    +

    (Note: in principle, it is possible to even patch existing executables without any recompilation if they are linked with the dynamic C runtime (ucrtbase.dll) – just put the mimalloc-override.dll into the import table (and put mimalloc-redirect.dll in the same folder) Such patching can be done for example with CFF Explorer).

    Static override

    On Unix systems, you can also statically link with mimalloc to override the standard malloc interface. The recommended way is to link the final program with the mimalloc single object file (mimalloc-override.o). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the mimalloc library, link it as the first object file. For example:

    gcc -o myprogram mimalloc-override.o myfile1.c ...

    List of Overrides:

    diff --git a/docs/pages.html b/docs/pages.html index ad5549bf..8fcd6f08 100644 --- a/docs/pages.html +++ b/docs/pages.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    diff --git a/docs/using.html b/docs/using.html index c5dc12e7..047e35ec 100644 --- a/docs/using.html +++ b/docs/using.html @@ -37,7 +37,7 @@ Logo
    mi-malloc -  1.4 +  1.6
    From ecdb2cd7066f80c9017c91298c677b105cb95b19 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Apr 2020 12:37:00 -0700 Subject: [PATCH 26/42] document NUMA nodes setting --- doc/doxyfile | 2 +- readme.md | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/doc/doxyfile b/doc/doxyfile index 91adbeb8..6c1e30a0 100644 --- a/doc/doxyfile +++ b/doc/doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = mi-malloc # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4 +PROJECT_NUMBER = 1.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/readme.md b/readme.md index f1d54680..718d5e70 100644 --- a/readme.md +++ b/readme.md @@ -213,16 +213,20 @@ or via environment variables. - `MIMALLOC_SHOW_STATS=1`: show statistics when the program terminates. - `MIMALLOC_VERBOSE=1`: show verbose messages. - `MIMALLOC_SHOW_ERRORS=1`: show error and warning messages. -- `MIMALLOC_PAGE_RESET=0`: by default, mimalloc will reset (or purge) OS pages when not in use to signal to the OS +- `MIMALLOC_PAGE_RESET=0`: by default, mimalloc will reset (or purge) OS pages that are not in use, to signal to the OS that the underlying physical memory can be reused. This can reduce memory fragmentation in long running (server) - programs. By setting it to `0` no such page resets will be done which can improve performance for programs that are not long - running. As an alternative, the `MIMALLOC_RESET_DELAY=` can be set higher (100ms by default) to make the page + programs. By setting it to `0` this will no longer be done which can improve performance for batch-like programs. + As an alternative, the `MIMALLOC_RESET_DELAY=` can be set higher (100ms by default) to make the page reset occur less frequently instead of turning it off completely. +- `MIMALLOC_USE_NUMA_NODES=N`: pretend there are at most `N` NUMA nodes. If not set, the actual NUMA nodes are detected + at runtime. Setting `N` to 1 may avoid problems in some virtual environments. Also, setting it to a lower number than + the actual NUMA nodes is fine and will only cause threads to potentially allocate more memory across actual NUMA + nodes (but this can happen in any case as NUMA local allocation is always a best effort but not guaranteed). - `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages (2MiB) when available; for some workloads this can significantly improve performance. Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs to explicitly allow large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that - can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead when possible). + can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead whenever possible).