From 87d088b7e0850c2e6dff5849552df13aa6ff9c81 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 21 May 2024 12:31:57 -0700 Subject: [PATCH 001/305] bump version to v1.8.8 for further development --- cmake/mimalloc-config-version.cmake | 2 +- include/mimalloc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/mimalloc-config-version.cmake b/cmake/mimalloc-config-version.cmake index f7255251..f92d52e6 100644 --- a/cmake/mimalloc-config-version.cmake +++ b/cmake/mimalloc-config-version.cmake @@ -1,6 +1,6 @@ set(mi_version_major 1) set(mi_version_minor 8) -set(mi_version_patch 7) +set(mi_version_patch 8) set(mi_version ${mi_version_major}.${mi_version_minor}) set(PACKAGE_VERSION ${mi_version}) diff --git a/include/mimalloc.h b/include/mimalloc.h index ae6f99b4..0173a323 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MIMALLOC_H #define MIMALLOC_H -#define MI_MALLOC_VERSION 187 // major + 2 digits minor +#define MI_MALLOC_VERSION 188 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes From 78fa139a1c57e4fc6be4493af4e74c5e0711d302 Mon Sep 17 00:00:00 2001 From: "Daisuke Fujimura (fd0)" Date: Thu, 30 May 2024 19:38:06 +0900 Subject: [PATCH 002/305] Build on cygwin --- include/mimalloc/prim.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index 3f4574dd..16de2c5f 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -209,6 +209,7 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce // Nevertheless, it seems needed on older graviton platforms (see issue #851). // For now, we only enable this for specific platforms. #if !defined(__APPLE__) /* on apple (M1) the wrong register is read (tpidr_el0 instead of tpidrro_el0) so fall back to TLS slot assembly ()*/ \ + && !defined(__CYGWIN__) \ && !defined(MI_LIBC_MUSL) \ && (!defined(__clang_major__) || __clang_major__ >= 14) /* older clang versions emit bad code; fall back to using the TLS slot () */ #if (defined(__GNUC__) && (__GNUC__ >= 7) && defined(__aarch64__)) /* aarch64 for older gcc versions (issue #851) */ \ From 616db104a9147071a406a320fee6f51cf858ea74 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 1 Jun 2024 12:29:48 -0700 Subject: [PATCH 003/305] prevent UB in arena reservation --- include/mimalloc/internal.h | 8 ++++++++ src/arena.c | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 2954eabd..2a21f34b 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -329,6 +329,14 @@ static inline uintptr_t _mi_divide_up(uintptr_t size, size_t divider) { return (divider == 0 ? size : ((size + divider - 1) / divider)); } + +// clamp an integer +static inline size_t _mi_clamp(size_t sz, size_t min, size_t max) { + if (sz < min) return min; + else if (sz > max) return max; + else return sz; +} + // Is memory zero initialized? static inline bool mi_mem_is_zero(const void* p, size_t size) { for (size_t i = 0; i < size; i++) { diff --git a/src/arena.c b/src/arena.c index 25ce56ec..445cc309 100644 --- a/src/arena.c +++ b/src/arena.c @@ -358,8 +358,14 @@ static bool mi_arena_reserve(size_t req_size, bool allow_large, mi_arena_id_t re arena_reserve = arena_reserve/4; // be conservative if virtual reserve is not supported (for WASM for example) } arena_reserve = _mi_align_up(arena_reserve, MI_ARENA_BLOCK_SIZE); + arena_reserve = _mi_align_up(arena_reserve, MI_SEGMENT_SIZE); if (arena_count >= 8 && arena_count <= 128) { - arena_reserve = ((size_t)1<<(arena_count/8)) * arena_reserve; // scale up the arena sizes exponentially + // scale up the arena sizes exponentially every 8 entries (128 entries get to 589TiB) + const size_t multiplier = (size_t)1 << _mi_clamp(arena_count/8, 0, 16 ); + size_t reserve = 0; + if (!mi_mul_overflow(multiplier, arena_reserve, &reserve)) { + arena_reserve = reserve; + } } if (arena_reserve < req_size) return false; // should be able to at least handle the current allocation size From aeee7907a0324f6d7ee8b01b55721c4efe2dec7e Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 1 Jun 2024 13:20:28 -0700 Subject: [PATCH 004/305] fix spelling --- src/arena.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/arena.c b/src/arena.c index 445cc309..83582bad 100644 --- a/src/arena.c +++ b/src/arena.c @@ -510,7 +510,7 @@ static bool mi_arena_purge_range(mi_arena_t* arena, size_t idx, size_t startidx, size_t bitidx = startidx; bool all_purged = false; while (bitidx < endidx) { - // count consequetive ones in the purge mask + // count consecutive ones in the purge mask size_t count = 0; while (bitidx + count < endidx && (purge & ((size_t)1 << (bitidx + count))) != 0) { count++; @@ -547,7 +547,7 @@ static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force, mi if (purge != 0) { size_t bitidx = 0; while (bitidx < MI_BITMAP_FIELD_BITS) { - // find consequetive range of ones in the purge mask + // find consecutive range of ones in the purge mask size_t bitlen = 0; while (bitidx + bitlen < MI_BITMAP_FIELD_BITS && (purge & ((size_t)1 << (bitidx + bitlen))) != 0) { bitlen++; @@ -927,7 +927,7 @@ static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int arena->is_large = is_large; arena->purge_expire = 0; arena->search_idx = 0; - // consequetive bitmaps + // consecutive bitmaps arena->blocks_dirty = &arena->blocks_inuse[fields]; // just after inuse bitmap arena->blocks_abandoned = &arena->blocks_inuse[2 * fields]; // just after dirty bitmap arena->blocks_committed = (arena->memid.is_pinned ? NULL : &arena->blocks_inuse[3*fields]); // just after abandoned bitmap From f87a4c15b285a6d4c04c8813db2a26ebba807a4d Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 1 Jun 2024 13:41:13 -0700 Subject: [PATCH 005/305] increase max arenas --- src/arena.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arena.c b/src/arena.c index 83582bad..d97bf628 100644 --- a/src/arena.c +++ b/src/arena.c @@ -36,7 +36,7 @@ The arena allocation needs to be thread safe and we use an atomic bitmap to allo typedef uintptr_t mi_block_info_t; #define MI_ARENA_BLOCK_SIZE (MI_SEGMENT_SIZE) // 64MiB (must be at least MI_SEGMENT_ALIGN) #define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_BLOCK_SIZE/2) // 32MiB -#define MI_MAX_ARENAS (112) // not more than 126 (since we use 7 bits in the memid and an arena index + 1) +#define MI_MAX_ARENAS (255) // Limited as the reservation exponentially increases (and takes up .bss) // A memory arena descriptor typedef struct mi_arena_s { @@ -552,6 +552,7 @@ static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force, mi while (bitidx + bitlen < MI_BITMAP_FIELD_BITS && (purge & ((size_t)1 << (bitidx + bitlen))) != 0) { bitlen++; } + // temporarily claim the purge range as "in-use" to be thread-safe with allocation // try to claim the longest range of corresponding in_use bits const mi_bitmap_index_t bitmap_index = mi_bitmap_index_create(i, bitidx); while( bitlen > 0 ) { From d9aa19a7636d457f0b7b50e599649b86e8ade666 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 1 Jun 2024 15:57:18 -0700 Subject: [PATCH 006/305] add support for sub-processes (to supportpython/cpython#113717) --- include/mimalloc.h | 10 ++++++- include/mimalloc/internal.h | 9 ++++--- include/mimalloc/types.h | 20 ++++++++++++-- src/arena.c | 54 ++++++++++++++++++++----------------- src/free.c | 3 ++- src/init.c | 43 ++++++++++++++++++++++++++--- src/segment.c | 24 ++++++++++------- 7 files changed, 119 insertions(+), 44 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 0173a323..26bb849d 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -288,8 +288,16 @@ mi_decl_export bool mi_manage_os_memory_ex(void* start, size_t size, bool is_co mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id); #endif + +// Experimental: allow sub-processes whose memory segments stay separated (and no reclamation between them) +// Used for example for separate interpreter's in one process. +typedef void* mi_subproc_id_t; +mi_decl_export mi_subproc_id_t mi_subproc_new(void); +mi_decl_export void mi_subproc_delete(mi_subproc_id_t subproc); +mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t subproc); // this should be called right after a thread is created (and no allocation has taken place yet) + // deprecated -mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; +mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; // ------------------------------------------------------ diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 2a21f34b..65cd3569 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -130,14 +130,17 @@ void _mi_arena_unsafe_destroy_all(mi_stats_t* stats); bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment); void _mi_arena_segment_mark_abandoned(mi_segment_t* segment); -size_t _mi_arena_segment_abandoned_count(void); -typedef struct mi_arena_field_cursor_s { // abstract +void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid); +void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size); + +typedef struct mi_arena_field_cursor_s { // abstract struct mi_arena_id_t start; int count; size_t bitmap_idx; + mi_subproc_t* subproc; } mi_arena_field_cursor_t; -void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_arena_field_cursor_t* current); +void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current); mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous); // "segment-map.c" diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index ed326c69..6b90bf5d 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -307,7 +307,7 @@ typedef struct mi_page_s { mi_block_t* local_free; // list of deferred free blocks by this thread (migrates to `free`) uint16_t used; // number of blocks in use (including blocks in `thread_free`) uint8_t block_size_shift; // if not zero, then `(1 << block_size_shift) == block_size` (only used for fast path in `free.c:_mi_page_ptr_unalign`) - uint8_t heap_tag; // tag of the owning heap, used for separated heaps by object type + uint8_t heap_tag; // tag of the owning heap, used to separate heaps by object type // padding size_t block_size; // size available in each block (always `>0`) uint8_t* page_start; // start of the page area containing the blocks @@ -387,6 +387,7 @@ typedef struct mi_memid_s { // --------------------------------------------------------------- // Segments contain mimalloc pages // --------------------------------------------------------------- +typedef struct mi_subproc_s mi_subproc_t; // Segments are large allocated memory blocks (2MiB on 64 bit) from the OS. // Inside segments we allocated fixed size _pages_ that contain blocks. @@ -409,6 +410,7 @@ typedef struct mi_segment_s { size_t capacity; // count of available pages (`#free + used`) size_t segment_info_size;// space we are using from the first page for segment meta-data and possible guard pages. uintptr_t cookie; // verify addresses in secure mode: `_mi_ptr_cookie(segment) == segment->cookie` + mi_subproc_t* subproc; // segment belongs to sub process // layout like this to optimize access in `mi_free` _Atomic(mi_threadid_t) thread_id; // unique id of the thread owning this segment @@ -600,10 +602,23 @@ void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); #define mi_heap_stat_decrease(heap,stat,amount) mi_stat_decrease( (heap)->tld->stats.stat, amount) +// ------------------------------------------------------ +// Sub processes do not reclaim or visit segments +// from other sub processes +// ------------------------------------------------------ + +struct mi_subproc_s { + _Atomic(size_t) abandoned_count; // count of abandoned segments for this sup-process + mi_memid_t memid; // provenance +}; + +mi_subproc_t* mi_subproc_from_id(mi_subproc_id_t subproc_id); + // ------------------------------------------------------ // Thread Local data // ------------------------------------------------------ +// Milliseconds as in `int64_t` to avoid overflows typedef int64_t mi_msecs_t; // Queue of segments @@ -628,8 +643,9 @@ typedef struct mi_segments_tld_s { size_t current_size; // current size of all segments size_t peak_size; // peak size of all segments size_t reclaim_count;// number of reclaimed (abandoned) segments + mi_subproc_t* subproc; // sub-process this thread belongs to. mi_stats_t* stats; // points to tld stats - mi_os_tld_t* os; // points to os stats + mi_os_tld_t* os; // points to os tld } mi_segments_tld_t; // Thread local data diff --git a/src/arena.c b/src/arena.c index d97bf628..aeadd604 100644 --- a/src/arena.c +++ b/src/arena.c @@ -172,7 +172,7 @@ static void* mi_arena_static_zalloc(size_t size, size_t alignment, mi_memid_t* m return p; } -static void* mi_arena_meta_zalloc(size_t size, mi_memid_t* memid, mi_stats_t* stats) { +void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid) { *memid = _mi_memid_none(); // try static @@ -180,7 +180,7 @@ static void* mi_arena_meta_zalloc(size_t size, mi_memid_t* memid, mi_stats_t* st if (p != NULL) return p; // or fall back to the OS - p = _mi_os_alloc(size, memid, stats); + p = _mi_os_alloc(size, memid, &_mi_stats_main); if (p == NULL) return NULL; // zero the OS memory if needed @@ -191,9 +191,9 @@ static void* mi_arena_meta_zalloc(size_t size, mi_memid_t* memid, mi_stats_t* st return p; } -static void mi_arena_meta_free(void* p, mi_memid_t memid, size_t size, mi_stats_t* stats) { +void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size) { if (mi_memkind_is_os(memid.memkind)) { - _mi_os_free(p, size, memid, stats); + _mi_os_free(p, size, memid, &_mi_stats_main); } else { mi_assert(memid.memkind == MI_MEM_STATIC); @@ -709,7 +709,7 @@ static void mi_arenas_unsafe_destroy(void) { else { new_max_arena = i; } - mi_arena_meta_free(arena, arena->meta_memid, arena->meta_size, &_mi_stats_main); + _mi_arena_meta_free(arena, arena->meta_memid, arena->meta_size); } } @@ -752,13 +752,6 @@ bool _mi_arena_contains(const void* p) { the arena bitmaps. ----------------------------------------------------------- */ -// Maintain a count of all abandoned segments -static mi_decl_cache_align _Atomic(size_t)abandoned_count; - -size_t _mi_arena_segment_abandoned_count(void) { - return mi_atomic_load_relaxed(&abandoned_count); -} - // reclaim a specific abandoned segment; `true` on success. // sets the thread_id. bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) @@ -768,7 +761,7 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) // but we need to still claim it atomically -- we use the thread_id for that. size_t expected = 0; if (mi_atomic_cas_strong_acq_rel(&segment->thread_id, &expected, _mi_thread_id())) { - mi_atomic_decrement_relaxed(&abandoned_count); + mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); return true; } else { @@ -785,7 +778,7 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) bool was_marked = _mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx); if (was_marked) { mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); - mi_atomic_decrement_relaxed(&abandoned_count); + mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); } // mi_assert_internal(was_marked); @@ -802,9 +795,10 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) mi_assert_internal(segment->used == segment->abandoned); if (segment->memid.memkind != MI_MEM_ARENA) { // not in an arena; count it as abandoned and return - mi_atomic_increment_relaxed(&abandoned_count); + mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); return; } + // segment is in an arena size_t arena_idx; size_t bitmap_idx; mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); @@ -812,17 +806,19 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); mi_assert_internal(arena != NULL); const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - if (was_unmarked) { mi_atomic_increment_relaxed(&abandoned_count); } + if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } mi_assert_internal(was_unmarked); mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); } // start a cursor at a randomized arena -void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_arena_field_cursor_t* current) { +void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current) { + mi_assert_internal(heap->tld->segments.subproc == subproc); const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); current->start = (max_arena == 0 ? 0 : (mi_arena_id_t)( _mi_heap_random_next(heap) % max_arena)); current->count = 0; current->bitmap_idx = 0; + current->subproc = subproc; } // reclaim abandoned segments @@ -830,7 +826,7 @@ void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_arena_field_cursor_t* curre mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous ) { const int max_arena = (int)mi_atomic_load_relaxed(&mi_arena_count); - if (max_arena <= 0 || mi_atomic_load_relaxed(&abandoned_count) == 0) return NULL; + if (max_arena <= 0 || mi_atomic_load_relaxed(&previous->subproc->abandoned_count) == 0) return NULL; int count = previous->count; size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); @@ -853,14 +849,24 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr mi_bitmap_index_t bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); // try to reclaim it atomically if (_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) { - mi_atomic_decrement_relaxed(&abandoned_count); - previous->bitmap_idx = bitmap_idx; - previous->count = count; mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); - //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); - return segment; + // check that belongs to our sub-process + if (segment->subproc != previous->subproc) { + // it is from another subprocess, re-mark it and continue searching + const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); + mi_assert_internal(was_zero); + } + else { + // success, we unabandoned a segment in our sub-process + mi_atomic_decrement_relaxed(&previous->subproc->abandoned_count); + previous->bitmap_idx = bitmap_idx; + previous->count = count; + + //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); + return segment; + } } } } @@ -911,7 +917,7 @@ static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int const size_t bitmaps = (memid.is_pinned ? 3 : 5); const size_t asize = sizeof(mi_arena_t) + (bitmaps*fields*sizeof(mi_bitmap_field_t)); mi_memid_t meta_memid; - mi_arena_t* arena = (mi_arena_t*)mi_arena_meta_zalloc(asize, &meta_memid, &_mi_stats_main); // TODO: can we avoid allocating from the OS? + mi_arena_t* arena = (mi_arena_t*)_mi_arena_meta_zalloc(asize, &meta_memid); if (arena == NULL) return false; // already zero'd due to zalloc diff --git a/src/free.c b/src/free.c index c065d2f3..191ec9bf 100644 --- a/src/free.c +++ b/src/free.c @@ -240,7 +240,8 @@ static void mi_decl_noinline mi_free_block_mt(mi_page_t* page, mi_segment_t* seg { // the segment is abandoned, try to reclaim it into our heap if (_mi_segment_attempt_reclaim(mi_heap_get_default(), segment)) { - mi_assert_internal(_mi_prim_thread_id() == mi_atomic_load_relaxed(&segment->thread_id)); + mi_assert_internal(_mi_thread_id() == mi_atomic_load_relaxed(&segment->thread_id)); + mi_assert_internal(mi_heap_get_default()->tld->segments.subproc == segment->subproc); mi_free(block); // recursively free as now it will be a local free in our heap return; } diff --git a/src/init.c b/src/init.c index 62bb69dd..1922907b 100644 --- a/src/init.c +++ b/src/init.c @@ -125,18 +125,20 @@ mi_decl_thread mi_heap_t* _mi_heap_default = (mi_heap_t*)&_mi_heap_empty; extern mi_heap_t _mi_heap_main; -static mi_tld_t tld_main = { +static mi_decl_cache_align mi_subproc_t mi_subproc_default; + +static mi_decl_cache_align mi_tld_t tld_main = { 0, false, - &_mi_heap_main, &_mi_heap_main, + &_mi_heap_main, &_mi_heap_main, { { NULL, NULL }, {NULL ,NULL}, {NULL ,NULL, 0}, - 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, &mi_subproc_default, &tld_main.stats, &tld_main.os }, // segments { 0, &tld_main.stats }, // os { MI_STATS_NULL } // stats }; -mi_heap_t _mi_heap_main = { +mi_decl_cache_align mi_heap_t _mi_heap_main = { &tld_main, MI_ATOMIC_VAR_INIT(NULL), 0, // thread id @@ -179,6 +181,38 @@ mi_heap_t* _mi_heap_main_get(void) { } +/* ----------------------------------------------------------- + Sub process +----------------------------------------------------------- */ + +mi_subproc_id_t mi_subproc_new(void) { + mi_memid_t memid = _mi_memid_none(); + mi_subproc_t* subproc = (mi_subproc_t*)_mi_arena_meta_zalloc(sizeof(mi_subproc_t), &memid); + if (subproc == NULL) return NULL; + subproc->memid = memid; + return subproc; +} + +mi_subproc_t* mi_subproc_from_id(mi_subproc_id_t subproc_id) { + return (subproc_id == NULL ? &mi_subproc_default : (mi_subproc_t*)subproc_id); +} + +void mi_subproc_delete(mi_subproc_id_t subproc_id) { + if (subproc_id == NULL) return; + mi_subproc_t* subproc = mi_subproc_from_id(subproc_id); + _mi_arena_meta_free(subproc, subproc->memid, sizeof(mi_subproc_t)); +} + +void mi_subproc_add_current_thread(mi_subproc_id_t subproc_id) { + mi_heap_t* heap = mi_heap_get_default(); + if (heap == NULL) return; + mi_assert(heap->tld->segments.subproc == &mi_subproc_default); + if (heap->tld->segments.subproc != &mi_subproc_default) return; + heap->tld->segments.subproc = mi_subproc_from_id(subproc_id); +} + + + /* ----------------------------------------------------------- Initialization and freeing of the thread local heaps ----------------------------------------------------------- */ @@ -295,6 +329,7 @@ void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap) { _mi_memzero_aligned(tld,sizeof(mi_tld_t)); tld->heap_backing = bheap; tld->heaps = NULL; + tld->segments.subproc = &mi_subproc_default; tld->segments.stats = &tld->stats; tld->segments.os = &tld->os; tld->os.stats = &tld->stats; diff --git a/src/segment.c b/src/segment.c index fc13d2e7..205d8753 100644 --- a/src/segment.c +++ b/src/segment.c @@ -628,7 +628,8 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, segment->page_shift = page_shift; segment->segment_info_size = pre_size; segment->thread_id = _mi_thread_id(); - segment->cookie = _mi_ptr_cookie(segment); + segment->cookie = _mi_ptr_cookie(segment); + segment->subproc = tld->subproc; // set protection mi_segment_protect(segment, true, tld->os); @@ -880,6 +881,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, if (right_page_reclaimed != NULL) { *right_page_reclaimed = false; } // can be 0 still with abandoned_next, or already a thread id for segments outside an arena that are reclaimed on a free. mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0 || mi_atomic_load_relaxed(&segment->thread_id) == _mi_thread_id()); + mi_assert_internal(segment->subproc == heap->tld->segments.subproc); // only reclaim within the same subprocess mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); segment->abandoned_visits = 0; segment->was_reclaimed = true; @@ -899,12 +901,13 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, segment->abandoned--; mi_assert(page->next == NULL); _mi_stat_decrease(&tld->stats->pages_abandoned, 1); - // set the heap again and allow heap thread delayed free again. + // get the target heap for this thread which has a matching heap tag (so we reclaim into a matching heap) mi_heap_t* target_heap = _mi_heap_by_tag(heap, page->heap_tag); // allow custom heaps to separate objects if (target_heap == NULL) { target_heap = heap; - _mi_error_message(EINVAL, "page with tag %u cannot be reclaimed by a heap with the same tag (using %u instead)\n", page->heap_tag, heap->tag ); + _mi_error_message(EINVAL, "page with tag %u cannot be reclaimed by a heap with the same tag (using tag %u instead)\n", page->heap_tag, heap->tag ); } + // associate the heap with this page, and allow heap thread delayed free again. mi_page_set_heap(page, target_heap); _mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE, true); // override never (after heap is set) _mi_page_free_collect(page, false); // ensure used count is up to date @@ -944,7 +947,8 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, // attempt to reclaim a particular segment (called from multi threaded free `alloc.c:mi_free_block_mt`) bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { if (mi_atomic_load_relaxed(&segment->thread_id) != 0) return false; // it is not abandoned - // don't reclaim more from a free than half the current segments + if (segment->subproc != heap->tld->segments.subproc) return false; // only reclaim within the same subprocess + // don't reclaim more from a `free` call than half the current segments // this is to prevent a pure free-ing thread to start owning too many segments if (heap->tld->segments.reclaim_count * 2 > heap->tld->segments.count) return false; if (_mi_arena_segment_clear_abandoned(segment)) { // atomically unabandon @@ -957,17 +961,17 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) { mi_segment_t* segment; - mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, ¤t); + mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, ¤t); while ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL) { mi_segment_reclaim(segment, heap, 0, NULL, tld); } } -static long mi_segment_get_reclaim_tries(void) { +static long mi_segment_get_reclaim_tries(mi_segments_tld_t* tld) { // limit the tries to 10% (default) of the abandoned segments with at least 8 and at most 1024 tries. const size_t perc = (size_t)mi_option_get_clamp(mi_option_max_segment_reclaim, 0, 100); if (perc <= 0) return 0; - const size_t total_count = _mi_arena_segment_abandoned_count(); + const size_t total_count = mi_atomic_load_relaxed(&tld->subproc->abandoned_count); if (total_count == 0) return 0; const size_t relative_count = (total_count > 10000 ? (total_count / 100) * perc : (total_count * perc) / 100); // avoid overflow long max_tries = (long)(relative_count <= 1 ? 1 : (relative_count > 1024 ? 1024 : relative_count)); @@ -978,13 +982,14 @@ static long mi_segment_get_reclaim_tries(void) { static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, mi_page_kind_t page_kind, bool* reclaimed, mi_segments_tld_t* tld) { *reclaimed = false; - long max_tries = mi_segment_get_reclaim_tries(); + long max_tries = mi_segment_get_reclaim_tries(tld); if (max_tries <= 0) return NULL; mi_segment_t* segment; - mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, ¤t); + mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, ¤t); while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL)) { + mi_assert(segment->subproc == heap->tld->segments.subproc); // cursor only visits segments in our sub-process segment->abandoned_visits++; // todo: should we respect numa affinity for abondoned reclaim? perhaps only for the first visit? // todo: an arena exclusive heap will potentially visit many abandoned unsuitable segments and use many tries @@ -1232,5 +1237,6 @@ mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t pag mi_assert_internal(page == NULL || (mi_segment_page_size(_mi_page_segment(page)) - (MI_SECURE == 0 ? 0 : _mi_os_page_size())) >= block_size); // mi_segment_try_purge(tld); mi_assert_internal(page == NULL || mi_page_not_in_queue(page, tld)); + mi_assert_internal(page == NULL || _mi_page_segment(page)->subproc == tld->subproc); return page; } From 0b3cd5124999efc673afb26bab3f5a1c8eff4c22 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Sat, 1 Jun 2024 16:45:20 -0700 Subject: [PATCH 007/305] add initial primitive api for locks --- include/mimalloc/atomic.h | 21 +++++++++------- include/mimalloc/internal.h | 5 ---- include/mimalloc/prim.h | 24 +++++++++++++++--- include/mimalloc/track.h | 8 ++---- src/alloc.c | 10 ++++---- src/prim/emscripten/prim.c | 49 ++++++++++++++++++++++++++++++++++++- src/prim/unix/prim.c | 46 ++++++++++++++++++++++++++++++++++ src/prim/wasi/prim.c | 48 +++++++++++++++++++++++++++++++++--- src/prim/windows/prim.c | 35 +++++++++++++++++++------- test/main-override.cpp | 4 +-- test/test-stress.c | 6 ++--- 11 files changed, 208 insertions(+), 48 deletions(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index d5333dd9..2c313fdb 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -8,6 +8,17 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MIMALLOC_ATOMIC_H #define MIMALLOC_ATOMIC_H +// include windows.h or pthreads.h +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#elif !defined(_WIN32) && (defined(__EMSCRIPTEN_SHARED_MEMORY__) || !defined(__wasi__)) +#define MI_USE_PTHREADS +#include +#endif + // -------------------------------------------------------------------------------------------- // Atomics // We need to be portable between C, C++, and MSVC. @@ -133,10 +144,6 @@ static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { #elif defined(_MSC_VER) // Legacy MSVC plain C compilation wrapper that uses Interlocked operations to model C11 atomics. -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include #include #ifdef _WIN64 typedef LONG64 msc_intptr_t; @@ -306,7 +313,7 @@ typedef _Atomic(uintptr_t) mi_atomic_once_t; // Returns true only on the first invocation static inline bool mi_atomic_once( mi_atomic_once_t* once ) { - if (mi_atomic_load_relaxed(once) != 0) return false; // quick test + if (mi_atomic_load_relaxed(once) != 0) return false; // quick test uintptr_t expected = 0; return mi_atomic_cas_strong_acq_rel(once, &expected, (uintptr_t)1); // try to set to 1 } @@ -329,10 +336,6 @@ static inline void mi_atomic_yield(void) { std::this_thread::yield(); } #elif defined(_WIN32) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include static inline void mi_atomic_yield(void) { YieldProcessor(); } diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 65cd3569..9046e3ad 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -53,11 +53,6 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_decl_externc #endif -// pthreads -#if !defined(_WIN32) && !defined(__wasi__) -#define MI_USE_PTHREADS -#include -#endif // "options.c" void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message); diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index 3f4574dd..ba305dc1 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -114,6 +114,24 @@ void _mi_prim_thread_done_auto_done(void); // Called when the default heap for a thread changes void _mi_prim_thread_associate_default_heap(mi_heap_t* heap); +// Locks are only used if abandoned segment visiting is permitted +#if defined(_WIN32) +#define mi_lock_t CRITICAL_SECTION +#elif defined(MI_USE_PTHREADS) +#define mi_lock_t pthread_mutex_t +#else +#define mi_lock_t _Atomic(uintptr_t) +#endif + +// Take a lock (blocking). Return `true` on success. +bool _mi_prim_lock(mi_lock_t* lock); + +// Try to take lock and return `true` if successful. +bool _mi_prim_try_lock(mi_lock_t* lock); + +// Release a lock. +void _mi_prim_unlock(mi_lock_t* lock); + //------------------------------------------------------------------- // Thread id: `_mi_prim_thread_id()` @@ -235,10 +253,6 @@ static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept { #elif defined(_WIN32) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept { // Windows: works on Intel and ARM in both 32- and 64-bit return (uintptr_t)NtCurrentTeb(); @@ -370,4 +384,6 @@ static inline mi_heap_t* mi_prim_get_default_heap(void) { + + #endif // MIMALLOC_PRIM_H diff --git a/include/mimalloc/track.h b/include/mimalloc/track.h index a659d940..4b5709e2 100644 --- a/include/mimalloc/track.h +++ b/include/mimalloc/track.h @@ -34,7 +34,7 @@ The corresponding `mi_track_free` still uses the block start pointer and origina The `mi_track_resize` is currently unused but could be called on reallocations within a block. `mi_track_init` is called at program start. -The following macros are for tools like asan and valgrind to track whether memory is +The following macros are for tools like asan and valgrind to track whether memory is defined, undefined, or not accessible at all: #define mi_track_mem_defined(p,size) @@ -82,10 +82,6 @@ defined, undefined, or not accessible at all: #define MI_TRACK_HEAP_DESTROY 1 #define MI_TRACK_TOOL "ETW" -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include #include "../src/prim/windows/etw.h" #define mi_track_init() EventRegistermicrosoft_windows_mimalloc(); @@ -96,7 +92,7 @@ defined, undefined, or not accessible at all: // no tracking #define MI_TRACK_ENABLED 0 -#define MI_TRACK_HEAP_DESTROY 0 +#define MI_TRACK_HEAP_DESTROY 0 #define MI_TRACK_TOOL "none" #define mi_track_malloc_size(p,reqsize,size,zero) diff --git a/src/alloc.c b/src/alloc.c index 6c9c5baf..5ba8bb33 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -28,7 +28,7 @@ terms of the MIT license. A copy of the license can be found in the file // Fast allocation in a page: just pop from the free list. // Fall back to generic allocation only if the list is empty. // Note: in release mode the (inlined) routine is about 7 instructions with a single test. -extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept +extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept { mi_assert_internal(page->block_size == 0 /* empty heap */ || mi_page_block_size(page) >= size); mi_block_t* const block = page->free; @@ -61,7 +61,7 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_ } else { _mi_memzero_aligned(block, page->block_size - MI_PADDING_SIZE); - } + } } #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN @@ -123,9 +123,9 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, #if (MI_PADDING) if (size == 0) { size = sizeof(void*); } #endif - + mi_page_t* page = _mi_heap_get_free_small_page(heap, size + MI_PADDING_SIZE); - void* const p = _mi_page_malloc_zero(heap, page, size + MI_PADDING_SIZE, zero); + void* const p = _mi_page_malloc_zero(heap, page, size + MI_PADDING_SIZE, zero); mi_track_malloc(p,size,zero); #if MI_STAT>1 @@ -362,7 +362,7 @@ mi_decl_nodiscard mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_ #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif -#include + mi_decl_nodiscard mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept { // todo: use GetFullPathNameW to allow longer file names char buf[PATH_MAX]; diff --git a/src/prim/emscripten/prim.c b/src/prim/emscripten/prim.c index f3797c9e..6b5aa452 100644 --- a/src/prim/emscripten/prim.c +++ b/src/prim/emscripten/prim.c @@ -200,7 +200,7 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) { // Thread init/done //---------------------------------------------------------------- -#ifdef __EMSCRIPTEN_SHARED_MEMORY__ +#if defined(MI_USE_PTHREADS) // use pthread local storage keys to detect thread ending // (and used with MI_TLS_PTHREADS for the default heap) @@ -242,3 +242,50 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { } #endif + +//---------------------------------------------------------------- +// Locks +//---------------------------------------------------------------- + +#if defined(MI_USE_PTHREADS) + +bool _mi_prim_lock(mi_lock_t* lock) { + return (pthread_mutex_lock(lock) == 0); +} + +bool _mi_prim_try_lock(mi_lock_t* lock) { + return (pthread_mutex_trylock(lock) == 0); +} + +void _mi_prim_unlock(mi_lock_t* lock) { + pthread_mutex_unlock(lock); +} + +#else + +#include + +// fall back to poor man's locks. +bool _mi_prim_lock(mi_lock_t* lock) { + for(int i = 0; i < 1000; i++) { // for at most 1 second? + if (_mi_prim_try_lock(lock)) return true; + if (i < 25) { + mi_atomic_yield(); // first yield a bit + } + else { + emscripten_sleep(1); // then sleep for 1ms intervals + } + } + return true; +} + +bool _mi_prim_try_lock(mi_lock_t* lock) { + uintptr_t expected = 0; + return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1); +} + +void _mi_prim_unlock(mi_lock_t* lock) { + mi_atomic_store_release(lock,(uintptr_t)0); +} + +#endif \ No newline at end of file diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 99325d03..7935c1c6 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -880,3 +880,49 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { } #endif + + +//---------------------------------------------------------------- +// Locks +//---------------------------------------------------------------- + +#if defined(MI_USE_PTHREADS) + +bool _mi_prim_lock(mi_lock_t* lock) { + return (pthread_mutex_lock(lock) == 0); +} + +bool _mi_prim_try_lock(mi_lock_t* lock) { + return (pthread_mutex_trylock(lock) == 0); +} + +void _mi_prim_unlock(mi_lock_t* lock) { + pthread_mutex_unlock(lock); +} + +#else + +// fall back to poor man's locks. +bool _mi_prim_lock(mi_lock_t* lock) { + for(int i = 0; i < 1000; i++) { // for at most 1 second? + if (_mi_prim_try_lock(lock)) return true; + if (i < 25) { + mi_atomic_yield(); // first yield a bit + } + else { + usleep(1000); // then sleep for 1ms intervals + } + } + return true; +} + +bool _mi_prim_try_lock(mi_lock_t* lock) { + uintptr_t expected = 0; + return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1); +} + +void _mi_prim_unlock(mi_lock_t* lock) { + mi_atomic_store_release(lock,(uintptr_t)0); +} + +#endif diff --git a/src/prim/wasi/prim.c b/src/prim/wasi/prim.c index e95f67f5..3f3a2ea1 100644 --- a/src/prim/wasi/prim.c +++ b/src/prim/wasi/prim.c @@ -22,7 +22,7 @@ terms of the MIT license. A copy of the license can be found in the file void _mi_prim_mem_init( mi_os_mem_config_t* config ) { config->page_size = 64*MI_KiB; // WebAssembly has a fixed page size: 64KiB config->alloc_granularity = 16; - config->has_overcommit = false; + config->has_overcommit = false; config->has_partial_free = false; config->has_virtual_reserve = false; } @@ -134,7 +134,7 @@ int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_la //--------------------------------------------- int _mi_prim_commit(void* addr, size_t size, bool* is_zero) { - MI_UNUSED(addr); MI_UNUSED(size); + MI_UNUSED(addr); MI_UNUSED(size); *is_zero = false; return 0; } @@ -199,9 +199,9 @@ mi_msecs_t _mi_prim_clock_now(void) { // low resolution timer mi_msecs_t _mi_prim_clock_now(void) { #if !defined(CLOCKS_PER_SEC) || (CLOCKS_PER_SEC == 1000) || (CLOCKS_PER_SEC == 0) - return (mi_msecs_t)clock(); + return (mi_msecs_t)clock(); #elif (CLOCKS_PER_SEC < 1000) - return (mi_msecs_t)clock() * (1000 / (mi_msecs_t)CLOCKS_PER_SEC); + return (mi_msecs_t)clock() * (1000 / (mi_msecs_t)CLOCKS_PER_SEC); #else return (mi_msecs_t)clock() / ((mi_msecs_t)CLOCKS_PER_SEC / 1000); #endif @@ -278,3 +278,43 @@ void _mi_prim_thread_done_auto_done(void) { void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { MI_UNUSED(heap); } + +//---------------------------------------------------------------- +// Locks +//---------------------------------------------------------------- + +#if defined(MI_USE_PTHREADS) + +bool _mi_prim_lock(mi_lock_t* lock) { + return (pthread_mutex_lock(lock) == 0); +} + +bool _mi_prim_try_lock(mi_lock_t* lock) { + return (pthread_mutex_trylock(lock) == 0); +} + +void _mi_prim_unlock(mi_lock_t* lock) { + pthread_mutex_unlock(lock); +} + +#else + +// fall back to poor man's locks. +bool _mi_prim_lock(mi_lock_t* lock) { + for(int i = 0; i < 1000; i++) { // for at most 1 second? + if (_mi_prim_try_lock(lock)) return true; + mi_atomic_yield(); // this should never happen as wasi is single threaded? + } + return true; +} + +bool _mi_prim_try_lock(mi_lock_t* lock) { + uintptr_t expected = 0; + return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1); +} + +void _mi_prim_unlock(mi_lock_t* lock) { + mi_atomic_store_release(lock,(uintptr_t)0); +} + +#endif \ No newline at end of file diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 5074ad4c..760debb3 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -231,7 +231,7 @@ static void* win_virtual_alloc_prim(void* addr, size_t size, size_t try_alignmen else if (max_retry_msecs > 0 && (try_alignment <= 2*MI_SEGMENT_ALIGN) && (flags&MEM_COMMIT) != 0 && (flags&MEM_LARGE_PAGES) == 0 && win_is_out_of_memory_error(GetLastError())) { - // if committing regular memory and being out-of-memory, + // if committing regular memory and being out-of-memory, // keep trying for a bit in case memory frees up after all. See issue #894 _mi_warning_message("out-of-memory on OS allocation, try again... (attempt %lu, 0x%zx bytes, error code: 0x%x, address: %p, alignment: 0x%zx, flags: 0x%x)\n", tries, size, GetLastError(), addr, try_alignment, flags); long sleep_msecs = tries*40; // increasing waits @@ -316,7 +316,7 @@ int _mi_prim_commit(void* addr, size_t size, bool* is_zero) { return 0; } -int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit) { +int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit) { BOOL ok = VirtualFree(addr, size, MEM_DECOMMIT); *needs_recommit = true; // for safety, assume always decommitted even in the case of an error. return (ok ? 0 : (int)GetLastError()); @@ -468,7 +468,6 @@ mi_msecs_t _mi_prim_clock_now(void) { // Process Info //---------------------------------------------------------------- -#include #include static mi_msecs_t filetime_msecs(const FILETIME* ftime) { @@ -491,7 +490,7 @@ void _mi_prim_process_info(mi_process_info_t* pinfo) GetProcessTimes(GetCurrentProcess(), &ct, &et, &st, &ut); pinfo->utime = filetime_msecs(&ut); pinfo->stime = filetime_msecs(&st); - + // load psapi on demand if (pGetProcessMemoryInfo == NULL) { HINSTANCE hDll = LoadLibrary(TEXT("psapi.dll")); @@ -505,7 +504,7 @@ void _mi_prim_process_info(mi_process_info_t* pinfo) memset(&info, 0, sizeof(info)); if (pGetProcessMemoryInfo != NULL) { pGetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); - } + } pinfo->current_rss = (size_t)info.WorkingSetSize; pinfo->peak_rss = (size_t)info.PeakWorkingSetSize; pinfo->current_commit = (size_t)info.PagefileUsage; @@ -517,7 +516,7 @@ void _mi_prim_process_info(mi_process_info_t* pinfo) // Output //---------------------------------------------------------------- -void _mi_prim_out_stderr( const char* msg ) +void _mi_prim_out_stderr( const char* msg ) { // on windows with redirection, the C runtime cannot handle locale dependent output // after the main thread closes so we use direct console output. @@ -564,6 +563,23 @@ bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { } +//---------------------------------------------------------------- +// Locks +//---------------------------------------------------------------- + +bool _mi_prim_lock(mi_lock_t* lock) { + EnterCriticalSection(lock); + return true; +} + +bool _mi_prim_try_lock(mi_lock_t* lock) { + return TryEnterCriticalSection(lock); +} + +void _mi_prim_unlock(mi_lock_t* lock) { + LeaveCriticalSection(lock); +} + //---------------------------------------------------------------- // Random @@ -600,7 +616,7 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) { } if (pBCryptGenRandom == NULL) return false; } - return (pBCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); + return (pBCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); } #endif // MI_USE_RTLGENRANDOM @@ -636,9 +652,9 @@ void _mi_prim_thread_init_auto_done(void) { } void _mi_prim_thread_done_auto_done(void) { - // call thread-done on all threads (except the main thread) to prevent + // call thread-done on all threads (except the main thread) to prevent // dangling callback pointer if statically linked with a DLL; Issue #208 - FlsFree(mi_fls_key); + FlsFree(mi_fls_key); } void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { @@ -661,3 +677,4 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { } #endif + diff --git a/test/main-override.cpp b/test/main-override.cpp index 64ea178b..fc7f70f0 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -19,7 +19,7 @@ #endif #ifdef _WIN32 -#include +#include static void msleep(unsigned long msecs) { Sleep(msecs); } #else #include @@ -43,7 +43,7 @@ static void test_stl_allocators(); int main() { // mi_stats_reset(); // ignore earlier allocations - + test_std_string(); // heap_thread_free_huge(); /* diff --git a/test/test-stress.c b/test/test-stress.c index 14b3c3ae..0368007a 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -200,7 +200,7 @@ static void test_stress(void) { #ifndef NDEBUG //mi_collect(false); //mi_debug_show_arenas(); - #endif + #endif #if !defined(NDEBUG) || defined(MI_TSAN) if ((n + 1) % 10 == 0) { printf("- iterations left: %3d\n", ITER - (n + 1)); } #endif @@ -232,7 +232,7 @@ static void test_leak(void) { int main(int argc, char** argv) { #ifndef USE_STD_MALLOC mi_stats_reset(); - #endif + #endif // > mimalloc-test-stress [THREADS] [SCALE] [ITER] if (argc >= 2) { @@ -285,7 +285,7 @@ static void (*thread_entry_fun)(intptr_t) = &stress; #ifdef _WIN32 -#include +#include static DWORD WINAPI thread_entry(LPVOID param) { thread_entry_fun((intptr_t)param); From f93fb900b7495d320b2cfae4e69f1091917d278d Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Sat, 1 Jun 2024 17:25:45 -0700 Subject: [PATCH 008/305] move lock code to atomic.h --- include/mimalloc/atomic.h | 91 ++++++++++++++++++++++++++++++++++++++ include/mimalloc/prim.h | 17 ------- include/mimalloc/types.h | 2 - src/init.c | 2 +- src/prim/emscripten/prim.c | 47 -------------------- src/prim/unix/prim.c | 47 -------------------- src/prim/wasi/prim.c | 41 ----------------- src/prim/windows/prim.c | 19 -------- 8 files changed, 92 insertions(+), 174 deletions(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index 2c313fdb..4e3250f9 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -309,6 +309,11 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub) { return (intptr_t)mi_atomic_addi(p, -sub); } + +// ---------------------------------------------------------------------- +// Once and Guard +// ---------------------------------------------------------------------- + typedef _Atomic(uintptr_t) mi_atomic_once_t; // Returns true only on the first invocation @@ -329,7 +334,9 @@ typedef _Atomic(uintptr_t) mi_atomic_guard_t; +// ---------------------------------------------------------------------- // Yield +// ---------------------------------------------------------------------- #if defined(__cplusplus) #include static inline void mi_atomic_yield(void) { @@ -393,4 +400,88 @@ static inline void mi_atomic_yield(void) { #endif +// ---------------------------------------------------------------------- +// Locks are only used for abandoned segment visiting +// ---------------------------------------------------------------------- +#if defined(_WIN32) + +#define mi_lock_t CRITICAL_SECTION + +static inline bool _mi_prim_lock(mi_lock_t* lock) { + EnterCriticalSection(lock); + return true; +} + +static inline bool _mi_prim_try_lock(mi_lock_t* lock) { + return TryEnterCriticalSection(lock); +} + +static inline void _mi_prim_unlock(mi_lock_t* lock) { + LeaveCriticalSection(lock); +} + + +#elif defined(MI_USE_PTHREADS) + +#define mi_lock_t pthread_mutex_t + +static inline bool _mi_prim_lock(mi_lock_t* lock) { + return (pthread_mutex_lock(lock) == 0); +} + +static inline bool _mi_prim_try_lock(mi_lock_t* lock) { + return (pthread_mutex_trylock(lock) == 0); +} + +static inline void _mi_prim_unlock(mi_lock_t* lock) { + pthread_mutex_unlock(lock); +} + +#elif defined(__cplusplus) + +#include +#define mi_lock_t std::mutex + +static inline bool _mi_prim_lock(mi_lock_t* lock) { + lock->lock(); + return true; +} + +static inline bool _mi_prim_try_lock(mi_lock_t* lock) { + return (lock->try_lock(); +} + +static inline void _mi_prim_unlock(mi_lock_t* lock) { + lock->unlock(); +} + +#else + +// fall back to poor man's locks. +// this should only be the case in a single-threaded environment (like __wasi__) + +#define mi_lock_t _Atomic(uintptr_t) + +static inline bool _mi_prim_try_lock(mi_lock_t* lock) { + uintptr_t expected = 0; + return mi_atomic_cas_strong_acq_rel(lock, &expected, (uintptr_t)1); +} + +static inline bool _mi_prim_lock(mi_lock_t* lock) { + for (int i = 0; i < 1000; i++) { // for at most 1000 tries? + if (_mi_prim_try_lock(lock)) return true; + mi_atomic_yield(); + } + return true; +} + +static inline void _mi_prim_unlock(mi_lock_t* lock) { + mi_atomic_store_release(lock, (uintptr_t)0); +} + +#endif + + + + #endif // __MIMALLOC_ATOMIC_H diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index ba305dc1..640c966f 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -114,23 +114,6 @@ void _mi_prim_thread_done_auto_done(void); // Called when the default heap for a thread changes void _mi_prim_thread_associate_default_heap(mi_heap_t* heap); -// Locks are only used if abandoned segment visiting is permitted -#if defined(_WIN32) -#define mi_lock_t CRITICAL_SECTION -#elif defined(MI_USE_PTHREADS) -#define mi_lock_t pthread_mutex_t -#else -#define mi_lock_t _Atomic(uintptr_t) -#endif - -// Take a lock (blocking). Return `true` on success. -bool _mi_prim_lock(mi_lock_t* lock); - -// Try to take lock and return `true` if successful. -bool _mi_prim_try_lock(mi_lock_t* lock); - -// Release a lock. -void _mi_prim_unlock(mi_lock_t* lock); //------------------------------------------------------------------- diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 6b90bf5d..f4ba6739 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -612,8 +612,6 @@ struct mi_subproc_s { mi_memid_t memid; // provenance }; -mi_subproc_t* mi_subproc_from_id(mi_subproc_id_t subproc_id); - // ------------------------------------------------------ // Thread Local data // ------------------------------------------------------ diff --git a/src/init.c b/src/init.c index 1922907b..01625891 100644 --- a/src/init.c +++ b/src/init.c @@ -193,7 +193,7 @@ mi_subproc_id_t mi_subproc_new(void) { return subproc; } -mi_subproc_t* mi_subproc_from_id(mi_subproc_id_t subproc_id) { +static mi_subproc_t* mi_subproc_from_id(mi_subproc_id_t subproc_id) { return (subproc_id == NULL ? &mi_subproc_default : (mi_subproc_t*)subproc_id); } diff --git a/src/prim/emscripten/prim.c b/src/prim/emscripten/prim.c index 6b5aa452..944c0cb4 100644 --- a/src/prim/emscripten/prim.c +++ b/src/prim/emscripten/prim.c @@ -242,50 +242,3 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { } #endif - -//---------------------------------------------------------------- -// Locks -//---------------------------------------------------------------- - -#if defined(MI_USE_PTHREADS) - -bool _mi_prim_lock(mi_lock_t* lock) { - return (pthread_mutex_lock(lock) == 0); -} - -bool _mi_prim_try_lock(mi_lock_t* lock) { - return (pthread_mutex_trylock(lock) == 0); -} - -void _mi_prim_unlock(mi_lock_t* lock) { - pthread_mutex_unlock(lock); -} - -#else - -#include - -// fall back to poor man's locks. -bool _mi_prim_lock(mi_lock_t* lock) { - for(int i = 0; i < 1000; i++) { // for at most 1 second? - if (_mi_prim_try_lock(lock)) return true; - if (i < 25) { - mi_atomic_yield(); // first yield a bit - } - else { - emscripten_sleep(1); // then sleep for 1ms intervals - } - } - return true; -} - -bool _mi_prim_try_lock(mi_lock_t* lock) { - uintptr_t expected = 0; - return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1); -} - -void _mi_prim_unlock(mi_lock_t* lock) { - mi_atomic_store_release(lock,(uintptr_t)0); -} - -#endif \ No newline at end of file diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 7935c1c6..93785b22 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -22,7 +22,6 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc.h" #include "mimalloc/internal.h" -#include "mimalloc/atomic.h" #include "mimalloc/prim.h" #include // mmap @@ -880,49 +879,3 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { } #endif - - -//---------------------------------------------------------------- -// Locks -//---------------------------------------------------------------- - -#if defined(MI_USE_PTHREADS) - -bool _mi_prim_lock(mi_lock_t* lock) { - return (pthread_mutex_lock(lock) == 0); -} - -bool _mi_prim_try_lock(mi_lock_t* lock) { - return (pthread_mutex_trylock(lock) == 0); -} - -void _mi_prim_unlock(mi_lock_t* lock) { - pthread_mutex_unlock(lock); -} - -#else - -// fall back to poor man's locks. -bool _mi_prim_lock(mi_lock_t* lock) { - for(int i = 0; i < 1000; i++) { // for at most 1 second? - if (_mi_prim_try_lock(lock)) return true; - if (i < 25) { - mi_atomic_yield(); // first yield a bit - } - else { - usleep(1000); // then sleep for 1ms intervals - } - } - return true; -} - -bool _mi_prim_try_lock(mi_lock_t* lock) { - uintptr_t expected = 0; - return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1); -} - -void _mi_prim_unlock(mi_lock_t* lock) { - mi_atomic_store_release(lock,(uintptr_t)0); -} - -#endif diff --git a/src/prim/wasi/prim.c b/src/prim/wasi/prim.c index 3f3a2ea1..5d7a8132 100644 --- a/src/prim/wasi/prim.c +++ b/src/prim/wasi/prim.c @@ -9,7 +9,6 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc.h" #include "mimalloc/internal.h" -#include "mimalloc/atomic.h" #include "mimalloc/prim.h" #include // fputs @@ -278,43 +277,3 @@ void _mi_prim_thread_done_auto_done(void) { void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { MI_UNUSED(heap); } - -//---------------------------------------------------------------- -// Locks -//---------------------------------------------------------------- - -#if defined(MI_USE_PTHREADS) - -bool _mi_prim_lock(mi_lock_t* lock) { - return (pthread_mutex_lock(lock) == 0); -} - -bool _mi_prim_try_lock(mi_lock_t* lock) { - return (pthread_mutex_trylock(lock) == 0); -} - -void _mi_prim_unlock(mi_lock_t* lock) { - pthread_mutex_unlock(lock); -} - -#else - -// fall back to poor man's locks. -bool _mi_prim_lock(mi_lock_t* lock) { - for(int i = 0; i < 1000; i++) { // for at most 1 second? - if (_mi_prim_try_lock(lock)) return true; - mi_atomic_yield(); // this should never happen as wasi is single threaded? - } - return true; -} - -bool _mi_prim_try_lock(mi_lock_t* lock) { - uintptr_t expected = 0; - return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1); -} - -void _mi_prim_unlock(mi_lock_t* lock) { - mi_atomic_store_release(lock,(uintptr_t)0); -} - -#endif \ No newline at end of file diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 760debb3..bd874f9b 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -9,7 +9,6 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc.h" #include "mimalloc/internal.h" -#include "mimalloc/atomic.h" #include "mimalloc/prim.h" #include // fputs, stderr @@ -563,24 +562,6 @@ bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { } -//---------------------------------------------------------------- -// Locks -//---------------------------------------------------------------- - -bool _mi_prim_lock(mi_lock_t* lock) { - EnterCriticalSection(lock); - return true; -} - -bool _mi_prim_try_lock(mi_lock_t* lock) { - return TryEnterCriticalSection(lock); -} - -void _mi_prim_unlock(mi_lock_t* lock) { - LeaveCriticalSection(lock); -} - - //---------------------------------------------------------------- // Random //---------------------------------------------------------------- From 8f874555d5d42c4e1006bfc78f6cadfb167b1e30 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 07:47:08 -0700 Subject: [PATCH 009/305] add initial support for visiting abandoned segments per subprocess, upstream for python/cpython#114133 --- include/mimalloc.h | 11 +++-- include/mimalloc/atomic.h | 83 ++++++++++++++++++++------------- include/mimalloc/internal.h | 10 ++-- src/arena.c | 93 +++++++++++++++++++++++++++---------- src/heap.c | 45 ++++++++++-------- src/init.c | 14 ++++-- src/options.c | 5 ++ src/segment.c | 33 ++++++++++++- 8 files changed, 206 insertions(+), 88 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 26bb849d..9fc770cc 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -262,7 +262,7 @@ typedef struct mi_heap_area_s { typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg); -mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg); +mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); // Experimental mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept; @@ -292,9 +292,13 @@ mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t a // Experimental: allow sub-processes whose memory segments stay separated (and no reclamation between them) // Used for example for separate interpreter's in one process. typedef void* mi_subproc_id_t; +mi_decl_export mi_subproc_id_t mi_subproc_main(void); mi_decl_export mi_subproc_id_t mi_subproc_new(void); -mi_decl_export void mi_subproc_delete(mi_subproc_id_t subproc); -mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t subproc); // this should be called right after a thread is created (and no allocation has taken place yet) +mi_decl_export void mi_subproc_delete(mi_subproc_id_t subproc); +mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t subproc); // this should be called right after a thread is created (and no allocation has taken place yet) + +// Experimental: visit abandoned heap areas (from threads that have been terminated) +mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); // deprecated mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; @@ -355,6 +359,7 @@ typedef enum mi_option_e { mi_option_abandoned_reclaim_on_free, // allow to reclaim an abandoned segment on a free (=1) mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's) mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) + mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index 4e3250f9..d2711019 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -14,7 +14,7 @@ terms of the MIT license. A copy of the license can be found in the file #define WIN32_LEAN_AND_MEAN #endif #include -#elif !defined(_WIN32) && (defined(__EMSCRIPTEN_SHARED_MEMORY__) || !defined(__wasi__)) +#elif !defined(__wasi__) && (!defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)) #define MI_USE_PTHREADS #include #endif @@ -35,9 +35,9 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_atomic(name) std::atomic_##name #define mi_memory_order(name) std::memory_order_##name #if (__cplusplus >= 202002L) // c++20, see issue #571 -#define MI_ATOMIC_VAR_INIT(x) x + #define MI_ATOMIC_VAR_INIT(x) x #elif !defined(ATOMIC_VAR_INIT) -#define MI_ATOMIC_VAR_INIT(x) x + #define MI_ATOMIC_VAR_INIT(x) x #else #define MI_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x) #endif @@ -337,6 +337,7 @@ typedef _Atomic(uintptr_t) mi_atomic_guard_t; // ---------------------------------------------------------------------- // Yield // ---------------------------------------------------------------------- + #if defined(__cplusplus) #include static inline void mi_atomic_yield(void) { @@ -401,59 +402,73 @@ static inline void mi_atomic_yield(void) { // ---------------------------------------------------------------------- -// Locks are only used for abandoned segment visiting +// Locks are only used for abandoned segment visiting in `arena.c` // ---------------------------------------------------------------------- + #if defined(_WIN32) -#define mi_lock_t CRITICAL_SECTION +#define mi_lock_t CRITICAL_SECTION -static inline bool _mi_prim_lock(mi_lock_t* lock) { +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + return TryEnterCriticalSection(lock); +} +static inline bool mi_lock_acquire(mi_lock_t* lock) { EnterCriticalSection(lock); return true; } - -static inline bool _mi_prim_try_lock(mi_lock_t* lock) { - return TryEnterCriticalSection(lock); -} - -static inline void _mi_prim_unlock(mi_lock_t* lock) { +static inline void mi_lock_release(mi_lock_t* lock) { LeaveCriticalSection(lock); } +static inline void mi_lock_init(mi_lock_t* lock) { + InitializeCriticalSection(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + DeleteCriticalSection(lock); +} #elif defined(MI_USE_PTHREADS) #define mi_lock_t pthread_mutex_t -static inline bool _mi_prim_lock(mi_lock_t* lock) { - return (pthread_mutex_lock(lock) == 0); -} - -static inline bool _mi_prim_try_lock(mi_lock_t* lock) { +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { return (pthread_mutex_trylock(lock) == 0); } - -static inline void _mi_prim_unlock(mi_lock_t* lock) { +static inline bool mi_lock_acquire(mi_lock_t* lock) { + return (pthread_mutex_lock(lock) == 0); +} +static inline void mi_lock_release(mi_lock_t* lock) { pthread_mutex_unlock(lock); } +static inline void mi_lock_init(mi_lock_t* lock) { + (void)(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + (void)(lock); +} + #elif defined(__cplusplus) #include #define mi_lock_t std::mutex -static inline bool _mi_prim_lock(mi_lock_t* lock) { +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + return lock->lock_try_acquire(); +} +static inline bool mi_lock_acquire(mi_lock_t* lock) { lock->lock(); return true; } - -static inline bool _mi_prim_try_lock(mi_lock_t* lock) { - return (lock->try_lock(); -} - -static inline void _mi_prim_unlock(mi_lock_t* lock) { +static inline void mi_lock_release(mi_lock_t* lock) { lock->unlock(); } +static inline void mi_lock_init(mi_lock_t* lock) { + (void)(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + (void)(lock); +} #else @@ -462,22 +477,26 @@ static inline void _mi_prim_unlock(mi_lock_t* lock) { #define mi_lock_t _Atomic(uintptr_t) -static inline bool _mi_prim_try_lock(mi_lock_t* lock) { +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { uintptr_t expected = 0; return mi_atomic_cas_strong_acq_rel(lock, &expected, (uintptr_t)1); } - -static inline bool _mi_prim_lock(mi_lock_t* lock) { +static inline bool mi_lock_acquire(mi_lock_t* lock) { for (int i = 0; i < 1000; i++) { // for at most 1000 tries? - if (_mi_prim_try_lock(lock)) return true; + if (mi_lock_try_acquire(lock)) return true; mi_atomic_yield(); } return true; } - -static inline void _mi_prim_unlock(mi_lock_t* lock) { +static inline void mi_lock_release(mi_lock_t* lock) { mi_atomic_store_release(lock, (uintptr_t)0); } +static inline void mi_lock_init(mi_lock_t* lock) { + mi_lock_release(lock); +} +static inline void mi_lock_done(mi_lock_t* lock) { + (void)(lock); +} #endif diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 9046e3ad..89f04103 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -79,11 +79,12 @@ extern mi_decl_cache_align const mi_page_t _mi_page_empty; bool _mi_is_main_thread(void); size_t _mi_current_thread_count(void); bool _mi_preloading(void); // true while the C runtime is not initialized yet -mi_threadid_t _mi_thread_id(void) mi_attr_noexcept; -mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap void _mi_thread_done(mi_heap_t* heap); void _mi_thread_data_collect(void); void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap); +mi_threadid_t _mi_thread_id(void) mi_attr_noexcept; +mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap +mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id); // os.c void _mi_os_init(void); // called from process init @@ -136,7 +137,7 @@ typedef struct mi_arena_field_cursor_s { // abstract struct mi_subproc_t* subproc; } mi_arena_field_cursor_t; void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current); -mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous); +mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous, bool visit_all); // "segment-map.c" void _mi_segment_map_allocated_at(const mi_segment_t* segment); @@ -158,6 +159,7 @@ void _mi_segments_collect(bool force, 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); bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment); +bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); // "page.c" void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept mi_attr_malloc; @@ -189,6 +191,8 @@ void _mi_heap_set_default_direct(mi_heap_t* heap); bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid); void _mi_heap_unsafe_destroy_all(void); mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag); +void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page); +bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg); // "stats.c" void _mi_stats_done(mi_stats_t* stats); diff --git a/src/arena.c b/src/arena.c index aeadd604..59514950 100644 --- a/src/arena.c +++ b/src/arena.c @@ -40,23 +40,24 @@ typedef uintptr_t mi_block_info_t; // A memory arena descriptor typedef struct mi_arena_s { - mi_arena_id_t id; // arena id; 0 for non-specific - mi_memid_t memid; // memid of the memory area - _Atomic(uint8_t*) start; // the start of the memory area - size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) - size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) - size_t meta_size; // size of the arena structure itself (including its bitmaps) - mi_memid_t meta_memid; // memid of the arena structure itself (OS or static allocation) - int numa_node; // associated NUMA node - bool exclusive; // only allow allocations if specifically for this arena - bool is_large; // memory area consists of large- or huge OS pages (always committed) - _Atomic(size_t) search_idx; // optimization to start the search for free blocks - _Atomic(mi_msecs_t) purge_expire; // expiration time when blocks should be decommitted from `blocks_decommit`. - mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? - mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) - mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) - mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) - mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) + mi_arena_id_t id; // arena id; 0 for non-specific + mi_memid_t memid; // memid of the memory area + _Atomic(uint8_t*) start; // the start of the memory area + size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) + size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) + size_t meta_size; // size of the arena structure itself (including its bitmaps) + mi_memid_t meta_memid; // memid of the arena structure itself (OS or static allocation) + int numa_node; // associated NUMA node + bool exclusive; // only allow allocations if specifically for this arena + bool is_large; // memory area consists of large- or huge OS pages (always committed) + mi_lock_t abandoned_visit_lock; // lock is only used when abandoned segments are being visited + _Atomic(size_t) search_idx; // optimization to start the search for free blocks + _Atomic(mi_msecs_t) purge_expire; // expiration time when blocks should be decommitted from `blocks_decommit`. + mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? + mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) + mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) + mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) + mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) // do not add further fields here as the dirty, committed, purged, and abandoned bitmaps follow the inuse bitmap fields. } mi_arena_t; @@ -65,7 +66,6 @@ typedef struct mi_arena_s { static mi_decl_cache_align _Atomic(mi_arena_t*) mi_arenas[MI_MAX_ARENAS]; static mi_decl_cache_align _Atomic(size_t) mi_arena_count; // = 0 - //static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int numa_node, bool exclusive, mi_memid_t memid, mi_arena_id_t* arena_id) mi_attr_noexcept; /* ----------------------------------------------------------- @@ -702,6 +702,7 @@ static void mi_arenas_unsafe_destroy(void) { for (size_t i = 0; i < max_arena; i++) { mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[i]); if (arena != NULL) { + mi_lock_done(&arena->abandoned_visit_lock); if (arena->start != NULL && mi_memkind_is_os(arena->memid.memkind)) { mi_atomic_store_ptr_release(mi_arena_t, &mi_arenas[i], NULL); _mi_os_free(arena->start, mi_arena_size(arena), arena->memid, &_mi_stats_main); @@ -813,9 +814,9 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) // start a cursor at a randomized arena void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current) { - mi_assert_internal(heap->tld->segments.subproc == subproc); + mi_assert_internal(heap == NULL || heap->tld->segments.subproc == subproc); const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); - current->start = (max_arena == 0 ? 0 : (mi_arena_id_t)( _mi_heap_random_next(heap) % max_arena)); + current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)( _mi_heap_random_next(heap) % max_arena)); current->count = 0; current->bitmap_idx = 0; current->subproc = subproc; @@ -823,7 +824,7 @@ void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_aren // reclaim abandoned segments // this does not set the thread id (so it appears as still abandoned) -mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous ) +mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous, bool visit_all ) { const int max_arena = (int)mi_atomic_load_relaxed(&mi_arena_count); if (max_arena <= 0 || mi_atomic_load_relaxed(&previous->subproc->abandoned_count) == 0) return NULL; @@ -831,18 +832,31 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr int count = previous->count; size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1; - // visit arena's (from previous) + // visit arena's (from the previous cursor) for (; count < max_arena; count++, field_idx = 0, bit_idx = 0) { mi_arena_id_t arena_idx = previous->start + count; if (arena_idx >= max_arena) { arena_idx = arena_idx % max_arena; } // wrap around mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); if (arena != NULL) { + bool has_lock = false; // visit the abandoned fields (starting at previous_idx) - for ( ; field_idx < arena->field_count; field_idx++, bit_idx = 0) { + for (; field_idx < arena->field_count; field_idx++, bit_idx = 0) { size_t field = mi_atomic_load_relaxed(&arena->blocks_abandoned[field_idx]); if mi_unlikely(field != 0) { // skip zero fields quickly + // we only take the arena lock if there are actually abandoned segments present + if (!has_lock && mi_option_is_enabled(mi_option_visit_abandoned)) { + has_lock = (visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); + if (!has_lock) { + if (visit_all) { + _mi_error_message(EINVAL, "failed to visit all abandoned segments due to failure to acquire the visitor lock"); + } + // skip to next arena + break; + } + } + mi_assert_internal(has_lock || !mi_option_is_enabled(mi_option_visit_abandoned)); // visit each set bit in the field (todo: maybe use `ctz` here?) - for ( ; bit_idx < MI_BITMAP_FIELD_BITS; bit_idx++) { + for (; bit_idx < MI_BITMAP_FIELD_BITS; bit_idx++) { // pre-check if the bit is set size_t mask = ((size_t)1 << bit_idx); if mi_unlikely((field & mask) == mask) { @@ -852,7 +866,10 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); - // check that belongs to our sub-process + // check that the segment belongs to our sub-process + // note: this is the reason we need a lock in the case abandoned visiting is enabled. + // without the lock an abandoned visit may otherwise fail to visit all segments. + // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the arena lock. if (segment->subproc != previous->subproc) { // it is from another subprocess, re-mark it and continue searching const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); @@ -865,6 +882,7 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr previous->count = count; //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); + if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } return segment; } } @@ -872,6 +890,7 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr } } } + if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } } } // no more found @@ -881,6 +900,29 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr } +static bool mi_arena_visit_abandoned_blocks(mi_subproc_t* subproc, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + mi_arena_field_cursor_t current; + _mi_arena_field_cursor_init(NULL, subproc, ¤t); + mi_segment_t* segment; + while ((segment = _mi_arena_segment_clear_abandoned_next(¤t, true /* visit all */)) != NULL) { + if (!_mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg)) return false; + } + return true; +} + +bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + // (unfortunately) the visit_abandoned option must be enabled from the start. + // This is to avoid taking locks if abandoned list visiting is not required (as for most programs) + if (!mi_option_is_enabled(mi_option_visit_abandoned)) { + mi_assert(false); + _mi_error_message(EINVAL, "internal error: can only visit abandoned blocks when MIMALLOC_VISIT_ABANDONED=ON"); + return false; + } + // visit abandoned segments in the arena's + return mi_arena_visit_abandoned_blocks(_mi_subproc_from_id(subproc_id), heap_tag, visit_blocks, visitor, arg); +} + + /* ----------------------------------------------------------- Add an arena. ----------------------------------------------------------- */ @@ -934,6 +976,7 @@ static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int arena->is_large = is_large; arena->purge_expire = 0; arena->search_idx = 0; + mi_lock_init(&arena->abandoned_visit_lock); // consecutive bitmaps arena->blocks_dirty = &arena->blocks_inuse[fields]; // just after inuse bitmap arena->blocks_abandoned = &arena->blocks_inuse[2 * fields]; // just after dirty bitmap diff --git a/src/heap.c b/src/heap.c index f6f23549..2cde5fb0 100644 --- a/src/heap.c +++ b/src/heap.c @@ -137,6 +137,7 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) { // the main thread is abandoned (end-of-program), try to reclaim all abandoned segments. // if all memory is freed by now, all segments should be freed. + // note: this only collects in the current subprocess _mi_abandoned_reclaim_all(heap, &heap->tld->segments); } @@ -515,17 +516,21 @@ bool mi_check_owned(const void* p) { enable visiting all blocks of all heaps across threads ----------------------------------------------------------- */ -// Separate struct to keep `mi_page_t` out of the public interface -typedef struct mi_heap_area_ex_s { - mi_heap_area_t area; - mi_page_t* page; -} mi_heap_area_ex_t; +void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page) { + const size_t bsize = mi_page_block_size(page); + const size_t ubsize = mi_page_usable_block_size(page); + area->reserved = page->reserved * bsize; + area->committed = page->capacity * bsize; + area->blocks = mi_page_start(page); + area->used = page->used; // number of blocks in use (#553) + area->block_size = ubsize; + area->full_block_size = bsize; +} -static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_visit_fun* visitor, void* arg) { - mi_assert(xarea != NULL); - if (xarea==NULL) return true; - const mi_heap_area_t* area = &xarea->area; - mi_page_t* page = xarea->page; + +bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg) { + mi_assert(area != NULL); + if (area==NULL) return true; mi_assert(page != NULL); if (page == NULL) return true; @@ -590,23 +595,23 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v return true; } -typedef bool (mi_heap_area_visit_fun)(const mi_heap_t* heap, const mi_heap_area_ex_t* area, void* arg); +// Separate struct to keep `mi_page_t` out of the public interface +typedef struct mi_heap_area_ex_s { + mi_heap_area_t area; + mi_page_t* page; +} mi_heap_area_ex_t; + +typedef bool (mi_heap_area_visit_fun)(const mi_heap_t* heap, const mi_heap_area_ex_t* area, void* arg); + static bool mi_heap_visit_areas_page(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* vfun, void* arg) { MI_UNUSED(heap); MI_UNUSED(pq); mi_heap_area_visit_fun* fun = (mi_heap_area_visit_fun*)vfun; mi_heap_area_ex_t xarea; - const size_t bsize = mi_page_block_size(page); - const size_t ubsize = mi_page_usable_block_size(page); xarea.page = page; - xarea.area.reserved = page->reserved * bsize; - xarea.area.committed = page->capacity * bsize; - xarea.area.blocks = mi_page_start(page); - xarea.area.used = page->used; // number of blocks in use (#553) - xarea.area.block_size = ubsize; - xarea.area.full_block_size = bsize; + _mi_heap_area_init(&xarea.area, page); return fun(heap, &xarea, arg); } @@ -627,7 +632,7 @@ static bool mi_heap_area_visitor(const mi_heap_t* heap, const mi_heap_area_ex_t* mi_visit_blocks_args_t* args = (mi_visit_blocks_args_t*)arg; if (!args->visitor(heap, &xarea->area, NULL, xarea->area.block_size, args->arg)) return false; if (args->visit_blocks) { - return mi_heap_area_visit_blocks(xarea, args->visitor, args->arg); + return _mi_heap_area_visit_blocks(&xarea->area, xarea->page, args->visitor, args->arg); } else { return true; diff --git a/src/init.c b/src/init.c index 01625891..be8c16de 100644 --- a/src/init.c +++ b/src/init.c @@ -185,22 +185,30 @@ mi_heap_t* _mi_heap_main_get(void) { Sub process ----------------------------------------------------------- */ +static mi_decl_cache_align _Atomic(uintptr_t) mi_subproc_count; + +mi_subproc_id_t mi_subproc_main(void) { + return NULL; +} + mi_subproc_id_t mi_subproc_new(void) { mi_memid_t memid = _mi_memid_none(); mi_subproc_t* subproc = (mi_subproc_t*)_mi_arena_meta_zalloc(sizeof(mi_subproc_t), &memid); if (subproc == NULL) return NULL; + mi_atomic_increment_relaxed(&mi_subproc_count); subproc->memid = memid; return subproc; } -static mi_subproc_t* mi_subproc_from_id(mi_subproc_id_t subproc_id) { +mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id) { return (subproc_id == NULL ? &mi_subproc_default : (mi_subproc_t*)subproc_id); } void mi_subproc_delete(mi_subproc_id_t subproc_id) { if (subproc_id == NULL) return; - mi_subproc_t* subproc = mi_subproc_from_id(subproc_id); + mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id); _mi_arena_meta_free(subproc, subproc->memid, sizeof(mi_subproc_t)); + mi_atomic_decrement_relaxed(&mi_subproc_count); } void mi_subproc_add_current_thread(mi_subproc_id_t subproc_id) { @@ -208,7 +216,7 @@ void mi_subproc_add_current_thread(mi_subproc_id_t subproc_id) { if (heap == NULL) return; mi_assert(heap->tld->segments.subproc == &mi_subproc_default); if (heap->tld->segments.subproc != &mi_subproc_default) return; - heap->tld->segments.subproc = mi_subproc_from_id(subproc_id); + heap->tld->segments.subproc = _mi_subproc_from_id(subproc_id); } diff --git a/src/options.c b/src/options.c index db6e040f..32fa212b 100644 --- a/src/options.c +++ b/src/options.c @@ -94,6 +94,11 @@ static mi_option_desc_t options[_mi_option_last] = { 1, UNINIT, MI_OPTION(abandoned_reclaim_on_free) },// reclaim an abandoned segment on a free { 0, UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) { 400, UNINIT, MI_OPTION(retry_on_oom) }, // windows only: retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. +#if defined(MI_VISIT_ABANDONED) + { 1, INITIALIZED, MI_OPTION(visit_abandoned) }, // allow visiting heap blocks in abandonded segments; requires taking locks during reclaim. +#else + { 0, UNINIT, MI_OPTION(visit_abandoned) }, +#endif }; static void mi_option_init(mi_option_desc_t* desc); diff --git a/src/segment.c b/src/segment.c index 205d8753..dc82b89d 100644 --- a/src/segment.c +++ b/src/segment.c @@ -962,7 +962,7 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) { mi_segment_t* segment; mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, ¤t); - while ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL) { + while ((segment = _mi_arena_segment_clear_abandoned_next(¤t, true /* blocking */)) != NULL) { mi_segment_reclaim(segment, heap, 0, NULL, tld); } } @@ -987,7 +987,7 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, mi_segment_t* segment; mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, ¤t); - while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL)) + while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t, false /* non-blocking */)) != NULL)) { mi_assert(segment->subproc == heap->tld->segments.subproc); // cursor only visits segments in our sub-process segment->abandoned_visits++; @@ -1240,3 +1240,32 @@ mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t pag mi_assert_internal(page == NULL || _mi_page_segment(page)->subproc == tld->subproc); return page; } + + +/* ----------------------------------------------------------- + Visit blocks in a segment (only used for abandoned segments) +----------------------------------------------------------- */ + +static bool mi_segment_visit_page(mi_page_t* page, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + mi_heap_area_t area; + _mi_heap_area_init(&area, page); + if (!visitor(NULL, &area, NULL, area.block_size, arg)) return false; + if (visit_blocks) { + return _mi_heap_area_visit_blocks(&area, page, visitor, arg); + } + else { + return true; + } +} + +bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + for (size_t i = 0; i < segment->capacity; i++) { + mi_page_t* const page = &segment->pages[i]; + if (page->segment_in_use) { + if (heap_tag < 0 || (int)page->heap_tag == heap_tag) { + if (!mi_segment_visit_page(page, visit_blocks, visitor, arg)) return false; + } + } + } + return true; +} From 855e3b2549e0f2aa0277e43c4eeb8b1cbe1ea497 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 09:41:12 -0700 Subject: [PATCH 010/305] add support to visit _all_ abandoned segment blocks per sub-process, upstream for python/cpython#114133 --- include/mimalloc/types.h | 7 +- src/arena.c | 138 ++++++++++++++++++++++++++++----------- src/init.c | 21 ++++-- 3 files changed, 121 insertions(+), 45 deletions(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index f4ba6739..2506d454 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -404,7 +404,7 @@ typedef struct mi_segment_s { bool was_reclaimed; // true if it was reclaimed (used to limit on-free reclamation) size_t abandoned; // abandoned pages (i.e. the original owning thread stopped) (`abandoned <= used`) - size_t abandoned_visits; // count how often this segment is visited in the abandoned list (to force reclaim if it is too long) + size_t abandoned_visits; // count how often this segment is visited for reclaiming (to force reclaim if it is too long) size_t used; // count of pages in use (`used <= capacity`) size_t capacity; // count of available pages (`#free + used`) @@ -412,6 +412,9 @@ typedef struct mi_segment_s { uintptr_t cookie; // verify addresses in secure mode: `_mi_ptr_cookie(segment) == segment->cookie` mi_subproc_t* subproc; // segment belongs to sub process + struct mi_segment_s* abandoned_os_next; // only used for abandoned segments outside arena's, and only if `mi_option_visit_abandoned` is enabled + struct mi_segment_s* abandoned_os_prev; + // layout like this to optimize access in `mi_free` _Atomic(mi_threadid_t) thread_id; // unique id of the thread owning this segment size_t page_shift; // `1 << page_shift` == the page sizes == `page->block_size * page->reserved` (unless the first page, then `-segment_info_size`). @@ -609,6 +612,8 @@ void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); struct mi_subproc_s { _Atomic(size_t) abandoned_count; // count of abandoned segments for this sup-process + mi_lock_t abandoned_os_lock; // lock for the abandoned segments outside of arena's + mi_segment_t* abandoned_os_list; // doubly-linked list of abandoned segments outside of arena's (in OS allocated memory) mi_memid_t memid; // provenance }; diff --git a/src/arena.c b/src/arena.c index 59514950..913a02a9 100644 --- a/src/arena.c +++ b/src/arena.c @@ -757,17 +757,34 @@ bool _mi_arena_contains(const void* p) { // sets the thread_id. bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) { - if (segment->memid.memkind != MI_MEM_ARENA) { - // not in an arena, consider it un-abandoned now. - // but we need to still claim it atomically -- we use the thread_id for that. + if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { + // not in an arena + // if abandoned visiting is allowed, we need to take a lock on the abandoned os list + bool has_lock = false; + if (mi_option_is_enabled(mi_option_visit_abandoned)) { + has_lock = mi_lock_try_acquire(&segment->subproc->abandoned_os_lock); + if (!has_lock) { + return false; // failed to acquire the lock, we just give up + } + } + // abandon it, but we need to still claim it atomically -- we use the thread_id for that. + bool reclaimed = false; size_t expected = 0; if (mi_atomic_cas_strong_acq_rel(&segment->thread_id, &expected, _mi_thread_id())) { + // reclaim mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); - return true; - } - else { - return false; + reclaimed = true; + // and remove from the abandoned os list (if needed) + mi_segment_t* const next = segment->abandoned_os_next; + mi_segment_t* const prev = segment->abandoned_os_prev; + if (prev != NULL) { prev->abandoned_os_next = next; } + else { segment->subproc->abandoned_os_list = next; } + if (next != NULL) { next->abandoned_os_prev = prev; } + segment->abandoned_os_next = NULL; + segment->abandoned_os_prev = NULL; } + if (has_lock) { mi_lock_release(&segment->subproc->abandoned_os_lock); } + return reclaimed; } // arena segment: use the blocks_abandoned bitmap. size_t arena_idx; @@ -794,12 +811,30 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) { mi_atomic_store_release(&segment->thread_id, 0); mi_assert_internal(segment->used == segment->abandoned); - if (segment->memid.memkind != MI_MEM_ARENA) { - // not in an arena; count it as abandoned and return + if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { + // not in an arena; count it as abandoned and return (these can be reclaimed on a `free`) mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); + // if abandoned visiting is allowed, we need to take a lock on the abandoned os list to insert it + if (mi_option_is_enabled(mi_option_visit_abandoned)) { + if (!mi_lock_acquire(&segment->subproc->abandoned_os_lock)) { + _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); + } + else { + // push on the front of the list + mi_segment_t* next = segment->subproc->abandoned_os_list; + mi_assert_internal(next == NULL || next->abandoned_os_prev == NULL); + mi_assert_internal(segment->abandoned_os_prev == NULL); + mi_assert_internal(segment->abandoned_os_next == NULL); + if (next != NULL) { next->abandoned_os_prev = segment; } + segment->abandoned_os_prev = NULL; + segment->abandoned_os_next = next; + segment->subproc->abandoned_os_list = segment; + mi_lock_release(&segment->subproc->abandoned_os_lock); + } + } return; } - // segment is in an arena + // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap size_t arena_idx; size_t bitmap_idx; mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); @@ -822,6 +857,29 @@ void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_aren current->subproc = subproc; } +static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_subproc_t* subproc, mi_bitmap_index_t bitmap_idx) { + // try to reclaim an abandoned segment in the arena atomically + if (!_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) return NULL; + mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); + mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); + mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); + // check that the segment belongs to our sub-process + // note: this is the reason we need a lock in the case abandoned visiting is enabled. + // without the lock an abandoned visit may otherwise fail to visit all segments. + // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the arena lock. + if (segment->subproc != subproc) { + // it is from another subprocess, re-mark it and continue searching + const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); + mi_assert_internal(was_zero); MI_UNUSED(was_zero); + return NULL; + } + else { + // success, we unabandoned a segment in our sub-process + mi_atomic_decrement_relaxed(&subproc->abandoned_count); + return segment; + } +} + // reclaim abandoned segments // this does not set the thread id (so it appears as still abandoned) mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous, bool visit_all ) @@ -848,7 +906,7 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr has_lock = (visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); if (!has_lock) { if (visit_all) { - _mi_error_message(EINVAL, "failed to visit all abandoned segments due to failure to acquire the visitor lock"); + _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the visitor lock"); } // skip to next arena break; @@ -860,31 +918,14 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr // pre-check if the bit is set size_t mask = ((size_t)1 << bit_idx); if mi_unlikely((field & mask) == mask) { - mi_bitmap_index_t bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); - // try to reclaim it atomically - if (_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) { - mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); - mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); - mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); - // check that the segment belongs to our sub-process - // note: this is the reason we need a lock in the case abandoned visiting is enabled. - // without the lock an abandoned visit may otherwise fail to visit all segments. - // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the arena lock. - if (segment->subproc != previous->subproc) { - // it is from another subprocess, re-mark it and continue searching - const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - mi_assert_internal(was_zero); - } - else { - // success, we unabandoned a segment in our sub-process - mi_atomic_decrement_relaxed(&previous->subproc->abandoned_count); - previous->bitmap_idx = bitmap_idx; - previous->count = count; - - //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); - if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } - return segment; - } + const mi_bitmap_index_t bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); + mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, bitmap_idx); + if (segment != NULL) { + previous->bitmap_idx = bitmap_idx; + previous->count = count; + //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); + if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } + return segment; } } } @@ -910,16 +951,35 @@ static bool mi_arena_visit_abandoned_blocks(mi_subproc_t* subproc, int heap_tag, return true; } +static bool mi_subproc_visit_abandoned_os_blocks(mi_subproc_t* subproc, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { + _mi_error_message(EFAULT, "internal error: failed to acquire abandoned (OS) segment lock"); + return false; + } + bool all_visited = true; + for (mi_segment_t* segment = subproc->abandoned_os_list; segment != NULL; segment = segment->abandoned_os_next) { + if (!_mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg)) { + all_visited = false; + break; + } + } + mi_lock_release(&subproc->abandoned_os_lock); + return all_visited; +} + bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { // (unfortunately) the visit_abandoned option must be enabled from the start. // This is to avoid taking locks if abandoned list visiting is not required (as for most programs) if (!mi_option_is_enabled(mi_option_visit_abandoned)) { - mi_assert(false); - _mi_error_message(EINVAL, "internal error: can only visit abandoned blocks when MIMALLOC_VISIT_ABANDONED=ON"); + _mi_error_message(EFAULT, "internal error: can only visit abandoned blocks when MIMALLOC_VISIT_ABANDONED=ON"); return false; } + mi_subproc_t* const subproc = _mi_subproc_from_id(subproc_id); // visit abandoned segments in the arena's - return mi_arena_visit_abandoned_blocks(_mi_subproc_from_id(subproc_id), heap_tag, visit_blocks, visitor, arg); + if (!mi_arena_visit_abandoned_blocks(subproc, heap_tag, visit_blocks, visitor, arg)) return false; + // and visit abandoned segments outside arena's (in OS allocated memory) + if (!mi_subproc_visit_abandoned_os_blocks(subproc, heap_tag, visit_blocks, visitor, arg)) return false; + return true; } diff --git a/src/init.c b/src/init.c index be8c16de..f2d99d9e 100644 --- a/src/init.c +++ b/src/init.c @@ -171,7 +171,8 @@ static void mi_heap_main_init(void) { #endif _mi_heap_main.cookie = _mi_heap_random_next(&_mi_heap_main); _mi_heap_main.keys[0] = _mi_heap_random_next(&_mi_heap_main); - _mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main); + _mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main); + mi_lock_init(&mi_subproc_default.abandoned_os_lock); } } @@ -185,8 +186,6 @@ mi_heap_t* _mi_heap_main_get(void) { Sub process ----------------------------------------------------------- */ -static mi_decl_cache_align _Atomic(uintptr_t) mi_subproc_count; - mi_subproc_id_t mi_subproc_main(void) { return NULL; } @@ -195,8 +194,9 @@ mi_subproc_id_t mi_subproc_new(void) { mi_memid_t memid = _mi_memid_none(); mi_subproc_t* subproc = (mi_subproc_t*)_mi_arena_meta_zalloc(sizeof(mi_subproc_t), &memid); if (subproc == NULL) return NULL; - mi_atomic_increment_relaxed(&mi_subproc_count); subproc->memid = memid; + subproc->abandoned_os_list = NULL; + mi_lock_init(&subproc->abandoned_os_lock); return subproc; } @@ -207,8 +207,19 @@ mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id) { void mi_subproc_delete(mi_subproc_id_t subproc_id) { if (subproc_id == NULL) return; mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id); + // check if there are no abandoned segments still.. + bool safe_to_delete = false; + if (mi_lock_acquire(&subproc->abandoned_os_lock)) { + if (subproc->abandoned_os_list == NULL) { + safe_to_delete = true; + } + mi_lock_release(&subproc->abandoned_os_lock); + } + if (!safe_to_delete) return; + // safe to release + // todo: should we refcount subprocesses? + mi_lock_done(&subproc->abandoned_os_lock); _mi_arena_meta_free(subproc, subproc->memid, sizeof(mi_subproc_t)); - mi_atomic_decrement_relaxed(&mi_subproc_count); } void mi_subproc_add_current_thread(mi_subproc_id_t subproc_id) { From f7fe5bf20ea8a88f8a55f58549e21dfeadc5dc1f Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 10:28:30 -0700 Subject: [PATCH 011/305] optimize heap walks, by Sam Gross, upstream of python/cpython#114133 --- src/heap.c | 98 ++++++++++++++++++++++++++++++++++------------ test/test-stress.c | 14 +++++++ 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/src/heap.c b/src/heap.c index 2cde5fb0..be2800c1 100644 --- a/src/heap.c +++ b/src/heap.c @@ -528,46 +528,83 @@ void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page) { } +static void mi_get_fast_divisor(size_t divisor, uint64_t* magic, size_t* shift) { + mi_assert_internal(divisor > 0 && divisor <= UINT32_MAX); + *shift = 64 - mi_clz(divisor - 1); + *magic = ((((uint64_t)1 << 32) * (((uint64_t)1 << *shift) - divisor)) / divisor + 1); +} + +static size_t mi_fast_divide(size_t n, uint64_t magic, size_t shift) { + mi_assert_internal(n <= UINT32_MAX); + return ((((uint64_t)n * magic) >> 32) + n) >> shift; +} + bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg) { mi_assert(area != NULL); if (area==NULL) return true; mi_assert(page != NULL); if (page == NULL) return true; - _mi_page_free_collect(page,true); + _mi_page_free_collect(page,true); // collect both thread_delayed and local_free mi_assert_internal(page->local_free == NULL); if (page->used == 0) return true; - const size_t bsize = mi_page_block_size(page); - const size_t ubsize = mi_page_usable_block_size(page); // without padding - size_t psize; - uint8_t* pstart = _mi_segment_page_start(_mi_page_segment(page), page, &psize); + size_t psize; + uint8_t* const pstart = _mi_segment_page_start(_mi_page_segment(page), page, &psize); + mi_heap_t* const heap = mi_page_heap(page); + const size_t bsize = mi_page_block_size(page); + const size_t ubsize = mi_page_usable_block_size(page); // without padding + // optimize page with one block if (page->capacity == 1) { - // optimize page with one block mi_assert_internal(page->used == 1 && page->free == NULL); return visitor(mi_page_heap(page), area, pstart, ubsize, arg); } + mi_assert(bsize <= UINT32_MAX); + + // optimize full pages + if (page->used == page->capacity) { + uint8_t* block = pstart; + for (size_t i = 0; i < page->capacity; i++) { + if (!visitor(heap, area, block, ubsize, arg)) return false; + block += bsize; + } + return true; + } // create a bitmap of free blocks. #define MI_MAX_BLOCKS (MI_SMALL_PAGE_SIZE / sizeof(void*)) - uintptr_t free_map[MI_MAX_BLOCKS / sizeof(uintptr_t)]; - memset(free_map, 0, sizeof(free_map)); + uintptr_t free_map[MI_MAX_BLOCKS / MI_INTPTR_BITS]; + const uintptr_t bmapsize = _mi_divide_up(page->capacity, MI_INTPTR_BITS); + memset(free_map, 0, bmapsize * sizeof(intptr_t)); + if (page->capacity % MI_INTPTR_BITS != 0) { + // mark left-over bits at the end as free + size_t shift = (page->capacity % MI_INTPTR_BITS); + uintptr_t mask = (UINTPTR_MAX << shift); + free_map[bmapsize - 1] = mask; + } + + // fast repeated division by the block size + uint64_t magic; + size_t shift; + mi_get_fast_divisor(bsize, &magic, &shift); #if MI_DEBUG>1 size_t free_count = 0; #endif - for (mi_block_t* block = page->free; block != NULL; block = mi_block_next(page,block)) { + for (mi_block_t* block = page->free; block != NULL; block = mi_block_next(page, block)) { #if MI_DEBUG>1 free_count++; #endif mi_assert_internal((uint8_t*)block >= pstart && (uint8_t*)block < (pstart + psize)); size_t offset = (uint8_t*)block - pstart; mi_assert_internal(offset % bsize == 0); - size_t blockidx = offset / bsize; // Todo: avoid division? - mi_assert_internal( blockidx < MI_MAX_BLOCKS); - size_t bitidx = (blockidx / sizeof(uintptr_t)); - size_t bit = blockidx - (bitidx * sizeof(uintptr_t)); + mi_assert_internal(offset <= UINT32_MAX); + size_t blockidx = mi_fast_divide(offset, magic, shift); + mi_assert_internal(blockidx == offset / bsize); + mi_assert_internal(blockidx < MI_MAX_BLOCKS); + size_t bitidx = (blockidx / MI_INTPTR_BITS); + size_t bit = blockidx - (bitidx * MI_INTPTR_BITS); free_map[bitidx] |= ((uintptr_t)1 << bit); } mi_assert_internal(page->capacity == (free_count + page->used)); @@ -576,19 +613,30 @@ bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_ #if MI_DEBUG>1 size_t used_count = 0; #endif - for (size_t i = 0; i < page->capacity; i++) { - size_t bitidx = (i / sizeof(uintptr_t)); - size_t bit = i - (bitidx * sizeof(uintptr_t)); - uintptr_t m = free_map[bitidx]; - if (bit == 0 && m == UINTPTR_MAX) { - i += (sizeof(uintptr_t) - 1); // skip a run of free blocks + uint8_t* block = pstart; + for (size_t i = 0; i < bmapsize; i++) { + if (free_map[i] == 0) { + // every block is in use + for (size_t j = 0; j < MI_INTPTR_BITS; j++) { + #if MI_DEBUG>1 + used_count++; + #endif + if (!visitor(heap, area, block, ubsize, arg)) return false; + block += bsize; + } } - else if ((m & ((uintptr_t)1 << bit)) == 0) { - #if MI_DEBUG>1 - used_count++; - #endif - uint8_t* block = pstart + (i * bsize); - if (!visitor(mi_page_heap(page), area, block, ubsize, arg)) return false; + else { + // visit the used blocks in the mask + uintptr_t m = ~free_map[i]; + while (m != 0) { + #if MI_DEBUG>1 + used_count++; + #endif + size_t bitidx = mi_ctz(m); + if (!visitor(heap, area, block + (bitidx * bsize), ubsize, arg)) return false; + m &= m - 1; // clear least significant bit + } + block += bsize * MI_INTPTR_BITS; } } mi_assert_internal(page->used == used_count); diff --git a/test/test-stress.c b/test/test-stress.c index 0368007a..f82b9743 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -129,6 +129,16 @@ static void free_items(void* p) { custom_free(p); } +/* +static bool visit_blocks(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg) { + (void)(heap); (void)(area); + size_t* total = (size_t*)arg; + if (block != NULL) { + total += block_size; + } + return true; +} +*/ static void stress(intptr_t tid) { //bench_start_thread(); @@ -173,6 +183,10 @@ static void stress(intptr_t tid) { data[data_idx] = q; } } + // walk the heap + // size_t total = 0; + // mi_heap_visit_blocks(mi_heap_get_default(), true, visit_blocks, &total); + // free everything that is left for (size_t i = 0; i < retain_top; i++) { free_items(retained[i]); From 635d626c82e636e89163da6601dfe1f02a57e4a9 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 10:43:41 -0700 Subject: [PATCH 012/305] fix leak in abandoned block visiting --- src/arena.c | 4 +++- test/test-stress.c | 19 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/arena.c b/src/arena.c index 913a02a9..801475fd 100644 --- a/src/arena.c +++ b/src/arena.c @@ -946,7 +946,9 @@ static bool mi_arena_visit_abandoned_blocks(mi_subproc_t* subproc, int heap_tag, _mi_arena_field_cursor_init(NULL, subproc, ¤t); mi_segment_t* segment; while ((segment = _mi_arena_segment_clear_abandoned_next(¤t, true /* visit all */)) != NULL) { - if (!_mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg)) return false; + bool ok = _mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg); + _mi_arena_segment_mark_abandoned(segment); + if (!ok) return false; } return true; } diff --git a/test/test-stress.c b/test/test-stress.c index f82b9743..c3afde9b 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -39,6 +39,10 @@ static int ITER = 50; // N full iterations destructing and re-creating a #define STRESS // undefine for leak test +#ifndef NDEBUG +#define HEAP_WALK // walk the heap objects? +#endif + static bool allow_large_objects = true; // allow very large objects? (set to `true` if SCALE>100) static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`? @@ -129,7 +133,7 @@ static void free_items(void* p) { custom_free(p); } -/* +#ifdef HEAP_WALK static bool visit_blocks(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg) { (void)(heap); (void)(area); size_t* total = (size_t*)arg; @@ -138,7 +142,7 @@ static bool visit_blocks(const mi_heap_t* heap, const mi_heap_area_t* area, void } return true; } -*/ +#endif static void stress(intptr_t tid) { //bench_start_thread(); @@ -183,9 +187,12 @@ static void stress(intptr_t tid) { data[data_idx] = q; } } + + #ifdef HEAP_WALK // walk the heap - // size_t total = 0; - // mi_heap_visit_blocks(mi_heap_get_default(), true, visit_blocks, &total); + size_t total = 0; + mi_heap_visit_blocks(mi_heap_get_default(), true, visit_blocks, &total); + #endif // free everything that is left for (size_t i = 0; i < retain_top; i++) { @@ -205,6 +212,10 @@ static void test_stress(void) { uintptr_t r = rand(); for (int n = 0; n < ITER; n++) { run_os_threads(THREADS, &stress); + #ifdef HEAP_WALK + size_t total = 0; + mi_abandoned_visit_blocks(mi_subproc_main(), -1, true, visit_blocks, &total); + #endif for (int i = 0; i < TRANSFERS; i++) { if (chance(50, &r) || n + 1 == ITER) { // free all on last run, otherwise free half of the transfers void* p = atomic_exchange_ptr(&transfer[i], NULL); From 5501f59f6ce044b33149391132c3dd83b964e710 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 13:16:20 -0700 Subject: [PATCH 013/305] only reclaim for exclusive heaps in their associated arena --- include/mimalloc.h | 5 +++++ include/mimalloc/internal.h | 4 ++-- src/arena.c | 35 +++++++++++++++++++++-------------- src/heap.c | 13 +++++++++---- src/segment.c | 3 ++- test/test-stress.c | 6 ++++++ 6 files changed, 45 insertions(+), 21 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 9fc770cc..0b4b182c 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -300,6 +300,11 @@ mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t sub // Experimental: visit abandoned heap areas (from threads that have been terminated) mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); +// Experimental: create a new heap with a specified heap tag. Set `allow_destroy` to false to allow the thread +// to reclaim abandoned memory (with a compatible heap_tag and arena_id) but in that case `mi_heap_destroy` will +// fall back to `mi_heap_delete`. +mi_decl_export mi_decl_nodiscard mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); + // deprecated mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 89f04103..0b6cf056 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -131,8 +131,8 @@ void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid); void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size); typedef struct mi_arena_field_cursor_s { // abstract struct - mi_arena_id_t start; - int count; + size_t start; + size_t end; size_t bitmap_idx; mi_subproc_t* subproc; } mi_arena_field_cursor_t; diff --git a/src/arena.c b/src/arena.c index 801475fd..095c5745 100644 --- a/src/arena.c +++ b/src/arena.c @@ -850,11 +850,20 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) // start a cursor at a randomized arena void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current) { mi_assert_internal(heap == NULL || heap->tld->segments.subproc == subproc); - const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); - current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)( _mi_heap_random_next(heap) % max_arena)); - current->count = 0; - current->bitmap_idx = 0; + current->bitmap_idx = 0; current->subproc = subproc; + const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); + if (heap != NULL && heap->arena_id != _mi_arena_id_none()) { + // for a heap that is bound to one arena, only visit that arena + current->start = mi_arena_id_index(heap->arena_id); + current->end = current->start + 1; + } + else { + // otherwise visit all starting at a random location + current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); + current->end = current->start + max_arena; + } + mi_assert_internal(current->start < max_arena); } static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_subproc_t* subproc, mi_bitmap_index_t bitmap_idx) { @@ -884,16 +893,15 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_s // this does not set the thread id (so it appears as still abandoned) mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous, bool visit_all ) { - const int max_arena = (int)mi_atomic_load_relaxed(&mi_arena_count); + const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); if (max_arena <= 0 || mi_atomic_load_relaxed(&previous->subproc->abandoned_count) == 0) return NULL; - int count = previous->count; size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1; // visit arena's (from the previous cursor) - for (; count < max_arena; count++, field_idx = 0, bit_idx = 0) { - mi_arena_id_t arena_idx = previous->start + count; - if (arena_idx >= max_arena) { arena_idx = arena_idx % max_arena; } // wrap around + for ( ; previous->start < previous->end; previous->start++, field_idx = 0, bit_idx = 0) { + // index wraps around + size_t arena_idx = (previous->start >= max_arena ? previous->start % max_arena : previous->start); mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); if (arena != NULL) { bool has_lock = false; @@ -918,11 +926,9 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr // pre-check if the bit is set size_t mask = ((size_t)1 << bit_idx); if mi_unlikely((field & mask) == mask) { - const mi_bitmap_index_t bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); - mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, bitmap_idx); + previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); + mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, previous->bitmap_idx); if (segment != NULL) { - previous->bitmap_idx = bitmap_idx; - previous->count = count; //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } return segment; @@ -935,8 +941,9 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr } } // no more found + mi_assert(previous->start == previous->end); previous->bitmap_idx = 0; - previous->count = 0; + previous->start = previous->end = 0; return NULL; } diff --git a/src/heap.c b/src/heap.c index be2800c1..0049abc3 100644 --- a/src/heap.c +++ b/src/heap.c @@ -226,17 +226,22 @@ void _mi_heap_init(mi_heap_t* heap, mi_tld_t* tld, mi_arena_id_t arena_id, bool heap->tld->heaps = heap; } -mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id) { +mi_decl_nodiscard mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id) { mi_heap_t* bheap = mi_heap_get_backing(); mi_heap_t* heap = mi_heap_malloc_tp(bheap, mi_heap_t); // todo: OS allocate in secure mode? if (heap == NULL) return NULL; - // don't reclaim abandoned pages or otherwise destroy is unsafe - _mi_heap_init(heap, bheap->tld, arena_id, true /* no reclaim */, 0 /* default tag */); + mi_assert(heap_tag >= 0 && heap_tag < 256); + _mi_heap_init(heap, bheap->tld, arena_id, allow_destroy /* no reclaim? */, (uint8_t)heap_tag /* heap tag */); return heap; } +mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id) { + return mi_heap_new_ex(0 /* default heap tag */, false /* don't allow `mi_heap_destroy` */, arena_id); +} + mi_decl_nodiscard mi_heap_t* mi_heap_new(void) { - return mi_heap_new_in_arena(_mi_arena_id_none()); + // don't reclaim abandoned memory or otherwise destroy is unsafe + return mi_heap_new_ex(0 /* default heap tag */, true /* no reclaim */, _mi_arena_id_none()); } bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid) { diff --git a/src/segment.c b/src/segment.c index dc82b89d..8fccf18e 100644 --- a/src/segment.c +++ b/src/segment.c @@ -905,7 +905,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, mi_heap_t* target_heap = _mi_heap_by_tag(heap, page->heap_tag); // allow custom heaps to separate objects if (target_heap == NULL) { target_heap = heap; - _mi_error_message(EINVAL, "page with tag %u cannot be reclaimed by a heap with the same tag (using tag %u instead)\n", page->heap_tag, heap->tag ); + _mi_error_message(EINVAL, "page with tag %u cannot be reclaimed by a heap with the same tag (using heap tag %u instead)\n", page->heap_tag, heap->tag ); } // associate the heap with this page, and allow heap thread delayed free again. mi_page_set_heap(page, target_heap); @@ -948,6 +948,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { if (mi_atomic_load_relaxed(&segment->thread_id) != 0) return false; // it is not abandoned if (segment->subproc != heap->tld->segments.subproc) return false; // only reclaim within the same subprocess + if (!_mi_heap_memid_is_suitable(heap,segment->memid)) return false; // don't reclaim between exclusive and non-exclusive arena's // don't reclaim more from a `free` call than half the current segments // this is to prevent a pure free-ing thread to start owning too many segments if (heap->tld->segments.reclaim_count * 2 > heap->tld->segments.count) return false; diff --git a/test/test-stress.c b/test/test-stress.c index c3afde9b..599c6c2e 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -255,6 +255,12 @@ static void test_leak(void) { #endif int main(int argc, char** argv) { + #ifdef HEAP_WALK + mi_option_enable(mi_option_visit_abandoned); + #endif + #ifndef NDBEBUG + mi_option_set(mi_option_arena_reserve, 32 * 1024 /* in kib = 32MiB */); + #endif #ifndef USE_STD_MALLOC mi_stats_reset(); #endif From a964322a21907206909798771ab90a9ccf27f8d8 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 14:46:59 -0700 Subject: [PATCH 014/305] revise the segment map to only apply to OS allocated segments and reduce the .BSS footprint --- src/arena.c | 4 +- src/os.c | 15 ++-- src/segment-map.c | 166 +++++++++++++++++++-------------------------- test/test-stress.c | 2 +- 4 files changed, 82 insertions(+), 105 deletions(-) diff --git a/src/arena.c b/src/arena.c index 095c5745..24f1299c 100644 --- a/src/arena.c +++ b/src/arena.c @@ -36,7 +36,7 @@ The arena allocation needs to be thread safe and we use an atomic bitmap to allo typedef uintptr_t mi_block_info_t; #define MI_ARENA_BLOCK_SIZE (MI_SEGMENT_SIZE) // 64MiB (must be at least MI_SEGMENT_ALIGN) #define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_BLOCK_SIZE/2) // 32MiB -#define MI_MAX_ARENAS (255) // Limited as the reservation exponentially increases (and takes up .bss) +#define MI_MAX_ARENAS (132) // Limited as the reservation exponentially increases (and takes up .bss) // A memory arena descriptor typedef struct mi_arena_s { @@ -735,7 +735,7 @@ void _mi_arena_unsafe_destroy_all(mi_stats_t* stats) { bool _mi_arena_contains(const void* p) { const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); for (size_t i = 0; i < max_arena; i++) { - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[i]); + mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[i]); if (arena != NULL && arena->start <= (const uint8_t*)p && arena->start + mi_arena_block_size(arena->block_count) > (const uint8_t*)p) { return true; } diff --git a/src/os.c b/src/os.c index 88e7fcb3..4babd8da 100644 --- a/src/os.c +++ b/src/os.c @@ -157,7 +157,8 @@ static void mi_os_prim_free(void* addr, size_t size, bool still_committed, mi_st _mi_stat_decrease(&stats->reserved, size); } -void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t memid, mi_stats_t* tld_stats) { +void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t memid, mi_stats_t* stats) { + if (stats == NULL) stats = &_mi_stats_main; if (mi_memkind_is_os(memid.memkind)) { size_t csize = _mi_os_good_alloc_size(size); void* base = addr; @@ -171,10 +172,10 @@ void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t me // free it if (memid.memkind == MI_MEM_OS_HUGE) { mi_assert(memid.is_pinned); - mi_os_free_huge_os_pages(base, csize, tld_stats); + mi_os_free_huge_os_pages(base, csize, stats); } else { - mi_os_prim_free(base, csize, still_committed, tld_stats); + mi_os_prim_free(base, csize, still_committed, stats); } } else { @@ -183,8 +184,9 @@ void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t me } } -void _mi_os_free(void* p, size_t size, mi_memid_t memid, mi_stats_t* tld_stats) { - _mi_os_free_ex(p, size, true, memid, tld_stats); +void _mi_os_free(void* p, size_t size, mi_memid_t memid, mi_stats_t* stats) { + if (stats == NULL) stats = &_mi_stats_main; + _mi_os_free_ex(p, size, true, memid, stats); } @@ -299,6 +301,7 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit void* _mi_os_alloc(size_t size, mi_memid_t* memid, mi_stats_t* stats) { *memid = _mi_memid_none(); if (size == 0) return NULL; + if (stats == NULL) stats = &_mi_stats_main; size = _mi_os_good_alloc_size(size); bool os_is_large = false; bool os_is_zero = false; @@ -314,6 +317,7 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allo MI_UNUSED(&_mi_os_get_aligned_hint); // suppress unused warnings *memid = _mi_memid_none(); if (size == 0) return NULL; + if (stats == NULL) stats = &_mi_stats_main; size = _mi_os_good_alloc_size(size); alignment = _mi_align_up(alignment, _mi_os_page_size()); @@ -342,6 +346,7 @@ void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offse mi_assert(offset <= size); mi_assert((alignment % _mi_os_page_size()) == 0); *memid = _mi_memid_none(); + if (stats == NULL) stats = &_mi_stats_main; if (offset > MI_SEGMENT_SIZE) return NULL; if (offset == 0) { // regular aligned allocation diff --git a/src/segment-map.c b/src/segment-map.c index 1efb1e23..be461d7e 100644 --- a/src/segment-map.c +++ b/src/segment-map.c @@ -16,140 +16,112 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc/internal.h" #include "mimalloc/atomic.h" -#if (MI_INTPTR_SIZE>=8) && MI_TRACK_ASAN -#define MI_MAX_ADDRESS ((size_t)140 << 40) // 140TB (see issue #881) -#elif (MI_INTPTR_SIZE >= 8) -#define MI_MAX_ADDRESS ((size_t)40 << 40) // 40TB (to include huge page areas) +// Reduce total address space to reduce .bss (due to the `mi_segment_map`) +#if (MI_INTPTR_SIZE > 4) && MI_TRACK_ASAN +#define MI_SEGMENT_MAP_MAX_ADDRESS (128*1024ULL*MI_GiB) // 128 TiB (see issue #881) +#elif (MI_INTPTR_SIZE > 4) +#define MI_SEGMENT_MAP_MAX_ADDRESS (48*1024ULL*MI_GiB) // 48 TiB #else -#define MI_MAX_ADDRESS ((size_t)2 << 30) // 2Gb +#define MI_SEGMENT_MAP_MAX_ADDRESS (MAX_UINT32) #endif -#define MI_SEGMENT_MAP_BITS (MI_MAX_ADDRESS / MI_SEGMENT_SIZE) -#define MI_SEGMENT_MAP_SIZE (MI_SEGMENT_MAP_BITS / 8) -#define MI_SEGMENT_MAP_WSIZE (MI_SEGMENT_MAP_SIZE / MI_INTPTR_SIZE) +#define MI_SEGMENT_MAP_PART_SIZE (MI_INTPTR_SIZE*MI_KiB - 128) // 128 > sizeof(mi_memid_t) ! +#define MI_SEGMENT_MAP_PART_BITS (8*MI_SEGMENT_MAP_PART_SIZE) +#define MI_SEGMENT_MAP_PART_ENTRIES (MI_SEGMENT_MAP_PART_SIZE / MI_INTPTR_SIZE) +#define MI_SEGMENT_MAP_PART_BIT_SPAN (MI_SEGMENT_ALIGN) +#define MI_SEGMENT_MAP_PART_SPAN (MI_SEGMENT_MAP_PART_BITS * MI_SEGMENT_MAP_PART_BIT_SPAN) +#define MI_SEGMENT_MAP_MAX_PARTS ((MI_SEGMENT_MAP_MAX_ADDRESS / MI_SEGMENT_MAP_PART_SPAN) + 1) -static _Atomic(uintptr_t) mi_segment_map[MI_SEGMENT_MAP_WSIZE + 1]; // 2KiB per TB with 64MiB segments +// A part of the segment map. +typedef struct mi_segmap_part_s { + mi_memid_t memid; + _Atomic(uintptr_t) map[MI_SEGMENT_MAP_PART_ENTRIES]; +} mi_segmap_part_t; -static size_t mi_segment_map_index_of(const mi_segment_t* segment, size_t* bitidx) { +// Allocate parts on-demand to reduce .bss footprint +_Atomic(mi_segmap_part_t*) mi_segment_map[MI_SEGMENT_MAP_MAX_PARTS]; // = { NULL, .. } + + +static mi_segmap_part_t* mi_segment_map_index_of(const mi_segment_t* segment, bool create_on_demand, size_t* idx, size_t* bitidx) { // note: segment can be invalid or NULL. mi_assert_internal(_mi_ptr_segment(segment + 1) == segment); // is it aligned on MI_SEGMENT_SIZE? - if ((uintptr_t)segment >= MI_MAX_ADDRESS) { - *bitidx = 0; - return MI_SEGMENT_MAP_WSIZE; - } - else { - const uintptr_t segindex = ((uintptr_t)segment) / MI_SEGMENT_SIZE; - *bitidx = segindex % MI_INTPTR_BITS; - const size_t mapindex = segindex / MI_INTPTR_BITS; - mi_assert_internal(mapindex < MI_SEGMENT_MAP_WSIZE); - return mapindex; + *idx = 0; + *bitidx = 0; + if ((uintptr_t)segment >= MI_SEGMENT_MAP_MAX_ADDRESS) return NULL; + const uintptr_t segindex = ((uintptr_t)segment) / MI_SEGMENT_MAP_PART_SPAN; + if (segindex >= MI_SEGMENT_MAP_MAX_PARTS) return NULL; + mi_segmap_part_t* part = mi_atomic_load_ptr_relaxed(mi_segmap_part_t*, &mi_segment_map[segindex]); + + // allocate on demand to reduce .bss footprint + if (part == NULL) { + if (!create_on_demand) return NULL; + mi_memid_t memid; + part = (mi_segmap_part_t*)_mi_os_alloc(sizeof(mi_segmap_part_t), &memid, NULL); + if (part == NULL) return NULL; + mi_segmap_part_t* expected = NULL; + if (!mi_atomic_cas_ptr_strong_release(mi_segmap_part_t, &mi_segment_map[segindex], &expected, part)) { + _mi_os_free(part, sizeof(mi_segmap_part_t), memid, NULL); + part = expected; + if (part == NULL) return NULL; + } } + mi_assert(part != NULL); + const uintptr_t offset = ((uintptr_t)segment) % MI_SEGMENT_MAP_PART_SPAN; + const uintptr_t bitofs = offset / MI_SEGMENT_MAP_PART_BIT_SPAN; + *idx = bitofs / MI_INTPTR_BITS; + *bitidx = bitofs % MI_INTPTR_BITS; + return part; } void _mi_segment_map_allocated_at(const mi_segment_t* segment) { + if (segment->memid.memkind == MI_MEM_ARENA) return; // we lookup segments first in the arena's and don't need the segment map + size_t index; size_t bitidx; - size_t index = mi_segment_map_index_of(segment, &bitidx); - mi_assert_internal(index <= MI_SEGMENT_MAP_WSIZE); - if (index==MI_SEGMENT_MAP_WSIZE) return; - uintptr_t mask = mi_atomic_load_relaxed(&mi_segment_map[index]); + mi_segmap_part_t* part = mi_segment_map_index_of(segment, true /* alloc map if needed */, &index, &bitidx); + if (part == NULL) return; // outside our address range.. + uintptr_t mask = mi_atomic_load_relaxed(&part->map[index]); uintptr_t newmask; do { newmask = (mask | ((uintptr_t)1 << bitidx)); - } while (!mi_atomic_cas_weak_release(&mi_segment_map[index], &mask, newmask)); + } while (!mi_atomic_cas_weak_release(&part->map[index], &mask, newmask)); } void _mi_segment_map_freed_at(const mi_segment_t* segment) { + if (segment->memid.memkind == MI_MEM_ARENA) return; + size_t index; size_t bitidx; - size_t index = mi_segment_map_index_of(segment, &bitidx); - mi_assert_internal(index <= MI_SEGMENT_MAP_WSIZE); - if (index == MI_SEGMENT_MAP_WSIZE) return; - uintptr_t mask = mi_atomic_load_relaxed(&mi_segment_map[index]); + mi_segmap_part_t* part = mi_segment_map_index_of(segment, false /* don't alloc if not present */, &index, &bitidx); + if (part == NULL) return; // outside our address range.. + uintptr_t mask = mi_atomic_load_relaxed(&part->map[index]); uintptr_t newmask; do { newmask = (mask & ~((uintptr_t)1 << bitidx)); - } while (!mi_atomic_cas_weak_release(&mi_segment_map[index], &mask, newmask)); + } while (!mi_atomic_cas_weak_release(&part->map[index], &mask, newmask)); } // Determine the segment belonging to a pointer or NULL if it is not in a valid segment. static mi_segment_t* _mi_segment_of(const void* p) { if (p == NULL) return NULL; mi_segment_t* segment = _mi_ptr_segment(p); // segment can be NULL + size_t index; size_t bitidx; - size_t index = mi_segment_map_index_of(segment, &bitidx); - // fast path: for any pointer to valid small/medium/large object or first MI_SEGMENT_SIZE in huge - const uintptr_t mask = mi_atomic_load_relaxed(&mi_segment_map[index]); + mi_segmap_part_t* part = mi_segment_map_index_of(segment, false /* dont alloc if not present */, &index, &bitidx); + if (part == NULL) return NULL; + const uintptr_t mask = mi_atomic_load_relaxed(&part->map[index]); if mi_likely((mask & ((uintptr_t)1 << bitidx)) != 0) { + bool cookie_ok = (_mi_ptr_cookie(segment) == segment->cookie); + mi_assert_internal(cookie_ok); MI_UNUSED(cookie_ok); return segment; // yes, allocated by us } - if (index==MI_SEGMENT_MAP_WSIZE) return NULL; - - // TODO: maintain max/min allocated range for efficiency for more efficient rejection of invalid pointers? - - // search downwards for the first segment in case it is an interior pointer - // could be slow but searches in MI_INTPTR_SIZE * MI_SEGMENT_SIZE (512MiB) steps trough - // valid huge objects - // note: we could maintain a lowest index to speed up the path for invalid pointers? - size_t lobitidx; - size_t loindex; - uintptr_t lobits = mask & (((uintptr_t)1 << bitidx) - 1); - if (lobits != 0) { - loindex = index; - lobitidx = mi_bsr(lobits); // lobits != 0 - } - else if (index == 0) { - return NULL; - } - else { - mi_assert_internal(index > 0); - uintptr_t lomask = mask; - loindex = index; - do { - loindex--; - lomask = mi_atomic_load_relaxed(&mi_segment_map[loindex]); - } while (lomask != 0 && loindex > 0); - if (lomask == 0) return NULL; - lobitidx = mi_bsr(lomask); // lomask != 0 - } - mi_assert_internal(loindex < MI_SEGMENT_MAP_WSIZE); - // take difference as the addresses could be larger than the MAX_ADDRESS space. - size_t diff = (((index - loindex) * (8*MI_INTPTR_SIZE)) + bitidx - lobitidx) * MI_SEGMENT_SIZE; - segment = (mi_segment_t*)((uint8_t*)segment - diff); - - if (segment == NULL) return NULL; - mi_assert_internal((void*)segment < p); - bool cookie_ok = (_mi_ptr_cookie(segment) == segment->cookie); - mi_assert_internal(cookie_ok); - if mi_unlikely(!cookie_ok) return NULL; - if (((uint8_t*)segment + mi_segment_size(segment)) <= (uint8_t*)p) return NULL; // outside the range - mi_assert_internal(p >= (void*)segment && (uint8_t*)p < (uint8_t*)segment + mi_segment_size(segment)); - return segment; + return NULL; } // Is this a valid pointer in our heap? -static bool mi_is_valid_pointer(const void* p) { - return ((_mi_segment_of(p) != NULL) || (_mi_arena_contains(p))); +static bool mi_is_valid_pointer(const void* p) { + // first check if it is in an arena, then check if it is OS allocated + return (_mi_arena_contains(p) || _mi_segment_of(p) != NULL); } mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { return mi_is_valid_pointer(p); } - -/* -// Return the full segment range belonging to a pointer -static void* mi_segment_range_of(const void* p, size_t* size) { - mi_segment_t* segment = _mi_segment_of(p); - if (segment == NULL) { - if (size != NULL) *size = 0; - return NULL; - } - else { - if (size != NULL) *size = segment->segment_size; - return segment; - } - mi_assert_expensive(page == NULL || mi_segment_is_valid(_mi_page_segment(page),tld)); - mi_assert_internal(page == NULL || (mi_segment_page_size(_mi_page_segment(page)) - (MI_SECURE == 0 ? 0 : _mi_os_page_size())) >= block_size); - mi_reset_delayed(tld); - mi_assert_internal(page == NULL || mi_page_not_in_queue(page, tld)); - return page; -} -*/ diff --git a/test/test-stress.c b/test/test-stress.c index 599c6c2e..24dcf00f 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -258,7 +258,7 @@ int main(int argc, char** argv) { #ifdef HEAP_WALK mi_option_enable(mi_option_visit_abandoned); #endif - #ifndef NDBEBUG + #ifndef NDEBUG mi_option_set(mi_option_arena_reserve, 32 * 1024 /* in kib = 32MiB */); #endif #ifndef USE_STD_MALLOC From e8f4bdd1ea568b723da5c8362d5cdb092fa4cbc2 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 14:59:37 -0700 Subject: [PATCH 015/305] fix cast; make segment map static --- src/segment-map.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/segment-map.c b/src/segment-map.c index be461d7e..8927a8bd 100644 --- a/src/segment-map.c +++ b/src/segment-map.c @@ -39,8 +39,7 @@ typedef struct mi_segmap_part_s { } mi_segmap_part_t; // Allocate parts on-demand to reduce .bss footprint -_Atomic(mi_segmap_part_t*) mi_segment_map[MI_SEGMENT_MAP_MAX_PARTS]; // = { NULL, .. } - +static _Atomic(mi_segmap_part_t*) mi_segment_map[MI_SEGMENT_MAP_MAX_PARTS]; // = { NULL, .. } static mi_segmap_part_t* mi_segment_map_index_of(const mi_segment_t* segment, bool create_on_demand, size_t* idx, size_t* bitidx) { // note: segment can be invalid or NULL. @@ -50,7 +49,7 @@ static mi_segmap_part_t* mi_segment_map_index_of(const mi_segment_t* segment, bo if ((uintptr_t)segment >= MI_SEGMENT_MAP_MAX_ADDRESS) return NULL; const uintptr_t segindex = ((uintptr_t)segment) / MI_SEGMENT_MAP_PART_SPAN; if (segindex >= MI_SEGMENT_MAP_MAX_PARTS) return NULL; - mi_segmap_part_t* part = mi_atomic_load_ptr_relaxed(mi_segmap_part_t*, &mi_segment_map[segindex]); + mi_segmap_part_t* part = mi_atomic_load_ptr_relaxed(mi_segmap_part_t, &mi_segment_map[segindex]); // allocate on demand to reduce .bss footprint if (part == NULL) { From f87ec74bb3103f68f4e8b6f34098e09cbd1b306d Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 15:10:17 -0700 Subject: [PATCH 016/305] reduce delayed output from redirection to 16KiB to reduce the .bss size --- src/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.c b/src/options.c index 32fa212b..462a7c71 100644 --- a/src/options.c +++ b/src/options.c @@ -200,7 +200,7 @@ static void mi_cdecl mi_out_stderr(const char* msg, void* arg) { // an output function is registered it is called immediately with // the output up to that point. #ifndef MI_MAX_DELAY_OUTPUT -#define MI_MAX_DELAY_OUTPUT ((size_t)(32*1024)) +#define MI_MAX_DELAY_OUTPUT ((size_t)(16*1024)) #endif static char out_buf[MI_MAX_DELAY_OUTPUT+1]; static _Atomic(size_t) out_len; From f9076a5cf83a4326cee17e70c0b11baa056a5e57 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 15:54:49 -0700 Subject: [PATCH 017/305] use EFAULT if a target heap tag cannot be found on reclaim --- src/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index 8fccf18e..e484a38f 100644 --- a/src/segment.c +++ b/src/segment.c @@ -905,7 +905,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, mi_heap_t* target_heap = _mi_heap_by_tag(heap, page->heap_tag); // allow custom heaps to separate objects if (target_heap == NULL) { target_heap = heap; - _mi_error_message(EINVAL, "page with tag %u cannot be reclaimed by a heap with the same tag (using heap tag %u instead)\n", page->heap_tag, heap->tag ); + _mi_error_message(EFAULT, "page with tag %u cannot be reclaimed by a heap with the same tag (using heap tag %u instead)\n", page->heap_tag, heap->tag ); } // associate the heap with this page, and allow heap thread delayed free again. mi_page_set_heap(page, target_heap); From e4c8f42bb6b4169ff329393621474612f4cce4f5 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 2 Jun 2024 16:10:08 -0700 Subject: [PATCH 018/305] always include sys/prctl.h on linux to disable THP if large_os_pages are not enabled --- src/prim/unix/prim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 93785b22..63a36f25 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -30,9 +30,9 @@ terms of the MIT license. A copy of the license can be found in the file #if defined(__linux__) #include - #if defined(MI_NO_THP) - #include - #endif + //#if defined(MI_NO_THP) + #include // THP disable + //#endif #if defined(__GLIBC__) #include // linux mmap flags #else From 768872e4e0bdec168fe82358614e4dfbfde1c779 Mon Sep 17 00:00:00 2001 From: Daan Date: Sun, 2 Jun 2024 16:24:13 -0700 Subject: [PATCH 019/305] typo in stress test --- test/test-stress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-stress.c b/test/test-stress.c index 24dcf00f..544c2838 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -138,7 +138,7 @@ static bool visit_blocks(const mi_heap_t* heap, const mi_heap_area_t* area, void (void)(heap); (void)(area); size_t* total = (size_t*)arg; if (block != NULL) { - total += block_size; + *total += block_size; } return true; } From 6b15342709241f278256d0392926752b130b9d5e Mon Sep 17 00:00:00 2001 From: Daan Date: Sun, 2 Jun 2024 16:41:07 -0700 Subject: [PATCH 020/305] fix pthread initalization of mutexes --- include/mimalloc/atomic.h | 7 ++++--- src/arena.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index d2711019..3a0d4892 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -441,13 +441,13 @@ static inline void mi_lock_release(mi_lock_t* lock) { pthread_mutex_unlock(lock); } static inline void mi_lock_init(mi_lock_t* lock) { - (void)(lock); + pthread_mutex_init(lock, NULL); } static inline void mi_lock_done(mi_lock_t* lock) { - (void)(lock); + pthread_mutex_destroy(lock); } - +/* #elif defined(__cplusplus) #include @@ -469,6 +469,7 @@ static inline void mi_lock_init(mi_lock_t* lock) { static inline void mi_lock_done(mi_lock_t* lock) { (void)(lock); } +*/ #else diff --git a/src/arena.c b/src/arena.c index 24f1299c..7d7eb089 100644 --- a/src/arena.c +++ b/src/arena.c @@ -863,7 +863,7 @@ void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_aren current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); current->end = current->start + max_arena; } - mi_assert_internal(current->start < max_arena); + mi_assert_internal(current->start <= max_arena); } static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_subproc_t* subproc, mi_bitmap_index_t bitmap_idx) { From 58fbb679637b2e3ef3e8fbfcbf78aa7b4542cc93 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 09:25:53 -0700 Subject: [PATCH 021/305] fix c++ compilation --- include/mimalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 0b4b182c..d002ab79 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -303,7 +303,7 @@ mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int // Experimental: create a new heap with a specified heap tag. Set `allow_destroy` to false to allow the thread // to reclaim abandoned memory (with a compatible heap_tag and arena_id) but in that case `mi_heap_destroy` will // fall back to `mi_heap_delete`. -mi_decl_export mi_decl_nodiscard mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); +mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); // deprecated mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; From 84334e480a9aaa1d2d34817cf4d27939773dbe15 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 09:54:41 -0700 Subject: [PATCH 022/305] decrease meta allocation zone to 4k (to reduce .bss) --- src/arena.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arena.c b/src/arena.c index 7d7eb089..554df344 100644 --- a/src/arena.c +++ b/src/arena.c @@ -137,10 +137,10 @@ static bool mi_arena_memid_indices(mi_memid_t memid, size_t* arena_index, mi_bit /* ----------------------------------------------------------- Special static area for mimalloc internal structures - to avoid OS calls (for example, for the arena metadata) + to avoid OS calls (for example, for the arena metadata (~= 256b)) ----------------------------------------------------------- */ -#define MI_ARENA_STATIC_MAX (MI_INTPTR_SIZE*MI_KiB) // 8 KiB on 64-bit +#define MI_ARENA_STATIC_MAX ((MI_INTPTR_SIZE/2)*MI_KiB) // 4 KiB on 64-bit static mi_decl_cache_align uint8_t mi_arena_static[MI_ARENA_STATIC_MAX]; // must be cache aligned, see issue #895 static mi_decl_cache_align _Atomic(size_t) mi_arena_static_top; From f17ddc33952e52396d9c91e0d51dd0febe855470 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 09:55:02 -0700 Subject: [PATCH 023/305] increase thread data cache to32 entries --- src/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.c b/src/init.c index f2d99d9e..e84d3ed8 100644 --- a/src/init.c +++ b/src/init.c @@ -249,7 +249,7 @@ typedef struct mi_thread_data_s { // destroy many OS threads, this may causes too much overhead // per thread so we maintain a small cache of recently freed metadata. -#define TD_CACHE_SIZE (16) +#define TD_CACHE_SIZE (32) static _Atomic(mi_thread_data_t*) td_cache[TD_CACHE_SIZE]; static mi_thread_data_t* mi_thread_data_zalloc(void) { From 2ed97f3ebbfab4fc0493178e498885a7aff9e300 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 09:55:11 -0700 Subject: [PATCH 024/305] whitespace --- include/mimalloc.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index d002ab79..a315370e 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -294,11 +294,11 @@ mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t a typedef void* mi_subproc_id_t; mi_decl_export mi_subproc_id_t mi_subproc_main(void); mi_decl_export mi_subproc_id_t mi_subproc_new(void); -mi_decl_export void mi_subproc_delete(mi_subproc_id_t subproc); -mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t subproc); // this should be called right after a thread is created (and no allocation has taken place yet) +mi_decl_export void mi_subproc_delete(mi_subproc_id_t subproc); +mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t subproc); // this should be called right after a thread is created (and no allocation has taken place yet) // Experimental: visit abandoned heap areas (from threads that have been terminated) -mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); +mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); // Experimental: create a new heap with a specified heap tag. Set `allow_destroy` to false to allow the thread // to reclaim abandoned memory (with a compatible heap_tag and arena_id) but in that case `mi_heap_destroy` will @@ -306,7 +306,7 @@ mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); // deprecated -mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; +mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; // ------------------------------------------------------ From 7e23576efa9ea9738acc4a2aea701bb39b71c732 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 09:57:03 -0700 Subject: [PATCH 025/305] remove old mi_abandoned_await_readers --- include/mimalloc/internal.h | 1 - src/segment.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 0b6cf056..71cfad41 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -157,7 +157,6 @@ void _mi_segment_huge_page_reset(mi_segment_t* segment, mi_page_t* page, m void _mi_segments_collect(bool force, 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); bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment); bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); diff --git a/src/segment.c b/src/segment.c index e484a38f..ca334ea4 100644 --- a/src/segment.c +++ b/src/segment.c @@ -509,7 +509,6 @@ static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_se MI_UNUSED(fully_committed); mi_assert_internal((fully_committed && committed_size == segment_size) || (!fully_committed && committed_size < segment_size)); - _mi_abandoned_await_readers(); // prevent ABA issue if concurrent readers try to access our memory (that might be purged) _mi_arena_free(segment, segment_size, committed_size, segment->memid, tld->stats); } @@ -784,11 +783,6 @@ by scanning the arena memory (segments outside arena memoryare only reclaimed by a free). ----------------------------------------------------------- */ -// legacy: Wait until there are no more pending reads on segments that used to be in the abandoned list -void _mi_abandoned_await_readers(void) { - // nothing needed -} - /* ----------------------------------------------------------- Abandon segment/page ----------------------------------------------------------- */ From 1a9cf7bce26dea6843e2939a5af62b3248dfa9bb Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 11:43:35 -0700 Subject: [PATCH 026/305] switch between OS and arena allocation in stress test --- test/test-stress.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-stress.c b/test/test-stress.c index 544c2838..5cadb8c6 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -212,6 +212,10 @@ static void test_stress(void) { uintptr_t r = rand(); for (int n = 0; n < ITER; n++) { run_os_threads(THREADS, &stress); + #ifndef NDEBUG + // switch between arena and OS allocation for testing + mi_option_set_enabled(mi_option_disallow_arena_alloc, (n%2)==1); + #endif #ifdef HEAP_WALK size_t total = 0; mi_abandoned_visit_blocks(mi_subproc_main(), -1, true, visit_blocks, &total); From f02a0b354127b3d361beb88bd23c68f7028f5fc1 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 14:05:57 -0700 Subject: [PATCH 027/305] more aggressive reclaim from free for OS blocks --- src/arena.c | 50 +++++++++++++++++++++++++++------------------- src/segment.c | 6 +++++- test/test-stress.c | 2 +- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/arena.c b/src/arena.c index 554df344..52cfa3f1 100644 --- a/src/arena.c +++ b/src/arena.c @@ -764,7 +764,7 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) if (mi_option_is_enabled(mi_option_visit_abandoned)) { has_lock = mi_lock_try_acquire(&segment->subproc->abandoned_os_lock); if (!has_lock) { - return false; // failed to acquire the lock, we just give up + return false; // failed to acquire the lock, we just give up } } // abandon it, but we need to still claim it atomically -- we use the thread_id for that. @@ -777,9 +777,10 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) // and remove from the abandoned os list (if needed) mi_segment_t* const next = segment->abandoned_os_next; mi_segment_t* const prev = segment->abandoned_os_prev; + mi_assert_internal((next == NULL && prev == NULL) || mi_option_is_enabled(mi_option_visit_abandoned)); if (prev != NULL) { prev->abandoned_os_next = next; } - else { segment->subproc->abandoned_os_list = next; } - if (next != NULL) { next->abandoned_os_prev = prev; } + else { segment->subproc->abandoned_os_list = next; } + if (next != NULL) { next->abandoned_os_prev = prev; } segment->abandoned_os_next = NULL; segment->abandoned_os_prev = NULL; } @@ -809,32 +810,37 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) // clears the thread_id. void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) { - mi_atomic_store_release(&segment->thread_id, 0); mi_assert_internal(segment->used == segment->abandoned); if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { // not in an arena; count it as abandoned and return (these can be reclaimed on a `free`) - mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); // if abandoned visiting is allowed, we need to take a lock on the abandoned os list to insert it + bool has_lock = false; if (mi_option_is_enabled(mi_option_visit_abandoned)) { - if (!mi_lock_acquire(&segment->subproc->abandoned_os_lock)) { + has_lock = mi_lock_acquire(&segment->subproc->abandoned_os_lock); + if (!has_lock) { _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); - } - else { - // push on the front of the list - mi_segment_t* next = segment->subproc->abandoned_os_list; - mi_assert_internal(next == NULL || next->abandoned_os_prev == NULL); - mi_assert_internal(segment->abandoned_os_prev == NULL); - mi_assert_internal(segment->abandoned_os_next == NULL); - if (next != NULL) { next->abandoned_os_prev = segment; } - segment->abandoned_os_prev = NULL; - segment->abandoned_os_next = next; - segment->subproc->abandoned_os_list = segment; - mi_lock_release(&segment->subproc->abandoned_os_lock); - } + } + } + mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned (inside the lock) + mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); + if (has_lock) { + // push on the front of the list + mi_segment_t* next = segment->subproc->abandoned_os_list; + mi_assert_internal(next == NULL || next->abandoned_os_prev == NULL); + mi_assert_internal(segment->abandoned_os_prev == NULL); + mi_assert_internal(segment->abandoned_os_next == NULL); + if (next != NULL) { next->abandoned_os_prev = segment; } + segment->abandoned_os_prev = NULL; + segment->abandoned_os_next = next; + segment->subproc->abandoned_os_list = segment; + // and release the lock + mi_lock_release(&segment->subproc->abandoned_os_lock); } return; } + // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap + mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned size_t arena_idx; size_t bitmap_idx; mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); @@ -842,8 +848,10 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); mi_assert_internal(arena != NULL); const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } - mi_assert_internal(was_unmarked); + if (was_unmarked) { + // note: it could be unmarked if someone reclaimed in between the thread_id=0 and the claim + mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); + } mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); } diff --git a/src/segment.c b/src/segment.c index ca334ea4..b55f1ea8 100644 --- a/src/segment.c +++ b/src/segment.c @@ -938,6 +938,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, } } + // attempt to reclaim a particular segment (called from multi threaded free `alloc.c:mi_free_block_mt`) bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { if (mi_atomic_load_relaxed(&segment->thread_id) != 0) return false; // it is not abandoned @@ -945,7 +946,10 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { if (!_mi_heap_memid_is_suitable(heap,segment->memid)) return false; // don't reclaim between exclusive and non-exclusive arena's // don't reclaim more from a `free` call than half the current segments // this is to prevent a pure free-ing thread to start owning too many segments - if (heap->tld->segments.reclaim_count * 2 > heap->tld->segments.count) return false; + // (but not for out-of-arena segments as that is the main way to be reclaimed for those) + if (segment->memid.memkind == MI_MEM_ARENA && heap->tld->segments.reclaim_count * 2 > heap->tld->segments.count) { + return false; + } if (_mi_arena_segment_clear_abandoned(segment)) { // atomically unabandon mi_segment_t* res = mi_segment_reclaim(segment, heap, 0, NULL, &heap->tld->segments); mi_assert_internal(res == segment); diff --git a/test/test-stress.c b/test/test-stress.c index 5cadb8c6..675c54bc 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -306,8 +306,8 @@ int main(int argc, char** argv) { #ifndef USE_STD_MALLOC #ifndef NDEBUG - // mi_collect(true); mi_debug_show_arenas(true,true,true); + mi_collect(true); #endif mi_stats_print(NULL); #endif From a04905c88b113b82302f27a207e742bdee9fa375 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 15:20:35 -0700 Subject: [PATCH 028/305] revisit atomic reclaim for abandoned segments --- src/arena.c | 84 ++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/src/arena.c b/src/arena.c index 52cfa3f1..020743a1 100644 --- a/src/arena.c +++ b/src/arena.c @@ -758,35 +758,38 @@ bool _mi_arena_contains(const void* p) { bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) { if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - // not in an arena - // if abandoned visiting is allowed, we need to take a lock on the abandoned os list - bool has_lock = false; - if (mi_option_is_enabled(mi_option_visit_abandoned)) { - has_lock = mi_lock_try_acquire(&segment->subproc->abandoned_os_lock); - if (!has_lock) { - return false; // failed to acquire the lock, we just give up - } + // not in an arena, remove from list of abandoned os segments + mi_subproc_t* const subproc = segment->subproc; + if (!mi_lock_try_acquire(&subproc->abandoned_os_lock)) { + return false; // failed to acquire the lock, we just give up } - // abandon it, but we need to still claim it atomically -- we use the thread_id for that. + // remove atomically from the abandoned os list (if possible!) bool reclaimed = false; - size_t expected = 0; - if (mi_atomic_cas_strong_acq_rel(&segment->thread_id, &expected, _mi_thread_id())) { - // reclaim - mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); - reclaimed = true; - // and remove from the abandoned os list (if needed) - mi_segment_t* const next = segment->abandoned_os_next; - mi_segment_t* const prev = segment->abandoned_os_prev; - mi_assert_internal((next == NULL && prev == NULL) || mi_option_is_enabled(mi_option_visit_abandoned)); + mi_segment_t* const next = segment->abandoned_os_next; + mi_segment_t* const prev = segment->abandoned_os_prev; + if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { + #if MI_DEBUG>3 + // find ourselves in the abandoned list + bool found = false; + for (mi_segment_t* current = subproc->abandoned_os_list; !found && current != NULL; current = current->abandoned_os_next) { + if (current == segment) { found = true; } + } + mi_assert_internal(found); + #endif + // remove (atomically) from the list and reclaim if (prev != NULL) { prev->abandoned_os_next = next; } - else { segment->subproc->abandoned_os_list = next; } + else { subproc->abandoned_os_list = next; } if (next != NULL) { next->abandoned_os_prev = prev; } segment->abandoned_os_next = NULL; segment->abandoned_os_prev = NULL; + mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); + mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + reclaimed = true; } - if (has_lock) { mi_lock_release(&segment->subproc->abandoned_os_lock); } - return reclaimed; + mi_lock_release(&segment->subproc->abandoned_os_lock); + return reclaimed; } + // arena segment: use the blocks_abandoned bitmap. size_t arena_idx; size_t bitmap_idx; @@ -794,9 +797,10 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) mi_assert_internal(arena_idx < MI_MAX_ARENAS); mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); mi_assert_internal(arena != NULL); + // reclaim atomically bool was_marked = _mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx); if (was_marked) { - mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); + mi_assert_internal(mi_atomic_load_acquire(&segment->thread_id) == 0); mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); } @@ -811,19 +815,15 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) { mi_assert_internal(segment->used == segment->abandoned); + mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned for multi-thread free's if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - // not in an arena; count it as abandoned and return (these can be reclaimed on a `free`) - // if abandoned visiting is allowed, we need to take a lock on the abandoned os list to insert it - bool has_lock = false; - if (mi_option_is_enabled(mi_option_visit_abandoned)) { - has_lock = mi_lock_acquire(&segment->subproc->abandoned_os_lock); - if (!has_lock) { - _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); - } - } - mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned (inside the lock) - mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); - if (has_lock) { + // not in an arena; we use a list of abandoned segments + if (!mi_lock_acquire(&segment->subproc->abandoned_os_lock)) { + _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); + // we can continue but cannot visit/reclaim such blocks.. + } + else { + mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); // push on the front of the list mi_segment_t* next = segment->subproc->abandoned_os_list; mi_assert_internal(next == NULL || next->abandoned_os_prev == NULL); @@ -840,18 +840,16 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) } // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap - mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned size_t arena_idx; size_t bitmap_idx; mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); mi_assert_internal(arena_idx < MI_MAX_ARENAS); mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); mi_assert_internal(arena != NULL); + // set abandonment atomically const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - if (was_unmarked) { - // note: it could be unmarked if someone reclaimed in between the thread_id=0 and the claim - mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); - } + if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } + mi_assert_internal(was_unmarked); mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); } @@ -881,11 +879,11 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_s mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); // check that the segment belongs to our sub-process - // note: this is the reason we need a lock in the case abandoned visiting is enabled. - // without the lock an abandoned visit may otherwise fail to visit all segments. - // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the arena lock. + // note: this is the reason we need the `abandoned_visit` lock in the case abandoned visiting is enabled. + // without the lock an abandoned visit may otherwise fail to visit all abandoned segments in the sub-process. + // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the `abandoned_visit` lock. if (segment->subproc != subproc) { - // it is from another subprocess, re-mark it and continue searching + // it is from another sub-process, re-mark it and continue searching const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); mi_assert_internal(was_zero); MI_UNUSED(was_zero); return NULL; From 3333f776f9536e1a67cd260afae6473e2b68366e Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 15:37:05 -0700 Subject: [PATCH 029/305] push os abandoned blocks at the tail end --- include/mimalloc/types.h | 10 ++-- src/arena.c | 123 ++++++++++++++++++++++----------------- 2 files changed, 76 insertions(+), 57 deletions(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 2506d454..9c68e541 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -611,10 +611,12 @@ void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); // ------------------------------------------------------ struct mi_subproc_s { - _Atomic(size_t) abandoned_count; // count of abandoned segments for this sup-process - mi_lock_t abandoned_os_lock; // lock for the abandoned segments outside of arena's - mi_segment_t* abandoned_os_list; // doubly-linked list of abandoned segments outside of arena's (in OS allocated memory) - mi_memid_t memid; // provenance + _Atomic(size_t) abandoned_count; // count of abandoned segments for this sub-process + _Atomic(size_t) abandoned_os_list_count; // count of abandoned segments in the os-list + mi_lock_t abandoned_os_lock; // lock for the abandoned segments outside of arena's + mi_segment_t* abandoned_os_list; // doubly-linked list of abandoned segments outside of arena's (in OS allocated memory) + mi_segment_t* abandoned_os_list_tail; // the tail-end of the list + mi_memid_t memid; // provenance of this memory block }; // ------------------------------------------------------ diff --git a/src/arena.c b/src/arena.c index 020743a1..05872bfb 100644 --- a/src/arena.c +++ b/src/arena.c @@ -753,43 +753,49 @@ bool _mi_arena_contains(const void* p) { the arena bitmaps. ----------------------------------------------------------- */ +// reclaim a specific OS abandoned segment; `true` on success. +// sets the thread_id. +static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment) { + mi_assert(segment->memid.memkind != MI_MEM_ARENA); + // not in an arena, remove from list of abandoned os segments + mi_subproc_t* const subproc = segment->subproc; + if (!mi_lock_try_acquire(&subproc->abandoned_os_lock)) { + return false; // failed to acquire the lock, we just give up + } + // remove atomically from the abandoned os list (if possible!) + bool reclaimed = false; + mi_segment_t* const next = segment->abandoned_os_next; + mi_segment_t* const prev = segment->abandoned_os_prev; + if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { + #if MI_DEBUG>3 + // find ourselves in the abandoned list + bool found = false; + for (mi_segment_t* current = subproc->abandoned_os_list; !found && current != NULL; current = current->abandoned_os_next) { + if (current == segment) { found = true; } + } + mi_assert_internal(found); + #endif + // remove (atomically) from the list and reclaim + if (prev != NULL) { prev->abandoned_os_next = next; } + else { subproc->abandoned_os_list = next; } + if (next != NULL) { next->abandoned_os_prev = prev; } + else { subproc->abandoned_os_list_tail = prev; } + segment->abandoned_os_next = NULL; + segment->abandoned_os_prev = NULL; + mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); + mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + reclaimed = true; + } + mi_lock_release(&segment->subproc->abandoned_os_lock); + return reclaimed; +} + // reclaim a specific abandoned segment; `true` on success. // sets the thread_id. -bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) -{ +bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) { if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - // not in an arena, remove from list of abandoned os segments - mi_subproc_t* const subproc = segment->subproc; - if (!mi_lock_try_acquire(&subproc->abandoned_os_lock)) { - return false; // failed to acquire the lock, we just give up - } - // remove atomically from the abandoned os list (if possible!) - bool reclaimed = false; - mi_segment_t* const next = segment->abandoned_os_next; - mi_segment_t* const prev = segment->abandoned_os_prev; - if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { - #if MI_DEBUG>3 - // find ourselves in the abandoned list - bool found = false; - for (mi_segment_t* current = subproc->abandoned_os_list; !found && current != NULL; current = current->abandoned_os_next) { - if (current == segment) { found = true; } - } - mi_assert_internal(found); - #endif - // remove (atomically) from the list and reclaim - if (prev != NULL) { prev->abandoned_os_next = next; } - else { subproc->abandoned_os_list = next; } - if (next != NULL) { next->abandoned_os_prev = prev; } - segment->abandoned_os_next = NULL; - segment->abandoned_os_prev = NULL; - mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); - mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); - reclaimed = true; - } - mi_lock_release(&segment->subproc->abandoned_os_lock); - return reclaimed; + return mi_arena_segment_os_clear_abandoned(segment); } - // arena segment: use the blocks_abandoned bitmap. size_t arena_idx; size_t bitmap_idx; @@ -810,6 +816,34 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) return was_marked; } + +// mark a specific OS segment as abandoned +static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { + mi_assert(segment->memid.memkind != MI_MEM_ARENA); + // not in an arena; we use a list of abandoned segments + mi_subproc_t* const subproc = segment->subproc; + if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { + _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); + // we can continue but cannot visit/reclaim such blocks.. + } + else { + mi_atomic_increment_relaxed(&subproc->abandoned_count); + // push on the tail of the list (important for the visitor) + mi_segment_t* prev = subproc->abandoned_os_list_tail; + mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL); + mi_assert_internal(segment->abandoned_os_prev == NULL); + mi_assert_internal(segment->abandoned_os_next == NULL); + if (prev != NULL) { prev->abandoned_os_next = segment; } + else { subproc->abandoned_os_list = segment; } + subproc->abandoned_os_list_tail = segment; + segment->abandoned_os_prev = prev; + segment->abandoned_os_next = NULL; + // and release the lock + mi_lock_release(&subproc->abandoned_os_lock); + } + return; +} + // mark a specific segment as abandoned // clears the thread_id. void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) @@ -817,28 +851,9 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) mi_assert_internal(segment->used == segment->abandoned); mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned for multi-thread free's if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - // not in an arena; we use a list of abandoned segments - if (!mi_lock_acquire(&segment->subproc->abandoned_os_lock)) { - _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); - // we can continue but cannot visit/reclaim such blocks.. - } - else { - mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); - // push on the front of the list - mi_segment_t* next = segment->subproc->abandoned_os_list; - mi_assert_internal(next == NULL || next->abandoned_os_prev == NULL); - mi_assert_internal(segment->abandoned_os_prev == NULL); - mi_assert_internal(segment->abandoned_os_next == NULL); - if (next != NULL) { next->abandoned_os_prev = segment; } - segment->abandoned_os_prev = NULL; - segment->abandoned_os_next = next; - segment->subproc->abandoned_os_list = segment; - // and release the lock - mi_lock_release(&segment->subproc->abandoned_os_lock); - } + mi_arena_segment_os_mark_abandoned(segment); return; } - // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap size_t arena_idx; size_t bitmap_idx; @@ -853,6 +868,8 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); } + + // start a cursor at a randomized arena void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current) { mi_assert_internal(heap == NULL || heap->tld->segments.subproc == subproc); From 00dacba91f7c0420833190f033c08d241b68fdce Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 15:44:25 -0700 Subject: [PATCH 030/305] maintain count of the abandoned os list --- src/arena.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/arena.c b/src/arena.c index 05872bfb..afb2db33 100644 --- a/src/arena.c +++ b/src/arena.c @@ -768,12 +768,15 @@ static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment) { mi_segment_t* const prev = segment->abandoned_os_prev; if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { #if MI_DEBUG>3 - // find ourselves in the abandoned list + // find ourselves in the abandoned list (and check the count) bool found = false; - for (mi_segment_t* current = subproc->abandoned_os_list; !found && current != NULL; current = current->abandoned_os_next) { + size_t count = 0; + for (mi_segment_t* current = subproc->abandoned_os_list; current != NULL; current = current->abandoned_os_next) { if (current == segment) { found = true; } + count++; } mi_assert_internal(found); + mi_assert_internal(count == mi_atomic_load_relaxed(&subproc->abandoned_os_list_count)); #endif // remove (atomically) from the list and reclaim if (prev != NULL) { prev->abandoned_os_next = next; } @@ -782,7 +785,8 @@ static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment) { else { subproc->abandoned_os_list_tail = prev; } segment->abandoned_os_next = NULL; segment->abandoned_os_prev = NULL; - mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); + mi_atomic_decrement_relaxed(&subproc->abandoned_count); + mi_atomic_decrement_relaxed(&subproc->abandoned_os_list_count); mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); reclaimed = true; } @@ -827,8 +831,7 @@ static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { // we can continue but cannot visit/reclaim such blocks.. } else { - mi_atomic_increment_relaxed(&subproc->abandoned_count); - // push on the tail of the list (important for the visitor) + // push on the tail of the list (important for the visitor) mi_segment_t* prev = subproc->abandoned_os_list_tail; mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL); mi_assert_internal(segment->abandoned_os_prev == NULL); @@ -838,6 +841,8 @@ static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { subproc->abandoned_os_list_tail = segment; segment->abandoned_os_prev = prev; segment->abandoned_os_next = NULL; + mi_atomic_increment_relaxed(&subproc->abandoned_os_list_count); + mi_atomic_increment_relaxed(&subproc->abandoned_count); // and release the lock mi_lock_release(&subproc->abandoned_os_lock); } From 96b69d7ef63760629114b97aa47385d898ec4b7e Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 17:28:14 -0700 Subject: [PATCH 031/305] fix leak where OS abandoned blocks were not always reclaimed --- include/mimalloc/internal.h | 16 +- include/mimalloc/types.h | 3 +- src/arena.c | 610 ++++++++++++++++++++---------------- src/init.c | 3 + src/segment.c | 20 +- 5 files changed, 361 insertions(+), 291 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 71cfad41..6e87d5ae 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -131,13 +131,17 @@ void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid); void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size); typedef struct mi_arena_field_cursor_s { // abstract struct - size_t start; - size_t end; - size_t bitmap_idx; - mi_subproc_t* subproc; + size_t os_list_count; // max entries to visit in the OS abandoned list + size_t start; // start arena idx (may need to be wrapped) + size_t end; // end arena idx (exclusive, may need to be wrapped) + size_t bitmap_idx; // current bit idx for an arena + mi_subproc_t* subproc; // only visit blocks in this sub-process + bool visit_all; // ensure all abandoned blocks are seen (blocking) + bool hold_visit_lock; // if the subproc->abandoned_os_visit_lock is held } mi_arena_field_cursor_t; -void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current); -mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous, bool visit_all); +void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, bool visit_all, mi_arena_field_cursor_t* current); +mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous); +void _mi_arena_field_cursor_done(mi_arena_field_cursor_t* current); // "segment-map.c" void _mi_segment_map_allocated_at(const mi_segment_t* segment); diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 9c68e541..2fc83a30 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -613,7 +613,8 @@ void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); struct mi_subproc_s { _Atomic(size_t) abandoned_count; // count of abandoned segments for this sub-process _Atomic(size_t) abandoned_os_list_count; // count of abandoned segments in the os-list - mi_lock_t abandoned_os_lock; // lock for the abandoned segments outside of arena's + mi_lock_t abandoned_os_lock; // lock for the abandoned os segment list (outside of arena's) (this lock protect list operations) + mi_lock_t abandoned_os_visit_lock; // ensure only one thread per subproc visits the abandoned os list mi_segment_t* abandoned_os_list; // doubly-linked list of abandoned segments outside of arena's (in OS allocated memory) mi_segment_t* abandoned_os_list_tail; // the tail-end of the list mi_memid_t memid; // provenance of this memory block diff --git a/src/arena.c b/src/arena.c index afb2db33..77f42825 100644 --- a/src/arena.c +++ b/src/arena.c @@ -743,283 +743,6 @@ bool _mi_arena_contains(const void* p) { return false; } -/* ----------------------------------------------------------- - Abandoned blocks/segments. - This is used to atomically abandon/reclaim segments - (and crosses the arena API but it is convenient to have here). - Abandoned segments still have live blocks; they get reclaimed - when a thread frees a block in it, or when a thread needs a fresh - segment; these threads scan the abandoned segments through - the arena bitmaps. ------------------------------------------------------------ */ - -// reclaim a specific OS abandoned segment; `true` on success. -// sets the thread_id. -static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment) { - mi_assert(segment->memid.memkind != MI_MEM_ARENA); - // not in an arena, remove from list of abandoned os segments - mi_subproc_t* const subproc = segment->subproc; - if (!mi_lock_try_acquire(&subproc->abandoned_os_lock)) { - return false; // failed to acquire the lock, we just give up - } - // remove atomically from the abandoned os list (if possible!) - bool reclaimed = false; - mi_segment_t* const next = segment->abandoned_os_next; - mi_segment_t* const prev = segment->abandoned_os_prev; - if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { - #if MI_DEBUG>3 - // find ourselves in the abandoned list (and check the count) - bool found = false; - size_t count = 0; - for (mi_segment_t* current = subproc->abandoned_os_list; current != NULL; current = current->abandoned_os_next) { - if (current == segment) { found = true; } - count++; - } - mi_assert_internal(found); - mi_assert_internal(count == mi_atomic_load_relaxed(&subproc->abandoned_os_list_count)); - #endif - // remove (atomically) from the list and reclaim - if (prev != NULL) { prev->abandoned_os_next = next; } - else { subproc->abandoned_os_list = next; } - if (next != NULL) { next->abandoned_os_prev = prev; } - else { subproc->abandoned_os_list_tail = prev; } - segment->abandoned_os_next = NULL; - segment->abandoned_os_prev = NULL; - mi_atomic_decrement_relaxed(&subproc->abandoned_count); - mi_atomic_decrement_relaxed(&subproc->abandoned_os_list_count); - mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); - reclaimed = true; - } - mi_lock_release(&segment->subproc->abandoned_os_lock); - return reclaimed; -} - -// reclaim a specific abandoned segment; `true` on success. -// sets the thread_id. -bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment ) { - if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - return mi_arena_segment_os_clear_abandoned(segment); - } - // arena segment: use the blocks_abandoned bitmap. - size_t arena_idx; - size_t bitmap_idx; - mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); - mi_assert_internal(arena_idx < MI_MAX_ARENAS); - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); - mi_assert_internal(arena != NULL); - // reclaim atomically - bool was_marked = _mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx); - if (was_marked) { - mi_assert_internal(mi_atomic_load_acquire(&segment->thread_id) == 0); - mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); - mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); - } - // mi_assert_internal(was_marked); - mi_assert_internal(!was_marked || _mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); - //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); - return was_marked; -} - - -// mark a specific OS segment as abandoned -static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { - mi_assert(segment->memid.memkind != MI_MEM_ARENA); - // not in an arena; we use a list of abandoned segments - mi_subproc_t* const subproc = segment->subproc; - if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { - _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); - // we can continue but cannot visit/reclaim such blocks.. - } - else { - // push on the tail of the list (important for the visitor) - mi_segment_t* prev = subproc->abandoned_os_list_tail; - mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL); - mi_assert_internal(segment->abandoned_os_prev == NULL); - mi_assert_internal(segment->abandoned_os_next == NULL); - if (prev != NULL) { prev->abandoned_os_next = segment; } - else { subproc->abandoned_os_list = segment; } - subproc->abandoned_os_list_tail = segment; - segment->abandoned_os_prev = prev; - segment->abandoned_os_next = NULL; - mi_atomic_increment_relaxed(&subproc->abandoned_os_list_count); - mi_atomic_increment_relaxed(&subproc->abandoned_count); - // and release the lock - mi_lock_release(&subproc->abandoned_os_lock); - } - return; -} - -// mark a specific segment as abandoned -// clears the thread_id. -void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) -{ - mi_assert_internal(segment->used == segment->abandoned); - mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned for multi-thread free's - if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - mi_arena_segment_os_mark_abandoned(segment); - return; - } - // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap - size_t arena_idx; - size_t bitmap_idx; - mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); - mi_assert_internal(arena_idx < MI_MAX_ARENAS); - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); - mi_assert_internal(arena != NULL); - // set abandonment atomically - const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } - mi_assert_internal(was_unmarked); - mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); -} - - - -// start a cursor at a randomized arena -void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, mi_arena_field_cursor_t* current) { - mi_assert_internal(heap == NULL || heap->tld->segments.subproc == subproc); - current->bitmap_idx = 0; - current->subproc = subproc; - const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); - if (heap != NULL && heap->arena_id != _mi_arena_id_none()) { - // for a heap that is bound to one arena, only visit that arena - current->start = mi_arena_id_index(heap->arena_id); - current->end = current->start + 1; - } - else { - // otherwise visit all starting at a random location - current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); - current->end = current->start + max_arena; - } - mi_assert_internal(current->start <= max_arena); -} - -static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_subproc_t* subproc, mi_bitmap_index_t bitmap_idx) { - // try to reclaim an abandoned segment in the arena atomically - if (!_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) return NULL; - mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); - mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); - mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); - // check that the segment belongs to our sub-process - // note: this is the reason we need the `abandoned_visit` lock in the case abandoned visiting is enabled. - // without the lock an abandoned visit may otherwise fail to visit all abandoned segments in the sub-process. - // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the `abandoned_visit` lock. - if (segment->subproc != subproc) { - // it is from another sub-process, re-mark it and continue searching - const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - mi_assert_internal(was_zero); MI_UNUSED(was_zero); - return NULL; - } - else { - // success, we unabandoned a segment in our sub-process - mi_atomic_decrement_relaxed(&subproc->abandoned_count); - return segment; - } -} - -// reclaim abandoned segments -// this does not set the thread id (so it appears as still abandoned) -mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous, bool visit_all ) -{ - const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); - if (max_arena <= 0 || mi_atomic_load_relaxed(&previous->subproc->abandoned_count) == 0) return NULL; - - size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); - size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1; - // visit arena's (from the previous cursor) - for ( ; previous->start < previous->end; previous->start++, field_idx = 0, bit_idx = 0) { - // index wraps around - size_t arena_idx = (previous->start >= max_arena ? previous->start % max_arena : previous->start); - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); - if (arena != NULL) { - bool has_lock = false; - // visit the abandoned fields (starting at previous_idx) - for (; field_idx < arena->field_count; field_idx++, bit_idx = 0) { - size_t field = mi_atomic_load_relaxed(&arena->blocks_abandoned[field_idx]); - if mi_unlikely(field != 0) { // skip zero fields quickly - // we only take the arena lock if there are actually abandoned segments present - if (!has_lock && mi_option_is_enabled(mi_option_visit_abandoned)) { - has_lock = (visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); - if (!has_lock) { - if (visit_all) { - _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the visitor lock"); - } - // skip to next arena - break; - } - } - mi_assert_internal(has_lock || !mi_option_is_enabled(mi_option_visit_abandoned)); - // visit each set bit in the field (todo: maybe use `ctz` here?) - for (; bit_idx < MI_BITMAP_FIELD_BITS; bit_idx++) { - // pre-check if the bit is set - size_t mask = ((size_t)1 << bit_idx); - if mi_unlikely((field & mask) == mask) { - previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); - mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, previous->bitmap_idx); - if (segment != NULL) { - //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); - if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } - return segment; - } - } - } - } - } - if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } - } - } - // no more found - mi_assert(previous->start == previous->end); - previous->bitmap_idx = 0; - previous->start = previous->end = 0; - return NULL; -} - - -static bool mi_arena_visit_abandoned_blocks(mi_subproc_t* subproc, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { - mi_arena_field_cursor_t current; - _mi_arena_field_cursor_init(NULL, subproc, ¤t); - mi_segment_t* segment; - while ((segment = _mi_arena_segment_clear_abandoned_next(¤t, true /* visit all */)) != NULL) { - bool ok = _mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg); - _mi_arena_segment_mark_abandoned(segment); - if (!ok) return false; - } - return true; -} - -static bool mi_subproc_visit_abandoned_os_blocks(mi_subproc_t* subproc, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { - if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { - _mi_error_message(EFAULT, "internal error: failed to acquire abandoned (OS) segment lock"); - return false; - } - bool all_visited = true; - for (mi_segment_t* segment = subproc->abandoned_os_list; segment != NULL; segment = segment->abandoned_os_next) { - if (!_mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg)) { - all_visited = false; - break; - } - } - mi_lock_release(&subproc->abandoned_os_lock); - return all_visited; -} - -bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { - // (unfortunately) the visit_abandoned option must be enabled from the start. - // This is to avoid taking locks if abandoned list visiting is not required (as for most programs) - if (!mi_option_is_enabled(mi_option_visit_abandoned)) { - _mi_error_message(EFAULT, "internal error: can only visit abandoned blocks when MIMALLOC_VISIT_ABANDONED=ON"); - return false; - } - mi_subproc_t* const subproc = _mi_subproc_from_id(subproc_id); - // visit abandoned segments in the arena's - if (!mi_arena_visit_abandoned_blocks(subproc, heap_tag, visit_blocks, visitor, arg)) return false; - // and visit abandoned segments outside arena's (in OS allocated memory) - if (!mi_subproc_visit_abandoned_os_blocks(subproc, heap_tag, visit_blocks, visitor, arg)) return false; - return true; -} - - /* ----------------------------------------------------------- Add an arena. ----------------------------------------------------------- */ @@ -1256,3 +979,336 @@ int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserv return err; } + +/* ----------------------------------------------------------- + Abandoned blocks/segments: + + _mi_arena_segment_clear_abandoned + _mi_arena_segment_mark_abandoned + + This is used to atomically abandon/reclaim segments + (and crosses the arena API but it is convenient to have here). + + Abandoned segments still have live blocks; they get reclaimed + when a thread frees a block in it, or when a thread needs a fresh + segment. + + Abandoned segments are atomically marked in the `block_abandoned` + bitmap of arenas. Any segments allocated outside arenas are put + in the sub-process `abandoned_os_list`. This list is accessed + using locks but this should be uncommon and generally uncontended. + Reclaim and visiting either scan through the `block_abandoned` + bitmaps of the arena's, or visit the `abandoned_os_list` + + A potentially nicer design is to use arena's for everything + and perhaps have virtual arena's to map OS allocated memory + but this would lack the "density" of our current arena's. TBC. +----------------------------------------------------------- */ + +// reclaim a specific OS abandoned segment; `true` on success. +// sets the thread_id. +static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment, bool take_lock) { + mi_assert(segment->memid.memkind != MI_MEM_ARENA); + // not in an arena, remove from list of abandoned os segments + mi_subproc_t* const subproc = segment->subproc; + if (take_lock && !mi_lock_try_acquire(&subproc->abandoned_os_lock)) { + return false; // failed to acquire the lock, we just give up + } + // remove atomically from the abandoned os list (if possible!) + bool reclaimed = false; + mi_segment_t* const next = segment->abandoned_os_next; + mi_segment_t* const prev = segment->abandoned_os_prev; + if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { + #if MI_DEBUG>3 + // find ourselves in the abandoned list (and check the count) + bool found = false; + size_t count = 0; + for (mi_segment_t* current = subproc->abandoned_os_list; current != NULL; current = current->abandoned_os_next) { + if (current == segment) { found = true; } + count++; + } + mi_assert_internal(found); + mi_assert_internal(count == mi_atomic_load_relaxed(&subproc->abandoned_os_list_count)); + #endif + // remove (atomically) from the list and reclaim + if (prev != NULL) { prev->abandoned_os_next = next; } + else { subproc->abandoned_os_list = next; } + if (next != NULL) { next->abandoned_os_prev = prev; } + else { subproc->abandoned_os_list_tail = prev; } + segment->abandoned_os_next = NULL; + segment->abandoned_os_prev = NULL; + mi_atomic_decrement_relaxed(&subproc->abandoned_count); + mi_atomic_decrement_relaxed(&subproc->abandoned_os_list_count); + mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + reclaimed = true; + } + if (take_lock) { mi_lock_release(&segment->subproc->abandoned_os_lock); } + return reclaimed; +} + +// reclaim a specific abandoned segment; `true` on success. +// sets the thread_id. +bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment) { + if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { + return mi_arena_segment_os_clear_abandoned(segment, true /* take lock */); + } + // arena segment: use the blocks_abandoned bitmap. + size_t arena_idx; + size_t bitmap_idx; + mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); + mi_assert_internal(arena_idx < MI_MAX_ARENAS); + mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); + mi_assert_internal(arena != NULL); + // reclaim atomically + bool was_marked = _mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx); + if (was_marked) { + mi_assert_internal(mi_atomic_load_acquire(&segment->thread_id) == 0); + mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); + mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + } + // mi_assert_internal(was_marked); + mi_assert_internal(!was_marked || _mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); + //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); + return was_marked; +} + + +// mark a specific OS segment as abandoned +static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { + mi_assert(segment->memid.memkind != MI_MEM_ARENA); + // not in an arena; we use a list of abandoned segments + mi_subproc_t* const subproc = segment->subproc; + if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { + _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); + // we can continue but cannot visit/reclaim such blocks.. + } + else { + // push on the tail of the list (important for the visitor) + mi_segment_t* prev = subproc->abandoned_os_list_tail; + mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL); + mi_assert_internal(segment->abandoned_os_prev == NULL); + mi_assert_internal(segment->abandoned_os_next == NULL); + if (prev != NULL) { prev->abandoned_os_next = segment; } + else { subproc->abandoned_os_list = segment; } + subproc->abandoned_os_list_tail = segment; + segment->abandoned_os_prev = prev; + segment->abandoned_os_next = NULL; + mi_atomic_increment_relaxed(&subproc->abandoned_os_list_count); + mi_atomic_increment_relaxed(&subproc->abandoned_count); + // and release the lock + mi_lock_release(&subproc->abandoned_os_lock); + } + return; +} + +// mark a specific segment as abandoned +// clears the thread_id. +void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) +{ + mi_assert_internal(segment->used == segment->abandoned); + mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned for multi-thread free's + if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { + mi_arena_segment_os_mark_abandoned(segment); + return; + } + // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap + size_t arena_idx; + size_t bitmap_idx; + mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); + mi_assert_internal(arena_idx < MI_MAX_ARENAS); + mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); + mi_assert_internal(arena != NULL); + // set abandonment atomically + const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); + if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } + mi_assert_internal(was_unmarked); + mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); +} + + +/* ----------------------------------------------------------- + Iterate through the abandoned blocks/segments using a cursor. + This is used for reclaiming and abandoned block visiting. +----------------------------------------------------------- */ + +// start a cursor at a randomized arena +void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, bool visit_all, mi_arena_field_cursor_t* current) { + mi_assert_internal(heap == NULL || heap->tld->segments.subproc == subproc); + current->bitmap_idx = 0; + current->subproc = subproc; + current->visit_all = visit_all; + current->hold_visit_lock = false; + const size_t abandoned_count = mi_atomic_load_relaxed(&subproc->abandoned_count); + const size_t abandoned_list_count = mi_atomic_load_relaxed(&subproc->abandoned_os_list_count); + const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); + if (heap != NULL && heap->arena_id != _mi_arena_id_none()) { + // for a heap that is bound to one arena, only visit that arena + current->start = mi_arena_id_index(heap->arena_id); + current->end = current->start + 1; + current->os_list_count = 0; + } + else { + // otherwise visit all starting at a random location + if (abandoned_count > abandoned_list_count && max_arena > 0) { + current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); + current->end = current->start + max_arena; + } + else { + current->start = 0; + current->end = 0; + } + current->os_list_count = abandoned_list_count; // max entries to visit in the os abandoned list + } + mi_assert_internal(current->start <= max_arena); +} + +void _mi_arena_field_cursor_done(mi_arena_field_cursor_t* current) { + if (current->hold_visit_lock) { + mi_lock_release(¤t->subproc->abandoned_os_visit_lock); + current->hold_visit_lock = false; + } +} + +static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_subproc_t* subproc, mi_bitmap_index_t bitmap_idx) { + // try to reclaim an abandoned segment in the arena atomically + if (!_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) return NULL; + mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); + mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); + mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); + // check that the segment belongs to our sub-process + // note: this is the reason we need the `abandoned_visit` lock in the case abandoned visiting is enabled. + // without the lock an abandoned visit may otherwise fail to visit all abandoned segments in the sub-process. + // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the `abandoned_visit` lock. + if (segment->subproc != subproc) { + // it is from another sub-process, re-mark it and continue searching + const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); + mi_assert_internal(was_zero); MI_UNUSED(was_zero); + return NULL; + } + else { + // success, we unabandoned a segment in our sub-process + mi_atomic_decrement_relaxed(&subproc->abandoned_count); + return segment; + } +} + +static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_cursor_t* previous) { + const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); + size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); + size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1; + // visit arena's (from the previous cursor) + for (; previous->start < previous->end; previous->start++, field_idx = 0, bit_idx = 0) { + // index wraps around + size_t arena_idx = (previous->start >= max_arena ? previous->start % max_arena : previous->start); + mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); + if (arena != NULL) { + bool has_lock = false; + // visit the abandoned fields (starting at previous_idx) + for (; field_idx < arena->field_count; field_idx++, bit_idx = 0) { + size_t field = mi_atomic_load_relaxed(&arena->blocks_abandoned[field_idx]); + if mi_unlikely(field != 0) { // skip zero fields quickly + // we only take the arena lock if there are actually abandoned segments present + if (!has_lock && mi_option_is_enabled(mi_option_visit_abandoned)) { + has_lock = (previous->visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); + if (!has_lock) { + if (previous->visit_all) { + _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the visitor lock"); + } + // skip to next arena + break; + } + } + mi_assert_internal(has_lock || !mi_option_is_enabled(mi_option_visit_abandoned)); + // visit each set bit in the field (todo: maybe use `ctz` here?) + for (; bit_idx < MI_BITMAP_FIELD_BITS; bit_idx++) { + // pre-check if the bit is set + size_t mask = ((size_t)1 << bit_idx); + if mi_unlikely((field & mask) == mask) { + previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); + mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, previous->bitmap_idx); + if (segment != NULL) { + //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); + if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } + return segment; + } + } + } + } + } + if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } + } + } + return NULL; +} + +static mi_segment_t* mi_arena_segment_clear_abandoned_next_list(mi_arena_field_cursor_t* previous) { + // go through the abandoned_os_list + // we only allow one thread per sub-process to do to visit guarded by the `abandoned_os_visit_lock`. + // The lock is released when the cursor is released. + if (!previous->hold_visit_lock) { + previous->hold_visit_lock = (previous->visit_all ? mi_lock_acquire(&previous->subproc->abandoned_os_visit_lock) + : mi_lock_try_acquire(&previous->subproc->abandoned_os_visit_lock)); + if (!previous->hold_visit_lock) { + if (previous->visit_all) { + _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the OS visitor lock"); + } + return NULL; // we cannot get the lock, give up + } + } + // One list entry at a time + while (previous->os_list_count > 0) { + previous->os_list_count--; + const bool has_lock = mi_lock_acquire(&previous->subproc->abandoned_os_lock); // this could contend with concurrent OS block abandonment and reclaim from `free` + if (has_lock) { + mi_segment_t* segment = previous->subproc->abandoned_os_list; + // pop from head of the list, a subsequent mark will push at the end (and thus we iterate through os_list_count entries) + if (segment == NULL || mi_arena_segment_os_clear_abandoned(segment, false /* we already have the lock */)) { + mi_lock_release(&previous->subproc->abandoned_os_lock); + return segment; + } + // already abandoned, try again + mi_lock_release(&previous->subproc->abandoned_os_lock); + } + else { + _mi_error_message(EFAULT, "failed to acquire abandoned OS list lock during abandoned block visit\n"); + return NULL; + } + } + // done + mi_assert_internal(previous->os_list_count == 0); + return NULL; +} + + +// reclaim abandoned segments +// this does not set the thread id (so it appears as still abandoned) +mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous) { + if (previous->start < previous->end) { + // walk the arena + mi_segment_t* segment = mi_arena_segment_clear_abandoned_next_field(previous); + if (segment != NULL) { return segment; } + } + // no entries in the arena's anymore, walk the abandoned OS list + mi_assert_internal(previous->start == previous->end); + return mi_arena_segment_clear_abandoned_next_list(previous); +} + + +bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + // (unfortunately) the visit_abandoned option must be enabled from the start. + // This is to avoid taking locks if abandoned list visiting is not required (as for most programs) + if (!mi_option_is_enabled(mi_option_visit_abandoned)) { + _mi_error_message(EFAULT, "internal error: can only visit abandoned blocks when MIMALLOC_VISIT_ABANDONED=ON"); + return false; + } + mi_arena_field_cursor_t current; + _mi_arena_field_cursor_init(NULL, _mi_subproc_from_id(subproc_id), true /* visit all (blocking) */, ¤t); + mi_segment_t* segment; + bool ok = true; + while (ok && (segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL) { + ok = _mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg); + _mi_arena_segment_mark_abandoned(segment); + } + _mi_arena_field_cursor_done(¤t); + return ok; +} diff --git a/src/init.c b/src/init.c index e84d3ed8..08208ea7 100644 --- a/src/init.c +++ b/src/init.c @@ -173,6 +173,7 @@ static void mi_heap_main_init(void) { _mi_heap_main.keys[0] = _mi_heap_random_next(&_mi_heap_main); _mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main); mi_lock_init(&mi_subproc_default.abandoned_os_lock); + mi_lock_init(&mi_subproc_default.abandoned_os_visit_lock); } } @@ -197,6 +198,7 @@ mi_subproc_id_t mi_subproc_new(void) { subproc->memid = memid; subproc->abandoned_os_list = NULL; mi_lock_init(&subproc->abandoned_os_lock); + mi_lock_init(&subproc->abandoned_os_visit_lock); return subproc; } @@ -219,6 +221,7 @@ void mi_subproc_delete(mi_subproc_id_t subproc_id) { // safe to release // todo: should we refcount subprocesses? mi_lock_done(&subproc->abandoned_os_lock); + mi_lock_done(&subproc->abandoned_os_visit_lock); _mi_arena_meta_free(subproc, subproc->memid, sizeof(mi_subproc_t)); } diff --git a/src/segment.c b/src/segment.c index b55f1ea8..7a2d9e8e 100644 --- a/src/segment.c +++ b/src/segment.c @@ -960,10 +960,12 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) { mi_segment_t* segment; - mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, ¤t); - while ((segment = _mi_arena_segment_clear_abandoned_next(¤t, true /* blocking */)) != NULL) { + mi_arena_field_cursor_t current; + _mi_arena_field_cursor_init(heap, tld->subproc, true /* visit all, blocking */, ¤t); + while ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL) { mi_segment_reclaim(segment, heap, 0, NULL, tld); } + _mi_arena_field_cursor_done(¤t); } static long mi_segment_get_reclaim_tries(mi_segments_tld_t* tld) { @@ -984,9 +986,11 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, long max_tries = mi_segment_get_reclaim_tries(tld); if (max_tries <= 0) return NULL; - mi_segment_t* segment; - mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, ¤t); - while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t, false /* non-blocking */)) != NULL)) + mi_segment_t* result = NULL; + mi_segment_t* segment = NULL; + mi_arena_field_cursor_t current; + _mi_arena_field_cursor_init(heap, tld->subproc, false /* non-blocking */, ¤t); + while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL)) { mi_assert(segment->subproc == heap->tld->segments.subproc); // cursor only visits segments in our sub-process segment->abandoned_visits++; @@ -1008,7 +1012,8 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, // found a free page of the right kind, or page of the right block_size with free space // we return the result of reclaim (which is usually `segment`) as it might free // the segment due to concurrent frees (in which case `NULL` is returned). - return mi_segment_reclaim(segment, heap, block_size, reclaimed, tld); + result = mi_segment_reclaim(segment, heap, block_size, reclaimed, tld); + break; } else if (segment->abandoned_visits >= 3 && is_suitable) { // always reclaim on 3rd visit to limit the list length. @@ -1020,7 +1025,8 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, _mi_arena_segment_mark_abandoned(segment); } } - return NULL; + _mi_arena_field_cursor_done(¤t); + return result; } From 800034cb99a5a2324fd2e6c41bb3da713aab0aa3 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 17:58:34 -0700 Subject: [PATCH 032/305] refactor arena abandonment in a separate file --- CMakeLists.txt | 25 +- ide/vs2022/mimalloc-override.vcxproj | 10 + ide/vs2022/mimalloc-override.vcxproj.filters | 3 + ide/vs2022/mimalloc.vcxproj | 11 + ide/vs2022/mimalloc.vcxproj.filters | 6 + src/arena-abandoned.c | 342 ++++++++++++++++ src/arena.c | 398 +------------------ src/arena.h | 63 +++ src/static.c | 3 +- 9 files changed, 466 insertions(+), 395 deletions(-) create mode 100644 src/arena-abandoned.c create mode 100644 src/arena.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bcfe91d8..fca04263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ set(mi_sources src/alloc-aligned.c src/alloc-posix.c src/arena.c + src/arena-abandoned.c src/bitmap.c src/heap.c src/init.c @@ -61,7 +62,7 @@ set(mi_sources set(mi_cflags "") set(mi_cflags_static "") # extra flags for a static library build set(mi_cflags_dynamic "") # extra flags for a shared-object library build -set(mi_defines "") +set(mi_defines "") set(mi_libraries "") # ----------------------------------------------------------------------------- @@ -327,7 +328,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM list(APPEND mi_cflags_dynamic -ftls-model=initial-exec) message(STATUS "Use local dynamic TLS for the static build (since MI_LIBC_MUSL=ON)") else() - list(APPEND mi_cflags -ftls-model=initial-exec) + list(APPEND mi_cflags -ftls-model=initial-exec) endif() endif() if(MI_OVERRIDE) @@ -345,18 +346,18 @@ endif() # extra needed libraries -# we prefer -l test over `find_library` as sometimes core libraries +# we prefer -l test over `find_library` as sometimes core libraries # like `libatomic` are not on the system path (see issue #898) -function(find_link_library libname outlibname) - check_linker_flag(C "-l${libname}" mi_has_lib${libname}) +function(find_link_library libname outlibname) + check_linker_flag(C "-l${libname}" mi_has_lib${libname}) if (mi_has_lib${libname}) message(VERBOSE "link library: -l${libname}") - set(${outlibname} ${libname} PARENT_SCOPE) + set(${outlibname} ${libname} PARENT_SCOPE) else() find_library(MI_LIBPATH libname) if (MI_LIBPATH) message(VERBOSE "link library ${libname} at ${MI_LIBPATH}") - set(${outlibname} ${MI_LIBPATH} PARENT_SCOPE) + set(${outlibname} ${MI_LIBPATH} PARENT_SCOPE) else() message(VERBOSE "link library not found: ${libname}") set(${outlibname} "" PARENT_SCOPE) @@ -365,19 +366,19 @@ function(find_link_library libname outlibname) endfunction() if(WIN32) - list(APPEND mi_libraries psapi shell32 user32 advapi32 bcrypt) + list(APPEND mi_libraries psapi shell32 user32 advapi32 bcrypt) else() find_link_library("pthread" MI_LIB_PTHREAD) - if(MI_LIB_PTHREAD) + if(MI_LIB_PTHREAD) list(APPEND mi_libraries "${MI_LIB_PTHREAD}") endif() find_link_library("rt" MI_LIB_RT) - if(MI_LIB_RT) + if(MI_LIB_RT) list(APPEND mi_libraries "${MI_LIB_RT}") endif() find_link_library("atomic" MI_LIB_ATOMIC) - if(MI_LIB_ATOMIC) - list(APPEND mi_libraries "${MI_LIB_ATOMIC}") + if(MI_LIB_ATOMIC) + list(APPEND mi_libraries "${MI_LIB_ATOMIC}") endif() endif() diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index df2a0816..f83b0dee 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -236,6 +236,16 @@ + + + + + + + + + + diff --git a/ide/vs2022/mimalloc-override.vcxproj.filters b/ide/vs2022/mimalloc-override.vcxproj.filters index dd69c827..a9f66c35 100644 --- a/ide/vs2022/mimalloc-override.vcxproj.filters +++ b/ide/vs2022/mimalloc-override.vcxproj.filters @@ -58,6 +58,9 @@ Sources + + Sources + diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index 3e11d0fe..dfbdec64 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -213,6 +213,16 @@ + + + + + + + + + + false @@ -256,6 +266,7 @@ + diff --git a/ide/vs2022/mimalloc.vcxproj.filters b/ide/vs2022/mimalloc.vcxproj.filters index a387f5a5..cb0303e0 100644 --- a/ide/vs2022/mimalloc.vcxproj.filters +++ b/ide/vs2022/mimalloc.vcxproj.filters @@ -61,6 +61,9 @@ Sources + + Sources + @@ -90,6 +93,9 @@ Headers + + Headers + diff --git a/src/arena-abandoned.c b/src/arena-abandoned.c new file mode 100644 index 00000000..91327d5f --- /dev/null +++ b/src/arena-abandoned.c @@ -0,0 +1,342 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2019-2024, 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. +-----------------------------------------------------------------------------*/ + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "arena.h" + +/* ----------------------------------------------------------- + Abandoned blocks/segments: + + _mi_arena_segment_clear_abandoned + _mi_arena_segment_mark_abandoned + + This is used to atomically abandon/reclaim segments + (and crosses the arena API but it is convenient to have here). + + Abandoned segments still have live blocks; they get reclaimed + when a thread frees a block in it, or when a thread needs a fresh + segment. + + Abandoned segments are atomically marked in the `block_abandoned` + bitmap of arenas. Any segments allocated outside arenas are put + in the sub-process `abandoned_os_list`. This list is accessed + using locks but this should be uncommon and generally uncontended. + Reclaim and visiting either scan through the `block_abandoned` + bitmaps of the arena's, or visit the `abandoned_os_list` + + A potentially nicer design is to use arena's for everything + and perhaps have virtual arena's to map OS allocated memory + but this would lack the "density" of our current arena's. TBC. +----------------------------------------------------------- */ + + +// reclaim a specific OS abandoned segment; `true` on success. +// sets the thread_id. +static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment, bool take_lock) { + mi_assert(segment->memid.memkind != MI_MEM_ARENA); + // not in an arena, remove from list of abandoned os segments + mi_subproc_t* const subproc = segment->subproc; + if (take_lock && !mi_lock_try_acquire(&subproc->abandoned_os_lock)) { + return false; // failed to acquire the lock, we just give up + } + // remove atomically from the abandoned os list (if possible!) + bool reclaimed = false; + mi_segment_t* const next = segment->abandoned_os_next; + mi_segment_t* const prev = segment->abandoned_os_prev; + if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { + #if MI_DEBUG>3 + // find ourselves in the abandoned list (and check the count) + bool found = false; + size_t count = 0; + for (mi_segment_t* current = subproc->abandoned_os_list; current != NULL; current = current->abandoned_os_next) { + if (current == segment) { found = true; } + count++; + } + mi_assert_internal(found); + mi_assert_internal(count == mi_atomic_load_relaxed(&subproc->abandoned_os_list_count)); + #endif + // remove (atomically) from the list and reclaim + if (prev != NULL) { prev->abandoned_os_next = next; } + else { subproc->abandoned_os_list = next; } + if (next != NULL) { next->abandoned_os_prev = prev; } + else { subproc->abandoned_os_list_tail = prev; } + segment->abandoned_os_next = NULL; + segment->abandoned_os_prev = NULL; + mi_atomic_decrement_relaxed(&subproc->abandoned_count); + mi_atomic_decrement_relaxed(&subproc->abandoned_os_list_count); + mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + reclaimed = true; + } + if (take_lock) { mi_lock_release(&segment->subproc->abandoned_os_lock); } + return reclaimed; +} + +// reclaim a specific abandoned segment; `true` on success. +// sets the thread_id. +bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment) { + if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { + return mi_arena_segment_os_clear_abandoned(segment, true /* take lock */); + } + // arena segment: use the blocks_abandoned bitmap. + size_t arena_idx; + size_t bitmap_idx; + mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); + mi_arena_t* arena = mi_arena_from_index(arena_idx); + mi_assert_internal(arena != NULL); + // reclaim atomically + bool was_marked = _mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx); + if (was_marked) { + mi_assert_internal(mi_atomic_load_acquire(&segment->thread_id) == 0); + mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); + mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + } + // mi_assert_internal(was_marked); + mi_assert_internal(!was_marked || _mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); + //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); + return was_marked; +} + + +// mark a specific OS segment as abandoned +static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { + mi_assert(segment->memid.memkind != MI_MEM_ARENA); + // not in an arena; we use a list of abandoned segments + mi_subproc_t* const subproc = segment->subproc; + if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { + _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); + // we can continue but cannot visit/reclaim such blocks.. + } + else { + // push on the tail of the list (important for the visitor) + mi_segment_t* prev = subproc->abandoned_os_list_tail; + mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL); + mi_assert_internal(segment->abandoned_os_prev == NULL); + mi_assert_internal(segment->abandoned_os_next == NULL); + if (prev != NULL) { prev->abandoned_os_next = segment; } + else { subproc->abandoned_os_list = segment; } + subproc->abandoned_os_list_tail = segment; + segment->abandoned_os_prev = prev; + segment->abandoned_os_next = NULL; + mi_atomic_increment_relaxed(&subproc->abandoned_os_list_count); + mi_atomic_increment_relaxed(&subproc->abandoned_count); + // and release the lock + mi_lock_release(&subproc->abandoned_os_lock); + } + return; +} + +// mark a specific segment as abandoned +// clears the thread_id. +void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) +{ + mi_assert_internal(segment->used == segment->abandoned); + mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned for multi-thread free's + if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { + mi_arena_segment_os_mark_abandoned(segment); + return; + } + // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap + size_t arena_idx; + size_t bitmap_idx; + mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); + mi_arena_t* arena = mi_arena_from_index(arena_idx); + mi_assert_internal(arena != NULL); + // set abandonment atomically + const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); + if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } + mi_assert_internal(was_unmarked); + mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); +} + + +/* ----------------------------------------------------------- + Iterate through the abandoned blocks/segments using a cursor. + This is used for reclaiming and abandoned block visiting. +----------------------------------------------------------- */ + +// start a cursor at a randomized arena +void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, bool visit_all, mi_arena_field_cursor_t* current) { + mi_assert_internal(heap == NULL || heap->tld->segments.subproc == subproc); + current->bitmap_idx = 0; + current->subproc = subproc; + current->visit_all = visit_all; + current->hold_visit_lock = false; + const size_t abandoned_count = mi_atomic_load_relaxed(&subproc->abandoned_count); + const size_t abandoned_list_count = mi_atomic_load_relaxed(&subproc->abandoned_os_list_count); + const size_t max_arena = mi_arena_get_count(); + if (heap != NULL && heap->arena_id != _mi_arena_id_none()) { + // for a heap that is bound to one arena, only visit that arena + current->start = mi_arena_id_index(heap->arena_id); + current->end = current->start + 1; + current->os_list_count = 0; + } + else { + // otherwise visit all starting at a random location + if (abandoned_count > abandoned_list_count && max_arena > 0) { + current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); + current->end = current->start + max_arena; + } + else { + current->start = 0; + current->end = 0; + } + current->os_list_count = abandoned_list_count; // max entries to visit in the os abandoned list + } + mi_assert_internal(current->start <= max_arena); +} + +void _mi_arena_field_cursor_done(mi_arena_field_cursor_t* current) { + if (current->hold_visit_lock) { + mi_lock_release(¤t->subproc->abandoned_os_visit_lock); + current->hold_visit_lock = false; + } +} + +static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_subproc_t* subproc, mi_bitmap_index_t bitmap_idx) { + // try to reclaim an abandoned segment in the arena atomically + if (!_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) return NULL; + mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); + mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); + mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); + // check that the segment belongs to our sub-process + // note: this is the reason we need the `abandoned_visit` lock in the case abandoned visiting is enabled. + // without the lock an abandoned visit may otherwise fail to visit all abandoned segments in the sub-process. + // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the `abandoned_visit` lock. + if (segment->subproc != subproc) { + // it is from another sub-process, re-mark it and continue searching + const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); + mi_assert_internal(was_zero); MI_UNUSED(was_zero); + return NULL; + } + else { + // success, we unabandoned a segment in our sub-process + mi_atomic_decrement_relaxed(&subproc->abandoned_count); + return segment; + } +} + +static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_cursor_t* previous) { + const size_t max_arena = mi_arena_get_count(); + size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); + size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1; + // visit arena's (from the previous cursor) + for (; previous->start < previous->end; previous->start++, field_idx = 0, bit_idx = 0) { + // index wraps around + size_t arena_idx = (previous->start >= max_arena ? previous->start % max_arena : previous->start); + mi_arena_t* arena = mi_arena_from_index(arena_idx); + if (arena != NULL) { + bool has_lock = false; + // visit the abandoned fields (starting at previous_idx) + for (; field_idx < arena->field_count; field_idx++, bit_idx = 0) { + size_t field = mi_atomic_load_relaxed(&arena->blocks_abandoned[field_idx]); + if mi_unlikely(field != 0) { // skip zero fields quickly + // we only take the arena lock if there are actually abandoned segments present + if (!has_lock && mi_option_is_enabled(mi_option_visit_abandoned)) { + has_lock = (previous->visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); + if (!has_lock) { + if (previous->visit_all) { + _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the visitor lock"); + } + // skip to next arena + break; + } + } + mi_assert_internal(has_lock || !mi_option_is_enabled(mi_option_visit_abandoned)); + // visit each set bit in the field (todo: maybe use `ctz` here?) + for (; bit_idx < MI_BITMAP_FIELD_BITS; bit_idx++) { + // pre-check if the bit is set + size_t mask = ((size_t)1 << bit_idx); + if mi_unlikely((field & mask) == mask) { + previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); + mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, previous->bitmap_idx); + if (segment != NULL) { + //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); + if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } + return segment; + } + } + } + } + } + if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } + } + } + return NULL; +} + +static mi_segment_t* mi_arena_segment_clear_abandoned_next_list(mi_arena_field_cursor_t* previous) { + // go through the abandoned_os_list + // we only allow one thread per sub-process to do to visit guarded by the `abandoned_os_visit_lock`. + // The lock is released when the cursor is released. + if (!previous->hold_visit_lock) { + previous->hold_visit_lock = (previous->visit_all ? mi_lock_acquire(&previous->subproc->abandoned_os_visit_lock) + : mi_lock_try_acquire(&previous->subproc->abandoned_os_visit_lock)); + if (!previous->hold_visit_lock) { + if (previous->visit_all) { + _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the OS visitor lock"); + } + return NULL; // we cannot get the lock, give up + } + } + // One list entry at a time + while (previous->os_list_count > 0) { + previous->os_list_count--; + const bool has_lock = mi_lock_acquire(&previous->subproc->abandoned_os_lock); // this could contend with concurrent OS block abandonment and reclaim from `free` + if (has_lock) { + mi_segment_t* segment = previous->subproc->abandoned_os_list; + // pop from head of the list, a subsequent mark will push at the end (and thus we iterate through os_list_count entries) + if (segment == NULL || mi_arena_segment_os_clear_abandoned(segment, false /* we already have the lock */)) { + mi_lock_release(&previous->subproc->abandoned_os_lock); + return segment; + } + // already abandoned, try again + mi_lock_release(&previous->subproc->abandoned_os_lock); + } + else { + _mi_error_message(EFAULT, "failed to acquire abandoned OS list lock during abandoned block visit\n"); + return NULL; + } + } + // done + mi_assert_internal(previous->os_list_count == 0); + return NULL; +} + + +// reclaim abandoned segments +// this does not set the thread id (so it appears as still abandoned) +mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous) { + if (previous->start < previous->end) { + // walk the arena + mi_segment_t* segment = mi_arena_segment_clear_abandoned_next_field(previous); + if (segment != NULL) { return segment; } + } + // no entries in the arena's anymore, walk the abandoned OS list + mi_assert_internal(previous->start == previous->end); + return mi_arena_segment_clear_abandoned_next_list(previous); +} + + +bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { + // (unfortunately) the visit_abandoned option must be enabled from the start. + // This is to avoid taking locks if abandoned list visiting is not required (as for most programs) + if (!mi_option_is_enabled(mi_option_visit_abandoned)) { + _mi_error_message(EFAULT, "internal error: can only visit abandoned blocks when MIMALLOC_VISIT_ABANDONED=ON"); + return false; + } + mi_arena_field_cursor_t current; + _mi_arena_field_cursor_init(NULL, _mi_subproc_from_id(subproc_id), true /* visit all (blocking) */, ¤t); + mi_segment_t* segment; + bool ok = true; + while (ok && (segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL) { + ok = _mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg); + _mi_arena_segment_mark_abandoned(segment); + } + _mi_arena_field_cursor_done(¤t); + return ok; +} diff --git a/src/arena.c b/src/arena.c index 77f42825..8fa018ab 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019-2023, Microsoft Research, Daan Leijen +Copyright (c) 2019-2024, 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. @@ -10,70 +10,27 @@ terms of the MIT license. A copy of the license can be found in the file large blocks (>= MI_ARENA_MIN_BLOCK_SIZE, 4MiB). In contrast to the rest of mimalloc, the arenas are shared between threads and need to be accessed using atomic operations. - -Arenas are used to for huge OS page (1GiB) reservations or for reserving -OS memory upfront which can be improve performance or is sometimes needed -on embedded devices. We can also employ this with WASI or `sbrk` systems -to reserve large arenas upfront and be able to reuse the memory more effectively. - -The arena allocation needs to be thread safe and we use an atomic bitmap to allocate. -----------------------------------------------------------------------------*/ #include "mimalloc.h" #include "mimalloc/internal.h" #include "mimalloc/atomic.h" +#include "arena.h" -#include // memset -#include // ENOMEM - -#include "bitmap.h" // atomic bitmap - -/* ----------------------------------------------------------- - Arena allocation ------------------------------------------------------------ */ - -// Block info: bit 0 contains the `in_use` bit, the upper bits the -// size in count of arena blocks. -typedef uintptr_t mi_block_info_t; #define MI_ARENA_BLOCK_SIZE (MI_SEGMENT_SIZE) // 64MiB (must be at least MI_SEGMENT_ALIGN) #define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_BLOCK_SIZE/2) // 32MiB #define MI_MAX_ARENAS (132) // Limited as the reservation exponentially increases (and takes up .bss) -// A memory arena descriptor -typedef struct mi_arena_s { - mi_arena_id_t id; // arena id; 0 for non-specific - mi_memid_t memid; // memid of the memory area - _Atomic(uint8_t*) start; // the start of the memory area - size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) - size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) - size_t meta_size; // size of the arena structure itself (including its bitmaps) - mi_memid_t meta_memid; // memid of the arena structure itself (OS or static allocation) - int numa_node; // associated NUMA node - bool exclusive; // only allow allocations if specifically for this arena - bool is_large; // memory area consists of large- or huge OS pages (always committed) - mi_lock_t abandoned_visit_lock; // lock is only used when abandoned segments are being visited - _Atomic(size_t) search_idx; // optimization to start the search for free blocks - _Atomic(mi_msecs_t) purge_expire; // expiration time when blocks should be decommitted from `blocks_decommit`. - mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? - mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) - mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) - mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) - mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) - // do not add further fields here as the dirty, committed, purged, and abandoned bitmaps follow the inuse bitmap fields. -} mi_arena_t; - - // The available arenas static mi_decl_cache_align _Atomic(mi_arena_t*) mi_arenas[MI_MAX_ARENAS]; static mi_decl_cache_align _Atomic(size_t) mi_arena_count; // = 0 -//static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int numa_node, bool exclusive, mi_memid_t memid, mi_arena_id_t* arena_id) mi_attr_noexcept; /* ----------------------------------------------------------- Arena id's id = arena_index + 1 ----------------------------------------------------------- */ -static size_t mi_arena_id_index(mi_arena_id_t id) { +size_t mi_arena_id_index(mi_arena_id_t id) { return (size_t)(id <= 0 ? MI_MAX_ARENAS : id - 1); } @@ -100,6 +57,15 @@ bool _mi_arena_memid_is_suitable(mi_memid_t memid, mi_arena_id_t request_arena_i } } +size_t mi_arena_get_count(void) { + return mi_atomic_load_relaxed(&mi_arena_count); +} + +mi_arena_t* mi_arena_from_index(size_t idx) { + mi_assert_internal(idx < mi_arena_get_count()); + return mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[idx]); +} + /* ----------------------------------------------------------- Arena allocations get a (currently) 16-bit memory id where the @@ -126,7 +92,7 @@ static mi_memid_t mi_memid_create_arena(mi_arena_id_t id, bool is_exclusive, mi_ return memid; } -static bool mi_arena_memid_indices(mi_memid_t memid, size_t* arena_index, mi_bitmap_index_t* bitmap_index) { +bool mi_arena_memid_indices(mi_memid_t memid, size_t* arena_index, mi_bitmap_index_t* bitmap_index) { mi_assert_internal(memid.memkind == MI_MEM_ARENA); *arena_index = mi_arena_id_index(memid.mem.arena.id); *bitmap_index = memid.mem.arena.block_index; @@ -200,7 +166,7 @@ void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size) { } } -static void* mi_arena_block_start(mi_arena_t* arena, mi_bitmap_index_t bindex) { +void* mi_arena_block_start(mi_arena_t* arena, mi_bitmap_index_t bindex) { return (arena->start + mi_arena_block_size(mi_bitmap_index_bit(bindex))); } @@ -290,7 +256,7 @@ static void* mi_arena_try_alloc_at_id(mi_arena_id_t arena_id, bool match_numa_no mi_assert_internal(size <= mi_arena_block_size(bcount)); // Check arena suitability - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_index]); + mi_arena_t* arena = mi_arena_from_index(arena_index); if (arena == NULL) return NULL; if (!allow_large && arena->is_large) return NULL; if (!mi_arena_id_is_suitable(arena->id, arena->exclusive, req_arena_id)) return NULL; @@ -900,7 +866,7 @@ void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge) mi_debug_show_bitmap(" ", "committed blocks", arena->block_count, arena->blocks_committed, arena->field_count); } if (show_abandoned) { - abandoned_total += mi_debug_show_bitmap(" ", "abandoned blocks", arena->block_count, arena->blocks_abandoned, arena->field_count); + abandoned_total += mi_debug_show_bitmap(" ", "abandoned blocks", arena->block_count, arena->blocks_abandoned, arena->field_count); } if (show_purge && arena->blocks_purge != NULL) { purge_total += mi_debug_show_bitmap(" ", "purgeable blocks", arena->block_count, arena->blocks_purge, arena->field_count); @@ -980,335 +946,3 @@ int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserv } -/* ----------------------------------------------------------- - Abandoned blocks/segments: - - _mi_arena_segment_clear_abandoned - _mi_arena_segment_mark_abandoned - - This is used to atomically abandon/reclaim segments - (and crosses the arena API but it is convenient to have here). - - Abandoned segments still have live blocks; they get reclaimed - when a thread frees a block in it, or when a thread needs a fresh - segment. - - Abandoned segments are atomically marked in the `block_abandoned` - bitmap of arenas. Any segments allocated outside arenas are put - in the sub-process `abandoned_os_list`. This list is accessed - using locks but this should be uncommon and generally uncontended. - Reclaim and visiting either scan through the `block_abandoned` - bitmaps of the arena's, or visit the `abandoned_os_list` - - A potentially nicer design is to use arena's for everything - and perhaps have virtual arena's to map OS allocated memory - but this would lack the "density" of our current arena's. TBC. ------------------------------------------------------------ */ - -// reclaim a specific OS abandoned segment; `true` on success. -// sets the thread_id. -static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment, bool take_lock) { - mi_assert(segment->memid.memkind != MI_MEM_ARENA); - // not in an arena, remove from list of abandoned os segments - mi_subproc_t* const subproc = segment->subproc; - if (take_lock && !mi_lock_try_acquire(&subproc->abandoned_os_lock)) { - return false; // failed to acquire the lock, we just give up - } - // remove atomically from the abandoned os list (if possible!) - bool reclaimed = false; - mi_segment_t* const next = segment->abandoned_os_next; - mi_segment_t* const prev = segment->abandoned_os_prev; - if (next != NULL || prev != NULL || subproc->abandoned_os_list == segment) { - #if MI_DEBUG>3 - // find ourselves in the abandoned list (and check the count) - bool found = false; - size_t count = 0; - for (mi_segment_t* current = subproc->abandoned_os_list; current != NULL; current = current->abandoned_os_next) { - if (current == segment) { found = true; } - count++; - } - mi_assert_internal(found); - mi_assert_internal(count == mi_atomic_load_relaxed(&subproc->abandoned_os_list_count)); - #endif - // remove (atomically) from the list and reclaim - if (prev != NULL) { prev->abandoned_os_next = next; } - else { subproc->abandoned_os_list = next; } - if (next != NULL) { next->abandoned_os_prev = prev; } - else { subproc->abandoned_os_list_tail = prev; } - segment->abandoned_os_next = NULL; - segment->abandoned_os_prev = NULL; - mi_atomic_decrement_relaxed(&subproc->abandoned_count); - mi_atomic_decrement_relaxed(&subproc->abandoned_os_list_count); - mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); - reclaimed = true; - } - if (take_lock) { mi_lock_release(&segment->subproc->abandoned_os_lock); } - return reclaimed; -} - -// reclaim a specific abandoned segment; `true` on success. -// sets the thread_id. -bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment) { - if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - return mi_arena_segment_os_clear_abandoned(segment, true /* take lock */); - } - // arena segment: use the blocks_abandoned bitmap. - size_t arena_idx; - size_t bitmap_idx; - mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); - mi_assert_internal(arena_idx < MI_MAX_ARENAS); - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); - mi_assert_internal(arena != NULL); - // reclaim atomically - bool was_marked = _mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx); - if (was_marked) { - mi_assert_internal(mi_atomic_load_acquire(&segment->thread_id) == 0); - mi_atomic_decrement_relaxed(&segment->subproc->abandoned_count); - mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); - } - // mi_assert_internal(was_marked); - mi_assert_internal(!was_marked || _mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); - //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); - return was_marked; -} - - -// mark a specific OS segment as abandoned -static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { - mi_assert(segment->memid.memkind != MI_MEM_ARENA); - // not in an arena; we use a list of abandoned segments - mi_subproc_t* const subproc = segment->subproc; - if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { - _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); - // we can continue but cannot visit/reclaim such blocks.. - } - else { - // push on the tail of the list (important for the visitor) - mi_segment_t* prev = subproc->abandoned_os_list_tail; - mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL); - mi_assert_internal(segment->abandoned_os_prev == NULL); - mi_assert_internal(segment->abandoned_os_next == NULL); - if (prev != NULL) { prev->abandoned_os_next = segment; } - else { subproc->abandoned_os_list = segment; } - subproc->abandoned_os_list_tail = segment; - segment->abandoned_os_prev = prev; - segment->abandoned_os_next = NULL; - mi_atomic_increment_relaxed(&subproc->abandoned_os_list_count); - mi_atomic_increment_relaxed(&subproc->abandoned_count); - // and release the lock - mi_lock_release(&subproc->abandoned_os_lock); - } - return; -} - -// mark a specific segment as abandoned -// clears the thread_id. -void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) -{ - mi_assert_internal(segment->used == segment->abandoned); - mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned for multi-thread free's - if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { - mi_arena_segment_os_mark_abandoned(segment); - return; - } - // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap - size_t arena_idx; - size_t bitmap_idx; - mi_arena_memid_indices(segment->memid, &arena_idx, &bitmap_idx); - mi_assert_internal(arena_idx < MI_MAX_ARENAS); - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); - mi_assert_internal(arena != NULL); - // set abandonment atomically - const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } - mi_assert_internal(was_unmarked); - mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); -} - - -/* ----------------------------------------------------------- - Iterate through the abandoned blocks/segments using a cursor. - This is used for reclaiming and abandoned block visiting. ------------------------------------------------------------ */ - -// start a cursor at a randomized arena -void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, bool visit_all, mi_arena_field_cursor_t* current) { - mi_assert_internal(heap == NULL || heap->tld->segments.subproc == subproc); - current->bitmap_idx = 0; - current->subproc = subproc; - current->visit_all = visit_all; - current->hold_visit_lock = false; - const size_t abandoned_count = mi_atomic_load_relaxed(&subproc->abandoned_count); - const size_t abandoned_list_count = mi_atomic_load_relaxed(&subproc->abandoned_os_list_count); - const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); - if (heap != NULL && heap->arena_id != _mi_arena_id_none()) { - // for a heap that is bound to one arena, only visit that arena - current->start = mi_arena_id_index(heap->arena_id); - current->end = current->start + 1; - current->os_list_count = 0; - } - else { - // otherwise visit all starting at a random location - if (abandoned_count > abandoned_list_count && max_arena > 0) { - current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); - current->end = current->start + max_arena; - } - else { - current->start = 0; - current->end = 0; - } - current->os_list_count = abandoned_list_count; // max entries to visit in the os abandoned list - } - mi_assert_internal(current->start <= max_arena); -} - -void _mi_arena_field_cursor_done(mi_arena_field_cursor_t* current) { - if (current->hold_visit_lock) { - mi_lock_release(¤t->subproc->abandoned_os_visit_lock); - current->hold_visit_lock = false; - } -} - -static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_subproc_t* subproc, mi_bitmap_index_t bitmap_idx) { - // try to reclaim an abandoned segment in the arena atomically - if (!_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) return NULL; - mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); - mi_segment_t* segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); - mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); - // check that the segment belongs to our sub-process - // note: this is the reason we need the `abandoned_visit` lock in the case abandoned visiting is enabled. - // without the lock an abandoned visit may otherwise fail to visit all abandoned segments in the sub-process. - // for regular reclaim it is fine to miss one sometimes so without abandoned visiting we don't need the `abandoned_visit` lock. - if (segment->subproc != subproc) { - // it is from another sub-process, re-mark it and continue searching - const bool was_zero = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - mi_assert_internal(was_zero); MI_UNUSED(was_zero); - return NULL; - } - else { - // success, we unabandoned a segment in our sub-process - mi_atomic_decrement_relaxed(&subproc->abandoned_count); - return segment; - } -} - -static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_cursor_t* previous) { - const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count); - size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); - size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1; - // visit arena's (from the previous cursor) - for (; previous->start < previous->end; previous->start++, field_idx = 0, bit_idx = 0) { - // index wraps around - size_t arena_idx = (previous->start >= max_arena ? previous->start % max_arena : previous->start); - mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); - if (arena != NULL) { - bool has_lock = false; - // visit the abandoned fields (starting at previous_idx) - for (; field_idx < arena->field_count; field_idx++, bit_idx = 0) { - size_t field = mi_atomic_load_relaxed(&arena->blocks_abandoned[field_idx]); - if mi_unlikely(field != 0) { // skip zero fields quickly - // we only take the arena lock if there are actually abandoned segments present - if (!has_lock && mi_option_is_enabled(mi_option_visit_abandoned)) { - has_lock = (previous->visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); - if (!has_lock) { - if (previous->visit_all) { - _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the visitor lock"); - } - // skip to next arena - break; - } - } - mi_assert_internal(has_lock || !mi_option_is_enabled(mi_option_visit_abandoned)); - // visit each set bit in the field (todo: maybe use `ctz` here?) - for (; bit_idx < MI_BITMAP_FIELD_BITS; bit_idx++) { - // pre-check if the bit is set - size_t mask = ((size_t)1 << bit_idx); - if mi_unlikely((field & mask) == mask) { - previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); - mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, previous->bitmap_idx); - if (segment != NULL) { - //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); - if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } - return segment; - } - } - } - } - } - if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } - } - } - return NULL; -} - -static mi_segment_t* mi_arena_segment_clear_abandoned_next_list(mi_arena_field_cursor_t* previous) { - // go through the abandoned_os_list - // we only allow one thread per sub-process to do to visit guarded by the `abandoned_os_visit_lock`. - // The lock is released when the cursor is released. - if (!previous->hold_visit_lock) { - previous->hold_visit_lock = (previous->visit_all ? mi_lock_acquire(&previous->subproc->abandoned_os_visit_lock) - : mi_lock_try_acquire(&previous->subproc->abandoned_os_visit_lock)); - if (!previous->hold_visit_lock) { - if (previous->visit_all) { - _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the OS visitor lock"); - } - return NULL; // we cannot get the lock, give up - } - } - // One list entry at a time - while (previous->os_list_count > 0) { - previous->os_list_count--; - const bool has_lock = mi_lock_acquire(&previous->subproc->abandoned_os_lock); // this could contend with concurrent OS block abandonment and reclaim from `free` - if (has_lock) { - mi_segment_t* segment = previous->subproc->abandoned_os_list; - // pop from head of the list, a subsequent mark will push at the end (and thus we iterate through os_list_count entries) - if (segment == NULL || mi_arena_segment_os_clear_abandoned(segment, false /* we already have the lock */)) { - mi_lock_release(&previous->subproc->abandoned_os_lock); - return segment; - } - // already abandoned, try again - mi_lock_release(&previous->subproc->abandoned_os_lock); - } - else { - _mi_error_message(EFAULT, "failed to acquire abandoned OS list lock during abandoned block visit\n"); - return NULL; - } - } - // done - mi_assert_internal(previous->os_list_count == 0); - return NULL; -} - - -// reclaim abandoned segments -// this does not set the thread id (so it appears as still abandoned) -mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous) { - if (previous->start < previous->end) { - // walk the arena - mi_segment_t* segment = mi_arena_segment_clear_abandoned_next_field(previous); - if (segment != NULL) { return segment; } - } - // no entries in the arena's anymore, walk the abandoned OS list - mi_assert_internal(previous->start == previous->end); - return mi_arena_segment_clear_abandoned_next_list(previous); -} - - -bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { - // (unfortunately) the visit_abandoned option must be enabled from the start. - // This is to avoid taking locks if abandoned list visiting is not required (as for most programs) - if (!mi_option_is_enabled(mi_option_visit_abandoned)) { - _mi_error_message(EFAULT, "internal error: can only visit abandoned blocks when MIMALLOC_VISIT_ABANDONED=ON"); - return false; - } - mi_arena_field_cursor_t current; - _mi_arena_field_cursor_init(NULL, _mi_subproc_from_id(subproc_id), true /* visit all (blocking) */, ¤t); - mi_segment_t* segment; - bool ok = true; - while (ok && (segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL) { - ok = _mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg); - _mi_arena_segment_mark_abandoned(segment); - } - _mi_arena_field_cursor_done(¤t); - return ok; -} diff --git a/src/arena.h b/src/arena.h new file mode 100644 index 00000000..0b923d43 --- /dev/null +++ b/src/arena.h @@ -0,0 +1,63 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2019-2024, 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 MI_ARENA_H +#define MI_ARENA_H + +/* ---------------------------------------------------------------------------- +"Arenas" are fixed area's of OS memory from which we can allocate +large blocks (>= MI_ARENA_MIN_BLOCK_SIZE, 4MiB). +In contrast to the rest of mimalloc, the arenas are shared between +threads and need to be accessed using atomic operations. + +Arenas are also used to for huge OS page (1GiB) reservations or for reserving +OS memory upfront which can be improve performance or is sometimes needed +on embedded devices. We can also employ this with WASI or `sbrk` systems +to reserve large arenas upfront and be able to reuse the memory more effectively. + +The arena allocation needs to be thread safe and we use an atomic bitmap to allocate. +-----------------------------------------------------------------------------*/ +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "bitmap.h" + +/* ----------------------------------------------------------- + Arena allocation +----------------------------------------------------------- */ + +// A memory arena descriptor +typedef struct mi_arena_s { + mi_arena_id_t id; // arena id; 0 for non-specific + mi_memid_t memid; // memid of the memory area + _Atomic(uint8_t*) start; // the start of the memory area + size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) + size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) + size_t meta_size; // size of the arena structure itself (including its bitmaps) + mi_memid_t meta_memid; // memid of the arena structure itself (OS or static allocation) + int numa_node; // associated NUMA node + bool exclusive; // only allow allocations if specifically for this arena + bool is_large; // memory area consists of large- or huge OS pages (always committed) + mi_lock_t abandoned_visit_lock; // lock is only used when abandoned segments are being visited + _Atomic(size_t) search_idx; // optimization to start the search for free blocks + _Atomic(mi_msecs_t) purge_expire; // expiration time when blocks should be decommitted from `blocks_decommit`. + mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? + mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) + mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) + mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) + mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) + // do not add further fields here as the dirty, committed, purged, and abandoned bitmaps follow the inuse bitmap fields. +} mi_arena_t; + + +// Minimal exports for arena-abandoned. +size_t mi_arena_id_index(mi_arena_id_t id); +mi_arena_t* mi_arena_from_index(size_t idx); +size_t mi_arena_get_count(void); +void* mi_arena_block_start(mi_arena_t* arena, mi_bitmap_index_t bindex); +bool mi_arena_memid_indices(mi_memid_t memid, size_t* arena_index, mi_bitmap_index_t* bitmap_index); + +#endif \ No newline at end of file diff --git a/src/static.c b/src/static.c index bf025eb7..5e1b826c 100644 --- a/src/static.c +++ b/src/static.c @@ -24,6 +24,7 @@ terms of the MIT license. A copy of the license can be found in the file #include "alloc-aligned.c" #include "alloc-posix.c" #include "arena.c" +#include "arena-abandoned.c" #include "bitmap.c" #include "heap.c" #include "init.c" @@ -31,7 +32,7 @@ terms of the MIT license. A copy of the license can be found in the file #include "options.c" #include "os.c" #include "page.c" // includes page-queue.c -#include "random.c" +#include "random.c" #include "segment.c" #include "segment-map.c" #include "stats.c" From f7ba9d9da036fabc763354495e1facfb556898b1 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 18:04:59 -0700 Subject: [PATCH 033/305] refactor arena-abandoned to be an include for backward compat with existing build scripts --- CMakeLists.txt | 1 - ide/vs2022/mimalloc-override.vcxproj | 12 ++---- ide/vs2022/mimalloc.vcxproj | 12 ++---- src/arena-abandoned.c | 15 ++++++- src/arena.c | 42 ++++++++++++++++++- src/arena.h | 63 ---------------------------- src/free.c | 1 - src/static.c | 1 - 8 files changed, 63 insertions(+), 84 deletions(-) delete mode 100644 src/arena.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fca04263..9f19bf90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,6 @@ set(mi_sources src/alloc-aligned.c src/alloc-posix.c src/arena.c - src/arena-abandoned.c src/bitmap.c src/heap.c src/init.c diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index f83b0dee..e895fa3c 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -237,14 +237,10 @@ - - - - - - - - + true + true + true + true diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index dfbdec64..2c21eda4 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -214,14 +214,10 @@ - - - - - - - - + true + true + true + true diff --git a/src/arena-abandoned.c b/src/arena-abandoned.c index 91327d5f..2a7ade72 100644 --- a/src/arena-abandoned.c +++ b/src/arena-abandoned.c @@ -5,9 +5,22 @@ terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ +#if !defined(MI_IN_ARENA_C) +#error "this file should be included from 'arena.c' (so mi_arena_t is visible)" +// add includes help an IDE #include "mimalloc.h" #include "mimalloc/internal.h" -#include "arena.h" +#include "bitmap.h" +#endif + +typedef struct mi_arena_s mi_arena_t; + +// Minimal exports for arena-abandoned. +size_t mi_arena_id_index(mi_arena_id_t id); +mi_arena_t* mi_arena_from_index(size_t idx); +size_t mi_arena_get_count(void); +void* mi_arena_block_start(mi_arena_t* arena, mi_bitmap_index_t bindex); +bool mi_arena_memid_indices(mi_memid_t memid, size_t* arena_index, mi_bitmap_index_t* bitmap_index); /* ----------------------------------------------------------- Abandoned blocks/segments: diff --git a/src/arena.c b/src/arena.c index 8fa018ab..8a5e8952 100644 --- a/src/arena.c +++ b/src/arena.c @@ -10,11 +10,48 @@ terms of the MIT license. A copy of the license can be found in the file large blocks (>= MI_ARENA_MIN_BLOCK_SIZE, 4MiB). In contrast to the rest of mimalloc, the arenas are shared between threads and need to be accessed using atomic operations. + +Arenas are also used to for huge OS page (1GiB) reservations or for reserving +OS memory upfront which can be improve performance or is sometimes needed +on embedded devices. We can also employ this with WASI or `sbrk` systems +to reserve large arenas upfront and be able to reuse the memory more effectively. + +The arena allocation needs to be thread safe and we use an atomic bitmap to allocate. -----------------------------------------------------------------------------*/ + #include "mimalloc.h" #include "mimalloc/internal.h" #include "mimalloc/atomic.h" -#include "arena.h" +#include "bitmap.h" + + +/* ----------------------------------------------------------- + Arena allocation +----------------------------------------------------------- */ + +// A memory arena descriptor +typedef struct mi_arena_s { + mi_arena_id_t id; // arena id; 0 for non-specific + mi_memid_t memid; // memid of the memory area + _Atomic(uint8_t*)start; // the start of the memory area + size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) + size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) + size_t meta_size; // size of the arena structure itself (including its bitmaps) + mi_memid_t meta_memid; // memid of the arena structure itself (OS or static allocation) + int numa_node; // associated NUMA node + bool exclusive; // only allow allocations if specifically for this arena + bool is_large; // memory area consists of large- or huge OS pages (always committed) + mi_lock_t abandoned_visit_lock; // lock is only used when abandoned segments are being visited + _Atomic(size_t)search_idx; // optimization to start the search for free blocks + _Atomic(mi_msecs_t)purge_expire; // expiration time when blocks should be decommitted from `blocks_decommit`. + mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? + mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) + mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) + mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) + mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) + // do not add further fields here as the dirty, committed, purged, and abandoned bitmaps follow the inuse bitmap fields. +} mi_arena_t; + #define MI_ARENA_BLOCK_SIZE (MI_SEGMENT_SIZE) // 64MiB (must be at least MI_SEGMENT_ALIGN) #define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_BLOCK_SIZE/2) // 32MiB @@ -24,6 +61,9 @@ threads and need to be accessed using atomic operations. static mi_decl_cache_align _Atomic(mi_arena_t*) mi_arenas[MI_MAX_ARENAS]; static mi_decl_cache_align _Atomic(size_t) mi_arena_count; // = 0 +#define MI_IN_ARENA_C +#include "arena-abandoned.c" +#undef MI_IN_ARENA_C /* ----------------------------------------------------------- Arena id's diff --git a/src/arena.h b/src/arena.h deleted file mode 100644 index 0b923d43..00000000 --- a/src/arena.h +++ /dev/null @@ -1,63 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2019-2024, 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 MI_ARENA_H -#define MI_ARENA_H - -/* ---------------------------------------------------------------------------- -"Arenas" are fixed area's of OS memory from which we can allocate -large blocks (>= MI_ARENA_MIN_BLOCK_SIZE, 4MiB). -In contrast to the rest of mimalloc, the arenas are shared between -threads and need to be accessed using atomic operations. - -Arenas are also used to for huge OS page (1GiB) reservations or for reserving -OS memory upfront which can be improve performance or is sometimes needed -on embedded devices. We can also employ this with WASI or `sbrk` systems -to reserve large arenas upfront and be able to reuse the memory more effectively. - -The arena allocation needs to be thread safe and we use an atomic bitmap to allocate. ------------------------------------------------------------------------------*/ -#include "mimalloc.h" -#include "mimalloc/internal.h" -#include "bitmap.h" - -/* ----------------------------------------------------------- - Arena allocation ------------------------------------------------------------ */ - -// A memory arena descriptor -typedef struct mi_arena_s { - mi_arena_id_t id; // arena id; 0 for non-specific - mi_memid_t memid; // memid of the memory area - _Atomic(uint8_t*) start; // the start of the memory area - size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) - size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) - size_t meta_size; // size of the arena structure itself (including its bitmaps) - mi_memid_t meta_memid; // memid of the arena structure itself (OS or static allocation) - int numa_node; // associated NUMA node - bool exclusive; // only allow allocations if specifically for this arena - bool is_large; // memory area consists of large- or huge OS pages (always committed) - mi_lock_t abandoned_visit_lock; // lock is only used when abandoned segments are being visited - _Atomic(size_t) search_idx; // optimization to start the search for free blocks - _Atomic(mi_msecs_t) purge_expire; // expiration time when blocks should be decommitted from `blocks_decommit`. - mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? - mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) - mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) - mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) - mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) - // do not add further fields here as the dirty, committed, purged, and abandoned bitmaps follow the inuse bitmap fields. -} mi_arena_t; - - -// Minimal exports for arena-abandoned. -size_t mi_arena_id_index(mi_arena_id_t id); -mi_arena_t* mi_arena_from_index(size_t idx); -size_t mi_arena_get_count(void); -void* mi_arena_block_start(mi_arena_t* arena, mi_bitmap_index_t bindex); -bool mi_arena_memid_indices(mi_memid_t memid, size_t* arena_index, mi_bitmap_index_t* bitmap_index); - -#endif \ No newline at end of file diff --git a/src/free.c b/src/free.c index 191ec9bf..c6221fe7 100644 --- a/src/free.c +++ b/src/free.c @@ -9,7 +9,6 @@ terms of the MIT license. A copy of the license can be found in the file // add includes help an IDE #include "mimalloc.h" #include "mimalloc/internal.h" -#include "mimalloc/atomic.h" #include "mimalloc/prim.h" // _mi_prim_thread_id() #endif diff --git a/src/static.c b/src/static.c index 5e1b826c..9e06ce05 100644 --- a/src/static.c +++ b/src/static.c @@ -24,7 +24,6 @@ terms of the MIT license. A copy of the license can be found in the file #include "alloc-aligned.c" #include "alloc-posix.c" #include "arena.c" -#include "arena-abandoned.c" #include "bitmap.c" #include "heap.c" #include "init.c" From 537c51e227b2c4db433ba69818fa72e824a76538 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 18:06:53 -0700 Subject: [PATCH 034/305] fix vs 2022 ide --- ide/vs2022/mimalloc.vcxproj | 1 - ide/vs2022/mimalloc.vcxproj.filters | 3 --- 2 files changed, 4 deletions(-) diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index 2c21eda4..5efc8fd0 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -262,7 +262,6 @@ - diff --git a/ide/vs2022/mimalloc.vcxproj.filters b/ide/vs2022/mimalloc.vcxproj.filters index cb0303e0..54ee0fcb 100644 --- a/ide/vs2022/mimalloc.vcxproj.filters +++ b/ide/vs2022/mimalloc.vcxproj.filters @@ -93,9 +93,6 @@ Headers - - Headers - From 065f46cefbe730b01e4072845848ae489d9635c8 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 18:19:45 -0700 Subject: [PATCH 035/305] don't reset a segment thread id when iterating --- src/arena-abandoned.c | 5 ++++- src/segment.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arena-abandoned.c b/src/arena-abandoned.c index 2a7ade72..75e97faf 100644 --- a/src/arena-abandoned.c +++ b/src/arena-abandoned.c @@ -82,7 +82,10 @@ static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment, bool take segment->abandoned_os_prev = NULL; mi_atomic_decrement_relaxed(&subproc->abandoned_count); mi_atomic_decrement_relaxed(&subproc->abandoned_os_list_count); - mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + if (take_lock) { + // don't set the thread_id when iterating + mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); + } reclaimed = true; } if (take_lock) { mi_lock_release(&segment->subproc->abandoned_os_lock); } diff --git a/src/segment.c b/src/segment.c index 7a2d9e8e..7746bd0f 100644 --- a/src/segment.c +++ b/src/segment.c @@ -836,6 +836,7 @@ void _mi_segment_page_abandon(mi_page_t* page, mi_segments_tld_t* tld) { // Possibly clear pages and check if free space is available static bool mi_segment_check_free(mi_segment_t* segment, size_t block_size, bool* all_pages_free) { + mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0); bool has_page = false; size_t pages_used = 0; size_t pages_used_empty = 0; From 3f69119936779f708ba36128dc1704fb174e47d8 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 18:25:22 -0700 Subject: [PATCH 036/305] don't reset a segment thread id when iterating --- src/arena-abandoned.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/arena-abandoned.c b/src/arena-abandoned.c index 75e97faf..3b1b1823 100644 --- a/src/arena-abandoned.c +++ b/src/arena-abandoned.c @@ -82,8 +82,7 @@ static bool mi_arena_segment_os_clear_abandoned(mi_segment_t* segment, bool take segment->abandoned_os_prev = NULL; mi_atomic_decrement_relaxed(&subproc->abandoned_count); mi_atomic_decrement_relaxed(&subproc->abandoned_os_list_count); - if (take_lock) { - // don't set the thread_id when iterating + if (take_lock) { // don't reset the thread_id when iterating mi_atomic_store_release(&segment->thread_id, _mi_thread_id()); } reclaimed = true; From 76b0873ce2ebe3bc28543cb2293c0c62e4617243 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 20:28:47 -0700 Subject: [PATCH 037/305] fix asan tracking by explicitly setting memory to undefined before a free --- src/arena.c | 6 +++--- src/page.c | 2 +- test/test-stress.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/arena.c b/src/arena.c index 8a5e8952..0bd58aaa 100644 --- a/src/arena.c +++ b/src/arena.c @@ -627,6 +627,9 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi if (size==0) return; const bool all_committed = (committed_size == size); + // need to set all memory to undefined as some parts may still be marked as no_access (like padding etc.) + mi_track_mem_undefined(p,size); + if (mi_memkind_is_os(memid.memkind)) { // was a direct OS allocation, pass through if (!all_committed && committed_size > 0) { @@ -656,9 +659,6 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi return; } - // need to set all memory to undefined as some parts may still be marked as no_access (like padding etc.) - mi_track_mem_undefined(p,size); - // potentially decommit if (arena->memid.is_pinned || arena->blocks_committed == NULL) { mi_assert_internal(all_committed); diff --git a/src/page.c b/src/page.c index 5a18b780..96d1b24c 100644 --- a/src/page.c +++ b/src/page.c @@ -857,7 +857,7 @@ static mi_page_t* mi_find_page(mi_heap_t* heap, size_t size, size_t huge_alignme // huge allocation? const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` if mi_unlikely(req_size > (MI_LARGE_OBJ_SIZE_MAX - MI_PADDING_SIZE) || huge_alignment > 0) { - if mi_unlikely(req_size > MI_MAX_ALLOC_SIZE) { + if mi_unlikely(req_size > MI_MAX_ALLOC_SIZE) { _mi_error_message(EOVERFLOW, "allocation request is too large (%zu bytes)\n", req_size); return NULL; } diff --git a/test/test-stress.c b/test/test-stress.c index 675c54bc..2c031894 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -133,9 +133,9 @@ static void free_items(void* p) { custom_free(p); } -#ifdef HEAP_WALK +#ifdef HEAP_WALK static bool visit_blocks(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg) { - (void)(heap); (void)(area); + (void)(heap); (void)(area); size_t* total = (size_t*)arg; if (block != NULL) { *total += block_size; @@ -260,7 +260,7 @@ static void test_leak(void) { int main(int argc, char** argv) { #ifdef HEAP_WALK - mi_option_enable(mi_option_visit_abandoned); + mi_option_enable(mi_option_visit_abandoned); #endif #ifndef NDEBUG mi_option_set(mi_option_arena_reserve, 32 * 1024 /* in kib = 32MiB */); From b1188ea33624f407e580cb278cb896a42521273e Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 3 Jun 2024 20:57:00 -0700 Subject: [PATCH 038/305] fix potential race on subproc field in the segment --- include/mimalloc/types.h | 4 ++-- src/arena-abandoned.c | 3 ++- src/init.c | 8 ++++---- src/segment.c | 12 ++++++------ test/test-stress.c | 13 +++++-------- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 2fc83a30..31ed35f8 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -397,9 +397,10 @@ typedef struct mi_segment_s { bool allow_decommit; bool allow_purge; size_t segment_size; // for huge pages this may be different from `MI_SEGMENT_SIZE` + mi_subproc_t* subproc; // segment belongs to sub process // segment fields - struct mi_segment_s* next; // must be the first segment field after abandoned_next -- see `segment.c:segment_init` + struct mi_segment_s* next; // must be the first (non-constant) segment field -- see `segment.c:segment_init` struct mi_segment_s* prev; bool was_reclaimed; // true if it was reclaimed (used to limit on-free reclamation) @@ -410,7 +411,6 @@ typedef struct mi_segment_s { size_t capacity; // count of available pages (`#free + used`) size_t segment_info_size;// space we are using from the first page for segment meta-data and possible guard pages. uintptr_t cookie; // verify addresses in secure mode: `_mi_ptr_cookie(segment) == segment->cookie` - mi_subproc_t* subproc; // segment belongs to sub process struct mi_segment_s* abandoned_os_next; // only used for abandoned segments outside arena's, and only if `mi_option_visit_abandoned` is enabled struct mi_segment_s* abandoned_os_prev; diff --git a/src/arena-abandoned.c b/src/arena-abandoned.c index 3b1b1823..465a074d 100644 --- a/src/arena-abandoned.c +++ b/src/arena-abandoned.c @@ -162,8 +162,9 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) mi_arena_t* arena = mi_arena_from_index(arena_idx); mi_assert_internal(arena != NULL); // set abandonment atomically + mi_subproc_t* const subproc = segment->subproc; // don't access the segment after setting it abandoned const bool was_unmarked = _mi_bitmap_claim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx, NULL); - if (was_unmarked) { mi_atomic_increment_relaxed(&segment->subproc->abandoned_count); } + if (was_unmarked) { mi_atomic_increment_relaxed(&subproc->abandoned_count); } mi_assert_internal(was_unmarked); mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); } diff --git a/src/init.c b/src/init.c index 08208ea7..ead5a147 100644 --- a/src/init.c +++ b/src/init.c @@ -34,7 +34,7 @@ const mi_page_t _mi_page_empty = { MI_ATOMIC_VAR_INIT(0), // xthread_free MI_ATOMIC_VAR_INIT(0), // xheap NULL, NULL - #if MI_INTPTR_SIZE==4 + #if MI_INTPTR_SIZE==4 , { NULL } #endif }; @@ -129,7 +129,7 @@ static mi_decl_cache_align mi_subproc_t mi_subproc_default; static mi_decl_cache_align mi_tld_t tld_main = { 0, false, - &_mi_heap_main, &_mi_heap_main, + &_mi_heap_main, &_mi_heap_main, { { NULL, NULL }, {NULL ,NULL}, {NULL ,NULL, 0}, 0, 0, 0, 0, 0, &mi_subproc_default, &tld_main.stats, &tld_main.os @@ -171,7 +171,7 @@ static void mi_heap_main_init(void) { #endif _mi_heap_main.cookie = _mi_heap_random_next(&_mi_heap_main); _mi_heap_main.keys[0] = _mi_heap_random_next(&_mi_heap_main); - _mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main); + _mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main); mi_lock_init(&mi_subproc_default.abandoned_os_lock); mi_lock_init(&mi_subproc_default.abandoned_os_visit_lock); } @@ -341,7 +341,7 @@ static bool _mi_thread_heap_init(void) { mi_heap_t* heap = &td->heap; _mi_tld_init(tld, heap); // must be before `_mi_heap_init` _mi_heap_init(heap, tld, _mi_arena_id_none(), false /* can reclaim */, 0 /* default tag */); - _mi_heap_set_default_direct(heap); + _mi_heap_set_default_direct(heap); } return false; } diff --git a/src/segment.c b/src/segment.c index 7746bd0f..54a917ea 100644 --- a/src/segment.c +++ b/src/segment.c @@ -512,7 +512,7 @@ static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_se _mi_arena_free(segment, segment_size, committed_size, segment->memid, tld->stats); } -// called from `heap_collect`. +// called from `heap_collect`. void _mi_segments_collect(bool force, mi_segments_tld_t* tld) { mi_pages_try_purge(force,tld); #if MI_DEBUG>=2 @@ -563,6 +563,7 @@ static mi_segment_t* mi_segment_os_alloc(bool eager_delayed, size_t page_alignme segment->allow_decommit = !memid.is_pinned; segment->allow_purge = segment->allow_decommit && (mi_option_get(mi_option_purge_delay) >= 0); segment->segment_size = segment_size; + segment->subproc = tld->subproc; mi_segments_track_size((long)(segment_size), tld); _mi_segment_map_allocated_at(segment); return segment; @@ -628,7 +629,6 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, segment->segment_info_size = pre_size; segment->thread_id = _mi_thread_id(); segment->cookie = _mi_ptr_cookie(segment); - segment->subproc = tld->subproc; // set protection mi_segment_protect(segment, true, tld->os); @@ -896,7 +896,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, segment->abandoned--; mi_assert(page->next == NULL); _mi_stat_decrease(&tld->stats->pages_abandoned, 1); - // get the target heap for this thread which has a matching heap tag (so we reclaim into a matching heap) + // get the target heap for this thread which has a matching heap tag (so we reclaim into a matching heap) mi_heap_t* target_heap = _mi_heap_by_tag(heap, page->heap_tag); // allow custom heaps to separate objects if (target_heap == NULL) { target_heap = heap; @@ -961,7 +961,7 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) { mi_segment_t* segment; - mi_arena_field_cursor_t current; + mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, true /* visit all, blocking */, ¤t); while ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL) { mi_segment_reclaim(segment, heap, 0, NULL, tld); @@ -989,7 +989,7 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, mi_segment_t* result = NULL; mi_segment_t* segment = NULL; - mi_arena_field_cursor_t current; + mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, false /* non-blocking */, ¤t); while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL)) { @@ -1264,7 +1264,7 @@ static bool mi_segment_visit_page(mi_page_t* page, bool visit_blocks, mi_block_v } } -bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { +bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { for (size_t i = 0; i < segment->capacity; i++) { mi_page_t* const page = &segment->pages[i]; if (page->segment_in_use) { diff --git a/test/test-stress.c b/test/test-stress.c index 2c031894..2d1927cc 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -25,17 +25,14 @@ terms of the MIT license. // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // // argument defaults +#if !defined(MI_TSAN) static int THREADS = 32; // more repeatable if THREADS <= #processors -static int SCALE = 25; // scaling factor - -#if defined(MI_TSAN) -static int ITER = 10; // N full iterations destructing and re-creating all threads (on tsan reduce for azure pipeline limits) -#else -static int ITER = 50; // N full iterations destructing and re-creating all threads +#else // with thread-sanitizer reduce the defaults for azure pipeline limits +static int THREADS = 8; #endif -// static int THREADS = 8; // more repeatable if THREADS <= #processors -// static int SCALE = 100; // scaling factor +static int SCALE = 25; // scaling factor +static int ITER = 50; // N full iterations destructing and re-creating all threads #define STRESS // undefine for leak test From cf10af7824101e5d24c275f6d22b26033ac73066 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 21:07:48 -0700 Subject: [PATCH 039/305] re-enable tsan test in azure pipelines --- azure-pipelines.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 27dfa3e1..e3689407 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -108,12 +108,11 @@ jobs: CXX: clang++ BuildType: debug-ubsan-clang cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_DEBUG_UBSAN=ON - # Disable for now as it times out on the azure build machines - # Debug TSAN Clang++: - # CC: clang - # CXX: clang++ - # BuildType: debug-tsan-clang-cxx - # cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_USE_CXX=ON -DMI_DEBUG_TSAN=ON + Debug TSAN Clang++: + CC: clang + CXX: clang++ + BuildType: debug-tsan-clang-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMI_USE_CXX=ON -DMI_DEBUG_TSAN=ON steps: - task: CMake@1 From 0c322c556664563eea9a13b54dc7942b492d87c3 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 21:10:05 -0700 Subject: [PATCH 040/305] add reference to page_malloc_zero in C++ build --- src/alloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/alloc.c b/src/alloc.c index 5ba8bb33..267fab0c 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -584,6 +584,7 @@ mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) { #ifdef __cplusplus void* _mi_externs[] = { (void*)&_mi_page_malloc, + (void*)&_mi_page_malloc_zero, (void*)&_mi_heap_malloc_zero, (void*)&_mi_heap_malloc_zero_ex, (void*)&mi_malloc, From b123bbe6c0e3721d363785638808a92b1175759b Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 21:13:34 -0700 Subject: [PATCH 041/305] increase iterations for tsan test --- test/test-stress.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/test-stress.c b/test/test-stress.c index 2d1927cc..0dfa1668 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -27,12 +27,15 @@ terms of the MIT license. // argument defaults #if !defined(MI_TSAN) static int THREADS = 32; // more repeatable if THREADS <= #processors -#else // with thread-sanitizer reduce the defaults for azure pipeline limits -static int THREADS = 8; -#endif - static int SCALE = 25; // scaling factor static int ITER = 50; // N full iterations destructing and re-creating all threads +#else // with thread-sanitizer reduce the threads to test within the azure pipeline limits +static int THREADS = 8; +static int SCALE = 25; // scaling factor +static int ITER = 200; // N full iterations destructing and re-creating all threads +#endif + + #define STRESS // undefine for leak test From e0baf882bb1cfef1d0d20370de392fcd512b1fae Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 21:26:38 -0700 Subject: [PATCH 042/305] reduce UBSAN parameters to stay within pipeline limits --- CMakeLists.txt | 1 + test/test-stress.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f19bf90..7a730557 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -258,6 +258,7 @@ if(MI_DEBUG_UBSAN) if(CMAKE_BUILD_TYPE MATCHES "Debug") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(STATUS "Build with undefined-behavior sanitizer (MI_DEBUG_UBSAN=ON)") + list(APPEND mi_defines MI_UBSAN=1) list(APPEND mi_cflags -fsanitize=undefined -g -fno-sanitize-recover=undefined) list(APPEND mi_libraries -fsanitize=undefined) if (NOT MI_USE_CXX) diff --git a/test/test-stress.c b/test/test-stress.c index 0dfa1668..f9b3c9d6 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -25,14 +25,18 @@ terms of the MIT license. // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // // argument defaults -#if !defined(MI_TSAN) +#if defined(MI_TSAN) // with thread-sanitizer reduce the threads to test within the azure pipeline limits +static int THREADS = 8; +static int SCALE = 25; +static int ITER = 200; +#elif defined(MI_UBSAN) // with undefined behavious sanitizer reduce parameters to stay within the azure pipeline limits +static int THREADS = 8; +static int SCALE = 25; +static int ITER = 20; +#else static int THREADS = 32; // more repeatable if THREADS <= #processors static int SCALE = 25; // scaling factor static int ITER = 50; // N full iterations destructing and re-creating all threads -#else // with thread-sanitizer reduce the threads to test within the azure pipeline limits -static int THREADS = 8; -static int SCALE = 25; // scaling factor -static int ITER = 200; // N full iterations destructing and re-creating all threads #endif From 08fa864605a3d4d38e4ff4c44f21a72a4ada90c3 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 3 Jun 2024 21:30:02 -0700 Subject: [PATCH 043/305] rename arena-abandoned to arena-abandon --- src/{arena-abandoned.c => arena-abandon.c} | 2 -- src/arena.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) rename src/{arena-abandoned.c => arena-abandon.c} (99%) diff --git a/src/arena-abandoned.c b/src/arena-abandon.c similarity index 99% rename from src/arena-abandoned.c rename to src/arena-abandon.c index 465a074d..eaa8c7c9 100644 --- a/src/arena-abandoned.c +++ b/src/arena-abandon.c @@ -13,8 +13,6 @@ terms of the MIT license. A copy of the license can be found in the file #include "bitmap.h" #endif -typedef struct mi_arena_s mi_arena_t; - // Minimal exports for arena-abandoned. size_t mi_arena_id_index(mi_arena_id_t id); mi_arena_t* mi_arena_from_index(size_t idx); diff --git a/src/arena.c b/src/arena.c index 0bd58aaa..3bb8f502 100644 --- a/src/arena.c +++ b/src/arena.c @@ -62,7 +62,7 @@ static mi_decl_cache_align _Atomic(mi_arena_t*) mi_arenas[MI_MAX_ARENAS]; static mi_decl_cache_align _Atomic(size_t) mi_arena_count; // = 0 #define MI_IN_ARENA_C -#include "arena-abandoned.c" +#include "arena-abandon.c" #undef MI_IN_ARENA_C /* ----------------------------------------------------------- From e64684c9f941fa3485adef197de67463b0e74435 Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 4 Jun 2024 14:37:16 -0700 Subject: [PATCH 044/305] update documentation --- doc/mimalloc-doc.h | 340 ++++-- doc/mimalloc-doxygen.css | 11 + docs/annotated.html | 71 +- docs/bench.html | 73 +- docs/build.html | 73 +- docs/classes.html | 71 +- docs/doxygen.css | 716 ++++++------ docs/dynsections.js | 245 ++-- docs/environment.html | 91 +- docs/functions.html | 87 +- docs/functions_vars.html | 89 +- docs/group__aligned.html | 286 ++--- docs/group__aligned.js | 18 +- docs/group__analysis.html | 240 ++-- docs/group__analysis.js | 4 +- ...group__analysis_structmi__heap__area__t.js | 1 + docs/group__cpp.html | 274 ++--- docs/group__cpp.js | 16 +- docs/group__extended.html | 931 ++++++++++----- docs/group__extended.js | 22 +- docs/group__heap.html | 695 +++++------ docs/group__heap.js | 46 +- docs/group__malloc.html | 354 +++--- docs/group__malloc.js | 22 +- docs/group__options.html | 344 +++--- docs/group__options.js | 34 +- docs/group__posix.html | 533 +++++---- docs/group__posix.js | 18 +- docs/group__typed.html | 297 ++--- docs/group__zeroinit.html | 377 +++--- docs/group__zeroinit.js | 22 +- docs/index.html | 87 +- docs/jquery.js | 11 +- docs/mimalloc-doc_8h_source.html | 973 +++++++++------- docs/mimalloc-doxygen.css | 11 + docs/navtree.css | 18 +- docs/navtree.js | 873 +++++++------- docs/navtreedata.js | 2 +- docs/navtreeindex0.js | 288 +++-- docs/overrides.html | 123 +- docs/pages.html | 73 +- docs/resize.js | 181 +-- docs/search/all_1.js | 4 +- docs/search/all_2.js | 8 +- docs/search/all_3.js | 4 +- docs/search/all_4.js | 4 +- docs/search/all_5.js | 4 +- docs/search/all_6.js | 152 +-- docs/search/all_7.js | 3 +- docs/search/all_8.js | 3 +- docs/search/all_9.js | 191 ++- docs/search/all_a.js | 3 +- docs/search/all_b.js | 4 +- docs/search/all_c.js | 4 +- docs/search/all_d.js | 3 +- docs/search/classes_0.js | 4 +- docs/search/enums_0.js | 2 +- docs/search/enumvalues_0.js | 2 +- docs/search/enumvalues_1.js | 44 +- docs/search/functions_0.js | 247 ++-- docs/search/groups_0.js | 4 +- docs/search/groups_1.js | 2 +- docs/search/groups_2.js | 2 +- docs/search/groups_3.js | 2 +- docs/search/groups_4.js | 3 +- docs/search/groups_5.js | 3 +- docs/search/groups_6.js | 3 +- docs/search/groups_7.js | 2 +- docs/search/groups_8.js | 2 +- docs/search/pages_0.js | 2 +- docs/search/pages_1.js | 2 +- docs/search/pages_2.js | 2 +- docs/search/pages_3.js | 4 +- docs/search/pages_4.js | 3 +- docs/search/search.css | 162 +-- docs/search/search.js | 1034 ++++++++--------- docs/search/searchdata.js | 9 +- docs/search/typedefs_0.js | 12 +- docs/search/variables_0.js | 4 +- docs/search/variables_1.js | 2 +- docs/search/variables_2.js | 2 +- docs/search/variables_3.js | 2 +- docs/tabs.css | 14 +- docs/using.html | 75 +- 84 files changed, 5808 insertions(+), 5271 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index f7f358a7..42454e9f 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -25,12 +25,15 @@ without code changes, for example, on Unix you can use it as: ``` Notable aspects of the design include: - - __small and consistent__: the library is about 8k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic _heartbeat_ and deferred freeing (for bounded worst-case times with reference counting). + Partly due to its simplicity, mimalloc has been ported to many systems (Windows, macOS, + Linux, WASM, various BSD's, Haiku, MUSL, etc) and has excellent support for dynamic overriding. + At the same time, it is an industrial strength allocator that runs (very) large scale + distributed services on thousands of machines with excellent worst case latencies. - __free list sharding__: instead of one big free list (per size class) we have many smaller lists per "mimalloc page" which reduces fragmentation and increases locality -- @@ -45,23 +48,23 @@ Notable aspects of the design include: and the chance of contending on a single location will be low -- this is quite similar to randomized algorithms like skip lists where adding a random oracle removes the need for a more complex algorithm. -- __eager page reset__: when a "page" becomes empty (with increased chance - due to free list sharding) the memory is marked to the OS as unused ("reset" or "purged") +- __eager page purging__: when a "page" becomes empty (with increased chance + due to free list sharding) the memory is marked to the OS as unused (reset or decommitted) reducing (real) memory pressure and fragmentation, especially in long running programs. -- __secure__: _mimalloc_ can be build in secure mode, adding guard pages, +- __secure__: _mimalloc_ can be built in secure mode, adding guard pages, randomized allocation, encrypted free lists, etc. to protect against various - heap vulnerabilities. The performance penalty is only around 5% on average + heap vulnerabilities. The performance penalty is usually around 10% on average over our benchmarks. - __first-class heaps__: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately. - __bounded__: it does not suffer from _blowup_ \[1\], has bounded worst-case allocation - times (_wcat_), bounded space overhead (~0.2% meta-data, with low internal fragmentation), - and has no internal points of contention using only atomic operations. -- __fast__: In our benchmarks (see [below](#performance)), - _mimalloc_ outperforms all other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), - and usually uses less memory (up to 25% more in the worst case). A nice property - is that it does consistently well over a wide range of benchmarks. + times (_wcat_) (upto OS primitives), bounded space overhead (~0.2% meta-data, with low + internal fragmentation), and has no internal points of contention using only atomic operations. +- __fast__: In our benchmarks (see [below](#bench)), + _mimalloc_ outperforms other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), + and often uses less memory. A nice property is that it does consistently well over a wide range + of benchmarks. There is also good huge OS page support for larger server programs. You can read more on the design of _mimalloc_ in the [technical report](https://www.microsoft.com/en-us/research/publication/mimalloc-free-list-sharding-in-action) @@ -428,7 +431,7 @@ int mi_reserve_os_memory(size_t size, bool commit, bool allow_large); /// allocated in some manner and available for use my mimalloc. /// @param start Start of the memory area /// @param size The size of the memory area. -/// @param commit Is the area already committed? +/// @param is_committed Is the area already committed? /// @param is_large Does it consist of large OS pages? Set this to \a true as well for memory /// that should not be decommitted or protected (like rdma etc.) /// @param is_zero Does the area consists of zero's? @@ -453,7 +456,7 @@ int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t /// Reserve \a pages of huge OS pages (1GiB) at a specific \a numa_node, /// but stops after at most `timeout_msecs` seconds. /// @param pages The number of 1GiB pages to reserve. -/// @param numa_node The NUMA node where the memory is reserved (start at 0). +/// @param numa_node The NUMA node where the memory is reserved (start at 0). Use -1 for no affinity. /// @param timeout_msecs Maximum number of milli-seconds to try reserving, or 0 for no timeout. /// @returns 0 if successful, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. /// @@ -486,6 +489,79 @@ bool mi_is_redirected(); /// on other systems as the amount of read/write accessible memory reserved by mimalloc. void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults); +/// @brief Show all current arena's. +/// @param show_inuse Show the arena blocks that are in use. +/// @param show_abandoned Show the abandoned arena blocks. +/// @param show_purge Show arena blocks scheduled for purging. +void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge); + +/// Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory. +/// Each arena has an associated identifier. +typedef int mi_arena_id_t; + +/// @brief Return the size of an arena. +/// @param arena_id The arena identifier. +/// @param size Returned size in bytes of the (virtual) arena area. +/// @return base address of the arena. +void* mi_arena_area(mi_arena_id_t arena_id, size_t* size); + +/// @brief Reserve huge OS pages (1GiB) into a single arena. +/// @param pages Number of 1GiB pages to reserve. +/// @param numa_node The associated NUMA node, or -1 for no NUMA preference. +/// @param timeout_msecs Max amount of milli-seconds this operation is allowed to take. (0 is infinite) +/// @param exclusive If exclusive, only a heap associated with this arena can allocate in it. +/// @param arena_id The arena identifier. +/// @return 0 if successful, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. +int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id); + +/// @brief Reserve OS memory to be managed in an arena. +/// @param size Size the reserve. +/// @param commit Should the memory be initially committed? +/// @param allow_large Allow the use of large OS pages? +/// @param exclusive Is the returned arena exclusive? +/// @param arena_id The new arena identifier. +/// @return Zero on success, an error code otherwise. +int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id); + +/// @brief Manage externally allocated memory as a mimalloc arena. This memory will not be freed by mimalloc. +/// @param start Start address of the area. +/// @param size Size in bytes of the area. +/// @param is_committed Is the memory already committed? +/// @param is_large Does it consist of (pinned) large OS pages? +/// @param is_zero Is the memory zero-initialized? +/// @param numa_node Associated NUMA node, or -1 to have no NUMA preference. +/// @param exclusive Is the arena exclusive (where only heaps associated with the arena can allocate in it) +/// @param arena_id The new arena identifier. +/// @return `true` if successful. +bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id); + +/// @brief Create a new heap that only allocates in the specified arena. +/// @param arena_id The arena identifier. +/// @return The new heap or `NULL`. +mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id); + +/// A process can associate threads with sub-processes. +/// A sub-process will not reclaim memory from (abandoned heaps/threads) +/// other subprocesses. +typedef void* mi_subproc_id_t; + +/// @brief Get the main sub-process identifier. +mi_subproc_id_t mi_subproc_main(void); + +/// @brief Create a fresh sub-process (with no associated threads yet). +/// @return The new sub-process identifier. +mi_subproc_id_t mi_subproc_new(void); + +/// @brief Delete a previously created sub-process. +/// @param subproc The sub-process identifier. +/// Only delete sub-processes if all associated threads have terminated. +void mi_subproc_delete(mi_subproc_id_t subproc); + +/// Add the current thread to the given sub-process. +/// This should be called right after a thread is created (and no allocation has taken place yet) +void mi_subproc_add_current_thread(mi_subproc_id_t subproc); + + /// \} // ------------------------------------------------------ @@ -574,12 +650,12 @@ void mi_heap_delete(mi_heap_t* heap); /// heap is set to the backing heap. void mi_heap_destroy(mi_heap_t* heap); -/// Set the default heap to use for mi_malloc() et al. +/// Set the default heap to use in the current thread for mi_malloc() et al. /// @param heap The new default heap. /// @returns The previous default heap. mi_heap_t* mi_heap_set_default(mi_heap_t* heap); -/// Get the default heap that is used for mi_malloc() et al. +/// Get the default heap that is used for mi_malloc() et al. (for the current thread). /// @returns The current default heap. mi_heap_t* mi_heap_get_default(); @@ -764,6 +840,7 @@ typedef struct mi_heap_area_s { size_t committed; ///< current committed bytes of this area size_t used; ///< bytes in use by allocated blocks size_t block_size; ///< size in bytes of one block + size_t full_block_size; ///< size in bytes of a full block including padding and metadata. } mi_heap_area_t; /// Visitor function passed to mi_heap_visit_blocks() @@ -788,6 +865,11 @@ typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* a /// @returns \a true if all areas and blocks were visited. 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 abandoned heaps. +/// Note: requires the option `mi_option_allow_visit_abandoned` to be set +/// at the start of the program. +bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); + /// \} /// \defgroup options Runtime Options @@ -799,34 +881,38 @@ bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block /// Runtime options. typedef enum mi_option_e { // stable options - mi_option_show_errors, ///< Print error messages to `stderr`. - mi_option_show_stats, ///< Print statistics to `stderr` when the program is done. - mi_option_verbose, ///< Print verbose messages to `stderr`. + mi_option_show_errors, ///< Print error messages. + mi_option_show_stats, ///< Print statistics on termination. + mi_option_verbose, ///< Print verbose messages. + mi_option_max_errors, ///< issue at most N error messages + mi_option_max_warnings, ///< issue at most N warning messages - // the following options are experimental - mi_option_eager_commit, ///< Eagerly commit segments (4MiB) (enabled by default). - mi_option_large_os_pages, ///< Use large OS pages (2MiB in size) if possible - mi_option_reserve_huge_os_pages, ///< The number of huge OS pages (1GiB in size) to reserve at the start of the program. - mi_option_reserve_huge_os_pages_at, ///< Reserve huge OS pages at node N. - mi_option_reserve_os_memory, ///< Reserve specified amount of OS memory at startup, e.g. "1g" or "512m". - mi_option_segment_cache, ///< The number of segments per thread to keep cached (0). - mi_option_page_reset, ///< Reset page memory after \a mi_option_reset_delay milliseconds when it becomes free. - mi_option_abandoned_page_reset, //< Reset free page memory when a thread terminates. - mi_option_use_numa_nodes, ///< Pretend there are at most N NUMA nodes; Use 0 to use the actual detected NUMA nodes at runtime. - mi_option_eager_commit_delay, ///< the first N segments per thread are not eagerly committed (=1). - mi_option_os_tag, ///< OS tag to assign to mimalloc'd memory - mi_option_limit_os_alloc, ///< If set to 1, do not use OS memory for allocation (but only pre-reserved arenas) + // advanced options + mi_option_reserve_huge_os_pages, ///< reserve N huge OS pages (1GiB pages) at startup + mi_option_reserve_huge_os_pages_at, ///< Reserve N huge OS pages at a specific NUMA node N. + mi_option_reserve_os_memory, ///< reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use `mi_option_get_size`) + mi_option_allow_large_os_pages, ///< allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process. + mi_option_purge_decommits, ///< should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit) + mi_option_arena_reserve, ///< initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use `mi_option_get_size`) + mi_option_os_tag, ///< tag used for OS logging (macOS only for now) (=100) + mi_option_retry_on_oom, ///< retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) - // v1.x specific options - mi_option_eager_region_commit, ///< Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows) - mi_option_segment_reset, ///< Experimental - mi_option_reset_delay, ///< Delay in milli-seconds before resetting a page (100ms by default) - mi_option_reset_decommits, ///< Experimental - - // v2.x specific options - mi_option_allow_decommit, ///< Enable decommitting memory (=on) - mi_option_decommit_delay, ///< Decommit page memory after N milli-seconds delay (25ms). - mi_option_segment_decommit_delay, ///< Decommit large segment memory after N milli-seconds delay (500ms). + // experimental options + mi_option_eager_commit, ///< eager commit segments? (after `eager_commit_delay` segments) (enabled by default). + mi_option_eager_commit_delay, ///< the first N segments per thread are not eagerly committed (but per page in the segment on demand) + mi_option_arena_eager_commit, ///< eager commit arenas? Use 2 to enable just on overcommit systems (=2) + mi_option_abandoned_page_purge, ///< immediately purge delayed purges on thread termination + mi_option_purge_delay, ///< memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10) + mi_option_use_numa_nodes, ///< 0 = use all available numa nodes, otherwise use at most N nodes. + mi_option_disallow_os_alloc, ///< 1 = do not use OS memory for allocation (but only programmatically reserved arenas) + mi_option_limit_os_alloc, ///< If set to 1, do not use OS memory for allocation (but only pre-reserved arenas) + mi_option_max_segment_reclaim, ///< max. percentage of the abandoned segments can be reclaimed per try (=10%) + mi_option_destroy_on_exit, ///< if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe + mi_option_arena_purge_mult, ///< multiplier for `purge_delay` for the purging delay for arenas (=10) + mi_option_abandoned_reclaim_on_free, ///< allow to reclaim an abandoned segment on a free (=1) + mi_option_purge_extend_delay, ///< extend purge delay on each subsequent delay (=1) + mi_option_disallow_arena_alloc, ///< 1 = do not use arena's for allocation (except if using specific arena id's) + mi_option_visit_abandoned, ///< allow visiting heap blocks from abandoned threads (=0) _mi_option_last } mi_option_t; @@ -838,7 +924,10 @@ void mi_option_disable(mi_option_t option); void mi_option_set_enabled(mi_option_t option, bool enable); void mi_option_set_enabled_default(mi_option_t option, bool enable); -long mi_option_get(mi_option_t option); +long mi_option_get(mi_option_t option); +long mi_option_get_clamp(mi_option_t option, long min, long max); +size_t mi_option_get_size(mi_option_t option); + void mi_option_set(mi_option_t option, long value); void mi_option_set_default(mi_option_t option, long value); @@ -852,21 +941,27 @@ void mi_option_set_default(mi_option_t option, long value); /// /// \{ -void* mi_recalloc(void* p, size_t count, size_t size); -size_t mi_malloc_size(const void* p); -size_t mi_malloc_usable_size(const void *p); - /// Just as `free` but also checks if the pointer `p` belongs to our heap. void mi_cfree(void* p); +void* mi__expand(void* p, size_t newsize); + +void* mi_recalloc(void* p, size_t count, size_t size); +size_t mi_malloc_size(const void* p); +size_t mi_malloc_good_size(size_t size); +size_t mi_malloc_usable_size(const void *p); int mi_posix_memalign(void** p, size_t alignment, size_t size); int mi__posix_memalign(void** p, size_t alignment, size_t size); void* mi_memalign(size_t alignment, size_t size); void* mi_valloc(size_t size); - void* mi_pvalloc(size_t size); void* mi_aligned_alloc(size_t alignment, size_t size); +unsigned short* mi_wcsdup(const unsigned short* s); +unsigned char* mi_mbsdup(const unsigned char* s); +int mi_dupenv_s(char** buf, size_t* size, const char* name); +int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name); + /// Correspond s to [reallocarray](https://www.freebsd.org/cgi/man.cgi?query=reallocarray&sektion=3&manpath=freebsd-release-ports) /// in FreeBSD. void* mi_reallocarray(void* p, size_t count, size_t size); @@ -874,6 +969,9 @@ void* mi_reallocarray(void* p, size_t count, size_t size); /// Corresponds to [reallocarr](https://man.netbsd.org/reallocarr.3) in NetBSD. int mi_reallocarr(void* p, size_t count, size_t size); +void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment); +void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset); + void mi_free_size(void* p, size_t size); void mi_free_size_aligned(void* p, size_t size, size_t alignment); void mi_free_aligned(void* p, size_t alignment); @@ -998,7 +1096,7 @@ mimalloc uses only safe OS calls (`mmap` and `VirtualAlloc`) and can co-exist with other allocators linked to the same program. If you use `cmake`, you can simply use: ``` -find_package(mimalloc 1.0 REQUIRED) +find_package(mimalloc 2.1 REQUIRED) ``` in your `CMakeLists.txt` to find a locally installed mimalloc. Then use either: ``` @@ -1071,38 +1169,63 @@ See \ref overrides for more info. /*! \page environment Environment Options -You can set further options either programmatically (using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), -or via environment variables. +You can set further options either programmatically (using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), 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 - 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 + +Advanced options: + +- `MIMALLOC_ARENA_EAGER_COMMIT=2`: turns on eager commit for the large arenas (usually 1GiB) from which mimalloc + allocates segments and pages. Set this to 2 (default) to + only enable this on overcommit systems (e.g. Linux). Set this to 1 to enable explicitly on other systems + as well (like Windows or macOS) which may improve performance (as the whole arena is committed at once). + Note that eager commit only increases the commit but not the actual the peak resident set + (rss) so it is generally ok to enable this. +- `MIMALLOC_PURGE_DELAY=N`: the delay in `N` milli-seconds (by default `10`) after which mimalloc will purge + OS pages that are not in use. This signals to the OS that the underlying physical memory can be reused which + can reduce memory fragmentation especially in long running (server) programs. Setting `N` to `0` purges immediately when + a page becomes unused which can improve memory usage but also decreases performance. Setting `N` to a higher + value like `100` can improve performance (sometimes by a lot) at the cost of potentially using more memory at times. + Setting it to `-1` disables purging completely. +- `MIMALLOC_PURGE_DECOMMITS=1`: By default "purging" memory means unused memory is decommitted (`MEM_DECOMMIT` on Windows, + `MADV_DONTNEED` (which decresease rss immediately) on `mmap` systems). Set this to 0 to instead "reset" unused + memory on a purge (`MEM_RESET` on Windows, generally `MADV_FREE` (which does not decrease rss immediately) on `mmap` systems). + Mimalloc generally does not "free" OS memory but only "purges" OS memory, in other words, it tries to keep virtual + address ranges and decommits within those ranges (to make the underlying physical memory available to other processes). + +Further options for large workloads and services: + +- `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_ALLOW_LARGE_OS_PAGES=1`: use large OS pages (2 or 4MiB) when available; for some workloads this can significantly + improve performance. When this option is disabled, it also disables transparent huge pages (THP) for the process + (on Linux and Android). Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs + to explicitly give permissions for 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_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB _huge_ OS pages. This reserves the huge pages at + can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead whenever 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 + Usually it is better to not use `MIMALLOC_ALLOW_LARGE_OS_PAGES=1` 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 + Note that we usually need to explicitly give permission for 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` (`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). -- `MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N`: where N is the numa node. This reserves the huge pages at a specific numa node. - (`N` is -1 by default to reserve huge pages evenly among the given number of numa nodes (or use the available ones as detected)) + and allocate just a little to take up space in the huge OS page area (which cannot be purged as huge OS pages are pinned + to physical memory). + The huge pages are usually allocated evenly among NUMA nodes. + We can use `MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N` where `N` is the numa node (starting at 0) to allocate all + the huge pages at a specific numa node instead. 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. +OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the memory usage to grow in large 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 @@ -1111,87 +1234,100 @@ OS will copy the entire 1GiB huge page (or 2MiB large page) which can cause the /*! \page overrides Overriding Malloc -Overriding the standard `malloc` can be done either _dynamically_ or _statically_. +Overriding the standard `malloc` (and `new`) can be done either _dynamically_ or _statically_. ## Dynamic override This is the recommended way to override the standard malloc interface. +### Dynamic Override on Linux, BSD -### Linux, BSD - -On these systems we preload the mimalloc shared +On these ELF-based systems we preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the _mimalloc_ library. - -- `env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram` +``` +> env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram +``` You can set extra environment variables to check that mimalloc is running, like: ``` -env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram +> env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram ``` or run with the debug version to get detailed statistics: ``` -env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram +> env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram ``` -### MacOS +### Dynamic Override on MacOS On macOS we can also preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the _mimalloc_ library. - -- `env DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram` +``` +> env DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram +``` 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: macOS support for dynamic overriding is recent, please report any issues.) +### Dynamic Override on Windows -### Windows - -Overriding on Windows is robust and has the -particular advantage to be able to redirect all malloc/free calls that go through +Dynamically overriding on mimalloc 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. +As it intercepts all allocation calls on a low level, it can be used reliably +on large programs that include other 3rd party components. +There are four requirements to make the overriding work robustly: -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`). +1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). +2. Link your program explicitly with `mimalloc-override.dll` library. + To ensure the `mimalloc-override.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. +3. The [`mimalloc-redirect.dll`](bin) (or `mimalloc-redirect32.dll`) must be put + in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). + The redirection DLL ensures that all calls to the C runtime malloc API get redirected to + mimalloc functions (which reside in `mimalloc-override.dll`). +4. Ensure the `mimalloc-override.dll` comes as early as possible in the import + list of the final executable (so it can intercept all potential allocations). -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 +For best performance on Windows with C++, it 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). +[`mimalloc-new-delete.h`](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 even patch existing executables without any recompilation +We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we cannot always +ensure the the DLL comes first in the import table of the final executable. +In many cases though we can 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)). - +Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388) or +the [`minject`](bin) program. ## Static override -On Unix systems, you can also statically link with _mimalloc_ to override the standard +On Unix-like 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 +_mimalloc_ single object file (`mimalloc.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.o myfile1.c ... +``` -``` -gcc -o myprogram mimalloc-override.o myfile1.c ... -``` +Another way to override statically that works on all platforms, is to +link statically to mimalloc (as shown in the introduction) and include a +header file in each source file that re-defines `malloc` etc. to `mi_malloc`. +This is provided by [`mimalloc-override.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-override.h). This only works reliably though if all sources are +under your control or otherwise mixing of pointers from different heaps may occur! ## List of Overrides: diff --git a/doc/mimalloc-doxygen.css b/doc/mimalloc-doxygen.css index b24f5643..c889a8d2 100644 --- a/doc/mimalloc-doxygen.css +++ b/doc/mimalloc-doxygen.css @@ -47,3 +47,14 @@ div.fragment { #nav-sync img { display: none; } +h1,h2,h3,h4,h5,h6 { + transition:none; +} +.memtitle { + background-image: none; + background-color: #EEE; +} +table.memproto, .memproto { + text-shadow: none; + font-size: 110%; +} diff --git a/docs/annotated.html b/docs/annotated.html index 948a8863..e31fddc4 100644 --- a/docs/annotated.html +++ b/docs/annotated.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Structures + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + + @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html'); -
@@ -88,20 +91,26 @@ $(document).ready(function(){initNavTree('annotated.html',''); initResizable();
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Data Structures
+
Data Structures
Here are the data structures with brief descriptions:
- +
 Cmi_heap_area_tAn area of heap space contains blocks of a single size
 Cmi_stl_allocatorstd::allocator implementation for mimalloc for use in STL containers
 Cmi_stl_allocatorstd::allocator implementation for mimalloc for use in STL containers
@@ -109,7 +118,7 @@ $(document).ready(function(){initNavTree('annotated.html',''); initResizable(); diff --git a/docs/bench.html b/docs/bench.html index 213ff24b..31b5f3bc 100644 --- a/docs/bench.html +++ b/docs/bench.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Performance + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html'); -
@@ -88,26 +91,32 @@ $(document).ready(function(){initNavTree('bench.html',''); initResizable(); });
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
-
Performance
+
+
Performance

We tested mimalloc against many other top allocators over a wide range of benchmarks, ranging from various real world programs to synthetic benchmarks that see how the allocator behaves under more extreme circumstances.

In our benchmarks, mimalloc always outperforms all other leading allocators (jemalloc, tcmalloc, Hoard, etc) (Jan 2021), and usually uses less memory (up to 25% more in the worst case). A nice property is that it does consistently well over the wide range of benchmarks.

-

See the Performance section in the mimalloc repository for benchmark results, or the technical report for detailed benchmark results.

+

See the Performance section in the mimalloc repository for benchmark results, or the the technical report for detailed benchmark results.

diff --git a/docs/build.html b/docs/build.html index 41e0199f..4641e179 100644 --- a/docs/build.html +++ b/docs/build.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Building + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
-
@@ -88,17 +91,23 @@ $(document).ready(function(){initNavTree('build.html',''); initResizable(); });
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
-
Building
+
+
Building
-

Checkout the sources from GitHub:

git clone https://github.com/microsoft/mimalloc
+

Checkout the sources from GitHub:

git clone https://github.com/microsoft/mimalloc

Windows

Open ide/vs2019/mimalloc.sln in Visual Studio 2019 and build (or ide/vs2017/mimalloc.sln). The mimalloc project builds a static library (in out/msvc-x64), while the mimalloc-override project builds a DLL for overriding malloc in the entire program.

macOS, Linux, BSD, etc.

@@ -130,7 +139,7 @@ $(document).ready(function(){initNavTree('build.html',''); initResizable(); }); diff --git a/docs/classes.html b/docs/classes.html index 3baa0db0..6604efc2 100644 --- a/docs/classes.html +++ b/docs/classes.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Structure Index + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
-
@@ -88,20 +91,26 @@ $(document).ready(function(){initNavTree('classes.html',''); initResizable(); })
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Data Structure Index
+
Data Structure Index
@@ -109,7 +118,7 @@ $(document).ready(function(){initNavTree('classes.html',''); initResizable(); }) diff --git a/docs/doxygen.css b/docs/doxygen.css index 38091805..1f39f3ad 100644 --- a/docs/doxygen.css +++ b/docs/doxygen.css @@ -1,26 +1,31 @@ -/* The standard CSS for doxygen 1.9.1 */ +/* The standard CSS for doxygen 1.11.0*/ -body, table, div, p, dl { - font: 400 14px/22px Roboto,sans-serif; +body { + background-color: white; + color: black; } -p.reference, p.definition { - font: 400 14px/22px Roboto,sans-serif; +body, table, div, p, dl { + font-weight: 400; + font-size: 14px; + font-family: Roboto,sans-serif; + line-height: 22px; } /* @group Heading Levels */ -h1.groupheader { - font-size: 150%; -} - .title { - font: 400 14px/28px Roboto,sans-serif; + font-family: Roboto,sans-serif; + line-height: 28px; font-size: 150%; font-weight: bold; margin: 10px 2px; } +h1.groupheader { + font-size: 150%; +} + h2.groupheader { border-bottom: 1px solid #474D4E; color: #0A0B0B; @@ -53,15 +58,6 @@ dt { font-weight: bold; } -ul.multicol { - -moz-column-gap: 1em; - -webkit-column-gap: 1em; - column-gap: 1em; - -moz-column-count: 3; - -webkit-column-count: 3; - column-count: 3; -} - p.startli, p.startdd { margin-top: 2px; } @@ -113,7 +109,6 @@ h3.version { } div.navtab { - border-right: 1px solid #636C6D; padding-right: 15px; text-align: right; line-height: 110%; @@ -127,6 +122,7 @@ td.navtab { padding-right: 6px; padding-left: 6px; } + td.navtabHL { background-image: url('tab_a.png'); background-repeat:repeat-x; @@ -135,7 +131,7 @@ td.navtabHL { } td.navtabHL a, td.navtabHL a:visited { - color: #fff; + color: white; text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); } @@ -151,6 +147,12 @@ div.qindex{ color: #A0A0A0; } +#main-menu a:focus { + outline: auto; + z-index: 10; + position: relative; +} + dt.alphachar{ font-size: 180%; font-weight: bold; @@ -176,6 +178,10 @@ dt.alphachar{ line-height: 1.15em; } +.classindex dl.even { + background-color: white; +} + .classindex dl.odd { background-color: #F0F1F1; } @@ -206,11 +212,13 @@ a { } a:hover { - text-decoration: underline; + text-decoration: none; + background: linear-gradient(to bottom, transparent 0,transparent calc(100% - 1px), currentColor 100%); } -.contents a.qindexHL:visited { - color: #FFFFFF; +a:hover > span.arrow { + text-decoration: none; + background : #F2F3F3; } a.el { @@ -228,14 +236,68 @@ a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { color: #171919; } +a.code.hl_class { /* style for links to class names in code snippets */ } +a.code.hl_struct { /* style for links to struct names in code snippets */ } +a.code.hl_union { /* style for links to union names in code snippets */ } +a.code.hl_interface { /* style for links to interface names in code snippets */ } +a.code.hl_protocol { /* style for links to protocol names in code snippets */ } +a.code.hl_category { /* style for links to category names in code snippets */ } +a.code.hl_exception { /* style for links to exception names in code snippets */ } +a.code.hl_service { /* style for links to service names in code snippets */ } +a.code.hl_singleton { /* style for links to singleton names in code snippets */ } +a.code.hl_concept { /* style for links to concept names in code snippets */ } +a.code.hl_namespace { /* style for links to namespace names in code snippets */ } +a.code.hl_package { /* style for links to package names in code snippets */ } +a.code.hl_define { /* style for links to macro names in code snippets */ } +a.code.hl_function { /* style for links to function names in code snippets */ } +a.code.hl_variable { /* style for links to variable names in code snippets */ } +a.code.hl_typedef { /* style for links to typedef names in code snippets */ } +a.code.hl_enumvalue { /* style for links to enum value names in code snippets */ } +a.code.hl_enumeration { /* style for links to enumeration names in code snippets */ } +a.code.hl_signal { /* style for links to Qt signal names in code snippets */ } +a.code.hl_slot { /* style for links to Qt slot names in code snippets */ } +a.code.hl_friend { /* style for links to friend names in code snippets */ } +a.code.hl_dcop { /* style for links to KDE3 DCOP names in code snippets */ } +a.code.hl_property { /* style for links to property names in code snippets */ } +a.code.hl_event { /* style for links to event names in code snippets */ } +a.code.hl_sequence { /* style for links to sequence names in code snippets */ } +a.code.hl_dictionary { /* style for links to dictionary names in code snippets */ } + /* @end */ dl.el { margin-left: -1cm; } +ul.check { + list-style:none; + text-indent: -16px; + padding-left: 38px; +} +li.unchecked:before { + content: "\2610\A0"; +} +li.checked:before { + content: "\2611\A0"; +} + +ol { + text-indent: 0px; +} + ul { - overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ + text-indent: 0px; + overflow: visible; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; + list-style-type: none; } #side-nav ul { @@ -249,35 +311,70 @@ ul { .fragment { text-align: left; direction: ltr; - overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-x: auto; overflow-y: hidden; + position: relative; + min-height: 12px; + margin: 10px 0px; + padding: 10px 10px; + border: 1px solid #90989A; + border-radius: 4px; + background-color: #F7F8F8; + color: black; } pre.fragment { - border: 1px solid #90989A; - background-color: #F7F8F8; - padding: 4px 6px; - margin: 4px 8px 4px 2px; - overflow: auto; - word-wrap: break-word; - font-size: 9pt; - line-height: 125%; - font-family: monospace, fixed; - font-size: 105%; + word-wrap: break-word; + font-size: 10pt; + line-height: 125%; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; } -div.fragment { - padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ - margin: 4px 8px 4px 2px; - background-color: #F7F8F8; - border: 1px solid #90989A; +.clipboard { + width: 24px; + height: 24px; + right: 5px; + top: 5px; + opacity: 0; + position: absolute; + display: inline; + overflow: auto; + fill: black; + justify-content: center; + align-items: center; + cursor: pointer; +} + +.clipboard.success { + border: 1px solid black; + border-radius: 4px; +} + +.fragment:hover .clipboard, .clipboard.success { + opacity: .28; +} + +.clipboard:hover, .clipboard.success { + opacity: 1 !important; +} + +.clipboard:active:not([class~=success]) svg { + transform: scale(.91); +} + +.clipboard.success svg { + fill: #2EC82E; +} + +.clipboard.success { + border-color: #2EC82E; } div.line { - font-family: monospace, fixed; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; font-size: 13px; min-height: 13px; - line-height: 1.0; + line-height: 1.2; text-wrap: unrestricted; white-space: -moz-pre-wrap; /* Moz */ white-space: -pre-wrap; /* Opera 4-6 */ @@ -310,19 +407,35 @@ div.line.glow { box-shadow: 0 0 10px cyan; } +span.fold { + margin-left: 5px; + margin-right: 1px; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; + display: inline-block; + width: 12px; + height: 12px; + background-repeat:no-repeat; + background-position:center; +} span.lineno { padding-right: 4px; + margin-right: 9px; text-align: right; - border-right: 2px solid #0F0; + border-right: 2px solid #00FF00; + color: black; background-color: #E8E8E8; white-space: pre; } -span.lineno a { +span.lineno a, span.lineno a:visited { + color: #171919; background-color: #D8D8D8; } span.lineno a:hover { + color: #171919; background-color: #C8C8C8; } @@ -335,24 +448,6 @@ span.lineno a:hover { user-select: none; } -div.ah, span.ah { - background-color: black; - font-weight: bold; - color: #FFFFFF; - margin-bottom: 3px; - margin-top: 3px; - padding: 0.2em; - border: solid thin #333; - border-radius: 0.5em; - -webkit-border-radius: .5em; - -moz-border-radius: .5em; - box-shadow: 2px 2px 3px #999; - -webkit-box-shadow: 2px 2px 3px #999; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; - background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); - background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); -} - div.classindex ul { list-style: none; padding-left: 0; @@ -374,7 +469,6 @@ div.groupText { } body { - background-color: white; color: black; margin: 0; } @@ -385,33 +479,15 @@ div.contents { margin-right: 8px; } -td.indexkey { - background-color: #D6D9D9; - font-weight: bold; - border: 1px solid #90989A; - margin: 2px 0px 2px 0; - padding: 2px 10px; - white-space: nowrap; - vertical-align: top; -} - -td.indexvalue { - background-color: #D6D9D9; - border: 1px solid #90989A; - padding: 2px 10px; - margin: 2px 0px; -} - -tr.memlist { - background-color: #DADDDE; -} - p.formulaDsp { text-align: center; } -img.formulaDsp { - +img.dark-mode-visible { + display: none; +} +img.light-mode-visible { + display: none; } img.formulaInl, img.inline { @@ -437,52 +513,63 @@ address.footer { img.footer { border: 0px; vertical-align: middle; + width: 104px; +} + +.compoundTemplParams { + color: #171919; + font-size: 80%; + line-height: 120%; } /* @group Code Colorization */ span.keyword { - color: #008000 + color: #008000; } span.keywordtype { - color: #604020 + color: #604020; } span.keywordflow { - color: #e08000 + color: #E08000; } span.comment { - color: #800000 + color: #800000; } span.preprocessor { - color: #806020 + color: #806020; } span.stringliteral { - color: #002080 + color: #002080; } span.charliteral { - color: #008080 + color: #008080; } -span.vhdldigit { - color: #ff00ff +span.xmlcdata { + color: black; } -span.vhdlchar { - color: #000000 +span.vhdldigit { + color: #FF00FF; } -span.vhdlkeyword { - color: #700070 +span.vhdlchar { + color: #000000; } -span.vhdllogic { - color: #ff0000 +span.vhdlkeyword { + color: #700070; +} + +span.vhdllogic { + color: #FF0000; } blockquote { @@ -492,34 +579,8 @@ blockquote { padding: 0 12px 0 16px; } -blockquote.DocNodeRTL { - border-left: 0; - border-right: 2px solid #5B6364; - margin: 0 4px 0 24px; - padding: 0 16px 0 12px; -} - /* @end */ -/* -.search { - color: #003399; - font-weight: bold; -} - -form.search { - margin-bottom: 0px; - margin-top: 0px; -} - -input.search { - font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #e8eef2; -} -*/ - td.tiny { font-size: 75%; } @@ -527,11 +588,12 @@ td.tiny { .dirtab { padding: 4px; border-collapse: collapse; - border: 1px solid #636C6D; + border: 1px solid #060606; } th.dirtab { - background: #D6D9D9; + background-color: #0B0C0C; + color: #FFFFFF; font-weight: bold; } @@ -641,15 +703,6 @@ table.memberdecls { margin-left: 9px; } -.memnav { - background-color: #D6D9D9; - border: 1px solid #636C6D; - text-align: center; - margin: 2px; - margin-right: 15px; - padding: 2px; -} - .mempage { width: 100%; } @@ -689,20 +742,12 @@ table.memberdecls { font-weight: bold; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); background-color: #BDC2C3; - /* opera specific markup */ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); border-top-right-radius: 4px; - /* firefox specific markup */ - -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - -moz-border-radius-topright: 4px; - /* webkit specific markup */ - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - -webkit-border-top-right-radius: 4px; - } .overload { - font-family: "courier new",courier,monospace; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; font-size: 65%; } @@ -711,11 +756,10 @@ table.memberdecls { border-left: 1px solid #697273; border-right: 1px solid #697273; padding: 6px 10px 2px 10px; - background-color: #F7F8F8; border-top-width: 0; background-image:url('nav_g.png'); background-repeat:repeat-x; - background-color: #FFFFFF; + background-color: white; /* opera specific markup */ border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; @@ -745,17 +789,25 @@ dl.reflist dd { .paramtype { white-space: nowrap; + padding: 0px; + padding-bottom: 1px; } .paramname { - color: #602020; white-space: nowrap; + padding: 0px; + padding-bottom: 1px; + margin-left: 2px; } + .paramname em { + color: #602020; font-style: normal; + margin-right: 1px; } -.paramname code { - line-height: 14px; + +.paramname .paramdefval { + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; } .params, .retval, .exception, .tparams { @@ -774,7 +826,7 @@ dl.reflist dd { } .params .paramdir, .tparams .paramdir { - font-family: "courier new",courier,monospace; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; vertical-align: top; } @@ -858,9 +910,14 @@ div.directory { border-left: 1px solid rgba(0,0,0,0.05); } +.directory tr.odd { + padding-left: 6px; + background-color: #F0F1F1; +} + .directory tr.even { padding-left: 6px; - background-color: #EDEFEF; + background-color: white; } .directory img { @@ -896,7 +953,8 @@ div.directory { } .icon { - font-family: Arial, Helvetica; + font-family: Arial,Helvetica; + line-height: normal; font-weight: bold; font-size: 12px; height: 14px; @@ -920,8 +978,7 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('folderopen.png'); - background-position: 0px -4px; + background-image:url('folderopen.svg'); background-repeat: repeat-y; vertical-align:top; display: inline-block; @@ -931,8 +988,7 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('folderclosed.png'); - background-position: 0px -4px; + background-image:url('folderclosed.svg'); background-repeat: repeat-y; vertical-align:top; display: inline-block; @@ -942,17 +998,13 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('doc.png'); + background-image:url('doc.svg'); background-position: 0px -4px; background-repeat: repeat-y; vertical-align:top; display: inline-block; } -table.directory { - font: 400 14px Roboto,sans-serif; -} - /* @end */ div.dynheader { @@ -994,15 +1046,10 @@ table.doxtable th { } table.fieldtable { - /*width: 100%;*/ margin-bottom: 10px; border: 1px solid #697273; border-spacing: 0px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; border-radius: 4px; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; - -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); } @@ -1023,7 +1070,6 @@ table.fieldtable { .fieldtable td.fielddoc { border-bottom: 1px solid #697273; - /*width: 100%;*/ } .fieldtable td.fielddoc p:first-child { @@ -1039,7 +1085,7 @@ table.fieldtable { } .fieldtable th { - background-image:url('nav_f.png'); + background-image: url('nav_f.png'); background-repeat:repeat-x; background-color: #C4C8C9; font-size: 90%; @@ -1048,10 +1094,6 @@ table.fieldtable { padding-top: 5px; text-align:left; font-weight: 400; - -moz-border-radius-topleft: 4px; - -moz-border-radius-topright: 4px; - -webkit-border-top-left-radius: 4px; - -webkit-border-top-right-radius: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom: 1px solid #697273; @@ -1071,12 +1113,12 @@ table.fieldtable { .navpath ul { font-size: 11px; - background-image:url('tab_b.png'); + background-image: url('tab_b.png'); background-repeat:repeat-x; background-position: 0 -5px; height:30px; line-height:30px; - color:#494F50; + color:#040404; border:solid 1px #8C9596; overflow:hidden; margin:0px; @@ -1092,14 +1134,13 @@ table.fieldtable { background-image:url('bc_s.png'); background-repeat:no-repeat; background-position:right; - color:#0A0B0B; + color: #0A0B0B; } .navpath li.navelem a { height:32px; display:block; - text-decoration: none; outline: none; color: #040404; font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; @@ -1109,7 +1150,8 @@ table.fieldtable { .navpath li.navelem a:hover { - color:#2E3233; + color: white; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); } .navpath li.footer @@ -1121,7 +1163,7 @@ table.fieldtable { background-image:none; background-repeat:no-repeat; background-position:right; - color:#0A0B0B; + color: #050505; font-size: 8pt; } @@ -1166,7 +1208,7 @@ div.ingroups a div.header { - background-image:url('nav_h.png'); + background-image: url('nav_h.png'); background-repeat:repeat-x; background-color: #F2F3F3; margin: 0px; @@ -1187,17 +1229,13 @@ dl { padding: 0 0 0 0; } -/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +/* + dl.section { margin-left: 0px; padding-left: 0px; } -dl.section.DocNodeRTL { - margin-right: 0px; - padding-right: 0px; -} - dl.note { margin-left: -7px; padding-left: 3px; @@ -1205,33 +1243,13 @@ dl.note { border-color: #D0C000; } -dl.note.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #D0C000; -} - -dl.warning, dl.attention { +dl.warning, dl.attention, dl.important { margin-left: -7px; padding-left: 3px; border-left: 4px solid; border-color: #FF0000; } -dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #FF0000; -} - dl.pre, dl.post, dl.invariant { margin-left: -7px; padding-left: 3px; @@ -1239,16 +1257,6 @@ dl.pre, dl.post, dl.invariant { border-color: #00D000; } -dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #00D000; -} - dl.deprecated { margin-left: -7px; padding-left: 3px; @@ -1256,16 +1264,6 @@ dl.deprecated { border-color: #505050; } -dl.deprecated.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #505050; -} - dl.todo { margin-left: -7px; padding-left: 3px; @@ -1273,16 +1271,6 @@ dl.todo { border-color: #00C0E0; } -dl.todo.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #00C0E0; -} - dl.test { margin-left: -7px; padding-left: 3px; @@ -1290,16 +1278,6 @@ dl.test { border-color: #3030E0; } -dl.test.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #3030E0; -} - dl.bug { margin-left: -7px; padding-left: 3px; @@ -1307,20 +1285,110 @@ dl.bug { border-color: #C08050; } -dl.bug.DocNodeRTL { - margin-left: 0; - padding-left: 0; - border-left: 0; - margin-right: -7px; - padding-right: 3px; - border-right: 4px solid; - border-color: #C08050; +*/ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a, dl.test a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.important, dl.note, dl.deprecated, dl.bug, +dl.invariant, dl.pre, dl.post, dl.todo, dl.test, dl.remark { + padding: 10px; + margin: 10px 0px; + overflow: hidden; + margin-left: 0; + border-radius: 4px; } dl.section dd { - margin-bottom: 6px; + margin-bottom: 2px; } +dl.warning, dl.attention, dl.important { + background: #f8d1cc; + border-left: 8px solid #b61825; + color: #75070f; +} + +dl.warning dt, dl.attention dt, dl.important dt { + color: #b61825; +} + +dl.note, dl.remark { + background: #faf3d8; + border-left: 8px solid #f3a600; + color: #5f4204; +} + +dl.note dt, dl.remark dt { + color: #f3a600; +} + +dl.todo { + background: #e4f3ff; + border-left: 8px solid #1879C4; + color: #274a5c; +} + +dl.todo dt { + color: #1879C4; +} + +dl.test { + background: #e8e8ff; + border-left: 8px solid #3939C4; + color: #1a1a5c; +} + +dl.test dt { + color: #3939C4; +} + +dl.bug dt a { + color: #5b2bdd !important; +} + +dl.bug { + background: #e4dafd; + border-left: 8px solid #5b2bdd; + color: #2a0d72; +} + +dl.bug dt a { + color: #5b2bdd !important; +} + +dl.deprecated { + background: #ecf0f3; + border-left: 8px solid #5b6269; + color: #43454a; +} + +dl.deprecated dt a { + color: #5b6269 !important; +} + +dl.note dd, dl.warning dd, dl.pre dd, dl.post dd, +dl.remark dd, dl.attention dd, dl.important dd, dl.invariant dd, +dl.bug dd, dl.deprecated dd, dl.todo dd, dl.test dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre, dl.post { + background: #d8f1e3; + border-left: 8px solid #44b86f; + color: #265532; +} + +dl.invariant dt, dl.pre dt, dl.post dt { + color: #44b86f; +} + + +#projectrow +{ + height: 56px; +} #projectlogo { @@ -1337,25 +1405,29 @@ dl.section dd { #projectalign { vertical-align: middle; + padding-left: 0.5em; } #projectname { - font: 300% Tahoma, Arial,sans-serif; + font-size: 200%; + font-family: Tahoma,Arial,sans-serif; margin: 0px; padding: 2px 0px; } #projectbrief { - font: 120% Tahoma, Arial,sans-serif; + font-size: 90%; + font-family: Tahoma,Arial,sans-serif; margin: 0px; padding: 0px; } #projectnumber { - font: 50% Tahoma, Arial,sans-serif; + font-size: 50%; + font-family: 50% Tahoma,Arial,sans-serif; margin: 0px; padding: 0px; } @@ -1366,6 +1438,7 @@ dl.section dd { margin: 0px; width: 100%; border-bottom: 1px solid #212425; + background-color: white; } .image @@ -1398,11 +1471,6 @@ dl.section dd { font-weight: bold; } -div.zoom -{ - border: 1px solid #4F5657; -} - dl.citelist { margin-bottom:50px; } @@ -1433,27 +1501,16 @@ div.toc { width: 200px; } -.PageDocRTL-title div.toc { - float: left !important; - text-align: right; -} - div.toc li { - background: url("bdwn.png") no-repeat scroll 0 5px transparent; - font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + background: url("data:image/svg+xml;utf8,&%238595;") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,'DejaVu Sans',Geneva,sans-serif; margin-top: 5px; padding-left: 10px; padding-top: 2px; } -.PageDocRTL-title div.toc li { - background-position-x: right !important; - padding-left: 0 !important; - padding-right: 10px; -} - div.toc h3 { - font: bold 12px/1.2 Arial,FreeSans,sans-serif; + font: bold 12px/1.2 Verdana,'DejaVu Sans',Geneva,sans-serif; color: #171919; border-bottom: 0 none; margin: 0; @@ -1474,11 +1531,11 @@ div.toc li.level2 { } div.toc li.level3 { - margin-left: 30px; + margin-left: 15px; } div.toc li.level4 { - margin-left: 45px; + margin-left: 15px; } span.emoji { @@ -1487,24 +1544,8 @@ span.emoji { */ } -.PageDocRTL-title div.toc li.level1 { - margin-left: 0 !important; - margin-right: 0; -} - -.PageDocRTL-title div.toc li.level2 { - margin-left: 0 !important; - margin-right: 15px; -} - -.PageDocRTL-title div.toc li.level3 { - margin-left: 0 !important; - margin-right: 30px; -} - -.PageDocRTL-title div.toc li.level4 { - margin-left: 0 !important; - margin-right: 45px; +span.obfuscator { + display: none; } .inherit_header { @@ -1541,7 +1582,8 @@ tr.heading h2 { #powerTip { cursor: default; - white-space: nowrap; + /*white-space: nowrap;*/ + color: black; background-color: white; border: 1px solid gray; border-radius: 4px 4px 4px 4px; @@ -1564,6 +1606,10 @@ tr.heading h2 { font-weight: bold; } +#powerTip a { + color: #171919; +} + #powerTip div.ttname { font-weight: bold; } @@ -1575,7 +1621,9 @@ tr.heading h2 { #powerTip div { margin: 0px; padding: 0px; - font: 12px/16px Roboto,sans-serif; + font-size: 12px; + font-family: Roboto,sans-serif; + line-height: 16px; } #powerTip:before, #powerTip:after { @@ -1620,12 +1668,12 @@ tr.heading h2 { } #powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { - border-top-color: #FFFFFF; + border-top-color: white; border-width: 10px; margin: 0px -10px; } -#powerTip.n:before { - border-top-color: #808080; +#powerTip.n:before, #powerTip.ne:before, #powerTip.nw:before { + border-top-color: gray; border-width: 11px; margin: 0px -11px; } @@ -1648,13 +1696,13 @@ tr.heading h2 { } #powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { - border-bottom-color: #FFFFFF; + border-bottom-color: white; border-width: 10px; margin: 0px -10px; } #powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { - border-bottom-color: #808080; + border-bottom-color: gray; border-width: 11px; margin: 0px -11px; } @@ -1675,13 +1723,13 @@ tr.heading h2 { left: 100%; } #powerTip.e:after { - border-left-color: #FFFFFF; + border-left-color: gray; border-width: 10px; top: 50%; margin-top: -10px; } #powerTip.e:before { - border-left-color: #808080; + border-left-color: gray; border-width: 11px; top: 50%; margin-top: -11px; @@ -1691,13 +1739,13 @@ tr.heading h2 { right: 100%; } #powerTip.w:after { - border-right-color: #FFFFFF; + border-right-color: gray; border-width: 10px; top: 50%; margin-top: -10px; } #powerTip.w:before { - border-right-color: #808080; + border-right-color: gray; border-width: 11px; top: 50%; margin-top: -11px; @@ -1758,35 +1806,33 @@ th.markdownTableHeadCenter, td.markdownTableBodyCenter { text-align: center } -.DocNodeRTL { - text-align: right; - direction: rtl; -} - -.DocNodeLTR { - text-align: left; - direction: ltr; -} - -table.DocNodeRTL { - width: auto; - margin-right: 0; - margin-left: auto; -} - -table.DocNodeLTR { - width: auto; - margin-right: auto; - margin-left: 0; -} - tt, code, kbd, samp { display: inline-block; - direction:ltr; } /* @end */ u { text-decoration: underline; } + +details>summary { + list-style-type: none; +} + +details > summary::-webkit-details-marker { + display: none; +} + +details>summary::before { + content: "\25ba"; + padding-right:4px; + font-size: 80%; +} + +details[open]>summary::before { + content: "\25bc"; + padding-right:4px; + font-size: 80%; +} + diff --git a/docs/dynsections.js b/docs/dynsections.js index 3174bd7b..3cc426a6 100644 --- a/docs/dynsections.js +++ b/docs/dynsections.js @@ -22,100 +22,177 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -function toggleVisibility(linkObj) -{ - var base = $(linkObj).attr('id'); - var summary = $('#'+base+'-summary'); - var content = $('#'+base+'-content'); - var trigger = $('#'+base+'-trigger'); - var src=$(trigger).attr('src'); - if (content.is(':visible')===true) { - content.hide(); - summary.show(); - $(linkObj).addClass('closed').removeClass('opened'); - $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); - } else { - content.show(); - summary.hide(); - $(linkObj).removeClass('closed').addClass('opened'); - $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); - } - return false; + +function toggleVisibility(linkObj) { + return dynsection.toggleVisibility(linkObj); } -function updateStripes() -{ - $('table.directory tr'). - removeClass('even').filter(':visible:even').addClass('even'); -} +let dynsection = { -function toggleLevel(level) -{ - $('table.directory tr').each(function() { - var l = this.id.split('_').length-1; - var i = $('#img'+this.id.substring(3)); - var a = $('#arr'+this.id.substring(3)); - if (l'); + // add vertical lines to other rows + $('span[class=lineno]').not(':eq(0)').append(''); + // add toggle controls to lines with fold divs + $('div[class=foldopen]').each(function() { + // extract specific id to use + const id = $(this).attr('id').replace('foldopen',''); + // extract start and end foldable fragment attributes + const start = $(this).attr('data-start'); + const end = $(this).attr('data-end'); + // replace normal fold span with controls for the first line of a foldable fragment + $(this).find('span[class=fold]:first').replaceWith(''); + // append div for folded (closed) representation + $(this).after(''); + // extract the first line from the "open" section to represent closed content + const line = $(this).children().first().clone(); + // remove any glow that might still be active on the original line + $(line).removeClass('glow'); + if (start) { + // if line already ends with a start marker (e.g. trailing {), remove it + $(line).html($(line).html().replace(new RegExp('\\s*'+start+'\\s*$','g'),'')); + } + // replace minus with plus symbol + $(line).find('span[class=fold]').css('background-image',codefold.plusImg[relPath]); + // append ellipsis + $(line).append(' '+start+''+end); + // insert constructed line into closed div + $('#foldclosed'+id).html(line); + }); + }, +}; /* @license-end */ diff --git a/docs/environment.html b/docs/environment.html index 58d20e1b..682e92c6 100644 --- a/docs/environment.html +++ b/docs/environment.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Environment Options + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
-
@@ -88,34 +91,48 @@ $(document).ready(function(){initNavTree('environment.html',''); initResizable()
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
-
Environment Options
+
+
Environment Options
-

You can set further options either programmatically (using mi_option_set), or via environment variables.

+

You can set further options either programmatically (using mi_option_set), 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 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).
  • -
  • MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N: where N is the numa node. This reserves the huge pages at a specific numa node. (N is -1 by default to reserve huge pages evenly among the given number of numa nodes (or use the available ones as detected))
-

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.

+

Advanced options:

+
    +
  • MIMALLOC_ARENA_EAGER_COMMIT=2: turns on eager commit for the large arenas (usually 1GiB) from which mimalloc allocates segments and pages. Set this to 2 (default) to only enable this on overcommit systems (e.g. Linux). Set this to 1 to enable explicitly on other systems as well (like Windows or macOS) which may improve performance (as the whole arena is committed at once). Note that eager commit only increases the commit but not the actual the peak resident set (rss) so it is generally ok to enable this.
  • +
  • MIMALLOC_PURGE_DELAY=N: the delay in N milli-seconds (by default 10) after which mimalloc will purge OS pages that are not in use. This signals to the OS that the underlying physical memory can be reused which can reduce memory fragmentation especially in long running (server) programs. Setting N to 0 purges immediately when a page becomes unused which can improve memory usage but also decreases performance. Setting N to a higher value like 100 can improve performance (sometimes by a lot) at the cost of potentially using more memory at times. Setting it to -1 disables purging completely.
  • +
  • MIMALLOC_PURGE_DECOMMITS=1: By default "purging" memory means unused memory is decommitted (MEM_DECOMMIT on Windows, MADV_DONTNEED (which decresease rss immediately) on mmap systems). Set this to 0 to instead "reset" unused memory on a purge (MEM_RESET on Windows, generally MADV_FREE (which does not decrease rss immediately) on mmap systems). Mimalloc generally does not "free" OS memory but only "purges" OS memory, in other words, it tries to keep virtual address ranges and decommits within those ranges (to make the underlying physical memory available to other processes).
  • +
+

Further options for large workloads and services:

+
    +
  • 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_ALLOW_LARGE_OS_PAGES=1: use large OS pages (2 or 4MiB) when available; for some workloads this can significantly improve performance. When this option is disabled, it also disables transparent huge pages (THP) for the process (on Linux and Android). Use MIMALLOC_VERBOSE to check if the large OS pages are enabled – usually one needs to explicitly give permissions for 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 whenever 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_ALLOW_LARGE_OS_PAGES=1 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 give permission for 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 purged as huge OS pages are pinned to physical memory). The huge pages are usually allocated evenly among NUMA nodes. We can use MIMALLOC_RESERVE_HUGE_OS_PAGES_AT=N where N is the numa node (starting at 0) to allocate all the huge pages at a specific numa node instead.
  • +
+

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 large increments.

diff --git a/docs/functions.html b/docs/functions.html index 0419c965..f04c90dd 100644 --- a/docs/functions.html +++ b/docs/functions.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Fields + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
-
@@ -88,35 +91,33 @@ $(document).ready(function(){initNavTree('functions.html',''); initResizable();
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
diff --git a/docs/functions_vars.html b/docs/functions_vars.html index d5252ae7..afd66afc 100644 --- a/docs/functions_vars.html +++ b/docs/functions_vars.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Data Fields - Variables + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + + @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html'); -
@@ -88,35 +91,33 @@ $(document).ready(function(){initNavTree('functions_vars.html',''); initResizabl
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
diff --git a/docs/group__aligned.html b/docs/group__aligned.html index c9ad48ed..93ecd920 100644 --- a/docs/group__aligned.html +++ b/docs/group__aligned.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Aligned Allocation + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + + @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html'); -
@@ -88,61 +91,64 @@ $(document).ready(function(){initNavTree('group__aligned.html',''); initResizabl
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
Aligned Allocation
+
Aligned Allocation
- -

Allocating aligned memory blocks. -More...

- - - - + + +

+

Macros

#define MI_ALIGNMENT_MAX
 The maximum supported alignment size (currently 1MiB). More...
 
#define MI_BLOCK_ALIGNMENT_MAX
 The maximum supported alignment size (currently 1MiB).
 
- - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +

+

Functions

void * mi_malloc_aligned (size_t size, size_t alignment)
 Allocate size bytes aligned by alignment. More...
 
void * mi_zalloc_aligned (size_t size, size_t alignment)
 
void * mi_calloc_aligned (size_t count, size_t size, size_t alignment)
 
void * mi_realloc_aligned (void *p, size_t newsize, size_t alignment)
 
void * mi_malloc_aligned_at (size_t size, size_t alignment, size_t offset)
 Allocate size bytes aligned by alignment at a specified offset. More...
 
void * mi_zalloc_aligned_at (size_t size, size_t alignment, size_t offset)
 
void * mi_calloc_aligned_at (size_t count, size_t size, size_t alignment, size_t offset)
 
void * mi_realloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
 
void * mi_malloc_aligned (size_t size, size_t alignment)
 Allocate size bytes aligned by alignment.
 
void * mi_zalloc_aligned (size_t size, size_t alignment)
 
void * mi_calloc_aligned (size_t count, size_t size, size_t alignment)
 
void * mi_realloc_aligned (void *p, size_t newsize, size_t alignment)
 
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_zalloc_aligned_at (size_t size, size_t alignment, size_t offset)
 
void * mi_calloc_aligned_at (size_t count, size_t size, size_t alignment, size_t offset)
 
void * mi_realloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
 

Detailed Description

Allocating aligned memory blocks.

Macro Definition Documentation

- -

◆ MI_ALIGNMENT_MAX

+ +

◆ MI_BLOCK_ALIGNMENT_MAX

- +
#define MI_ALIGNMENT_MAX#define MI_BLOCK_ALIGNMENT_MAX
@@ -152,102 +158,78 @@ Functions

Function Documentation

- -

◆ mi_calloc_aligned()

+ +

◆ mi_calloc_aligned()

- + - - + - - + - - - - - - - +
void* mi_calloc_aligned void * mi_calloc_aligned (size_t count, size_t count,
size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_calloc_aligned_at()

+ +

◆ mi_calloc_aligned_at()

- + - - + - - + - - + - - - - - - - +
void* mi_calloc_aligned_at void * mi_calloc_aligned_at (size_t count, size_t count,
size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_malloc_aligned()

+ +

◆ mi_malloc_aligned()

- + - - + - - - - - - - +
void* mi_malloc_aligned void * mi_malloc_aligned (size_t size, size_t size,
size_t alignment 
)size_t alignment )
@@ -256,7 +238,7 @@ Functions
Parameters
- +
sizenumber of bytes to allocate.
alignmentthe minimal alignment of the allocated memory. Must be less than MI_ALIGNMENT_MAX.
alignmentthe minimal alignment of the allocated memory. Must be less than MI_BLOCK_ALIGNMENT_MAX.
@@ -271,34 +253,26 @@ Functions
- -

◆ mi_malloc_aligned_at()

+ +

◆ mi_malloc_aligned_at()

- + - - + - - + - - - - - - - +
void* mi_malloc_aligned_at void * mi_malloc_aligned_at (size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
@@ -317,136 +291,104 @@ Functions
- -

◆ mi_realloc_aligned()

+ +

◆ mi_realloc_aligned()

- + - - + - - + - - - - - - - +
void* mi_realloc_aligned void * mi_realloc_aligned (void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment 
)size_t alignment )
- -

◆ mi_realloc_aligned_at()

+ +

◆ mi_realloc_aligned_at()

- + - - + - - + - - + - - - - - - - +
void* mi_realloc_aligned_at void * mi_realloc_aligned_at (void * p, void * p,
size_t newsize, size_t newsize,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
- -

◆ mi_zalloc_aligned()

+ +

◆ mi_zalloc_aligned()

- + - - + - - - - - - - +
void* mi_zalloc_aligned void * mi_zalloc_aligned (size_t size, size_t size,
size_t alignment 
)size_t alignment )
- -

◆ mi_zalloc_aligned_at()

+ +

◆ mi_zalloc_aligned_at()

- + - - + - - + - - - - - - - +
void* mi_zalloc_aligned_at void * mi_zalloc_aligned_at (size_t size, size_t size,
size_t alignment, size_t alignment,
size_t offset 
)size_t offset )
@@ -458,7 +400,7 @@ Functions diff --git a/docs/group__aligned.js b/docs/group__aligned.js index 06ccb0c3..3bcc1d68 100644 --- a/docs/group__aligned.js +++ b/docs/group__aligned.js @@ -1,12 +1,12 @@ var group__aligned = [ - [ "MI_ALIGNMENT_MAX", "group__aligned.html#ga83c03016066b438f51a8095e9140be06", null ], - [ "mi_calloc_aligned", "group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9", null ], - [ "mi_calloc_aligned_at", "group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3", null ], - [ "mi_malloc_aligned", "group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56", null ], - [ "mi_malloc_aligned_at", "group__aligned.html#ga5850da130c936bd77db039dcfbc8295d", null ], - [ "mi_realloc_aligned", "group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae", null ], - [ "mi_realloc_aligned_at", "group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb", null ], - [ "mi_zalloc_aligned", "group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819", null ], - [ "mi_zalloc_aligned_at", "group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8", null ] + [ "MI_BLOCK_ALIGNMENT_MAX", "group__aligned.html#ga2e3fc59317bd730a71788c4d56ac8bff", null ], + [ "mi_calloc_aligned", "group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1", null ], + [ "mi_calloc_aligned_at", "group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3", null ], + [ "mi_malloc_aligned", "group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c", null ], + [ "mi_malloc_aligned_at", "group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca", null ], + [ "mi_realloc_aligned", "group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf", null ], + [ "mi_realloc_aligned_at", "group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6", null ], + [ "mi_zalloc_aligned", "group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82", null ], + [ "mi_zalloc_aligned_at", "group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba", null ] ]; \ No newline at end of file diff --git a/docs/group__analysis.html b/docs/group__analysis.html index 6ceb4d54..9e9cee73 100644 --- a/docs/group__analysis.html +++ b/docs/group__analysis.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Heap Introspection + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
-
@@ -88,9 +91,16 @@ $(document).ready(function(){initNavTree('group__analysis.html',''); initResizab
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
@@ -98,46 +108,45 @@ $(document).ready(function(){initNavTree('group__analysis.html',''); initResizab Data Structures | Typedefs | Functions
-
-
Heap Introspection
+
Heap Introspection
- -

Inspect the heap at runtime. -More...

- - - + +

+

Data Structures

struct  mi_heap_area_t
 An area of heap space contains blocks of a single size. More...
struct  mi_heap_area_t
 An area of heap space contains blocks of a single size. More...
 
- - - - + + +

+

Typedefs

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)
 Visitor function passed to mi_heap_visit_blocks() More...
 
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)
 Visitor function passed to mi_heap_visit_blocks()
 
- - - + + - - + + - - + + - - + + + + +

+

Functions

bool mi_heap_contains_block (mi_heap_t *heap, const void *p)
 Does a heap contain a pointer to a previously allocated block? More...
bool mi_heap_contains_block (mi_heap_t *heap, const void *p)
 Does a heap contain a pointer to a previously allocated block?
 
bool mi_heap_check_owned (mi_heap_t *heap, const void *p)
 Check safely if any pointer is part of a heap. More...
bool mi_heap_check_owned (mi_heap_t *heap, const void *p)
 Check safely if any pointer is part of a heap.
 
bool mi_check_owned (const void *p)
 Check safely if any pointer is part of the default heap of this thread. More...
bool mi_check_owned (const void *p)
 Check safely if any pointer is part of the default heap of this 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. More...
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.
 
bool mi_abandoned_visit_blocks (mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun *visitor, void *arg)
 Visit all areas and blocks in abandoned heaps.
 

Detailed Description

Inspect the heap at runtime.


Data Structure Documentation

-

◆ mi_heap_area_t

+

◆ mi_heap_area_t

@@ -152,31 +161,37 @@ Functions
+size_t +void * +size_t +size_t + + + +size_t

Typedef Documentation

- -

◆ mi_block_visit_fun

+ +

◆ mi_block_visit_fun

Data Fields
-size_t block_size size in bytes of one block
-void * blocks start of the area containing heap blocks
-size_t committed current committed bytes of this area
-size_t +full_block_size +size in bytes of a full block including padding and metadata.
+size_t reserved bytes reserved for this area
-size_t used @@ -186,27 +201,66 @@ bytes in use by allocated blocks
- +
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)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)
-

Visitor function passed to mi_heap_visit_blocks()

+

Visitor function passed to mi_heap_visit_blocks()

Returns
true if ok, false to stop visiting (i.e. break)

This function is always first called for every area with block as a NULL pointer. If visit_all_blocks was true, the function is then called for every allocated block in that area.

Function Documentation

- -

◆ mi_check_owned()

+ +

◆ mi_abandoned_visit_blocks()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
bool mi_abandoned_visit_blocks (mi_subproc_id_t subproc_id,
int heap_tag,
bool visit_blocks,
mi_block_visit_fun * visitor,
void * arg )
+
+ +

Visit all areas and blocks in abandoned heaps.

+

Note: requires the option mi_option_allow_visit_abandoned to be set at the start of the program.

+ +
+
+ +

◆ mi_check_owned()

@@ -214,8 +268,7 @@ bytes in use by allocated blocks bool mi_check_owned ( - const void *  - p) + const void * p) @@ -229,14 +282,14 @@ bytes in use by allocated blocks
Returns
true if p points to a block in default heap of this thread.
-

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
+

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
-mi_heap_get_default()
+mi_heap_get_default()
- -

◆ mi_heap_check_owned()

+ +

◆ mi_heap_check_owned()

@@ -244,19 +297,12 @@ bytes in use by allocated blocks bool mi_heap_check_owned ( - mi_heap_t *  - heap, + mi_heap_t * heap, - const void *  - p  - - - - ) - + const void * p )
@@ -270,14 +316,14 @@ bytes in use by allocated blocks
Returns
true if p points to a block in heap.
-

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
+

Note: expensive function, linear in the pages in the heap.

See also
mi_heap_contains_block()
-mi_heap_get_default()
+mi_heap_get_default()
- -

◆ mi_heap_contains_block()

+ +

◆ mi_heap_contains_block()

@@ -285,19 +331,12 @@ bytes in use by allocated blocks bool mi_heap_contains_block ( - mi_heap_t *  - heap, + mi_heap_t * heap, - const void *  - p  - - - - ) - + const void * p )
@@ -311,12 +350,12 @@ bytes in use by allocated blocks
Returns
true if the block pointed to by p is in the heap.
-
See also
mi_heap_check_owned()
+
See also
mi_heap_check_owned()
- -

◆ mi_heap_visit_blocks()

+ +

◆ mi_heap_visit_blocks()

@@ -324,31 +363,22 @@ bytes in use by allocated blocks bool mi_heap_visit_blocks ( - const mi_heap_t *  - heap, + const mi_heap_t * heap, - bool  - visit_all_blocks, + bool visit_all_blocks, - mi_block_visit_fun *  - visitor, + mi_block_visit_fun * visitor, - void *  - arg  - - - - ) - + void * arg )
@@ -372,7 +402,7 @@ bytes in use by allocated blocks diff --git a/docs/group__analysis.js b/docs/group__analysis.js index 35178362..f60c7943 100644 --- a/docs/group__analysis.js +++ b/docs/group__analysis.js @@ -4,10 +4,12 @@ var group__analysis = [ "block_size", "group__analysis.html#a332a6c14d736a99699d5453a1cb04b41", null ], [ "blocks", "group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8", null ], [ "committed", "group__analysis.html#ab47526df656d8837ec3e97f11b83f835", null ], + [ "full_block_size", "group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3", null ], [ "reserved", "group__analysis.html#ae848a3e6840414891035423948ca0383", null ], [ "used", "group__analysis.html#ab820302c5cd0df133eb8e51650a008b4", null ] ] ], - [ "mi_block_visit_fun", "group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65", null ], + [ "mi_block_visit_fun", "group__analysis.html#ga8255dc9371e6b299d9802a610c4e34ec", null ], + [ "mi_abandoned_visit_blocks", "group__analysis.html#ga6a4865a887b2ec5247854af61562503c", null ], [ "mi_check_owned", "group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5", null ], [ "mi_heap_check_owned", "group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377", null ], [ "mi_heap_contains_block", "group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af", null ], diff --git a/docs/group__analysis_structmi__heap__area__t.js b/docs/group__analysis_structmi__heap__area__t.js index 2dbabc5c..6e40ef07 100644 --- a/docs/group__analysis_structmi__heap__area__t.js +++ b/docs/group__analysis_structmi__heap__area__t.js @@ -3,6 +3,7 @@ var group__analysis_structmi__heap__area__t = [ "block_size", "group__analysis.html#a332a6c14d736a99699d5453a1cb04b41", null ], [ "blocks", "group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8", null ], [ "committed", "group__analysis.html#ab47526df656d8837ec3e97f11b83f835", null ], + [ "full_block_size", "group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3", null ], [ "reserved", "group__analysis.html#ae848a3e6840414891035423948ca0383", null ], [ "used", "group__analysis.html#ab820302c5cd0df133eb8e51650a008b4", null ] ]; \ No newline at end of file diff --git a/docs/group__cpp.html b/docs/group__cpp.html index 2ad5303a..a3319eaf 100644 --- a/docs/group__cpp.html +++ b/docs/group__cpp.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: C++ wrappers + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
-
@@ -88,59 +91,62 @@ $(document).ready(function(){initNavTree('group__cpp.html',''); initResizable();
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
-
-
C++ wrappers
+
C++ wrappers
- -

mi_ prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling std::get_new_handler and raising a std::bad_alloc exception on failure. -More...

- - - + +

+

Data Structures

struct  mi_stl_allocator< T >
 std::allocator implementation for mimalloc for use in STL containers. More...
struct  mi_stl_allocator< T >
 std::allocator implementation for mimalloc for use in STL containers. More...
 
- - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + +

+

Functions

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 on failure. More...
 
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 exception on failure. More...
 
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 exception on failure. More...
 
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. More...
 
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. More...
 
void * mi_new_realloc (void *p, size_t newsize)
 like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure. More...
 
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 exception on failure. More...
 
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 on failure.
 
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 exception on failure.
 
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 exception on failure.
 
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_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_new_realloc (void *p, size_t newsize)
 like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.
 
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 exception on failure.
 

Detailed Description

-

mi_ prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling std::get_new_handler and raising a std::bad_alloc exception on failure.

-

Note: use the mimalloc-new-delete.h header to override the new and delete operators globally. The wrappers here are mostly for convience for library writers that need to interface with mimalloc from C++.

+

mi_ prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling std::get_new_handler and raising a std::bad_alloc exception on failure.

+

Note: use the mimalloc-new-delete.h header to override the new and delete operators globally. The wrappers here are mostly for convenience for library writers that need to interface with mimalloc from C++.


Data Structure Documentation

-

◆ mi_stl_allocator

+

◆ mi_stl_allocator

@@ -150,10 +156,8 @@ Functions
-

template<class T>
-struct mi_stl_allocator< T >

- -

std::allocator implementation for mimalloc for use in STL containers.

+
template<class T>
+struct mi_stl_allocator< T >

std::allocator implementation for mimalloc for use in STL containers.

For example:

std::vector<int, mi_stl_allocator<int> > vec;
vec.push_back(1);
vec.pop_back();
@@ -161,94 +165,63 @@ struct mi_stl_allocator< T >

Function Documentation

- -

◆ mi_new()

+ +

◆ mi_new()

- - - - - -
- + - - +
void* mi_new void * mi_new (std::size_t n)std::size_t n)
-
-noexcept
-

like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_aligned()

+ +

◆ mi_new_aligned()

- - - - - -
- + - - + - - - - - - - +
void* mi_new_aligned void * mi_new_aligned (std::size_t n, std::size_t n,
std::align_val_t alignment 
)std::align_val_t alignment )
-
-noexcept
-

like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_aligned_nothrow()

+ +

◆ mi_new_aligned_nothrow()

- + - - + - - - - - - - +
void* mi_new_aligned_nothrow void * mi_new_aligned_nothrow (size_t n, size_t n,
size_t alignment 
)size_t alignment )
@@ -257,55 +230,39 @@ struct mi_stl_allocator< T >
- -

◆ mi_new_n()

+ +

◆ mi_new_n()

- - - - - -
- + - - + - - - - - - - +
void* mi_new_n void * mi_new_n (size_t count, size_t count,
size_t size 
)size_t size )
-
-noexcept
-

like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_nothrow()

+ +

◆ mi_new_nothrow()

- + - - +
void* mi_new_nothrow void * mi_new_nothrow (size_t n)size_t n)
@@ -315,69 +272,54 @@ struct mi_stl_allocator< T >
- -

◆ mi_new_realloc()

+ +

◆ mi_new_realloc()

- + - - + - - - - - - - +
void* mi_new_realloc void * mi_new_realloc (void * p, void * p,
size_t newsize 
)size_t newsize )
-

like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

- -

◆ mi_new_reallocn()

+ +

◆ mi_new_reallocn()

- + - - + - - + - - - - - - - +
void* mi_new_reallocn void * mi_new_reallocn (void * p, void * p,
size_t newcount, size_t newcount,
size_t size 
)size_t size )
-

like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

+

like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception on failure.

@@ -386,7 +328,7 @@ struct mi_stl_allocator< T > diff --git a/docs/group__cpp.js b/docs/group__cpp.js index 20706646..355f1ac6 100644 --- a/docs/group__cpp.js +++ b/docs/group__cpp.js @@ -1,11 +1,11 @@ var group__cpp = [ - [ "mi_stl_allocator", "group__cpp.html#structmi__stl__allocator", null ], - [ "mi_new", "group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545", null ], - [ "mi_new_aligned", "group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3", null ], - [ "mi_new_aligned_nothrow", "group__cpp.html#gab5e29558926d934c3f1cae8c815f942c", null ], - [ "mi_new_n", "group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81", null ], - [ "mi_new_nothrow", "group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a", null ], - [ "mi_new_realloc", "group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e", null ], - [ "mi_new_reallocn", "group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907", null ] + [ "mi_stl_allocator< T >", "group__cpp.html#structmi__stl__allocator", null ], + [ "mi_new", "group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a", null ], + [ "mi_new_aligned", "group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8", null ], + [ "mi_new_aligned_nothrow", "group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7", null ], + [ "mi_new_n", "group__cpp.html#gadd11b85c15d21d308386844b5233856c", null ], + [ "mi_new_nothrow", "group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54", null ], + [ "mi_new_realloc", "group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0", null ], + [ "mi_new_reallocn", "group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67", null ] ]; \ No newline at end of file diff --git a/docs/group__extended.html b/docs/group__extended.html index bf71e925..16ae2c5f 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Extended Functions + - + + @@ -29,22 +31,18 @@
- + - -
-
mi-malloc -  1.7/2.0 +
+
mi-malloc 1.8/2.1
+
- -   + @@ -56,10 +54,15 @@
- + +
@@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
-
@@ -88,9 +91,16 @@ $(document).ready(function(){initNavTree('group__extended.html',''); initResizab
- +
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
@@ -98,106 +108,141 @@ $(document).ready(function(){initNavTree('group__extended.html',''); initResizab Macros | Typedefs | Functions
-
-
Extended Functions
+
Extended Functions
-

Extended functionality. +

Extended functionality. More...

- - - + +

+

Macros

#define MI_SMALL_SIZE_MAX
 Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems)) More...
#define MI_SMALL_SIZE_MAX
 Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems))
 
- - - - - - - - - - + + + + + + + + + + + + + + +

+

Typedefs

typedef void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
 Type of deferred free functions. More...
 
typedef void() mi_output_fun(const char *msg, void *arg)
 Type of output functions. More...
 
typedef void() mi_error_fun(int err, void *arg)
 Type of error callback functions. More...
 
typedef void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
 Type of deferred free functions.
 
typedef void mi_output_fun(const char *msg, void *arg)
 Type of output functions.
 
typedef void mi_error_fun(int err, void *arg)
 Type of error callback functions.
 
typedef int mi_arena_id_t
 Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.
 
typedef void * mi_subproc_id_t
 A process can associate threads with sub-processes.
 
- - - - - - - - - + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+

Functions

void * mi_malloc_small (size_t size)
 Allocate a small object. More...
 
void * mi_zalloc_small (size_t size)
 Allocate a zero initialized small object. More...
 
size_t mi_usable_size (void *p)
 Return the available bytes in a memory block. More...
void * mi_malloc_small (size_t size)
 Allocate a small object.
 
void * mi_zalloc_small (size_t size)
 Allocate a zero initialized small object.
 
size_t mi_usable_size (void *p)
 Return the available bytes in a memory block.
 
size_t mi_good_size (size_t size)
 Return the used allocation size. More...
size_t mi_good_size (size_t size)
 Return the used allocation size.
 
void mi_collect (bool force)
 Eagerly free memory. More...
void mi_collect (bool force)
 Eagerly free memory.
 
void mi_stats_print (void *out)
 Deprecated. More...
void mi_stats_print (void *out)
 Deprecated.
 
void mi_stats_print_out (mi_output_fun *out, void *arg)
 Print the main statistics. More...
void mi_stats_print_out (mi_output_fun *out, void *arg)
 Print the main statistics.
 
void mi_stats_reset (void)
 Reset statistics. More...
void mi_stats_reset (void)
 Reset statistics.
 
void mi_stats_merge (void)
 Merge thread local statistics with the main statistics and reset. More...
void mi_stats_merge (void)
 Merge thread local statistics with the main statistics and reset.
 
void mi_thread_init (void)
 Initialize mimalloc on a thread. More...
void mi_thread_init (void)
 Initialize mimalloc on a thread.
 
void mi_thread_done (void)
 Uninitialize mimalloc on a thread. More...
void mi_thread_done (void)
 Uninitialize mimalloc on a thread.
 
void mi_thread_stats_print_out (mi_output_fun *out, void *arg)
 Print out heap statistics for this thread. More...
void mi_thread_stats_print_out (mi_output_fun *out, void *arg)
 Print out heap statistics for this thread.
 
void mi_register_deferred_free (mi_deferred_free_fun *deferred_free, void *arg)
 Register a deferred free function. More...
void mi_register_deferred_free (mi_deferred_free_fun *deferred_free, void *arg)
 Register a deferred free function.
 
void mi_register_output (mi_output_fun *out, void *arg)
 Register an output function. More...
void mi_register_output (mi_output_fun *out, void *arg)
 Register an output function.
 
void mi_register_error (mi_error_fun *errfun, void *arg)
 Register an error callback function. More...
void mi_register_error (mi_error_fun *errfun, void *arg)
 Register an error callback function.
 
bool mi_is_in_heap_region (const void *p)
 Is a pointer part of our heap? More...
bool mi_is_in_heap_region (const void *p)
 Is a pointer part of our heap?
 
int mi_reserve_os_memory (size_t size, bool commit, bool allow_large)
 Reserve OS memory for use by mimalloc. More...
int mi_reserve_os_memory (size_t size, bool commit, bool allow_large)
 Reserve OS memory for use by mimalloc.
 
bool mi_manage_os_memory (void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node)
 Manage a particular memory area for use by mimalloc. More...
bool mi_manage_os_memory (void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node)
 Manage a particular memory area for use by mimalloc.
 
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 timeout_msecs seconds. More...
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 timeout_msecs seconds.
 
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 seconds. More...
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 seconds.
 
bool mi_is_redirected ()
 Is the C runtime malloc API redirected? More...
bool mi_is_redirected ()
 Is the C runtime malloc API redirected?
 
void mi_process_info (size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)
 Return process information (time and memory usage). More...
void mi_process_info (size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)
 Return process information (time and memory usage).
 
void mi_debug_show_arenas (bool show_inuse, bool show_abandoned, bool show_purge)
 Show all current arena's.
 
void * mi_arena_area (mi_arena_id_t arena_id, size_t *size)
 Return the size of an arena.
 
int mi_reserve_huge_os_pages_at_ex (size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t *arena_id)
 Reserve huge OS pages (1GiB) into a single arena.
 
int mi_reserve_os_memory_ex (size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t *arena_id)
 Reserve OS memory to be managed in an arena.
 
bool mi_manage_os_memory_ex (void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t *arena_id)
 Manage externally allocated memory as a mimalloc arena.
 
mi_heap_tmi_heap_new_in_arena (mi_arena_id_t arena_id)
 Create a new heap that only allocates in the specified arena.
 
mi_subproc_id_t mi_subproc_main (void)
 Get the main sub-process identifier.
 
mi_subproc_id_t mi_subproc_new (void)
 Create a fresh sub-process (with no associated threads yet).
 
void mi_subproc_delete (mi_subproc_id_t subproc)
 Delete a previously created sub-process.
 
void mi_subproc_add_current_thread (mi_subproc_id_t subproc)
 Add the current thread to the given sub-process.
 

Detailed Description

Extended functionality.

Macro Definition Documentation

- -

◆ MI_SMALL_SIZE_MAX

+ +

◆ MI_SMALL_SIZE_MAX

@@ -208,19 +253,36 @@ Functions
-

Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems))

+

Maximum size allowed for small allocations in mi_malloc_small and mi_zalloc_small (usually 128*sizeof(void*) (= 1KB on 64-bit systems))

Typedef Documentation

- -

◆ mi_deferred_free_fun

+ +

◆ mi_arena_id_t

- + + +
typedef void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)typedef int mi_arena_id_t
+
+ +

Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.

+

Each arena has an associated identifier.

+ +
+
+ +

◆ mi_deferred_free_fun

+ +
+
+ + +
typedef void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
@@ -234,18 +296,18 @@ Functions -
See also
mi_register_deferred_free
+
See also
mi_register_deferred_free
- -

◆ mi_error_fun

+ +

◆ mi_error_fun

- +
typedef void() mi_error_fun(int err, void *arg)typedef void mi_error_fun(int err, void *arg)
@@ -253,23 +315,23 @@ Functions

Type of error callback functions.

Parameters
- +
errError code (see mi_register_error() for a complete list).
errError code (see mi_register_error() for a complete list).
argArgument that was passed at registration to hold extra state.
-
See also
mi_register_error()
+
See also
mi_register_error()
- -

◆ mi_output_fun

+ +

◆ mi_output_fun

- +
typedef void() mi_output_fun(const char *msg, void *arg)typedef void mi_output_fun(const char *msg, void *arg)
@@ -282,13 +344,61 @@ Functions -
See also
mi_register_output()
+
See also
mi_register_output()
+ +
+
+ +

◆ mi_subproc_id_t

+ +
+
+ + + + +
typedef void* mi_subproc_id_t
+
+ +

A process can associate threads with sub-processes.

+

A sub-process will not reclaim memory from (abandoned heaps/threads) other subprocesses.

Function Documentation

- -

◆ mi_collect()

+ +

◆ mi_arena_area()

+ +
+
+ + + + + + + + + + + +
void * mi_arena_area (mi_arena_id_t arena_id,
size_t * size )
+
+ +

Return the size of an arena.

+
Parameters
+ + + +
arena_idThe arena identifier.
sizeReturned size in bytes of the (virtual) arena area.
+
+
+
Returns
base address of the arena.
+ +
+
+ +

◆ mi_collect()

@@ -296,8 +406,7 @@ Functions void mi_collect ( - bool  - force) + bool force) @@ -314,8 +423,44 @@ Functions
- -

◆ mi_good_size()

+ +

◆ mi_debug_show_arenas()

+ +
+
+ + + + + + + + + + + + + + + + +
void mi_debug_show_arenas (bool show_inuse,
bool show_abandoned,
bool show_purge )
+
+ +

Show all current arena's.

+
Parameters
+ + + + +
show_inuseShow the arena blocks that are in use.
show_abandonedShow the abandoned arena blocks.
show_purgeShow arena blocks scheduled for purging.
+
+
+ +
+
+ +

◆ mi_good_size()

@@ -323,8 +468,7 @@ Functions size_t mi_good_size ( - size_t  - size) + size_t size) @@ -339,12 +483,38 @@ Functions
Returns
the size n that will be allocated, where n >= size.

Generally, mi_usable_size(mi_malloc(size)) == mi_good_size(size). This can be used to reduce internal wasted space when allocating buffers for example.

-
See also
mi_usable_size()
+
See also
mi_usable_size()
- -

◆ mi_is_in_heap_region()

+ +

◆ mi_heap_new_in_arena()

+ +
+
+ + + + + + + +
mi_heap_t * mi_heap_new_in_arena (mi_arena_id_t arena_id)
+
+ +

Create a new heap that only allocates in the specified arena.

+
Parameters
+ + +
arena_idThe arena identifier.
+
+
+
Returns
The new heap or NULL.
+ +
+
+ +

◆ mi_is_in_heap_region()

@@ -352,8 +522,7 @@ Functions bool mi_is_in_heap_region ( - const void *  - p) + const void * p) @@ -370,8 +539,8 @@ Functions
- -

◆ mi_is_redirected()

+ +

◆ mi_is_redirected()

@@ -379,7 +548,7 @@ Functions bool mi_is_redirected ( - ) + ) @@ -387,21 +556,20 @@ Functions

Is the C runtime malloc API redirected?

Returns
true if all malloc API calls are redirected to mimalloc.
-

Currenty only used on Windows.

+

Currently only used on Windows.

- -

◆ mi_malloc_small()

+ +

◆ mi_malloc_small()

- + - - +
void* mi_malloc_small void * mi_malloc_small (size_t size)size_t size)
@@ -410,7 +578,7 @@ Functions

Allocate a small object.

Parameters
- +
sizeThe size in bytes, can be at most MI_SMALL_SIZE_MAX.
sizeThe size in bytes, can be at most MI_SMALL_SIZE_MAX.
@@ -418,8 +586,8 @@ Functions
- -

◆ mi_manage_os_memory()

+ +

◆ mi_manage_os_memory()

@@ -427,43 +595,32 @@ Functions bool mi_manage_os_memory ( - void *  - start, + void * start, - size_t  - size, + size_t size, - bool  - is_committed, + bool is_committed, - bool  - is_large, + bool is_large, - bool  - is_zero, + bool is_zero, - int  - numa_node  - - - - ) - + int numa_node )
@@ -473,7 +630,7 @@ Functions - + @@ -484,8 +641,75 @@ Functions - -

◆ mi_process_info()

+ +

◆ mi_manage_os_memory_ex()

+ +
+
+
startStart of the memory area
sizeThe size of the memory area.
commitIs the area already committed?
is_committedIs the area already committed?
is_largeDoes it consist of large OS pages? Set this to true as well for memory that should not be decommitted or protected (like rdma etc.)
is_zeroDoes the area consists of zero's?
numa_nodePossible associated numa node or -1.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bool mi_manage_os_memory_ex (void * start,
size_t size,
bool is_committed,
bool is_large,
bool is_zero,
int numa_node,
bool exclusive,
mi_arena_id_t * arena_id )
+
+ +

Manage externally allocated memory as a mimalloc arena.

+

This memory will not be freed by mimalloc.

Parameters
+ + + + + + + + + +
startStart address of the area.
sizeSize in bytes of the area.
is_committedIs the memory already committed?
is_largeDoes it consist of (pinned) large OS pages?
is_zeroIs the memory zero-initialized?
numa_nodeAssociated NUMA node, or -1 to have no NUMA preference.
exclusiveIs the arena exclusive (where only heaps associated with the arena can allocate in it)
arena_idThe new arena identifier.
+
+
+
Returns
true if successful.
+ +
+
+ +

◆ mi_process_info()

@@ -493,55 +717,42 @@ Functions void mi_process_info ( - size_t *  - elapsed_msecs, + size_t * elapsed_msecs, - size_t *  - user_msecs, + size_t * user_msecs, - size_t *  - system_msecs, + size_t * system_msecs, - size_t *  - current_rss, + size_t * current_rss, - size_t *  - peak_rss, + size_t * peak_rss, - size_t *  - current_commit, + size_t * current_commit, - size_t *  - peak_commit, + size_t * peak_commit, - size_t *  - page_faults  - - - - ) - + size_t * page_faults )
@@ -564,8 +775,8 @@ Functions
- -

◆ mi_register_deferred_free()

+ +

◆ mi_register_deferred_free()

@@ -573,19 +784,12 @@ Functions void mi_register_deferred_free ( - mi_deferred_free_fun *  - deferred_free, + mi_deferred_free_fun * deferred_free, - void *  - arg  - - - - ) - + void * arg )
@@ -602,8 +806,8 @@ Functions
- -

◆ mi_register_error()

+ +

◆ mi_register_error()

@@ -611,19 +815,12 @@ Functions void mi_register_error ( - mi_error_fun *  - errfun, + mi_error_fun * errfun, - void *  - arg  - - - - ) - + void * arg )
@@ -640,14 +837,14 @@ Functions
  • EAGAIN: Double free was detected (only in debug and secure mode).
  • EFAULT: Corrupted free list or meta-data was detected (only in debug and secure mode).
  • ENOMEM: Not enough memory available to satisfy the request.
  • -
  • EOVERFLOW: Too large a request, for example in mi_calloc(), the count and size parameters are too large.
  • +
  • EOVERFLOW: Too large a request, for example in mi_calloc(), the count and size parameters are too large.
  • EINVAL: Trying to free or re-allocate an invalid pointer.
  • - -

    ◆ mi_register_output()

    + +

    ◆ mi_register_output()

    @@ -655,19 +852,12 @@ Functions void mi_register_output ( - mi_output_fun *  - out, + mi_output_fun * out, - void *  - arg  - - - - ) - + void * arg )
    @@ -684,8 +874,8 @@ Functions
    - -

    ◆ mi_reserve_huge_os_pages_at()

    + +

    ◆ mi_reserve_huge_os_pages_at()

    @@ -693,25 +883,17 @@ Functions int mi_reserve_huge_os_pages_at ( - size_t  - pages, + size_t pages, - int  - numa_node, + int numa_node, - size_t  - timeout_msecs  - - - - ) - + size_t timeout_msecs )
    @@ -720,18 +902,67 @@ Functions
    Parameters
    - +
    pagesThe number of 1GiB pages to reserve.
    numa_nodeThe NUMA node where the memory is reserved (start at 0).
    numa_nodeThe NUMA node where the memory is reserved (start at 0). Use -1 for no affinity.
    timeout_msecsMaximum number of milli-seconds to try reserving, or 0 for no timeout.
    -
    Returns
    0 if successfull, ENOMEM if running out of memory, or ETIMEDOUT if timed out.
    +
    Returns
    0 if successful, ENOMEM if running out of memory, or ETIMEDOUT if timed out.

    The reserved memory is used by mimalloc to satisfy allocations. May quit before timeout_msecs are expired if it estimates it will take more than 1.5 times timeout_msecs. The time limit is needed because on some operating systems it can take a long time to reserve contiguous memory if the physical memory is fragmented.

    - -

    ◆ mi_reserve_huge_os_pages_interleave()

    + +

    ◆ mi_reserve_huge_os_pages_at_ex()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int mi_reserve_huge_os_pages_at_ex (size_t pages,
    int numa_node,
    size_t timeout_msecs,
    bool exclusive,
    mi_arena_id_t * arena_id )
    +
    + +

    Reserve huge OS pages (1GiB) into a single arena.

    +
    Parameters
    + + + + + + +
    pagesNumber of 1GiB pages to reserve.
    numa_nodeThe associated NUMA node, or -1 for no NUMA preference.
    timeout_msecsMax amount of milli-seconds this operation is allowed to take. (0 is infinite)
    exclusiveIf exclusive, only a heap associated with this arena can allocate in it.
    arena_idThe arena identifier.
    +
    +
    +
    Returns
    0 if successful, ENOMEM if running out of memory, or ETIMEDOUT if timed out.
    + +
    +
    + +

    ◆ mi_reserve_huge_os_pages_interleave()

    @@ -739,25 +970,17 @@ Functions int mi_reserve_huge_os_pages_interleave ( - size_t  - pages, + size_t pages, - size_t  - numa_nodes, + size_t numa_nodes, - size_t  - timeout_msecs  - - - - ) - + size_t timeout_msecs )
    @@ -771,13 +994,13 @@ Functions -
    Returns
    0 if successfull, ENOMEM if running out of memory, or ETIMEDOUT if timed out.
    +
    Returns
    0 if successful, ENOMEM if running out of memory, or ETIMEDOUT if timed out.

    The reserved memory is used by mimalloc to satisfy allocations. May quit before timeout_msecs are expired if it estimates it will take more than 1.5 times timeout_msecs. The time limit is needed because on some operating systems it can take a long time to reserve contiguous memory if the physical memory is fragmented.

    - -

    ◆ mi_reserve_os_memory()

    + +

    ◆ mi_reserve_os_memory()

    @@ -785,25 +1008,17 @@ Functions int mi_reserve_os_memory ( - size_t  - size, + size_t size, - bool  - commit, + bool commit, - bool  - allow_large  - - - - ) - + bool allow_large )
    @@ -821,8 +1036,57 @@ Functions
    - -

    ◆ mi_stats_merge()

    + +

    ◆ mi_reserve_os_memory_ex()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int mi_reserve_os_memory_ex (size_t size,
    bool commit,
    bool allow_large,
    bool exclusive,
    mi_arena_id_t * arena_id )
    +
    + +

    Reserve OS memory to be managed in an arena.

    +
    Parameters
    + + + + + + +
    sizeSize the reserve.
    commitShould the memory be initially committed?
    allow_largeAllow the use of large OS pages?
    exclusiveIs the returned arena exclusive?
    arena_idThe new arena identifier.
    +
    +
    +
    Returns
    Zero on success, an error code otherwise.
    + +
    +
    + +

    ◆ mi_stats_merge()

    @@ -830,8 +1094,7 @@ Functions void mi_stats_merge ( - void  - ) + void ) @@ -841,8 +1104,8 @@ Functions
    - -

    ◆ mi_stats_print()

    + +

    ◆ mi_stats_print()

    @@ -850,8 +1113,7 @@ Functions void mi_stats_print ( - void *  - out) + void * out) @@ -868,8 +1130,8 @@ Functions
    - -

    ◆ mi_stats_print_out()

    + +

    ◆ mi_stats_print_out()

    @@ -877,19 +1139,12 @@ Functions void mi_stats_print_out ( - mi_output_fun *  - out, + mi_output_fun * out, - void *  - arg  - - - - ) - + void * arg )
    @@ -906,8 +1161,8 @@ Functions
    - -

    ◆ mi_stats_reset()

    + +

    ◆ mi_stats_reset()

    @@ -915,8 +1170,7 @@ Functions void mi_stats_reset ( - void  - ) + void ) @@ -926,8 +1180,92 @@ Functions
    - -

    ◆ mi_thread_done()

    + +

    ◆ mi_subproc_add_current_thread()

    + +
    +
    + + + + + + + +
    void mi_subproc_add_current_thread (mi_subproc_id_t subproc)
    +
    + +

    Add the current thread to the given sub-process.

    +

    This should be called right after a thread is created (and no allocation has taken place yet)

    + +
    +
    + +

    ◆ mi_subproc_delete()

    + +
    +
    + + + + + + + +
    void mi_subproc_delete (mi_subproc_id_t subproc)
    +
    + +

    Delete a previously created sub-process.

    +
    Parameters
    + + +
    subprocThe sub-process identifier. Only delete sub-processes if all associated threads have terminated.
    +
    +
    + +
    +
    + +

    ◆ mi_subproc_main()

    + +
    +
    + + + + + + + +
    mi_subproc_id_t mi_subproc_main (void )
    +
    + +

    Get the main sub-process identifier.

    + +
    +
    + +

    ◆ mi_subproc_new()

    + +
    +
    + + + + + + + +
    mi_subproc_id_t mi_subproc_new (void )
    +
    + +

    Create a fresh sub-process (with no associated threads yet).

    +
    Returns
    The new sub-process identifier.
    + +
    +
    + +

    ◆ mi_thread_done()

    @@ -935,8 +1273,7 @@ Functions void mi_thread_done ( - void  - ) + void ) @@ -947,8 +1284,8 @@ Functions
    - -

    ◆ mi_thread_init()

    + +

    ◆ mi_thread_init()

    @@ -956,8 +1293,7 @@ Functions void mi_thread_init ( - void  - ) + void ) @@ -968,8 +1304,8 @@ Functions
    - -

    ◆ mi_thread_stats_print_out()

    + +

    ◆ mi_thread_stats_print_out()

    @@ -977,19 +1313,12 @@ Functions void mi_thread_stats_print_out ( - mi_output_fun *  - out, + mi_output_fun * out, - void *  - arg  - - - - ) - + void * arg )
    @@ -1006,8 +1335,8 @@ Functions
    - -

    ◆ mi_usable_size()

    + +

    ◆ mi_usable_size()

    @@ -1015,8 +1344,7 @@ Functions size_t mi_usable_size ( - void *  - p) + void * p) @@ -1035,21 +1363,20 @@ Functions
    malloc_usable_size (Linux)
    -mi_good_size()
    +mi_good_size()
    - -

    ◆ mi_zalloc_small()

    + +

    ◆ mi_zalloc_small()

    - + - - +
    void* mi_zalloc_small void * mi_zalloc_small (size_t size)size_t size)
    @@ -1058,7 +1385,7 @@ Functions

    Allocate a zero initialized small object.

    Parameters
    - +
    sizeThe size in bytes, can be at most MI_SMALL_SIZE_MAX.
    sizeThe size in bytes, can be at most MI_SMALL_SIZE_MAX.
    @@ -1071,7 +1398,7 @@ Functions diff --git a/docs/group__extended.js b/docs/group__extended.js index c217aaca..cb7009f0 100644 --- a/docs/group__extended.js +++ b/docs/group__extended.js @@ -1,29 +1,41 @@ var group__extended = [ [ "MI_SMALL_SIZE_MAX", "group__extended.html#ga1ea64283508718d9d645c38efc2f4305", null ], - [ "mi_deferred_free_fun", "group__extended.html#ga299dae78d25ce112e384a98b7309c5be", null ], - [ "mi_error_fun", "group__extended.html#ga251d369cda3f1c2a955c555486ed90e5", null ], - [ "mi_output_fun", "group__extended.html#gad823d23444a4b77a40f66bf075a98a0c", null ], + [ "mi_arena_id_t", "group__extended.html#ga99fe38650d0b02e0e0f89ee024db91d3", null ], + [ "mi_deferred_free_fun", "group__extended.html#ga292a45f7dbc7cd23c5352ce1f0002816", null ], + [ "mi_error_fun", "group__extended.html#ga83fc6a688b322261e1c2deab000b0591", null ], + [ "mi_output_fun", "group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d", null ], + [ "mi_subproc_id_t", "group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d", null ], + [ "mi_arena_area", "group__extended.html#ga9a25a00a22151619a0be91a10af7787f", null ], [ "mi_collect", "group__extended.html#ga421430e2226d7d468529cec457396756", null ], + [ "mi_debug_show_arenas", "group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7", null ], [ "mi_good_size", "group__extended.html#gac057927cd06c854b45fe7847e921bd47", null ], + [ "mi_heap_new_in_arena", "group__extended.html#gaaf2d9976576d5efd5544be12848af949", null ], [ "mi_is_in_heap_region", "group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6", null ], [ "mi_is_redirected", "group__extended.html#gaad25050b19f30cd79397b227e0157a3f", null ], - [ "mi_malloc_small", "group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99", null ], + [ "mi_malloc_small", "group__extended.html#ga7f050bc6b897da82692174f5fce59cde", null ], [ "mi_manage_os_memory", "group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf", null ], + [ "mi_manage_os_memory_ex", "group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e", null ], [ "mi_process_info", "group__extended.html#ga7d862c2affd5790381da14eb102a364d", null ], [ "mi_register_deferred_free", "group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece", null ], [ "mi_register_error", "group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45", null ], [ "mi_register_output", "group__extended.html#gae5b17ff027cd2150b43a33040250cf3f", null ], [ "mi_reserve_huge_os_pages_at", "group__extended.html#ga7795a13d20087447281858d2c771cca1", null ], + [ "mi_reserve_huge_os_pages_at_ex", "group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52", null ], [ "mi_reserve_huge_os_pages_interleave", "group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50", null ], [ "mi_reserve_os_memory", "group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767", null ], + [ "mi_reserve_os_memory_ex", "group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b", null ], [ "mi_stats_merge", "group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1", null ], [ "mi_stats_print", "group__extended.html#ga2d126e5c62d3badc35445e5d84166df2", null ], [ "mi_stats_print_out", "group__extended.html#ga537f13b299ddf801e49a5a94fde02c79", null ], [ "mi_stats_reset", "group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99", null ], + [ "mi_subproc_add_current_thread", "group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c", null ], + [ "mi_subproc_delete", "group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e", null ], + [ "mi_subproc_main", "group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806", null ], + [ "mi_subproc_new", "group__extended.html#ga8068cac328e41fa2170faef707315243", null ], [ "mi_thread_done", "group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf", null ], [ "mi_thread_init", "group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17", null ], [ "mi_thread_stats_print_out", "group__extended.html#gab1dac8476c46cb9eecab767eb40c1525", null ], [ "mi_usable_size", "group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee", null ], - [ "mi_zalloc_small", "group__extended.html#ga220f29f40a44404b0061c15bc1c31152", null ] + [ "mi_zalloc_small", "group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e", null ] ]; \ No newline at end of file diff --git a/docs/group__heap.html b/docs/group__heap.html index 5f976989..28160d39 100644 --- a/docs/group__heap.html +++ b/docs/group__heap.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Heap Allocation + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,110 +91,113 @@ $(document).ready(function(){initNavTree('group__heap.html',''); initResizable()
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Heap Allocation
    +
    Heap Allocation
    - -

    First-class heaps that can be destroyed in one go. -More...

    - - - + +

    +

    Typedefs

    typedef struct mi_heap_s mi_heap_t
     Type of first-class heaps. More...
    typedef struct mi_heap_s mi_heap_t
     Type of first-class heaps.
     
    - - - - - - + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +

    Functions

    mi_heap_tmi_heap_new ()
     Create a new heap that can be used for allocation. More...
     
    void mi_heap_delete (mi_heap_t *heap)
     Delete a previously allocated heap. More...
    mi_heap_tmi_heap_new ()
     Create a new heap that can be used for allocation.
     
    void mi_heap_delete (mi_heap_t *heap)
     Delete a previously allocated heap.
     
    void mi_heap_destroy (mi_heap_t *heap)
     Destroy a heap, freeing all its still allocated blocks. More...
    void mi_heap_destroy (mi_heap_t *heap)
     Destroy a heap, freeing all its still allocated blocks.
     
    mi_heap_tmi_heap_set_default (mi_heap_t *heap)
     Set the default heap to use for mi_malloc() et al. More...
     
    mi_heap_tmi_heap_get_default ()
     Get the default heap that is used for mi_malloc() et al. More...
     
    mi_heap_tmi_heap_get_backing ()
     Get the backing heap. More...
     
    void mi_heap_collect (mi_heap_t *heap, bool force)
     Release outstanding resources in a specific heap. More...
    mi_heap_tmi_heap_set_default (mi_heap_t *heap)
     Set the default heap to use in the current thread for mi_malloc() et al.
     
    mi_heap_tmi_heap_get_default ()
     Get the default heap that is used for mi_malloc() et al.
     
    mi_heap_tmi_heap_get_backing ()
     Get the backing heap.
     
    void mi_heap_collect (mi_heap_t *heap, bool force)
     Release outstanding resources in a specific heap.
     
    void * mi_heap_malloc (mi_heap_t *heap, size_t size)
     Allocate in a specific heap. More...
     
    void * mi_heap_malloc_small (mi_heap_t *heap, size_t size)
     Allocate a small object in a specific heap. More...
     
    void * mi_heap_zalloc (mi_heap_t *heap, size_t size)
     Allocate zero-initialized in a specific heap. More...
     
    void * mi_heap_calloc (mi_heap_t *heap, size_t count, size_t size)
     Allocate count zero-initialized elements in a specific heap. More...
     
    void * mi_heap_mallocn (mi_heap_t *heap, size_t count, size_t size)
     Allocate count elements in a specific heap. More...
     
    char * mi_heap_strdup (mi_heap_t *heap, const char *s)
     Duplicate a string in a specific heap. More...
     
    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. More...
     
    char * mi_heap_realpath (mi_heap_t *heap, const char *fname, char *resolved_name)
     Resolve a file path name using a specific heap to allocate the result. More...
     
    void * mi_heap_realloc (mi_heap_t *heap, void *p, size_t newsize)
     
    void * mi_heap_reallocn (mi_heap_t *heap, void *p, size_t count, size_t size)
     
    void * mi_heap_reallocf (mi_heap_t *heap, void *p, size_t newsize)
     
    void * mi_heap_malloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
     
    void * mi_heap_malloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_zalloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
     
    void * mi_heap_zalloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_calloc_aligned (mi_heap_t *heap, size_t count, size_t size, size_t alignment)
     
    void * mi_heap_calloc_aligned_at (mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_realloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
     
    void * mi_heap_realloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
     
    void * mi_heap_malloc (mi_heap_t *heap, size_t size)
     Allocate in a specific heap.
     
    void * mi_heap_malloc_small (mi_heap_t *heap, size_t size)
     Allocate a small object in a specific heap.
     
    void * mi_heap_zalloc (mi_heap_t *heap, size_t size)
     Allocate zero-initialized in a specific heap.
     
    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_mallocn (mi_heap_t *heap, size_t count, size_t size)
     Allocate count elements in a specific heap.
     
    char * mi_heap_strdup (mi_heap_t *heap, const char *s)
     Duplicate a string in a specific heap.
     
    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.
     
    char * mi_heap_realpath (mi_heap_t *heap, const char *fname, char *resolved_name)
     Resolve a file path name using a specific heap to allocate the result.
     
    void * mi_heap_realloc (mi_heap_t *heap, void *p, size_t newsize)
     
    void * mi_heap_reallocn (mi_heap_t *heap, void *p, size_t count, size_t size)
     
    void * mi_heap_reallocf (mi_heap_t *heap, void *p, size_t newsize)
     
    void * mi_heap_malloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
     
    void * mi_heap_malloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_zalloc_aligned (mi_heap_t *heap, size_t size, size_t alignment)
     
    void * mi_heap_zalloc_aligned_at (mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_calloc_aligned (mi_heap_t *heap, size_t count, size_t size, size_t alignment)
     
    void * mi_heap_calloc_aligned_at (mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_realloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
     
    void * mi_heap_realloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
     

    Detailed Description

    First-class heaps that can be destroyed in one go.

    Typedef Documentation

    - -

    ◆ mi_heap_t

    + +

    ◆ mi_heap_t

    - +
    typedef struct mi_heap_s mi_heap_ttypedef struct mi_heap_s mi_heap_t
    @@ -202,131 +208,104 @@ Functions

    Function Documentation

    - -

    ◆ mi_heap_calloc()

    + +

    ◆ mi_heap_calloc()

    - + - - + - - + - - - - - - - +
    void* mi_heap_calloc void * mi_heap_calloc (mi_heap_theap, mi_heap_t * heap,
    size_t count, size_t count,
    size_t size 
    )size_t size )

    Allocate count zero-initialized elements in a specific heap.

    -
    See also
    mi_calloc()
    +
    See also
    mi_calloc()
    - -

    ◆ mi_heap_calloc_aligned()

    + +

    ◆ mi_heap_calloc_aligned()

    - + - - + - - + - - + - - - - - - - +
    void* mi_heap_calloc_aligned void * mi_heap_calloc_aligned (mi_heap_theap, mi_heap_t * heap,
    size_t count, size_t count,
    size_t size, size_t size,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_heap_calloc_aligned_at()

    + +

    ◆ mi_heap_calloc_aligned_at()

    - + - - + - - + - - + - - + - - - - - - - +
    void* mi_heap_calloc_aligned_at void * mi_heap_calloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
    size_t count, size_t count,
    size_t size, size_t size,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    - -

    ◆ mi_heap_collect()

    + +

    ◆ mi_heap_collect()

    @@ -334,19 +313,12 @@ Functions void mi_heap_collect ( - mi_heap_t *  - heap, + mi_heap_t * heap, - bool  - force  - - - - ) - + bool force )
    @@ -355,8 +327,8 @@ Functions
    - -

    ◆ mi_heap_delete()

    + +

    ◆ mi_heap_delete()

    @@ -364,21 +336,20 @@ Functions void mi_heap_delete ( - mi_heap_t *  - heap) + mi_heap_t * heap)

    Delete a previously allocated heap.

    -

    This will release resources and migrate any still allocated blocks in this heap (efficienty) to the default heap.

    +

    This will release resources and migrate any still allocated blocks in this heap (efficiently) to the default heap.

    If heap is the default heap, the default heap is set to the backing heap.

    - -

    ◆ mi_heap_destroy()

    + +

    ◆ mi_heap_destroy()

    @@ -386,8 +357,7 @@ Functions void mi_heap_destroy ( - mi_heap_t *  - heap) + mi_heap_t * heap) @@ -399,16 +369,16 @@ Functions
    - -

    ◆ mi_heap_get_backing()

    + +

    ◆ mi_heap_get_backing()

    - + - +
    mi_heap_t* mi_heap_get_backing mi_heap_t * mi_heap_get_backing ())
    @@ -419,209 +389,170 @@ Functions
    - -

    ◆ mi_heap_get_default()

    + +

    ◆ mi_heap_get_default()

    - + - +
    mi_heap_t* mi_heap_get_default mi_heap_t * mi_heap_get_default ())
    -

    Get the default heap that is used for mi_malloc() et al.

    -
    Returns
    The current default heap.
    +

    Get the default heap that is used for mi_malloc() et al.

    +

    (for the current thread).

    Returns
    The current default heap.
    - -

    ◆ mi_heap_malloc()

    + +

    ◆ mi_heap_malloc()

    - + - - + - - - - - - - +
    void* mi_heap_malloc void * mi_heap_malloc (mi_heap_theap, mi_heap_t * heap,
    size_t size 
    )size_t size )

    Allocate in a specific heap.

    -
    See also
    mi_malloc()
    +
    See also
    mi_malloc()
    - -

    ◆ mi_heap_malloc_aligned()

    + +

    ◆ mi_heap_malloc_aligned()

    - + - - + - - + - - - - - - - +
    void* mi_heap_malloc_aligned void * mi_heap_malloc_aligned (mi_heap_theap, mi_heap_t * heap,
    size_t size, size_t size,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_heap_malloc_aligned_at()

    + +

    ◆ mi_heap_malloc_aligned_at()

    - + - - + - - + - - + - - - - - - - +
    void* mi_heap_malloc_aligned_at void * mi_heap_malloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
    size_t size, size_t size,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    - -

    ◆ mi_heap_malloc_small()

    + +

    ◆ mi_heap_malloc_small()

    - + - - + - - - - - - - +
    void* mi_heap_malloc_small void * mi_heap_malloc_small (mi_heap_theap, mi_heap_t * heap,
    size_t size 
    )size_t size )

    Allocate a small object in a specific heap.

    -

    size must be smaller or equal to MI_SMALL_SIZE_MAX().

    See also
    mi_malloc()
    +

    size must be smaller or equal to MI_SMALL_SIZE_MAX().

    See also
    mi_malloc()
    - -

    ◆ mi_heap_mallocn()

    + +

    ◆ mi_heap_mallocn()

    - + - - + - - + - - - - - - - +
    void* mi_heap_mallocn void * mi_heap_mallocn (mi_heap_theap, mi_heap_t * heap,
    size_t count, size_t count,
    size_t size 
    )size_t size )

    Allocate count elements in a specific heap.

    -
    See also
    mi_mallocn()
    +
    See also
    mi_mallocn()
    - -

    ◆ mi_heap_new()

    + +

    ◆ mi_heap_new()

    - + - +
    mi_heap_t* mi_heap_new mi_heap_t * mi_heap_new ())
    @@ -631,254 +562,201 @@ Functions
    - -

    ◆ mi_heap_realloc()

    + +

    ◆ mi_heap_realloc()

    - + - - + - - + - - - - - - - +
    void* mi_heap_realloc void * mi_heap_realloc (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newsize 
    )size_t newsize )
    - -

    ◆ mi_heap_realloc_aligned()

    + +

    ◆ mi_heap_realloc_aligned()

    - + - - + - - + - - + - - - - - - - +
    void* mi_heap_realloc_aligned void * mi_heap_realloc_aligned (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newsize, size_t newsize,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_heap_realloc_aligned_at()

    + +

    ◆ mi_heap_realloc_aligned_at()

    - + - - + - - + - - + - - + - - - - - - - +
    void* mi_heap_realloc_aligned_at void * mi_heap_realloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newsize, size_t newsize,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    - -

    ◆ mi_heap_reallocf()

    + +

    ◆ mi_heap_reallocf()

    - + - - + - - + - - - - - - - +
    void* mi_heap_reallocf void * mi_heap_reallocf (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newsize 
    )size_t newsize )
    - -

    ◆ mi_heap_reallocn()

    + +

    ◆ mi_heap_reallocn()

    - + - - + - - + - - + - - - - - - - +
    void* mi_heap_reallocn void * mi_heap_reallocn (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t count, size_t count,
    size_t size 
    )size_t size )
    - -

    ◆ mi_heap_realpath()

    + +

    ◆ mi_heap_realpath()

    - + - - + - - + - - - - - - - +
    char* mi_heap_realpath char * mi_heap_realpath (mi_heap_theap, mi_heap_t * heap,
    const char * fname, const char * fname,
    char * resolved_name 
    )char * resolved_name )

    Resolve a file path name using a specific heap to allocate the result.

    -
    See also
    mi_realpath()
    +
    See also
    mi_realpath()
    - -

    ◆ mi_heap_set_default()

    + +

    ◆ mi_heap_set_default()

    - + - - +
    mi_heap_t* mi_heap_set_default mi_heap_t * mi_heap_set_default (mi_heap_theap)mi_heap_t * heap)
    -

    Set the default heap to use for mi_malloc() et al.

    +

    Set the default heap to use in the current thread for mi_malloc() et al.

    Parameters
    @@ -889,173 +767,134 @@ Functions - -

    ◆ mi_heap_strdup()

    + +

    ◆ mi_heap_strdup()

    heapThe new default heap.
    - + - - + - - - - - - - +
    char* mi_heap_strdup char * mi_heap_strdup (mi_heap_theap, mi_heap_t * heap,
    const char * s 
    )const char * s )

    Duplicate a string in a specific heap.

    -
    See also
    mi_strdup()
    +
    See also
    mi_strdup()
    - -

    ◆ mi_heap_strndup()

    + +

    ◆ mi_heap_strndup()

    - + - - + - - + - - - - - - - +
    char* mi_heap_strndup char * mi_heap_strndup (mi_heap_theap, mi_heap_t * heap,
    const char * s, const char * s,
    size_t n 
    )size_t n )

    Duplicate a string of at most length n in a specific heap.

    -
    See also
    mi_strndup()
    +
    See also
    mi_strndup()
    - -

    ◆ mi_heap_zalloc()

    + +

    ◆ mi_heap_zalloc()

    - + - - + - - - - - - - +
    void* mi_heap_zalloc void * mi_heap_zalloc (mi_heap_theap, mi_heap_t * heap,
    size_t size 
    )size_t size )

    Allocate zero-initialized in a specific heap.

    -
    See also
    mi_zalloc()
    +
    See also
    mi_zalloc()
    - -

    ◆ mi_heap_zalloc_aligned()

    + +

    ◆ mi_heap_zalloc_aligned()

    - + - - + - - + - - - - - - - +
    void* mi_heap_zalloc_aligned void * mi_heap_zalloc_aligned (mi_heap_theap, mi_heap_t * heap,
    size_t size, size_t size,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_heap_zalloc_aligned_at()

    + +

    ◆ mi_heap_zalloc_aligned_at()

    - + - - + - - + - - + - - - - - - - +
    void* mi_heap_zalloc_aligned_at void * mi_heap_zalloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
    size_t size, size_t size,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    @@ -1067,7 +906,7 @@ Functions diff --git a/docs/group__heap.js b/docs/group__heap.js index 13d13778..8b6118d5 100644 --- a/docs/group__heap.js +++ b/docs/group__heap.js @@ -1,30 +1,30 @@ var group__heap = [ [ "mi_heap_t", "group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2", null ], - [ "mi_heap_calloc", "group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55", null ], - [ "mi_heap_calloc_aligned", "group__heap.html#ga4af03a6e2b93fae77424d93f889705c3", null ], - [ "mi_heap_calloc_aligned_at", "group__heap.html#ga08ca6419a5c057a4d965868998eef487", null ], + [ "mi_heap_calloc", "group__heap.html#gac0098aaf231d3e9586c73136d5df95da", null ], + [ "mi_heap_calloc_aligned", "group__heap.html#gacafcc26df827c7a7de5e850217566108", null ], + [ "mi_heap_calloc_aligned_at", "group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4", null ], [ "mi_heap_collect", "group__heap.html#ga7922f7495cde30b1984d0e6072419298", null ], [ "mi_heap_delete", "group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409", null ], [ "mi_heap_destroy", "group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d", null ], - [ "mi_heap_get_backing", "group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc", null ], - [ "mi_heap_get_default", "group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05", null ], - [ "mi_heap_malloc", "group__heap.html#ga9cbed01e42c0647907295de92c3fa296", null ], - [ "mi_heap_malloc_aligned", "group__heap.html#gab5b87e1805306f70df38789fcfcf6653", null ], - [ "mi_heap_malloc_aligned_at", "group__heap.html#ga23acd7680fb0976dde3783254c6c874b", null ], - [ "mi_heap_malloc_small", "group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368", null ], - [ "mi_heap_mallocn", "group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0", null ], - [ "mi_heap_new", "group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11", null ], - [ "mi_heap_realloc", "group__heap.html#gaaef3395f66be48f37bdc8322509c5d81", null ], - [ "mi_heap_realloc_aligned", "group__heap.html#gafc603b696bd14cae6da28658f950d98c", null ], - [ "mi_heap_realloc_aligned_at", "group__heap.html#gaf96c788a1bf553fe2d371de9365e047c", null ], - [ "mi_heap_reallocf", "group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527", null ], - [ "mi_heap_reallocn", "group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8", null ], - [ "mi_heap_realpath", "group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0", null ], - [ "mi_heap_set_default", "group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422", null ], - [ "mi_heap_strdup", "group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5", null ], - [ "mi_heap_strndup", "group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a", null ], - [ "mi_heap_zalloc", "group__heap.html#ga903104592c8ed53417a3762da6241133", null ], - [ "mi_heap_zalloc_aligned", "group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0", null ], - [ "mi_heap_zalloc_aligned_at", "group__heap.html#ga45fb43a62776fbebbdf1edd99b527954", null ] + [ "mi_heap_get_backing", "group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a", null ], + [ "mi_heap_get_default", "group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909", null ], + [ "mi_heap_malloc", "group__heap.html#gab374e206c7034e0d899fb934e4f4a863", null ], + [ "mi_heap_malloc_aligned", "group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5", null ], + [ "mi_heap_malloc_aligned_at", "group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa", null ], + [ "mi_heap_malloc_small", "group__heap.html#ga012c5c8abe22b10043de39ff95909541", null ], + [ "mi_heap_mallocn", "group__heap.html#gab0f755c0b21c387fe8e9024200faa372", null ], + [ "mi_heap_new", "group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a", null ], + [ "mi_heap_realloc", "group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a", null ], + [ "mi_heap_realloc_aligned", "group__heap.html#gaccf8c249872f30bf1c2493a09197d734", null ], + [ "mi_heap_realloc_aligned_at", "group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5", null ], + [ "mi_heap_reallocf", "group__heap.html#gae7cd171425bee04c683c65a3701f0b4a", null ], + [ "mi_heap_reallocn", "group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29", null ], + [ "mi_heap_realpath", "group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2", null ], + [ "mi_heap_set_default", "group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a", null ], + [ "mi_heap_strdup", "group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a", null ], + [ "mi_heap_strndup", "group__heap.html#gad224df78f1fbee942df8adf023e12cf3", null ], + [ "mi_heap_zalloc", "group__heap.html#gabebc796399619d964d8db77aa835e8c1", null ], + [ "mi_heap_zalloc_aligned", "group__heap.html#ga6466bde8b5712aa34e081a8317f9f471", null ], + [ "mi_heap_zalloc_aligned_at", "group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819", null ] ]; \ No newline at end of file diff --git a/docs/group__malloc.html b/docs/group__malloc.html index c110fdb9..69bc4c9a 100644 --- a/docs/group__malloc.html +++ b/docs/group__malloc.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Basic Allocation + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,89 +91,88 @@ $(document).ready(function(){initNavTree('group__malloc.html',''); initResizable
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Basic Allocation
    +
    Basic Allocation
    -

    The basic allocation interface. +

    The basic allocation interface. More...

    - - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + +

    +

    Functions

    void mi_free (void *p)
     Free previously allocated memory. More...
    void mi_free (void *p)
     Free previously allocated memory.
     
    void * mi_malloc (size_t size)
     Allocate size bytes. More...
     
    void * mi_zalloc (size_t size)
     Allocate zero-initialized size bytes. More...
     
    void * mi_calloc (size_t count, size_t size)
     Allocate zero-initialized count elements of size bytes. More...
     
    void * mi_realloc (void *p, size_t newsize)
     Re-allocate memory to newsize bytes. More...
     
    void * mi_recalloc (void *p, size_t count, size_t size)
     Re-allocate memory to count elements of size bytes, with extra memory initialized to zero. More...
    void * mi_malloc (size_t size)
     Allocate size bytes.
     
    void * mi_zalloc (size_t size)
     Allocate zero-initialized size bytes.
     
    void * mi_calloc (size_t count, size_t size)
     Allocate zero-initialized count elements of size bytes.
     
    void * mi_realloc (void *p, size_t newsize)
     Re-allocate memory to newsize bytes.
     
    void * mi_recalloc (void *p, size_t count, size_t size)
     Re-allocate memory to count elements of size bytes, with extra memory initialized to zero.
     
    void * mi_expand (void *p, size_t newsize)
     Try to re-allocate memory to newsize bytes in place. More...
     
    void * mi_mallocn (size_t count, size_t size)
     Allocate count elements of size bytes. More...
     
    void * mi_reallocn (void *p, size_t count, size_t size)
     Re-allocate memory to count elements of size bytes. More...
     
    void * mi_reallocf (void *p, size_t newsize)
     Re-allocate memory to newsize bytes,. More...
     
    char * mi_strdup (const char *s)
     Allocate and duplicate a string. More...
     
    char * mi_strndup (const char *s, size_t n)
     Allocate and duplicate a string up to n bytes. More...
     
    char * mi_realpath (const char *fname, char *resolved_name)
     Resolve a file path name. More...
     
    void * mi_expand (void *p, size_t newsize)
     Try to re-allocate memory to newsize bytes in place.
     
    void * mi_mallocn (size_t count, size_t size)
     Allocate count elements of size bytes.
     
    void * mi_reallocn (void *p, size_t count, size_t size)
     Re-allocate memory to count elements of size bytes.
     
    void * mi_reallocf (void *p, size_t newsize)
     Re-allocate memory to newsize bytes,.
     
    char * mi_strdup (const char *s)
     Allocate and duplicate a string.
     
    char * mi_strndup (const char *s, size_t n)
     Allocate and duplicate a string up to n bytes.
     
    char * mi_realpath (const char *fname, char *resolved_name)
     Resolve a file path name.
     

    Detailed Description

    The basic allocation interface.

    Function Documentation

    - -

    ◆ mi_calloc()

    + +

    ◆ mi_calloc()

    - + - - + - - - - - - - +
    void* mi_calloc void * mi_calloc (size_t count, size_t count,
    size_t size 
    )size_t size )
    @@ -184,32 +186,25 @@ Functions
    Returns
    pointer to the allocated memory of size*count bytes, or NULL if either out of memory or when count*size overflows.
    -

    Returns a unique pointer if called with either size or count of 0.

    See also
    mi_zalloc()
    +

    Returns a unique pointer if called with either size or count of 0.

    See also
    mi_zalloc()
    - -

    ◆ mi_expand()

    + +

    ◆ mi_expand()

    - + - - + - - - - - - - +
    void* mi_expand void * mi_expand (void * p, void * p,
    size_t newsize 
    )size_t newsize )
    @@ -226,8 +221,8 @@ Functions
    - -

    ◆ mi_free()

    + +

    ◆ mi_free()

    @@ -235,8 +230,7 @@ Functions void mi_free ( - void *  - p) + void * p) @@ -252,17 +246,16 @@ Functions
    - -

    ◆ mi_malloc()

    + +

    ◆ mi_malloc()

    - + - - +
    void* mi_malloc void * mi_malloc (size_t size)size_t size)
    @@ -279,28 +272,21 @@ Functions
    - -

    ◆ mi_mallocn()

    + +

    ◆ mi_mallocn()

    - + - - + - - - - - - - +
    void* mi_mallocn void * mi_mallocn (size_t count, size_t count,
    size_t size 
    )size_t size )
    @@ -314,34 +300,27 @@ Functions
    Returns
    A pointer to a block of count * size bytes, or NULL if out of memory or if count * size overflows.
    -

    If there is no overflow, it behaves exactly like mi_malloc(p,count*size).

    See also
    mi_calloc()
    +

    If there is no overflow, it behaves exactly like mi_malloc(count*size).

    See also
    mi_calloc()
    mi_zallocn()
    - -

    ◆ mi_realloc()

    + +

    ◆ mi_realloc()

    - + - - + - - - - - - - +
    void* mi_realloc void * mi_realloc (void * p, void * p,
    size_t newsize 
    )size_t newsize )
    @@ -358,28 +337,21 @@ mi_zallocn()
    - -

    ◆ mi_reallocf()

    + +

    ◆ mi_reallocf()

    - + - - + - - - - - - - +
    void* mi_reallocf void * mi_reallocf (void * p, void * p,
    size_t newsize 
    )size_t newsize )
    @@ -393,39 +365,31 @@ mi_zallocn()
    Returns
    pointer to the re-allocated memory of newsize bytes, or NULL if out of memory.
    -

    In contrast to mi_realloc(), if NULL is returned, the original pointer p is freed (if it was not NULL itself). Otherwise the original pointer is either freed or returned as the reallocated result (in case it fits in-place with the new size). If the pointer p is NULL, it behaves as mi_malloc(newsize). If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.

    +

    In contrast to mi_realloc(), if NULL is returned, the original pointer p is freed (if it was not NULL itself). Otherwise the original pointer is either freed or returned as the reallocated result (in case it fits in-place with the new size). If the pointer p is NULL, it behaves as mi_malloc(newsize). If newsize is larger than the original size allocated for p, the bytes after size are uninitialized.

    See also
    reallocf (on BSD)
    - -

    ◆ mi_reallocn()

    + +

    ◆ mi_reallocn()

    - + - - + - - + - - - - - - - +
    void* mi_reallocn void * mi_reallocn (void * p, void * p,
    size_t count, size_t count,
    size_t size 
    )size_t size )
    @@ -444,28 +408,21 @@ mi_zallocn()
    - -

    ◆ mi_realpath()

    + +

    ◆ mi_realpath()

    - + - - + - - - - - - - +
    char* mi_realpath char * mi_realpath (const char * fname, const char * fname,
    char * resolved_name 
    )char * resolved_name )
    @@ -479,13 +436,13 @@ mi_zallocn()
    Returns
    If successful a pointer to the resolved absolute file name, or NULL on failure (with errno set to the error code).
    -

    If resolved_name was NULL, the returned result should be freed with mi_free().

    -

    Replacement for the standard realpath() such that mi_free() can be used on the returned result (if resolved_name was NULL).

    +

    If resolved_name was NULL, the returned result should be freed with mi_free().

    +

    Replacement for the standard realpath() such that mi_free() can be used on the returned result (if resolved_name was NULL).

    - -

    ◆ mi_recalloc()

    + +

    ◆ mi_recalloc()

    @@ -493,25 +450,17 @@ mi_zallocn() void * mi_recalloc ( - void *  - p, + void * p, - size_t  - count, + size_t count, - size_t  - size  - - - - ) - + size_t size )
    @@ -526,23 +475,22 @@ mi_zallocn()
    Returns
    A pointer to a re-allocated block of count * size bytes, or NULL if out of memory or if count * size overflows.
    -

    If there is no overflow, it behaves exactly like mi_rezalloc(p,count*size).

    See also
    mi_reallocn()
    +

    If there is no overflow, it behaves exactly like mi_rezalloc(p,count*size).

    See also
    mi_reallocn()
    recallocarray() (on BSD).
    - -

    ◆ mi_strdup()

    + +

    ◆ mi_strdup()

    - + - - +
    char* mi_strdup char * mi_strdup (const char * s)const char * s)
    @@ -556,32 +504,25 @@ mi_zallocn()
    Returns
    a pointer to newly allocated memory initialized to string s, or NULL if either out of memory or if s is NULL.
    -

    Replacement for the standard strdup() such that mi_free() can be used on the returned result.

    +

    Replacement for the standard strdup() such that mi_free() can be used on the returned result.

    - -

    ◆ mi_strndup()

    + +

    ◆ mi_strndup()

    - + - - + - - - - - - - +
    char* mi_strndup char * mi_strndup (const char * s, const char * s,
    size_t n 
    )size_t n )
    @@ -595,21 +536,20 @@ mi_zallocn()
    Returns
    a pointer to newly allocated memory initialized to string s up to the first n bytes (and always zero terminated), or NULL if either out of memory or if s is NULL.
    -

    Replacement for the standard strndup() such that mi_free() can be used on the returned result.

    +

    Replacement for the standard strndup() such that mi_free() can be used on the returned result.

    - -

    ◆ mi_zalloc()

    + +

    ◆ mi_zalloc()

    - + - - +
    void* mi_zalloc void * mi_zalloc (size_t size)size_t size)
    @@ -631,7 +571,7 @@ mi_zallocn() diff --git a/docs/group__malloc.js b/docs/group__malloc.js index 7293ffaf..5b076520 100644 --- a/docs/group__malloc.js +++ b/docs/group__malloc.js @@ -1,16 +1,16 @@ var group__malloc = [ - [ "mi_calloc", "group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d", null ], - [ "mi_expand", "group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4", null ], + [ "mi_calloc", "group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56", null ], + [ "mi_expand", "group__malloc.html#ga19299856216cfbb08e2628593654dfb0", null ], [ "mi_free", "group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95", null ], - [ "mi_malloc", "group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a", null ], - [ "mi_mallocn", "group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6", null ], - [ "mi_realloc", "group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6", null ], - [ "mi_reallocf", "group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0", null ], - [ "mi_reallocn", "group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853", null ], - [ "mi_realpath", "group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe", null ], + [ "mi_malloc", "group__malloc.html#gae1dd97b542420c87ae085e822b1229e8", null ], + [ "mi_mallocn", "group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6", null ], + [ "mi_realloc", "group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583", null ], + [ "mi_reallocf", "group__malloc.html#ga4dc3a4067037b151a64629fe8a332641", null ], + [ "mi_reallocn", "group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467", null ], + [ "mi_realpath", "group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd", null ], [ "mi_recalloc", "group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc", null ], - [ "mi_strdup", "group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2", null ], - [ "mi_strndup", "group__malloc.html#gaaabf971c2571891433477e2d21a35266", null ], - [ "mi_zalloc", "group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000", null ] + [ "mi_strdup", "group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889", null ], + [ "mi_strndup", "group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d", null ], + [ "mi_zalloc", "group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8", null ] ]; \ No newline at end of file diff --git a/docs/group__options.html b/docs/group__options.html index 6c63e172..617f1067 100644 --- a/docs/group__options.html +++ b/docs/group__options.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Runtime Options + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,128 +91,174 @@ $(document).ready(function(){initNavTree('group__options.html',''); initResizabl
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Runtime Options
    +
    Runtime Options
    - -

    Set runtime behavior. -More...

    - - - +

    +

    Enumerations

    enum  mi_option_t {
    -  mi_option_show_errors -, mi_option_show_stats -, mi_option_verbose -, mi_option_eager_commit +
    enum  mi_option_t {
    +  mi_option_show_errors +, mi_option_show_stats +, mi_option_verbose +, mi_option_max_errors ,
    -  mi_option_eager_region_commit -, mi_option_large_os_pages -, mi_option_reserve_huge_os_pages -, mi_option_reserve_huge_os_pages_at +  mi_option_max_warnings +, mi_option_reserve_huge_os_pages +, mi_option_reserve_huge_os_pages_at +, mi_option_reserve_os_memory ,
    -  mi_option_segment_cache -, mi_option_page_reset -, mi_option_segment_reset -, mi_option_reset_delay +  mi_option_allow_large_os_pages +, mi_option_purge_decommits +, mi_option_arena_reserve +, mi_option_os_tag ,
    -  mi_option_use_numa_nodes -, mi_option_reset_decommits -, mi_option_eager_commit_delay -, mi_option_os_tag +  mi_option_retry_on_oom +, mi_option_eager_commit +, mi_option_eager_commit_delay +, mi_option_arena_eager_commit ,
    -  _mi_option_last +  mi_option_abandoned_page_purge +, mi_option_purge_delay +, mi_option_use_numa_nodes +, mi_option_disallow_os_alloc +,
    +  mi_option_limit_os_alloc +, mi_option_max_segment_reclaim +, mi_option_destroy_on_exit +, mi_option_arena_purge_mult +,
    +  mi_option_abandoned_reclaim_on_free +, mi_option_purge_extend_delay +, mi_option_disallow_arena_alloc +, mi_option_visit_abandoned +,
    +  _mi_option_last
    }
     Runtime options. More...
     Runtime options. More...
     
    - - + - + - + - + - + - + - + + + + + - +

    +

    Functions

    bool mi_option_is_enabled (mi_option_t option)
    bool mi_option_is_enabled (mi_option_t option)
     
    void mi_option_enable (mi_option_t option)
    void mi_option_enable (mi_option_t option)
     
    void mi_option_disable (mi_option_t option)
    void mi_option_disable (mi_option_t option)
     
    void mi_option_set_enabled (mi_option_t option, bool enable)
    void mi_option_set_enabled (mi_option_t option, bool enable)
     
    void mi_option_set_enabled_default (mi_option_t option, bool enable)
    void mi_option_set_enabled_default (mi_option_t option, bool enable)
     
    long mi_option_get (mi_option_t option)
    long mi_option_get (mi_option_t option)
     
    void mi_option_set (mi_option_t option, long value)
    long mi_option_get_clamp (mi_option_t option, long min, long max)
     
    size_t mi_option_get_size (mi_option_t option)
     
    void mi_option_set (mi_option_t option, long value)
     
    void mi_option_set_default (mi_option_t option, long value)
    void mi_option_set_default (mi_option_t option, long value)
     

    Detailed Description

    Set runtime behavior.

    Enumeration Type Documentation

    - -

    ◆ mi_option_t

    + +

    ◆ mi_option_t

    - +
    enum mi_option_tenum mi_option_t

    Runtime options.

    - - - - - - - - - - - - - - - - - + + + + + + + + + + + + +
    Enumerator
    mi_option_show_errors 

    Print error messages to stderr.

    +
    Enumerator
    mi_option_show_errors 

    Print error messages.

    mi_option_show_stats 

    Print statistics to stderr when the program is done.

    +
    mi_option_show_stats 

    Print statistics on termination.

    mi_option_verbose 

    Print verbose messages to stderr.

    +
    mi_option_verbose 

    Print verbose messages.

    mi_option_eager_commit 

    Eagerly commit segments (4MiB) (enabled by default).

    +
    mi_option_max_errors 

    issue at most N error messages

    mi_option_eager_region_commit 

    Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)

    +
    mi_option_max_warnings 

    issue at most N warning messages

    mi_option_large_os_pages 

    Use large OS pages (2MiB in size) if possible.

    +
    mi_option_reserve_huge_os_pages 

    reserve N huge OS pages (1GiB pages) at startup

    mi_option_reserve_huge_os_pages 

    The number of huge OS pages (1GiB in size) to reserve at the start of the program.

    +
    mi_option_reserve_huge_os_pages_at 

    Reserve N huge OS pages at a specific NUMA node N.

    mi_option_reserve_huge_os_pages_at 

    Reserve huge OS pages at node N.

    +
    mi_option_reserve_os_memory 

    reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use mi_option_get_size)

    mi_option_segment_cache 

    The number of segments per thread to keep cached.

    +
    mi_option_allow_large_os_pages 

    allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.

    mi_option_page_reset 

    Reset page memory after mi_option_reset_delay milliseconds when it becomes free.

    +
    mi_option_purge_decommits 

    should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)

    mi_option_segment_reset 

    Experimental.

    +
    mi_option_arena_reserve 

    initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use mi_option_get_size)

    mi_option_reset_delay 

    Delay in milli-seconds before resetting a page (100ms by default)

    +
    mi_option_os_tag 

    tag used for OS logging (macOS only for now) (=100)

    mi_option_use_numa_nodes 

    Pretend there are at most N NUMA nodes.

    +
    mi_option_retry_on_oom 

    retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)

    mi_option_reset_decommits 

    Experimental.

    +
    mi_option_eager_commit 

    eager commit segments? (after eager_commit_delay segments) (enabled by default).

    mi_option_eager_commit_delay 

    Experimental.

    +
    mi_option_eager_commit_delay 

    the first N segments per thread are not eagerly committed (but per page in the segment on demand)

    mi_option_os_tag 

    OS tag to assign to mimalloc'd memory.

    +
    mi_option_arena_eager_commit 

    eager commit arenas? Use 2 to enable just on overcommit systems (=2)

    _mi_option_last 
    mi_option_abandoned_page_purge 

    immediately purge delayed purges on thread termination

    +
    mi_option_purge_delay 

    memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10)

    +
    mi_option_use_numa_nodes 

    0 = use all available numa nodes, otherwise use at most N nodes.

    +
    mi_option_disallow_os_alloc 

    1 = do not use OS memory for allocation (but only programmatically reserved arenas)

    +
    mi_option_limit_os_alloc 

    If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)

    +
    mi_option_max_segment_reclaim 

    max. percentage of the abandoned segments can be reclaimed per try (=10%)

    +
    mi_option_destroy_on_exit 

    if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe

    +
    mi_option_arena_purge_mult 

    multiplier for purge_delay for the purging delay for arenas (=10)

    +
    mi_option_abandoned_reclaim_on_free 

    allow to reclaim an abandoned segment on a free (=1)

    +
    mi_option_purge_extend_delay 

    extend purge delay on each subsequent delay (=1)

    +
    mi_option_disallow_arena_alloc 

    1 = do not use arena's for allocation (except if using specific arena id's)

    +
    mi_option_visit_abandoned 

    allow visiting heap blocks from abandoned threads (=0)

    +
    _mi_option_last 

    Function Documentation

    - -

    ◆ mi_option_disable()

    + +

    ◆ mi_option_disable()

    @@ -217,8 +266,7 @@ Functions void mi_option_disable ( - mi_option_t  - option) + mi_option_t option) @@ -226,8 +274,8 @@ Functions
    - -

    ◆ mi_option_enable()

    + +

    ◆ mi_option_enable()

    @@ -235,8 +283,7 @@ Functions void mi_option_enable ( - mi_option_t  - option) + mi_option_t option) @@ -244,8 +291,8 @@ Functions
    - -

    ◆ mi_option_get()

    + +

    ◆ mi_option_get()

    @@ -253,8 +300,7 @@ Functions long mi_option_get ( - mi_option_t  - option) + mi_option_t option) @@ -262,8 +308,51 @@ Functions
    - -

    ◆ mi_option_is_enabled()

    + +

    ◆ mi_option_get_clamp()

    + +
    +
    + + + + + + + + + + + + + + + + +
    long mi_option_get_clamp (mi_option_t option,
    long min,
    long max )
    +
    + +
    +
    + +

    ◆ mi_option_get_size()

    + +
    +
    + + + + + + + +
    size_t mi_option_get_size (mi_option_t option)
    +
    + +
    +
    + +

    ◆ mi_option_is_enabled()

    @@ -271,8 +360,7 @@ Functions bool mi_option_is_enabled ( - mi_option_t  - option) + mi_option_t option) @@ -280,8 +368,8 @@ Functions
    - -

    ◆ mi_option_set()

    + +

    ◆ mi_option_set()

    @@ -289,27 +377,20 @@ Functions void mi_option_set ( - mi_option_t  - option, + mi_option_t option, - long  - value  - - - - ) - + long value )
    - -

    ◆ mi_option_set_default()

    + +

    ◆ mi_option_set_default()

    @@ -317,27 +398,20 @@ Functions void mi_option_set_default ( - mi_option_t  - option, + mi_option_t option, - long  - value  - - - - ) - + long value )
    - -

    ◆ mi_option_set_enabled()

    + +

    ◆ mi_option_set_enabled()

    @@ -345,27 +419,20 @@ Functions void mi_option_set_enabled ( - mi_option_t  - option, + mi_option_t option, - bool  - enable  - - - - ) - + bool enable )
    - -

    ◆ mi_option_set_enabled_default()

    + +

    ◆ mi_option_set_enabled_default()

    @@ -373,19 +440,12 @@ Functions void mi_option_set_enabled_default ( - mi_option_t  - option, + mi_option_t option, - bool  - enable  - - - - ) - + bool enable )
    @@ -397,7 +457,7 @@ Functions diff --git a/docs/group__options.js b/docs/group__options.js index c8836cdc..b152f7bc 100644 --- a/docs/group__options.js +++ b/docs/group__options.js @@ -4,24 +4,38 @@ var group__options = [ "mi_option_show_errors", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0", null ], [ "mi_option_show_stats", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda", null ], [ "mi_option_verbose", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777", null ], - [ "mi_option_eager_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b", null ], - [ "mi_option_eager_region_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad", null ], - [ "mi_option_large_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e", null ], + [ "mi_option_max_errors", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a", null ], + [ "mi_option_max_warnings", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665", null ], [ "mi_option_reserve_huge_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2", null ], [ "mi_option_reserve_huge_os_pages_at", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c", null ], - [ "mi_option_segment_cache", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1", null ], - [ "mi_option_page_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968", null ], - [ "mi_option_segment_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d", null ], - [ "mi_option_reset_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5", null ], - [ "mi_option_use_numa_nodes", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74", null ], - [ "mi_option_reset_decommits", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536", null ], - [ "mi_option_eager_commit_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c", null ], + [ "mi_option_reserve_os_memory", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333", null ], + [ "mi_option_allow_large_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556", null ], + [ "mi_option_purge_decommits", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4", null ], + [ "mi_option_arena_reserve", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de", null ], [ "mi_option_os_tag", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf", null ], + [ "mi_option_retry_on_oom", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e", null ], + [ "mi_option_eager_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b", null ], + [ "mi_option_eager_commit_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c", null ], + [ "mi_option_arena_eager_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5", null ], + [ "mi_option_abandoned_page_purge", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c", null ], + [ "mi_option_purge_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290", null ], + [ "mi_option_use_numa_nodes", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74", null ], + [ "mi_option_disallow_os_alloc", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6", null ], + [ "mi_option_limit_os_alloc", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc", null ], + [ "mi_option_max_segment_reclaim", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909", null ], + [ "mi_option_destroy_on_exit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88", null ], + [ "mi_option_arena_purge_mult", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e", null ], + [ "mi_option_abandoned_reclaim_on_free", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9", null ], + [ "mi_option_purge_extend_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487", null ], + [ "mi_option_disallow_arena_alloc", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40", null ], + [ "mi_option_visit_abandoned", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e", null ], [ "_mi_option_last", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a", null ] ] ], [ "mi_option_disable", "group__options.html#gaebf6ff707a2e688ebb1a2296ca564054", null ], [ "mi_option_enable", "group__options.html#ga04180ae41b0d601421dd62ced40ca050", null ], [ "mi_option_get", "group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a", null ], + [ "mi_option_get_clamp", "group__options.html#ga96ad9c406338bd314cfe878cfc9bf723", null ], + [ "mi_option_get_size", "group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c", null ], [ "mi_option_is_enabled", "group__options.html#ga459ad98f18b3fc9275474807fe0ca188", null ], [ "mi_option_set", "group__options.html#gaf84921c32375e25754dc2ee6a911fa60", null ], [ "mi_option_set_default", "group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90", null ], diff --git a/docs/group__posix.html b/docs/group__posix.html index 37c87028..2e904e81 100644 --- a/docs/group__posix.html +++ b/docs/group__posix.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Posix + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,62 +91,101 @@ $(document).ready(function(){initNavTree('group__posix.html',''); initResizable(
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Posix
    +
    Posix
    - -

    mi_ prefixed implementations of various Posix, Unix, and C++ allocation functions. -More...

    - - - - - - - + + - + + + + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + + + + + - + - +

    +

    Functions

    size_t mi_malloc_size (const void *p)
     
    size_t mi_malloc_usable_size (const void *p)
     
    void mi_cfree (void *p)
     Just as free but also checks if the pointer p belongs to our heap. More...
    void mi_cfree (void *p)
     Just as free but also checks if the pointer p belongs to our heap.
     
    int mi_posix_memalign (void **p, size_t alignment, size_t size)
    void * mi__expand (void *p, size_t newsize)
     
    size_t mi_malloc_size (const void *p)
     
    size_t mi_malloc_good_size (size_t size)
     
    size_t mi_malloc_usable_size (const void *p)
     
    int mi_posix_memalign (void **p, size_t alignment, size_t size)
     
    int mi__posix_memalign (void **p, size_t alignment, size_t size)
    int mi__posix_memalign (void **p, size_t alignment, size_t size)
     
    void * mi_memalign (size_t alignment, size_t size)
     
    void * mi_valloc (size_t size)
     
    void * mi_pvalloc (size_t size)
     
    void * mi_aligned_alloc (size_t alignment, size_t size)
     
    void * mi_reallocarray (void *p, size_t count, size_t size)
     Correspond s to reallocarray in FreeBSD. More...
     
    int mi_reallocarr (void *p, size_t count, size_t size)
     Corresponds to reallocarr in NetBSD. More...
    void * mi_memalign (size_t alignment, size_t size)
     
    void * mi_valloc (size_t size)
     
    void * mi_pvalloc (size_t size)
     
    void * mi_aligned_alloc (size_t alignment, size_t size)
     
    unsigned short * mi_wcsdup (const unsigned short *s)
     
    unsigned char * mi_mbsdup (const unsigned char *s)
     
    int mi_dupenv_s (char **buf, size_t *size, const char *name)
     
    int mi_wdupenv_s (unsigned short **buf, size_t *size, const unsigned short *name)
     
    void * mi_reallocarray (void *p, size_t count, size_t size)
     Correspond s to reallocarray in FreeBSD.
     
    int mi_reallocarr (void *p, size_t count, size_t size)
     Corresponds to reallocarr in NetBSD.
     
    void mi_free_size (void *p, size_t size)
    void * mi_aligned_recalloc (void *p, size_t newcount, size_t size, size_t alignment)
     
    void * mi_aligned_offset_recalloc (void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
     
    void mi_free_size (void *p, size_t size)
     
    void mi_free_size_aligned (void *p, size_t size, size_t alignment)
    void mi_free_size_aligned (void *p, size_t size, size_t alignment)
     
    void mi_free_aligned (void *p, size_t alignment)
    void mi_free_aligned (void *p, size_t alignment)
     

    Detailed Description

    -

    mi_ prefixed implementations of various Posix, Unix, and C++ allocation functions.

    -

    Defined for convenience as all redirect to the regular mimalloc API.

    +

    mi_ prefixed implementations of various Posix, Unix, and C++ allocation functions. Defined for convenience as all redirect to the regular mimalloc API.

    Function Documentation

    - -

    ◆ mi__posix_memalign()

    + +

    ◆ mi__expand()

    + +
    +
    + + + + + + + + + + + +
    void * mi__expand (void * p,
    size_t newsize )
    +
    + +
    +
    + +

    ◆ mi__posix_memalign()

    @@ -151,61 +193,113 @@ Functions int mi__posix_memalign ( - void **  - p, + void ** p, - size_t  - alignment, + size_t alignment, - size_t  - size  - - - - ) - + size_t size )
    - -

    ◆ mi_aligned_alloc()

    + +

    ◆ mi_aligned_alloc()

    - + - - + - - - - - - - +
    void* mi_aligned_alloc void * mi_aligned_alloc (size_t alignment, size_t alignment,
    size_t size 
    )size_t size )
    - -

    ◆ mi_cfree()

    + +

    ◆ mi_aligned_offset_recalloc()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    void * mi_aligned_offset_recalloc (void * p,
    size_t newcount,
    size_t size,
    size_t alignment,
    size_t offset )
    +
    + +
    +
    + +

    ◆ mi_aligned_recalloc()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    void * mi_aligned_recalloc (void * p,
    size_t newcount,
    size_t size,
    size_t alignment )
    +
    + +
    +
    + +

    ◆ mi_cfree()

    @@ -213,8 +307,7 @@ Functions void mi_cfree ( - void *  - p) + void * p) @@ -224,8 +317,34 @@ Functions
    - -

    ◆ mi_free_aligned()

    + +

    ◆ mi_dupenv_s()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int mi_dupenv_s (char ** buf,
    size_t * size,
    const char * name )
    +
    + +
    +
    + +

    ◆ mi_free_aligned()

    @@ -233,27 +352,20 @@ Functions void mi_free_aligned ( - void *  - p, + void * p, - size_t  - alignment  - - - - ) - + size_t alignment )
    - -

    ◆ mi_free_size()

    + +

    ◆ mi_free_size()

    @@ -261,27 +373,20 @@ Functions void mi_free_size ( - void *  - p, + void * p, - size_t  - size  - - - - ) - + size_t size )
    - -

    ◆ mi_free_size_aligned()

    + +

    ◆ mi_free_size_aligned()

    @@ -289,33 +394,42 @@ Functions void mi_free_size_aligned ( - void *  - p, + void * p, - size_t  - size, + size_t size, - size_t  - alignment  - - - - ) - + size_t alignment )
    - -

    ◆ mi_malloc_size()

    + +

    ◆ mi_malloc_good_size()

    + +
    +
    + + + + + + + +
    size_t mi_malloc_good_size (size_t size)
    +
    + +
    +
    + +

    ◆ mi_malloc_size()

    @@ -323,8 +437,7 @@ Functions size_t mi_malloc_size ( - const void *  - p) + const void * p) @@ -332,8 +445,8 @@ Functions
    - -

    ◆ mi_malloc_usable_size()

    + +

    ◆ mi_malloc_usable_size()

    @@ -341,8 +454,7 @@ Functions size_t mi_malloc_usable_size ( - const void *  - p) + const void * p) @@ -350,36 +462,46 @@ Functions
    - -

    ◆ mi_memalign()

    + +

    ◆ mi_mbsdup()

    - + - - - - - + - - - - - - -
    void* mi_memalign unsigned char * mi_mbsdup (size_t alignment,
    const unsigned char * s) size_t size 
    )
    - -

    ◆ mi_posix_memalign()

    + +

    ◆ mi_memalign()

    + +
    +
    + + + + + + + + + + + +
    void * mi_memalign (size_t alignment,
    size_t size )
    +
    + +
    +
    + +

    ◆ mi_posix_memalign()

    @@ -387,42 +509,33 @@ Functions int mi_posix_memalign ( - void **  - p, + void ** p, - size_t  - alignment, + size_t alignment, - size_t  - size  - - - - ) - + size_t size )
    - -

    ◆ mi_pvalloc()

    + +

    ◆ mi_pvalloc()

    - + - - +
    void* mi_pvalloc void * mi_pvalloc (size_t size)size_t size)
    @@ -430,8 +543,8 @@ Functions
    - -

    ◆ mi_reallocarr()

    + +

    ◆ mi_reallocarr()

    @@ -439,25 +552,17 @@ Functions int mi_reallocarr ( - void *  - p, + void * p, - size_t  - count, + size_t count, - size_t  - size  - - - - ) - + size_t size )
    @@ -466,34 +571,26 @@ Functions
    - -

    ◆ mi_reallocarray()

    + +

    ◆ mi_reallocarray()

    - + - - + - - + - - - - - - - +
    void* mi_reallocarray void * mi_reallocarray (void * p, void * p,
    size_t count, size_t count,
    size_t size 
    )size_t size )
    @@ -502,22 +599,64 @@ Functions
    - -

    ◆ mi_valloc()

    + +

    ◆ mi_valloc()

    - + - - +
    void* mi_valloc void * mi_valloc (size_t size)size_t size)
    +
    +
    + +

    ◆ mi_wcsdup()

    + +
    +
    + + + + + + + +
    unsigned short * mi_wcsdup (const unsigned short * s)
    +
    + +
    +
    + +

    ◆ mi_wdupenv_s()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int mi_wdupenv_s (unsigned short ** buf,
    size_t * size,
    const unsigned short * name )
    +
    +
    @@ -525,7 +664,7 @@ Functions diff --git a/docs/group__posix.js b/docs/group__posix.js index 50c248c8..ea4ed269 100644 --- a/docs/group__posix.js +++ b/docs/group__posix.js @@ -1,17 +1,25 @@ var group__posix = [ + [ "mi__expand", "group__posix.html#ga66bcfeb4faedbb42b796bc680821ef84", null ], [ "mi__posix_memalign", "group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a", null ], - [ "mi_aligned_alloc", "group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5", null ], + [ "mi_aligned_alloc", "group__posix.html#ga430ed1513f0571ff83be00ec58a98ee0", null ], + [ "mi_aligned_offset_recalloc", "group__posix.html#ga16570deddd559001b44953eedbad0084", null ], + [ "mi_aligned_recalloc", "group__posix.html#gaf82cbb4b4f24acf723348628451798d3", null ], [ "mi_cfree", "group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7", null ], + [ "mi_dupenv_s", "group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958", null ], [ "mi_free_aligned", "group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9", null ], [ "mi_free_size", "group__posix.html#gae01389eedab8d67341ff52e2aad80ebb", null ], [ "mi_free_size_aligned", "group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc", null ], + [ "mi_malloc_good_size", "group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071", null ], [ "mi_malloc_size", "group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de", null ], [ "mi_malloc_usable_size", "group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17", null ], - [ "mi_memalign", "group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e", null ], + [ "mi_mbsdup", "group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0", null ], + [ "mi_memalign", "group__posix.html#ga726867f13fd29ca36064954c0285b1d8", null ], [ "mi_posix_memalign", "group__posix.html#gacff84f226ba9feb2031b8992e5579447", null ], - [ "mi_pvalloc", "group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e", null ], + [ "mi_pvalloc", "group__posix.html#ga644bebccdbb2821542dd8c7e7641f476", null ], [ "mi_reallocarr", "group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5", null ], - [ "mi_reallocarray", "group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088", null ], - [ "mi_valloc", "group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b", null ] + [ "mi_reallocarray", "group__posix.html#gadfeccb72748a2f6305474a37d9d57bce", null ], + [ "mi_valloc", "group__posix.html#ga50cafb9722020402f065de93799f64ca", null ], + [ "mi_wcsdup", "group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf", null ], + [ "mi_wdupenv_s", "group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1", null ] ]; \ No newline at end of file diff --git a/docs/group__typed.html b/docs/group__typed.html index 3c00adb4..94efe409 100644 --- a/docs/group__typed.html +++ b/docs/group__typed.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Typed Macros + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html'); -
    @@ -88,65 +91,67 @@ $(document).ready(function(){initNavTree('group__typed.html',''); initResizable(
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Typed Macros
    +
    Typed Macros
    - -

    Typed allocation macros. -More...

    - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + +

    +

    Macros

    #define mi_malloc_tp(tp)
     Allocate a block of type tp. More...
    #define mi_malloc_tp(tp)
     Allocate a block of type tp.
     
    #define mi_zalloc_tp(tp)
     Allocate a zero-initialized block of type tp. More...
    #define mi_zalloc_tp(tp)
     Allocate a zero-initialized block of type tp.
     
    #define mi_calloc_tp(tp, count)
     Allocate count zero-initialized blocks of type tp. More...
    #define mi_calloc_tp(tp, count)
     Allocate count zero-initialized blocks of type tp.
     
    #define mi_mallocn_tp(tp, count)
     Allocate count blocks of type tp. More...
    #define mi_mallocn_tp(tp, count)
     Allocate count blocks of type tp.
     
    #define mi_reallocn_tp(p, tp, count)
     Re-allocate to count blocks of type tp. More...
    #define mi_reallocn_tp(p, tp, count)
     Re-allocate to count blocks of type tp.
     
    #define mi_heap_malloc_tp(hp, tp)
     Allocate a block of type tp in a heap hp. More...
    #define mi_heap_malloc_tp(hp, tp)
     Allocate a block of type tp in a heap hp.
     
    #define mi_heap_zalloc_tp(hp, tp)
     Allocate a zero-initialized block of type tp in a heap hp. More...
    #define mi_heap_zalloc_tp(hp, tp)
     Allocate a zero-initialized block of type tp in a heap hp.
     
    #define mi_heap_calloc_tp(hp, tp, count)
     Allocate count zero-initialized blocks of type tp in a heap hp. More...
    #define mi_heap_calloc_tp(hp, tp, count)
     Allocate count zero-initialized blocks of type tp in a heap hp.
     
    #define mi_heap_mallocn_tp(hp, tp, count)
     Allocate count blocks of type tp in a heap hp. More...
    #define mi_heap_mallocn_tp(hp, tp, count)
     Allocate count blocks of type tp in a heap hp.
     
    #define mi_heap_reallocn_tp(hp, p, tp, count)
     Re-allocate to count blocks of type tp in a heap hp. More...
    #define mi_heap_reallocn_tp(hp, p, tp, count)
     Re-allocate to count blocks of type tp in a heap hp.
     
    #define mi_heap_recalloc_tp(hp, p, tp, count)
     Re-allocate to count zero initialized blocks of type tp in a heap hp. More...
    #define mi_heap_recalloc_tp(hp, p, tp, count)
     Re-allocate to count zero initialized blocks of type tp in a heap hp.
     

    Detailed Description

    -

    Typed allocation macros.

    -

    For example:

    int* p = mi_malloc_tp(int)
    -
    #define mi_malloc_tp(tp)
    Allocate a block of type tp.
    Definition: mimalloc-doc.h:692
    +

    Typed allocation macros. For example:

    int* p = mi_malloc_tp(int)
    +
    #define mi_malloc_tp(tp)
    Allocate a block of type tp.
    Definition mimalloc-doc.h:768

    Macro Definition Documentation

    - -

    ◆ mi_calloc_tp

    + +

    ◆ mi_calloc_tp

    @@ -154,19 +159,12 @@ Macros #define mi_calloc_tp ( -   - tp, + tp, -   - count  - - - - ) - + count )
    @@ -175,8 +173,8 @@ Macros
    - -

    ◆ mi_heap_calloc_tp

    + +

    ◆ mi_heap_calloc_tp

    @@ -184,25 +182,17 @@ Macros #define mi_heap_calloc_tp ( -   - hp, + hp, -   - tp, + tp, -   - count  - - - - ) - + count )
    @@ -211,8 +201,8 @@ Macros
    - -

    ◆ mi_heap_malloc_tp

    + +

    ◆ mi_heap_malloc_tp

    @@ -220,19 +210,12 @@ Macros #define mi_heap_malloc_tp ( -   - hp, + hp, -   - tp  - - - - ) - + tp )
    @@ -241,8 +224,8 @@ Macros
    - -

    ◆ mi_heap_mallocn_tp

    + +

    ◆ mi_heap_mallocn_tp

    @@ -250,25 +233,17 @@ Macros #define mi_heap_mallocn_tp ( -   - hp, + hp, -   - tp, + tp, -   - count  - - - - ) - + count )
    @@ -277,8 +252,8 @@ Macros
    - -

    ◆ mi_heap_reallocn_tp

    + +

    ◆ mi_heap_reallocn_tp

    @@ -286,31 +261,22 @@ Macros #define mi_heap_reallocn_tp ( -   - hp, + hp, -   - p, + p, -   - tp, + tp, -   - count  - - - - ) - + count )
    @@ -319,8 +285,8 @@ Macros
    - -

    ◆ mi_heap_recalloc_tp

    + +

    ◆ mi_heap_recalloc_tp

    @@ -328,31 +294,22 @@ Macros #define mi_heap_recalloc_tp ( -   - hp, + hp, -   - p, + p, -   - tp, + tp, -   - count  - - - - ) - + count )
    @@ -361,8 +318,8 @@ Macros
    - -

    ◆ mi_heap_zalloc_tp

    + +

    ◆ mi_heap_zalloc_tp

    @@ -370,19 +327,12 @@ Macros #define mi_heap_zalloc_tp ( -   - hp, + hp, -   - tp  - - - - ) - + tp )
    @@ -391,8 +341,8 @@ Macros
    - -

    ◆ mi_malloc_tp

    + +

    ◆ mi_malloc_tp

    @@ -400,8 +350,7 @@ Macros #define mi_malloc_tp ( -   - tp) + tp) @@ -415,13 +364,13 @@ Macros
    Returns
    A pointer to an object of type tp, or NULL if out of memory.
    -

    Example:

    int* p = mi_malloc_tp(int)
    -
    See also
    mi_malloc()
    +

    Example:

    int* p = mi_malloc_tp(int)
    +
    See also
    mi_malloc()
    - -

    ◆ mi_mallocn_tp

    + +

    ◆ mi_mallocn_tp

    @@ -429,19 +378,12 @@ Macros #define mi_mallocn_tp ( -   - tp, + tp, -   - count  - - - - ) - + count )
    @@ -450,8 +392,8 @@ Macros
    - -

    ◆ mi_reallocn_tp

    + +

    ◆ mi_reallocn_tp

    @@ -459,25 +401,17 @@ Macros #define mi_reallocn_tp ( -   - p, + p, -   - tp, + tp, -   - count  - - - - ) - + count )
    @@ -486,8 +420,8 @@ Macros
    - -

    ◆ mi_zalloc_tp

    + +

    ◆ mi_zalloc_tp

    @@ -495,8 +429,7 @@ Macros #define mi_zalloc_tp ( -   - tp) + tp) @@ -511,7 +444,7 @@ Macros diff --git a/docs/group__zeroinit.html b/docs/group__zeroinit.html index 41af9a27..9082c0cf 100644 --- a/docs/group__zeroinit.html +++ b/docs/group__zeroinit.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Zero initialized re-allocation + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,491 +91,393 @@ $(document).ready(function(){initNavTree('group__zeroinit.html',''); initResizab
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Zero initialized re-allocation
    +
    Zero initialized re-allocation
    - -

    The zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too. -More...

    - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +

    +

    Functions

    void * mi_rezalloc (void *p, size_t newsize)
     
    void * mi_rezalloc_aligned (void *p, size_t newsize, size_t alignment)
     
    void * mi_rezalloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
     
    void * mi_recalloc_aligned (void *p, size_t newcount, size_t size, size_t alignment)
     
    void * mi_recalloc_aligned_at (void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_rezalloc (mi_heap_t *heap, void *p, size_t newsize)
     
    void * mi_heap_recalloc (mi_heap_t *heap, void *p, size_t newcount, size_t size)
     
    void * mi_heap_rezalloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
     
    void * mi_heap_rezalloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
     
    void * mi_heap_recalloc_aligned (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
     
    void * mi_heap_recalloc_aligned_at (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
     
    void * mi_rezalloc (void *p, size_t newsize)
     
    void * mi_rezalloc_aligned (void *p, size_t newsize, size_t alignment)
     
    void * mi_rezalloc_aligned_at (void *p, size_t newsize, size_t alignment, size_t offset)
     
    void * mi_recalloc_aligned (void *p, size_t newcount, size_t size, size_t alignment)
     
    void * mi_recalloc_aligned_at (void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
     
    void * mi_heap_rezalloc (mi_heap_t *heap, void *p, size_t newsize)
     
    void * mi_heap_recalloc (mi_heap_t *heap, void *p, size_t newcount, size_t size)
     
    void * mi_heap_rezalloc_aligned (mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
     
    void * mi_heap_rezalloc_aligned_at (mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
     
    void * mi_heap_recalloc_aligned (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
     
    void * mi_heap_recalloc_aligned_at (mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
     

    Detailed Description

    -

    The zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too.

    -

    e.g. mi_calloc, mi_zalloc, mi_zalloc_aligned etc. see https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992

    +

    The zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too. e.g. mi_calloc, mi_zalloc, mi_zalloc_aligned etc. see https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992

    Function Documentation

    - -

    ◆ mi_heap_recalloc()

    + +

    ◆ mi_heap_recalloc()

    - + - - + - - + - - + - - - - - - - +
    void* mi_heap_recalloc void * mi_heap_recalloc (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newcount, size_t newcount,
    size_t size 
    )size_t size )
    - -

    ◆ mi_heap_recalloc_aligned()

    + +

    ◆ mi_heap_recalloc_aligned()

    - + - - + - - + - - + - - + - - - - - - - +
    void* mi_heap_recalloc_aligned void * mi_heap_recalloc_aligned (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newcount, size_t newcount,
    size_t size, size_t size,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_heap_recalloc_aligned_at()

    + +

    ◆ mi_heap_recalloc_aligned_at()

    - + - - + - - + - - + - - + - - + - - - - - - - +
    void* mi_heap_recalloc_aligned_at void * mi_heap_recalloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newcount, size_t newcount,
    size_t size, size_t size,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    - -

    ◆ mi_heap_rezalloc()

    + +

    ◆ mi_heap_rezalloc()

    - + - - + - - + - - - - - - - +
    void* mi_heap_rezalloc void * mi_heap_rezalloc (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newsize 
    )size_t newsize )
    - -

    ◆ mi_heap_rezalloc_aligned()

    + +

    ◆ mi_heap_rezalloc_aligned()

    - + - - + - - + - - + - - - - - - - +
    void* mi_heap_rezalloc_aligned void * mi_heap_rezalloc_aligned (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newsize, size_t newsize,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_heap_rezalloc_aligned_at()

    + +

    ◆ mi_heap_rezalloc_aligned_at()

    - + - - + - - + - - + - - + - - - - - - - +
    void* mi_heap_rezalloc_aligned_at void * mi_heap_rezalloc_aligned_at (mi_heap_theap, mi_heap_t * heap,
    void * p, void * p,
    size_t newsize, size_t newsize,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    - -

    ◆ mi_recalloc_aligned()

    + +

    ◆ mi_recalloc_aligned()

    - + - - + - - + - - + - - - - - - - +
    void* mi_recalloc_aligned void * mi_recalloc_aligned (void * p, void * p,
    size_t newcount, size_t newcount,
    size_t size, size_t size,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_recalloc_aligned_at()

    + +

    ◆ mi_recalloc_aligned_at()

    - + - - + - - + - - + - - + - - - - - - - +
    void* mi_recalloc_aligned_at void * mi_recalloc_aligned_at (void * p, void * p,
    size_t newcount, size_t newcount,
    size_t size, size_t size,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    - -

    ◆ mi_rezalloc()

    + +

    ◆ mi_rezalloc()

    - + - - + - - - - - - - +
    void* mi_rezalloc void * mi_rezalloc (void * p, void * p,
    size_t newsize 
    )size_t newsize )
    - -

    ◆ mi_rezalloc_aligned()

    + +

    ◆ mi_rezalloc_aligned()

    - + - - + - - + - - - - - - - +
    void* mi_rezalloc_aligned void * mi_rezalloc_aligned (void * p, void * p,
    size_t newsize, size_t newsize,
    size_t alignment 
    )size_t alignment )
    - -

    ◆ mi_rezalloc_aligned_at()

    + +

    ◆ mi_rezalloc_aligned_at()

    - + - - + - - + - - + - - - - - - - +
    void* mi_rezalloc_aligned_at void * mi_rezalloc_aligned_at (void * p, void * p,
    size_t newsize, size_t newsize,
    size_t alignment, size_t alignment,
    size_t offset 
    )size_t offset )
    @@ -584,7 +489,7 @@ Functions diff --git a/docs/group__zeroinit.js b/docs/group__zeroinit.js index b9297d21..505df602 100644 --- a/docs/group__zeroinit.js +++ b/docs/group__zeroinit.js @@ -1,14 +1,14 @@ var group__zeroinit = [ - [ "mi_heap_recalloc", "group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd", null ], - [ "mi_heap_recalloc_aligned", "group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3", null ], - [ "mi_heap_recalloc_aligned_at", "group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7", null ], - [ "mi_heap_rezalloc", "group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76", null ], - [ "mi_heap_rezalloc_aligned", "group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664", null ], - [ "mi_heap_rezalloc_aligned_at", "group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb", null ], - [ "mi_recalloc_aligned", "group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f", null ], - [ "mi_recalloc_aligned_at", "group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9", null ], - [ "mi_rezalloc", "group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6", null ], - [ "mi_rezalloc_aligned", "group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0", null ], - [ "mi_rezalloc_aligned_at", "group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1", null ] + [ "mi_heap_recalloc", "group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde", null ], + [ "mi_heap_recalloc_aligned", "group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32", null ], + [ "mi_heap_recalloc_aligned_at", "group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496", null ], + [ "mi_heap_rezalloc", "group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d", null ], + [ "mi_heap_rezalloc_aligned", "group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7", null ], + [ "mi_heap_rezalloc_aligned_at", "group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9", null ], + [ "mi_recalloc_aligned", "group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e", null ], + [ "mi_recalloc_aligned_at", "group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750", null ], + [ "mi_rezalloc", "group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756", null ], + [ "mi_rezalloc_aligned", "group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa", null ], + [ "mi_rezalloc_aligned_at", "group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270", null ] ]; \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 6cc439df..62d8b79c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,24 +1,26 @@ - + - - + + -mi-malloc: Main Page +mi-malloc: mi-malloc + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,28 +91,33 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    -
    mi-malloc Documentation
    +
    +
    mi-malloc

    This is the API documentation of the mimalloc allocator (pronounced "me-malloc") – a general purpose allocator with excellent performance characteristics. Initially developed by Daan Leijen for the run-time systems of the Koka and Lean languages.

    It is a drop-in replacement for malloc and can be used in other programs without code changes, for example, on Unix you can use it as:

    > LD_PRELOAD=/usr/bin/libmimalloc.so myprogram
    -

    Notable aspects of the design include:

    -
      -
    • small and consistent: the library is about 8k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic heartbeat and deferred freeing (for bounded worst-case times with reference counting).
    • +

    Notable aspects of the design include:

      +
    • small and consistent: the library is about 8k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic heartbeat and deferred freeing (for bounded worst-case times with reference counting). Partly due to its simplicity, mimalloc has been ported to many systems (Windows, macOS, Linux, WASM, various BSD's, Haiku, MUSL, etc) and has excellent support for dynamic overriding. At the same time, it is an industrial strength allocator that runs (very) large scale distributed services on thousands of machines with excellent worst case latencies.
    • free list sharding: instead of one big free list (per size class) we have many smaller lists per "mimalloc page" which reduces fragmentation and increases locality – things that are allocated close in time get allocated close in memory. (A mimalloc page contains blocks of one size class and is usually 64KiB on a 64-bit system).
    • free list multi-sharding: the big idea! Not only do we shard the free list per mimalloc page, but for each page we have multiple free lists. In particular, there is one list for thread-local free operations, and another one for concurrent free operations. Free-ing from another thread can now be a single CAS without needing sophisticated coordination between threads. Since there will be thousands of separate free lists, contention is naturally distributed over the heap, and the chance of contending on a single location will be low – this is quite similar to randomized algorithms like skip lists where adding a random oracle removes the need for a more complex algorithm.
    • -
    • eager page reset: when a "page" becomes empty (with increased chance due to free list sharding) the memory is marked to the OS as unused ("reset" or "purged") reducing (real) memory pressure and fragmentation, especially in long running programs.
    • -
    • secure: mimalloc can be build in secure mode, adding guard pages, randomized allocation, encrypted free lists, etc. to protect against various heap vulnerabilities. The performance penalty is only around 5% on average over our benchmarks.
    • +
    • eager page purging: when a "page" becomes empty (with increased chance due to free list sharding) the memory is marked to the OS as unused (reset or decommitted) reducing (real) memory pressure and fragmentation, especially in long running programs.
    • +
    • secure: mimalloc can be built in secure mode, adding guard pages, randomized allocation, encrypted free lists, etc. to protect against various heap vulnerabilities. The performance penalty is usually around 10% on average over our benchmarks.
    • first-class heaps: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately.
    • -
    • bounded: it does not suffer from blowup [1], has bounded worst-case allocation times (wcat), bounded space overhead (~0.2% meta-data, with at most 12.5% waste in allocation sizes), and has no internal points of contention using only atomic operations.
    • -
    • fast: In our benchmarks (see below), mimalloc outperforms all other leading allocators (jemalloc, tcmalloc, Hoard, etc), and usually uses less memory (up to 25% more in the worst case). A nice property is that it does consistently well over a wide range of benchmarks.
    • +
    • bounded: it does not suffer from blowup [1], has bounded worst-case allocation times (wcat) (upto OS primitives), bounded space overhead (~0.2% meta-data, with low internal fragmentation), and has no internal points of contention using only atomic operations.
    • +
    • fast: In our benchmarks (see below), mimalloc outperforms other leading allocators (jemalloc, tcmalloc, Hoard, etc), and often uses less memory. A nice property is that it does consistently well over a wide range of benchmarks. There is also good huge OS page support for larger server programs.

    You can read more on the design of mimalloc in the technical report which also has detailed benchmark results.

    Further information:

    @@ -130,12 +138,13 @@ $(document).ready(function(){initNavTree('index.html',''); initResizable(); });
  • C++ wrappers
  • +
    diff --git a/docs/jquery.js b/docs/jquery.js index 103c32d7..1dffb65b 100644 --- a/docs/jquery.js +++ b/docs/jquery.js @@ -1,12 +1,11 @@ -/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0a;a++)for(i in o[a])n=o[a][i],o[a].hasOwnProperty(i)&&void 0!==n&&(e[i]=t.isPlainObject(n)?t.isPlainObject(e[i])?t.widget.extend({},e[i],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,i){var n=i.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=s.call(arguments,1),h=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(h=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):h=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new i(o,this))})),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
    ",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
    "),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,(i>0||u>a(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}}),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var n=!1;t(document).on("mouseup",function(){n=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!n){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),n=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,n=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
    "),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element -},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),m&&(p-=l),g&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable});/** +!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(y){"use strict";y.ui=y.ui||{};y.ui.version="1.13.2";var n,i=0,h=Array.prototype.hasOwnProperty,a=Array.prototype.slice;y.cleanData=(n=y.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=y._data(i,"events"))&&e.remove&&y(i).triggerHandler("remove");n(t)}),y.widget=function(t,i,e){var s,n,o,h={},a=t.split(".")[0],r=a+"-"+(t=t.split(".")[1]);return e||(e=i,i=y.Widget),Array.isArray(e)&&(e=y.extend.apply(null,[{}].concat(e))),y.expr.pseudos[r.toLowerCase()]=function(t){return!!y.data(t,r)},y[a]=y[a]||{},s=y[a][t],n=y[a][t]=function(t,e){if(!this||!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},y.extend(n,s,{version:e.version,_proto:y.extend({},e),_childConstructors:[]}),(o=new i).options=y.widget.extend({},o.options),y.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)}function o(t){return i.prototype[e].apply(this,t)}h[e]="function"==typeof s?function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:s}),n.prototype=y.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},h,{constructor:n,namespace:a,widgetName:t,widgetFullName:r}),s?(y.each(s._childConstructors,function(t,e){var i=e.prototype;y.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),y.widget.bridge(t,n),n},y.widget.extend=function(t){for(var e,i,s=a.call(arguments,1),n=0,o=s.length;n",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=y(e||this.defaultElement||this)[0],this.element=y(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=y(),this.hoverable=y(),this.focusable=y(),this.classesElementLookup={},e!==this&&(y.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=y(e.style?e.ownerDocument:e.document||e),this.window=y(this.document[0].defaultView||this.document[0].parentWindow)),this.options=y.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:y.noop,_create:y.noop,_init:y.noop,destroy:function(){var i=this;this._destroy(),y.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:y.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return y.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=y.widget.extend({},this.options[t]),n=0;n
    "),i=e.children()[0];return y("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(D(s),D(n))?o.important="horizontal":o.important="vertical",p.using.call(this,t,o)}),h.offset(y.extend(l,{using:t}))})},y.ui.position={fit:{left:function(t,e){var i=e.within,s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,h=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),y.ui.plugin={add:function(t,e,i){var s,n=y.ui[t].prototype;for(s in i)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;n
    ").css({overflow:"hidden",position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&y(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy(),this._addedHandles.remove();function t(t){y(t).removeData("resizable").removeData("ui-resizable").off(".resizable")}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;case"aspectRatio":this._aspectRatio=!!e}},_setupHandles:function(){var t,e,i,s,n,o=this.options,h=this;if(this.handles=o.handles||(y(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=y(),this._addedHandles=y(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split(","),this.handles={},e=0;e"),this._addClass(n,"ui-resizable-handle "+s),n.css({zIndex:o.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.children(this.handles[t]).length||(this.element.append(n),this._addedHandles=this._addedHandles.add(n));this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=y(this.handles[e]),this._on(this.handles[e],{mousedown:h._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=y(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add(this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){h.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),h.axis=n&&n[1]?n[1]:"se")}),o.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._addedHandles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=y(this.handles[e])[0])!==t.target&&!y.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,n=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=y(s.containment).scrollLeft()||0,i+=y(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:n.width(),height:n.height()},this.originalSize=this._helper?{width:n.outerWidth(),height:n.outerHeight()}:{width:n.width(),height:n.height()},this.sizeDiff={width:n.outerWidth()-n.width(),height:n.outerHeight()-n.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=y(".ui-resizable-"+this.axis).css("cursor"),y("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),y.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,n=this.options,o=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:o.sizeDiff.height,i=e?0:o.sizeDiff.width,e={width:o.helper.width()-i,height:o.helper.height()-s},i=parseFloat(o.element.css("left"))+(o.position.left-o.originalPosition.left)||null,s=parseFloat(o.element.css("top"))+(o.position.top-o.originalPosition.top)||null,n.animate||this.element.css(y.extend(e,{top:s,left:i})),o.helper.height(o.size.height),o.helper.width(o.size.width),this._helper&&!n.animate&&this._proportionallyResize()),y("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,n={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=n.minHeight*this.aspectRatio,i=n.minWidth/this.aspectRatio,s=n.maxHeight*this.aspectRatio,t=n.maxWidth/this.aspectRatio,e>n.minWidth&&(n.minWidth=e),i>n.minHeight&&(n.minHeight=i),st.width,h=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,a=this.originalPosition.left+this.originalSize.width,r=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),h&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=a-e.minWidth),s&&l&&(t.left=a-e.maxWidth),h&&i&&(t.top=r-e.minHeight),n&&i&&(t.top=r-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e
    ").css({overflow:"hidden"}),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return y.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e,i){return y.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){y.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),y.ui.plugin.add("resizable","animate",{stop:function(e){var i=y(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,n=s.length&&/textarea/i.test(s[0].nodeName),o=n&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,h=n?0:i.sizeDiff.width,n={width:i.size.width-h,height:i.size.height-o},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,o=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(y.extend(n,o&&h?{top:o,left:h}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&y(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),y.ui.plugin.add("resizable","containment",{start:function(){var i,s,n=y(this).resizable("instance"),t=n.options,e=n.element,o=t.containment,h=o instanceof y?o.get(0):/parent/.test(o)?e.parent().get(0):o;h&&(n.containerElement=y(h),/document/.test(o)||o===document?(n.containerOffset={left:0,top:0},n.containerPosition={left:0,top:0},n.parentData={element:y(document),left:0,top:0,width:y(document).width(),height:y(document).height()||document.body.parentNode.scrollHeight}):(i=y(h),s=[],y(["Top","Right","Left","Bottom"]).each(function(t,e){s[t]=n._num(i.css("padding"+e))}),n.containerOffset=i.offset(),n.containerPosition=i.position(),n.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=n.containerOffset,e=n.containerSize.height,o=n.containerSize.width,o=n._hasScroll(h,"left")?h.scrollWidth:o,e=n._hasScroll(h)?h.scrollHeight:e,n.parentData={element:h,left:t.left,top:t.top,width:o,height:e}))},resize:function(t){var e=y(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.position,o=e._aspectRatio||t.shiftKey,h={top:0,left:0},a=e.containerElement,t=!0;a[0]!==document&&/static/.test(a.css("position"))&&(h=s),n.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-h.left),o&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),n.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),o&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0),i=e.containerElement.get(0)===e.element.parent().get(0),n=/relative|absolute/.test(e.containerElement.css("position")),i&&n?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),n=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-h.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-h.top:e.offset.top-s.top)),n+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-n,o&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,o&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=y(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,n=t.containerElement,o=y(t.helper),h=o.offset(),a=o.outerWidth()-t.sizeDiff.width,o=o.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o}),t._helper&&!e.animate&&/static/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o})}}),y.ui.plugin.add("resizable","alsoResize",{start:function(){var t=y(this).resizable("instance").options;y(t.alsoResize).each(function(){var t=y(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=y(this).resizable("instance"),s=e.options,n=e.originalSize,o=e.originalPosition,h={height:e.size.height-n.height||0,width:e.size.width-n.width||0,top:e.position.top-o.top||0,left:e.position.left-o.left||0};y(s.alsoResize).each(function(){var t=y(this),s=y(this).data("ui-resizable-alsoresize"),n={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];y.each(e,function(t,e){var i=(s[e]||0)+(h[e]||0);i&&0<=i&&(n[e]=i||null)}),t.css(n)})},stop:function(){y(this).removeData("ui-resizable-alsoresize")}}),y.ui.plugin.add("resizable","ghost",{start:function(){var t=y(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==y.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=y(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=y(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),y.ui.plugin.add("resizable","grid",{resize:function(){var t,e=y(this).resizable("instance"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,h=e.axis,a="number"==typeof i.grid?[i.grid,i.grid]:i.grid,r=a[0]||1,l=a[1]||1,u=Math.round((s.width-n.width)/r)*r,p=Math.round((s.height-n.height)/l)*l,d=n.width+u,c=n.height+p,f=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>c;i.grid=a,m&&(d+=r),s&&(c+=l),f&&(d-=r),g&&(c-=l),/^(se|s|e)$/.test(h)?(e.size.width=d,e.size.height=c):/^(ne)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.top=o.top-p):/^(sw)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.left=o.left-u):((c-l<=0||d-r<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0 - + - - + + mi-malloc: mimalloc-doc.h Source File + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html'); -
    @@ -88,473 +91,575 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html',''); init
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    mimalloc-doc.h
    +
    mimalloc-doc.h
    -
    1 /* ----------------------------------------------------------------------------
    -
    2 Copyright (c) 2018-2021, 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 
    -
    94 
    -
    95 
    -
    99 void mi_free(void* p);
    -
    100 
    -
    105 void* mi_malloc(size_t size);
    -
    106 
    -
    111 void* mi_zalloc(size_t size);
    -
    112 
    -
    122 void* mi_calloc(size_t count, size_t size);
    -
    123 
    -
    136 void* mi_realloc(void* p, size_t newsize);
    -
    137 
    -
    148 void* mi_recalloc(void* p, size_t count, size_t size);
    -
    149 
    -
    163 void* mi_expand(void* p, size_t newsize);
    -
    164 
    -
    174 void* mi_mallocn(size_t count, size_t size);
    -
    175 
    -
    185 void* mi_reallocn(void* p, size_t count, size_t size);
    -
    186 
    -
    203 void* mi_reallocf(void* p, size_t newsize);
    -
    204 
    -
    205 
    -
    214 char* mi_strdup(const char* s);
    -
    215 
    -
    225 char* mi_strndup(const char* s, size_t n);
    -
    226 
    -
    239 char* mi_realpath(const char* fname, char* resolved_name);
    -
    240 
    -
    242 
    -
    243 // ------------------------------------------------------
    -
    244 // Extended functionality
    -
    245 // ------------------------------------------------------
    -
    246 
    -
    250 
    -
    253 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
    -
    254 
    -
    262 void* mi_malloc_small(size_t size);
    -
    263 
    -
    271 void* mi_zalloc_small(size_t size);
    -
    272 
    -
    287 size_t mi_usable_size(void* p);
    -
    288 
    -
    298 size_t mi_good_size(size_t size);
    -
    299 
    -
    307 void mi_collect(bool force);
    -
    308 
    -
    313 void mi_stats_print(void* out);
    -
    314 
    -
    320 void mi_stats_print_out(mi_output_fun* out, void* arg);
    -
    321 
    -
    323 void mi_stats_reset(void);
    -
    324 
    -
    326 void mi_stats_merge(void);
    -
    327 
    -
    331 void mi_thread_init(void);
    -
    332 
    -
    337 void mi_thread_done(void);
    -
    338 
    - -
    345 
    -
    352 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    -
    353 
    -
    369 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    -
    370 
    -
    376 typedef void (mi_output_fun)(const char* msg, void* arg);
    -
    377 
    -
    384 void mi_register_output(mi_output_fun* out, void* arg);
    -
    385 
    -
    391 typedef void (mi_error_fun)(int err, void* arg);
    -
    392 
    -
    408 void mi_register_error(mi_error_fun* errfun, void* arg);
    -
    409 
    -
    414 bool mi_is_in_heap_region(const void* p);
    -
    415 
    -
    424 int mi_reserve_os_memory(size_t size, bool commit, bool allow_large);
    -
    425 
    -
    437 bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node);
    -
    438 
    -
    451 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    -
    452 
    -
    465 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    -
    466 
    -
    467 
    - -
    473 
    -
    487 void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults);
    -
    488 
    -
    490 
    -
    491 // ------------------------------------------------------
    -
    492 // Aligned allocation
    -
    493 // ------------------------------------------------------
    -
    494 
    -
    500 
    -
    502 #define MI_ALIGNMENT_MAX (1024*1024UL)
    -
    503 
    -
    516 void* mi_malloc_aligned(size_t size, size_t alignment);
    -
    517 void* mi_zalloc_aligned(size_t size, size_t alignment);
    -
    518 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    -
    519 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    520 
    -
    531 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    532 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    533 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    -
    534 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    535 
    -
    537 
    -
    543 
    -
    548 struct mi_heap_s;
    -
    549 
    -
    554 typedef struct mi_heap_s mi_heap_t;
    -
    555 
    - -
    558 
    - -
    567 
    - -
    576 
    - -
    581 
    - -
    585 
    - -
    592 
    -
    594 void mi_heap_collect(mi_heap_t* heap, bool force);
    -
    595 
    -
    598 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    -
    599 
    -
    603 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    -
    604 
    -
    607 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    -
    608 
    -
    611 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    -
    612 
    -
    615 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    -
    616 
    -
    619 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    -
    620 
    -
    623 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    -
    624 
    -
    627 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    -
    628 
    -
    629 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    630 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    -
    631 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    -
    632 
    -
    633 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    634 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    635 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    636 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    637 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    -
    638 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    -
    639 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    640 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    -
    641 
    -
    643 
    -
    644 
    -
    653 
    -
    654 void* mi_rezalloc(void* p, size_t newsize);
    -
    655 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    -
    656 
    -
    657 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    658 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    659 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    -
    660 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    661 
    -
    662 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    663 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    -
    664 
    -
    665 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    666 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    -
    667 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    -
    668 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    669 
    -
    671 
    -
    680 
    -
    692 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    -
    693 
    -
    695 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    -
    696 
    -
    698 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    -
    699 
    -
    701 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    -
    702 
    -
    704 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    -
    705 
    -
    707 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    -
    708 
    -
    710 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    -
    711 
    -
    713 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    -
    714 
    -
    716 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    -
    717 
    -
    719 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    -
    720 
    -
    722 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    -
    723 
    -
    725 
    -
    731 
    -
    738 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    -
    739 
    -
    748 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    -
    749 
    -
    757 bool mi_check_owned(const void* p);
    -
    758 
    -
    761 typedef struct mi_heap_area_s {
    -
    762  void* blocks;
    -
    763  size_t reserved;
    -
    764  size_t committed;
    -
    765  size_t used;
    -
    766  size_t block_size;
    - -
    768 
    -
    776 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);
    -
    777 
    -
    789 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    -
    790 
    -
    792 
    -
    798 
    -
    800 typedef enum mi_option_e {
    -
    801  // stable options
    - - - -
    805  // the following options are experimental
    - - - - - - - - - - - - - - - -
    821 
    -
    822 
    - - - -
    826 void mi_option_set_enabled(mi_option_t option, bool enable);
    -
    827 void mi_option_set_enabled_default(mi_option_t option, bool enable);
    -
    828 
    - -
    830 void mi_option_set(mi_option_t option, long value);
    -
    831 void mi_option_set_default(mi_option_t option, long value);
    -
    832 
    -
    833 
    -
    835 
    -
    842 
    -
    843 void* mi_recalloc(void* p, size_t count, size_t size);
    -
    844 size_t mi_malloc_size(const void* p);
    -
    845 size_t mi_malloc_usable_size(const void *p);
    -
    846 
    -
    848 void mi_cfree(void* p);
    -
    849 
    -
    850 int mi_posix_memalign(void** p, size_t alignment, size_t size);
    -
    851 int mi__posix_memalign(void** p, size_t alignment, size_t size);
    -
    852 void* mi_memalign(size_t alignment, size_t size);
    -
    853 void* mi_valloc(size_t size);
    -
    854 
    -
    855 void* mi_pvalloc(size_t size);
    -
    856 void* mi_aligned_alloc(size_t alignment, size_t size);
    -
    857 
    -
    860 void* mi_reallocarray(void* p, size_t count, size_t size);
    -
    861 
    -
    863 int mi_reallocarr(void* p, size_t count, size_t size);
    -
    864 
    -
    865 void mi_free_size(void* p, size_t size);
    -
    866 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    -
    867 void mi_free_aligned(void* p, size_t alignment);
    -
    868 
    -
    870 
    -
    883 
    -
    885 void* mi_new(std::size_t n) noexcept(false);
    -
    886 
    -
    888 void* mi_new_n(size_t count, size_t size) noexcept(false);
    -
    889 
    -
    891 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    -
    892 
    -
    894 void* mi_new_nothrow(size_t n);
    -
    895 
    -
    897 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    -
    898 
    -
    900 void* mi_new_realloc(void* p, size_t newsize);
    -
    901 
    -
    903 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    -
    904 
    -
    912 template<class T> struct mi_stl_allocator { }
    -
    913 
    -
    915 
    -
    void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
    -
    void * mi_zalloc_aligned(size_t size, size_t alignment)
    -
    void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
    -
    void * mi_calloc_aligned(size_t count, size_t size, size_t alignment)
    -
    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_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
    -
    void * mi_malloc_aligned(size_t size, size_t alignment)
    Allocate size bytes aligned by alignment.
    -
    void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    -
    size_t block_size
    size in bytes of one block
    Definition: mimalloc-doc.h:766
    -
    size_t committed
    current committed bytes of this area
    Definition: mimalloc-doc.h:764
    -
    size_t used
    bytes in use by allocated blocks
    Definition: mimalloc-doc.h:765
    -
    void * blocks
    start of the area containing heap blocks
    Definition: mimalloc-doc.h:762
    -
    size_t reserved
    bytes reserved for this area
    Definition: mimalloc-doc.h:763
    +
    1/* ----------------------------------------------------------------------------
    +
    2Copyright (c) 2018-2021, Microsoft Research, Daan Leijen
    +
    3This is free software; you can redistribute it and/or modify it under the
    +
    4terms 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
    +
    97
    +
    98
    +
    102void mi_free(void* p);
    +
    103
    +
    108void* mi_malloc(size_t size);
    +
    109
    +
    114void* mi_zalloc(size_t size);
    +
    115
    +
    125void* mi_calloc(size_t count, size_t size);
    +
    126
    +
    139void* mi_realloc(void* p, size_t newsize);
    +
    140
    +
    151void* mi_recalloc(void* p, size_t count, size_t size);
    +
    152
    +
    166void* mi_expand(void* p, size_t newsize);
    +
    167
    +
    177void* mi_mallocn(size_t count, size_t size);
    +
    178
    +
    188void* mi_reallocn(void* p, size_t count, size_t size);
    +
    189
    +
    206void* mi_reallocf(void* p, size_t newsize);
    +
    207
    +
    208
    +
    217char* mi_strdup(const char* s);
    +
    218
    +
    228char* mi_strndup(const char* s, size_t n);
    +
    229
    +
    242char* mi_realpath(const char* fname, char* resolved_name);
    +
    243
    +
    245
    +
    246// ------------------------------------------------------
    +
    247// Extended functionality
    +
    248// ------------------------------------------------------
    +
    249
    +
    253
    +
    256#define MI_SMALL_SIZE_MAX (128*sizeof(void*))
    +
    257
    +
    265void* mi_malloc_small(size_t size);
    +
    266
    +
    274void* mi_zalloc_small(size_t size);
    +
    275
    +
    290size_t mi_usable_size(void* p);
    +
    291
    +
    301size_t mi_good_size(size_t size);
    +
    302
    +
    310void mi_collect(bool force);
    +
    311
    +
    316void mi_stats_print(void* out);
    +
    317
    +
    323void mi_stats_print_out(mi_output_fun* out, void* arg);
    +
    324
    +
    326void mi_stats_reset(void);
    +
    327
    +
    329void mi_stats_merge(void);
    +
    330
    +
    334void mi_thread_init(void);
    +
    335
    +
    340void mi_thread_done(void);
    +
    341
    + +
    348
    +
    355typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    +
    356
    +
    372void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    +
    373
    +
    379typedef void (mi_output_fun)(const char* msg, void* arg);
    +
    380
    +
    387void mi_register_output(mi_output_fun* out, void* arg);
    +
    388
    +
    394typedef void (mi_error_fun)(int err, void* arg);
    +
    395
    +
    411void mi_register_error(mi_error_fun* errfun, void* arg);
    +
    412
    +
    417bool mi_is_in_heap_region(const void* p);
    +
    418
    +
    427int mi_reserve_os_memory(size_t size, bool commit, bool allow_large);
    +
    428
    +
    440bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node);
    +
    441
    +
    454int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    +
    455
    +
    468int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    +
    469
    +
    470
    + +
    476
    +
    490void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults);
    +
    491
    +
    496void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge);
    +
    497
    +
    500typedef int mi_arena_id_t;
    +
    501
    +
    506void* mi_arena_area(mi_arena_id_t arena_id, size_t* size);
    +
    507
    +
    515int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id);
    +
    516
    +
    524int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id);
    +
    525
    +
    536bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id);
    +
    537
    + +
    542
    +
    546typedef void* mi_subproc_id_t;
    +
    547
    + +
    550
    + +
    554
    + +
    559
    + +
    563
    +
    564
    +
    566
    +
    567// ------------------------------------------------------
    +
    568// Aligned allocation
    +
    569// ------------------------------------------------------
    +
    570
    +
    576
    +
    578#define MI_BLOCK_ALIGNMENT_MAX (1024*1024UL)
    +
    579
    +
    592void* mi_malloc_aligned(size_t size, size_t alignment);
    +
    593void* mi_zalloc_aligned(size_t size, size_t alignment);
    +
    594void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    +
    595void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    596
    +
    607void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    608void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    609void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    +
    610void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    611
    +
    613
    +
    619
    +
    624struct mi_heap_s;
    +
    625
    +
    630typedef struct mi_heap_s mi_heap_t;
    +
    631
    + +
    634
    + +
    643
    + +
    652
    + +
    657
    + +
    661
    + +
    668
    +
    670void mi_heap_collect(mi_heap_t* heap, bool force);
    +
    671
    +
    674void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    +
    675
    +
    679void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    +
    680
    +
    683void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    +
    684
    +
    687void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    +
    688
    +
    691void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    +
    692
    +
    695char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    +
    696
    +
    699char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    +
    700
    +
    703char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    +
    704
    +
    705void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    706void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    +
    707void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    +
    708
    +
    709void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    710void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    711void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    712void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    713void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    +
    714void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    +
    715void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    716void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    717
    +
    719
    +
    720
    +
    729
    +
    730void* mi_rezalloc(void* p, size_t newsize);
    +
    731void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    +
    732
    +
    733void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    734void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    735void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    +
    736void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    737
    +
    738void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    739void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    +
    740
    +
    741void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    742void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    743void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    +
    744void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    745
    +
    747
    +
    756
    +
    768#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    +
    769
    +
    771#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    +
    772
    +
    774#define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    +
    775
    +
    777#define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    +
    778
    +
    780#define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    +
    781
    +
    783#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    +
    784
    +
    786#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    +
    787
    +
    789#define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    +
    790
    +
    792#define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    +
    793
    +
    795#define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    +
    796
    +
    798#define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    +
    799
    +
    801
    +
    807
    +
    814bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    +
    815
    +
    824bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    +
    825
    +
    833bool mi_check_owned(const void* p);
    +
    834
    +
    +
    837typedef struct mi_heap_area_s {
    +
    838 void* blocks;
    +
    839 size_t reserved;
    +
    840 size_t committed;
    +
    841 size_t used;
    +
    842 size_t block_size;
    + + +
    +
    845
    +
    853typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    +
    854
    +
    866bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    867
    +
    871bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    872
    +
    874
    +
    880
    + +
    919
    +
    920
    + + + +
    924void mi_option_set_enabled(mi_option_t option, bool enable);
    + +
    926
    + +
    928long mi_option_get_clamp(mi_option_t option, long min, long max);
    + +
    930
    +
    931void mi_option_set(mi_option_t option, long value);
    +
    932void mi_option_set_default(mi_option_t option, long value);
    +
    933
    +
    934
    +
    936
    +
    943
    +
    945void mi_cfree(void* p);
    +
    946void* mi__expand(void* p, size_t newsize);
    +
    947
    +
    948void* mi_recalloc(void* p, size_t count, size_t size);
    +
    949size_t mi_malloc_size(const void* p);
    +
    950size_t mi_malloc_good_size(size_t size);
    +
    951size_t mi_malloc_usable_size(const void *p);
    +
    952
    +
    953int mi_posix_memalign(void** p, size_t alignment, size_t size);
    +
    954int mi__posix_memalign(void** p, size_t alignment, size_t size);
    +
    955void* mi_memalign(size_t alignment, size_t size);
    +
    956void* mi_valloc(size_t size);
    +
    957void* mi_pvalloc(size_t size);
    +
    958void* mi_aligned_alloc(size_t alignment, size_t size);
    +
    959
    +
    960unsigned short* mi_wcsdup(const unsigned short* s);
    +
    961unsigned char* mi_mbsdup(const unsigned char* s);
    +
    962int mi_dupenv_s(char** buf, size_t* size, const char* name);
    +
    963int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name);
    +
    964
    +
    967void* mi_reallocarray(void* p, size_t count, size_t size);
    +
    968
    +
    970int mi_reallocarr(void* p, size_t count, size_t size);
    +
    971
    +
    972void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment);
    +
    973void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    974
    +
    975void mi_free_size(void* p, size_t size);
    +
    976void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    +
    977void mi_free_aligned(void* p, size_t alignment);
    +
    978
    +
    980
    +
    993
    +
    995void* mi_new(std::size_t n) noexcept(false);
    +
    996
    +
    998void* mi_new_n(size_t count, size_t size) noexcept(false);
    +
    999
    +
    1001void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    +
    1002
    +
    1004void* mi_new_nothrow(size_t n);
    +
    1005
    +
    1007void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    +
    1008
    +
    1010void* mi_new_realloc(void* p, size_t newsize);
    +
    1011
    +
    1013void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    +
    1014
    +
    1022template<class T> struct mi_stl_allocator { }
    +
    1023
    +
    1025
    +
    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_calloc_aligned(size_t count, size_t size, size_t alignment)
    +
    void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
    +
    void * mi_malloc_aligned(size_t size, size_t alignment)
    Allocate size bytes aligned by alignment.
    +
    void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
    +
    void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
    +
    void * mi_zalloc_aligned(size_t size, size_t alignment)
    +
    void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    +
    size_t block_size
    size in bytes of one block
    Definition mimalloc-doc.h:842
    +
    size_t committed
    current committed bytes of this area
    Definition mimalloc-doc.h:840
    +
    size_t full_block_size
    size in bytes of a full block including padding and metadata.
    Definition mimalloc-doc.h:843
    +
    size_t used
    bytes in use by allocated blocks
    Definition mimalloc-doc.h:841
    +
    void * blocks
    start of the area containing heap blocks
    Definition mimalloc-doc.h:838
    +
    size_t reserved
    bytes reserved for this area
    Definition mimalloc-doc.h:839
    bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
    Check safely if any pointer is part of a heap.
    bool mi_check_owned(const void *p)
    Check safely if any pointer is part of the default heap of this thread.
    +
    bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun *visitor, void *arg)
    Visit all areas and blocks in abandoned heaps.
    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.
    +
    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:853
    bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
    Does a heap contain a pointer to a previously allocated block?
    -
    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:776
    -
    An area of heap space contains blocks of a single size.
    Definition: mimalloc-doc.h:761
    -
    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_new_realloc(void *p, size_t newsize)
    like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    -
    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...
    -
    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_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_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_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...
    -
    std::allocator implementation for mimalloc for use in STL containers.
    Definition: mimalloc-doc.h:912
    +
    An area of heap space contains blocks of a single size.
    Definition mimalloc-doc.h:837
    +
    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_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...
    +
    void * mi_new_realloc(void *p, size_t newsize)
    like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    +
    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_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_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_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...
    +
    std::allocator implementation for mimalloc for use in STL containers.
    Definition mimalloc-doc.h:1022
    int mi_reserve_os_memory(size_t size, bool commit, bool allow_large)
    Reserve OS memory for use by mimalloc.
    size_t mi_usable_size(void *p)
    Return the available bytes in a memory block.
    void mi_thread_done(void)
    Uninitialize mimalloc on a thread.
    -
    void * mi_zalloc_small(size_t size)
    Allocate a zero initialized small object.
    -
    void() mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition: mimalloc-doc.h:391
    -
    void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition: mimalloc-doc.h:352
    +
    void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition mimalloc-doc.h:355
    void mi_stats_print(void *out)
    Deprecated.
    +
    mi_subproc_id_t mi_subproc_main(void)
    Get the main sub-process identifier.
    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...
    +
    int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t *arena_id)
    Reserve OS memory to be managed in an arena.
    void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
    Register a deferred free function.
    void mi_stats_reset(void)
    Reset statistics.
    +
    bool mi_manage_os_memory_ex(void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t *arena_id)
    Manage externally allocated memory as a mimalloc arena.
    void mi_collect(bool force)
    Eagerly free memory.
    bool mi_manage_os_memory(void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node)
    Manage a particular memory area for use by mimalloc.
    +
    void * mi_zalloc_small(size_t size)
    Allocate a zero initialized small object.
    void mi_stats_print_out(mi_output_fun *out, void *arg)
    Print the main statistics.
    +
    int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t *arena_id)
    Reserve huge OS pages (1GiB) into a single arena.
    bool mi_is_in_heap_region(const void *p)
    Is a pointer part of our heap?
    -
    void * mi_malloc_small(size_t size)
    Allocate a small object.
    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_process_info(size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)
    Return process information (time and memory usage).
    +
    void * mi_malloc_small(size_t size)
    Allocate a small object.
    +
    mi_subproc_id_t mi_subproc_new(void)
    Create a fresh sub-process (with no associated threads yet).
    +
    void mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition mimalloc-doc.h:394
    void mi_stats_merge(void)
    Merge thread local statistics with the main statistics and reset.
    +
    void * mi_subproc_id_t
    A process can associate threads with sub-processes.
    Definition mimalloc-doc.h:546
    +
    int mi_arena_id_t
    Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.
    Definition mimalloc-doc.h:500
    +
    void * mi_arena_area(mi_arena_id_t arena_id, size_t *size)
    Return the size of an arena.
    void mi_register_error(mi_error_fun *errfun, void *arg)
    Register an error callback function.
    +
    void mi_subproc_delete(mi_subproc_id_t subproc)
    Delete a previously created sub-process.
    bool mi_is_redirected()
    Is the C runtime malloc API redirected?
    +
    mi_heap_t * mi_heap_new_in_arena(mi_arena_id_t arena_id)
    Create a new heap that only allocates in the specified arena.
    void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
    Print out heap statistics for this thread.
    size_t mi_good_size(size_t size)
    Return the used allocation size.
    -
    void() mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition: mimalloc-doc.h:376
    +
    void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge)
    Show all current arena's.
    +
    void mi_subproc_add_current_thread(mi_subproc_id_t subproc)
    Add the current thread to the given sub-process.
    +
    void mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition mimalloc-doc.h:379
    void mi_register_output(mi_output_fun *out, void *arg)
    Register an output function.
    void mi_thread_init(void)
    Initialize mimalloc on a thread.
    -
    char * mi_heap_realpath(mi_heap_t *heap, const char *fname, char *resolved_name)
    Resolve a file path name using a specific heap to allocate the result.
    -
    void * mi_heap_calloc_aligned_at(mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
    -
    char * mi_heap_strdup(mi_heap_t *heap, const char *s)
    Duplicate a string in a specific heap.
    -
    void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    +
    void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
    Allocate a small object in a specific heap.
    +
    mi_heap_t * mi_heap_get_default()
    Get the default heap that is used for mi_malloc() et al.
    void mi_heap_delete(mi_heap_t *heap)
    Delete a previously allocated heap.
    -
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition: mimalloc-doc.h:554
    -
    void * mi_heap_zalloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    -
    void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
    -
    void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
    -
    mi_heap_t * mi_heap_get_backing()
    Get the backing heap.
    -
    mi_heap_t * mi_heap_new()
    Create a new heap that can be used for allocation.
    +
    void * mi_heap_malloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    +
    mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
    Set the default heap to use in the current thread for mi_malloc() et al.
    +
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition mimalloc-doc.h:630
    +
    void * mi_heap_zalloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    +
    char * mi_heap_realpath(mi_heap_t *heap, const char *fname, char *resolved_name)
    Resolve a file path name using a specific heap to allocate the result.
    +
    char * mi_heap_strdup(mi_heap_t *heap, const char *s)
    Duplicate a string in a specific heap.
    +
    void * mi_heap_zalloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    +
    void * mi_heap_realloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    void mi_heap_collect(mi_heap_t *heap, bool force)
    Release outstanding resources in a specific heap.
    -
    void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
    Allocate count elements in a specific heap.
    -
    mi_heap_t * mi_heap_get_default()
    Get the default heap that is used for mi_malloc() et al.
    -
    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.
    -
    void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
    Allocate zero-initialized in a specific heap.
    -
    void * mi_heap_malloc(mi_heap_t *heap, size_t size)
    Allocate in a specific heap.
    void mi_heap_destroy(mi_heap_t *heap)
    Destroy a heap, freeing all its still allocated blocks.
    -
    void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
    Allocate a small object in a specific heap.
    -
    void * mi_heap_zalloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    -
    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_realloc(mi_heap_t *heap, void *p, size_t newsize)
    -
    void * mi_heap_malloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    -
    mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
    Set the default heap to use for mi_malloc() et al.
    -
    void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
    -
    void * mi_heap_realloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    -
    void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    -
    char * mi_realpath(const char *fname, char *resolved_name)
    Resolve a file path name.
    -
    void * mi_mallocn(size_t count, size_t size)
    Allocate count elements of size bytes.
    +
    void * mi_heap_calloc_aligned_at(mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
    +
    mi_heap_t * mi_heap_new()
    Create a new heap that can be used for allocation.
    +
    void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
    Allocate count elements in a specific heap.
    +
    void * mi_heap_malloc(mi_heap_t *heap, size_t size)
    Allocate in a specific heap.
    +
    void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
    Allocate zero-initialized in a specific heap.
    +
    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_realloc(mi_heap_t *heap, void *p, size_t newsize)
    +
    mi_heap_t * mi_heap_get_backing()
    Get the backing heap.
    +
    void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
    +
    void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
    +
    void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    +
    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.
    +
    void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
    +
    void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    +
    void * mi_realloc(void *p, size_t newsize)
    Re-allocate memory to newsize bytes.
    +
    void * mi_expand(void *p, size_t newsize)
    Try to re-allocate memory to newsize bytes in place.
    void * mi_recalloc(void *p, size_t count, size_t size)
    Re-allocate memory to count elements of size bytes, with extra memory initialized to zero.
    -
    void * mi_malloc(size_t size)
    Allocate size bytes.
    -
    void * mi_reallocn(void *p, size_t count, size_t size)
    Re-allocate memory to count elements of size bytes.
    -
    void * mi_calloc(size_t count, size_t size)
    Allocate zero-initialized count elements of size bytes.
    -
    char * mi_strndup(const char *s, size_t n)
    Allocate and duplicate a string up to n bytes.
    -
    void * mi_expand(void *p, size_t newsize)
    Try to re-allocate memory to newsize bytes in place.
    -
    char * mi_strdup(const char *s)
    Allocate and duplicate a string.
    -
    void * mi_realloc(void *p, size_t newsize)
    Re-allocate memory to newsize bytes.
    +
    char * mi_strdup(const char *s)
    Allocate and duplicate a string.
    +
    char * mi_strndup(const char *s, size_t n)
    Allocate and duplicate a string up to n bytes.
    +
    void * mi_reallocf(void *p, size_t newsize)
    Re-allocate memory to newsize bytes,.
    +
    void * mi_mallocn(size_t count, size_t size)
    Allocate count elements of size bytes.
    +
    void * mi_calloc(size_t count, size_t size)
    Allocate zero-initialized count elements of size bytes.
    +
    void * mi_reallocn(void *p, size_t count, size_t size)
    Re-allocate memory to count elements of size bytes.
    +
    char * mi_realpath(const char *fname, char *resolved_name)
    Resolve a file path name.
    +
    void * mi_malloc(size_t size)
    Allocate size bytes.
    +
    void * mi_zalloc(size_t size)
    Allocate zero-initialized size bytes.
    void mi_free(void *p)
    Free previously allocated memory.
    -
    void * mi_zalloc(size_t size)
    Allocate zero-initialized size bytes.
    -
    void * mi_reallocf(void *p, size_t newsize)
    Re-allocate memory to newsize bytes,.
    void mi_option_enable(mi_option_t option)
    +
    size_t mi_option_get_size(mi_option_t option)
    bool mi_option_is_enabled(mi_option_t option)
    void mi_option_set_enabled_default(mi_option_t option, bool enable)
    long mi_option_get(mi_option_t option)
    void mi_option_set_default(mi_option_t option, long value)
    +
    long mi_option_get_clamp(mi_option_t option, long min, long max)
    void mi_option_set_enabled(mi_option_t option, bool enable)
    void mi_option_disable(mi_option_t option)
    void mi_option_set(mi_option_t option, long value)
    -
    mi_option_t
    Runtime options.
    Definition: mimalloc-doc.h:800
    -
    @ mi_option_show_stats
    Print statistics to stderr when the program is done.
    Definition: mimalloc-doc.h:803
    -
    @ mi_option_use_numa_nodes
    Pretend there are at most N NUMA nodes.
    Definition: mimalloc-doc.h:815
    -
    @ mi_option_reset_delay
    Delay in milli-seconds before resetting a page (100ms by default)
    Definition: mimalloc-doc.h:814
    -
    @ mi_option_eager_commit_delay
    Experimental.
    Definition: mimalloc-doc.h:817
    -
    @ mi_option_eager_commit
    Eagerly commit segments (4MiB) (enabled by default).
    Definition: mimalloc-doc.h:806
    -
    @ mi_option_segment_cache
    The number of segments per thread to keep cached.
    Definition: mimalloc-doc.h:811
    -
    @ mi_option_eager_region_commit
    Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
    Definition: mimalloc-doc.h:807
    -
    @ mi_option_large_os_pages
    Use large OS pages (2MiB in size) if possible.
    Definition: mimalloc-doc.h:808
    -
    @ mi_option_os_tag
    OS tag to assign to mimalloc'd memory.
    Definition: mimalloc-doc.h:818
    -
    @ _mi_option_last
    Definition: mimalloc-doc.h:819
    -
    @ mi_option_verbose
    Print verbose messages to stderr.
    Definition: mimalloc-doc.h:804
    -
    @ mi_option_reserve_huge_os_pages_at
    Reserve huge OS pages at node N.
    Definition: mimalloc-doc.h:810
    -
    @ mi_option_reset_decommits
    Experimental.
    Definition: mimalloc-doc.h:816
    -
    @ mi_option_reserve_huge_os_pages
    The number of huge OS pages (1GiB in size) to reserve at the start of the program.
    Definition: mimalloc-doc.h:809
    -
    @ mi_option_page_reset
    Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
    Definition: mimalloc-doc.h:812
    -
    @ mi_option_segment_reset
    Experimental.
    Definition: mimalloc-doc.h:813
    -
    @ mi_option_show_errors
    Print error messages to stderr.
    Definition: mimalloc-doc.h:802
    +
    mi_option_t
    Runtime options.
    Definition mimalloc-doc.h:882
    +
    @ mi_option_abandoned_reclaim_on_free
    allow to reclaim an abandoned segment on a free (=1)
    Definition mimalloc-doc.h:912
    +
    @ mi_option_purge_extend_delay
    extend purge delay on each subsequent delay (=1)
    Definition mimalloc-doc.h:913
    +
    @ mi_option_show_stats
    Print statistics on termination.
    Definition mimalloc-doc.h:885
    +
    @ mi_option_use_numa_nodes
    0 = use all available numa nodes, otherwise use at most N nodes.
    Definition mimalloc-doc.h:906
    +
    @ mi_option_abandoned_page_purge
    immediately purge delayed purges on thread termination
    Definition mimalloc-doc.h:904
    +
    @ mi_option_eager_commit_delay
    the first N segments per thread are not eagerly committed (but per page in the segment on demand)
    Definition mimalloc-doc.h:902
    +
    @ mi_option_eager_commit
    eager commit segments? (after eager_commit_delay segments) (enabled by default).
    Definition mimalloc-doc.h:901
    +
    @ mi_option_visit_abandoned
    allow visiting heap blocks from abandoned threads (=0)
    Definition mimalloc-doc.h:915
    +
    @ mi_option_os_tag
    tag used for OS logging (macOS only for now) (=100)
    Definition mimalloc-doc.h:897
    +
    @ _mi_option_last
    Definition mimalloc-doc.h:917
    +
    @ mi_option_destroy_on_exit
    if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe
    Definition mimalloc-doc.h:910
    +
    @ mi_option_verbose
    Print verbose messages.
    Definition mimalloc-doc.h:886
    +
    @ mi_option_allow_large_os_pages
    allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.
    Definition mimalloc-doc.h:894
    +
    @ mi_option_arena_purge_mult
    multiplier for purge_delay for the purging delay for arenas (=10)
    Definition mimalloc-doc.h:911
    +
    @ mi_option_retry_on_oom
    retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)
    Definition mimalloc-doc.h:898
    +
    @ mi_option_purge_decommits
    should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)
    Definition mimalloc-doc.h:895
    +
    @ mi_option_limit_os_alloc
    If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)
    Definition mimalloc-doc.h:908
    +
    @ mi_option_reserve_huge_os_pages_at
    Reserve N huge OS pages at a specific NUMA node N.
    Definition mimalloc-doc.h:892
    +
    @ mi_option_max_segment_reclaim
    max. percentage of the abandoned segments can be reclaimed per try (=10%)
    Definition mimalloc-doc.h:909
    +
    @ mi_option_arena_reserve
    initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use ...
    Definition mimalloc-doc.h:896
    +
    @ mi_option_reserve_huge_os_pages
    reserve N huge OS pages (1GiB pages) at startup
    Definition mimalloc-doc.h:891
    +
    @ mi_option_disallow_os_alloc
    1 = do not use OS memory for allocation (but only programmatically reserved arenas)
    Definition mimalloc-doc.h:907
    +
    @ mi_option_purge_delay
    memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all...
    Definition mimalloc-doc.h:905
    +
    @ mi_option_disallow_arena_alloc
    1 = do not use arena's for allocation (except if using specific arena id's)
    Definition mimalloc-doc.h:914
    +
    @ mi_option_max_errors
    issue at most N error messages
    Definition mimalloc-doc.h:887
    +
    @ mi_option_max_warnings
    issue at most N warning messages
    Definition mimalloc-doc.h:888
    +
    @ mi_option_show_errors
    Print error messages.
    Definition mimalloc-doc.h:884
    +
    @ mi_option_reserve_os_memory
    reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use m...
    Definition mimalloc-doc.h:893
    +
    @ mi_option_arena_eager_commit
    eager commit arenas? Use 2 to enable just on overcommit systems (=2)
    Definition mimalloc-doc.h:903
    size_t mi_malloc_usable_size(const void *p)
    void mi_free_aligned(void *p, size_t alignment)
    -
    void * mi_aligned_alloc(size_t alignment, size_t size)
    +
    void * mi_aligned_offset_recalloc(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    +
    void * mi_aligned_alloc(size_t alignment, size_t size)
    size_t mi_malloc_size(const void *p)
    -
    void * mi_reallocarray(void *p, size_t count, size_t size)
    Correspond s to reallocarray in FreeBSD.
    +
    void * mi_valloc(size_t size)
    +
    void * mi_pvalloc(size_t size)
    +
    void * mi__expand(void *p, size_t newsize)
    +
    int mi_wdupenv_s(unsigned short **buf, size_t *size, const unsigned short *name)
    void mi_cfree(void *p)
    Just as free but also checks if the pointer p belongs to our heap.
    +
    void * mi_memalign(size_t alignment, size_t size)
    void mi_free_size_aligned(void *p, size_t size, size_t alignment)
    -
    void * mi_valloc(size_t size)
    +
    unsigned char * mi_mbsdup(const unsigned char *s)
    int mi_reallocarr(void *p, size_t count, size_t size)
    Corresponds to reallocarr in NetBSD.
    -
    void * mi_memalign(size_t alignment, size_t size)
    +
    size_t mi_malloc_good_size(size_t size)
    +
    unsigned short * mi_wcsdup(const unsigned short *s)
    +
    int mi_dupenv_s(char **buf, size_t *size, const char *name)
    int mi_posix_memalign(void **p, size_t alignment, size_t size)
    int mi__posix_memalign(void **p, size_t alignment, size_t size)
    +
    void * mi_reallocarray(void *p, size_t count, size_t size)
    Correspond s to reallocarray in FreeBSD.
    void mi_free_size(void *p, size_t size)
    -
    void * mi_pvalloc(size_t size)
    -
    void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    -
    void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
    -
    void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    -
    void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    -
    void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
    -
    void * mi_rezalloc(void *p, size_t newsize)
    -
    void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
    -
    void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    -
    void * mi_rezalloc_aligned(void *p, size_t newsize, size_t alignment)
    -
    void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
    -
    void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    +
    void * mi_aligned_recalloc(void *p, size_t newcount, size_t size, size_t alignment)
    +
    void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    +
    void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
    +
    void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
    +
    void * mi_rezalloc_aligned(void *p, size_t newsize, size_t alignment)
    +
    void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
    +
    void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    +
    void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
    +
    void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
    +
    void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    +
    void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
    +
    void * mi_rezalloc(void *p, size_t newsize)
    diff --git a/docs/mimalloc-doxygen.css b/docs/mimalloc-doxygen.css index b24f5643..c889a8d2 100644 --- a/docs/mimalloc-doxygen.css +++ b/docs/mimalloc-doxygen.css @@ -47,3 +47,14 @@ div.fragment { #nav-sync img { display: none; } +h1,h2,h3,h4,h5,h6 { + transition:none; +} +.memtitle { + background-image: none; + background-color: #EEE; +} +table.memproto, .memproto { + text-shadow: none; + font-size: 110%; +} diff --git a/docs/navtree.css b/docs/navtree.css index a270571a..5ec66982 100644 --- a/docs/navtree.css +++ b/docs/navtree.css @@ -22,10 +22,15 @@ #nav-tree .selected { background-image: url('tab_a.png'); background-repeat:repeat-x; - color: #fff; + color: white; text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); } +#nav-tree .selected .arrow { + color: #5B6364; + text-shadow: none; +} + #nav-tree img { margin:0px; padding:0px; @@ -37,7 +42,6 @@ text-decoration:none; padding:0px; margin:0px; - outline:none; } #nav-tree .label { @@ -52,7 +56,7 @@ #nav-tree .selected a { text-decoration:none; - color:#fff; + color:white; } #nav-tree .children_ul { @@ -67,7 +71,6 @@ #nav-tree { padding: 0px 0px; - background-color: #FAFAFF; font-size:14px; overflow:auto; } @@ -86,7 +89,8 @@ display:block; position: absolute; left: 0px; - width: 180px; + width: $width; + overflow : hidden; } .ui-resizable .ui-resizable-handle { @@ -94,7 +98,7 @@ } .ui-resizable-e { - background-image:url("splitbar.png"); + background-image:url('splitbar.png'); background-size:100%; background-repeat:repeat-y; background-attachment: scroll; @@ -117,7 +121,6 @@ } #nav-tree { - background-image:url('nav_h.png'); background-repeat:repeat-x; background-color: #F2F3F3; -webkit-overflow-scrolling : touch; /* iOS 5+ */ @@ -143,3 +146,4 @@ #nav-tree { display: none; } div.ui-resizable-handle { display: none; position: relative; } } + diff --git a/docs/navtree.js b/docs/navtree.js index 1e272d31..9027ce6a 100644 --- a/docs/navtree.js +++ b/docs/navtree.js @@ -22,525 +22,462 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -var navTreeSubIndices = new Array(); -var arrowDown = '▼'; -var arrowRight = '►'; -function getData(varName) -{ - var i = varName.lastIndexOf('/'); - var n = i>=0 ? varName.substring(i+1) : varName; - return eval(n.replace(/\-/g,'_')); -} +function initNavTree(toroot,relpath) { + let navTreeSubIndices = []; + const ARROW_DOWN = '▼'; + const ARROW_RIGHT = '►'; + const NAVPATH_COOKIE_NAME = ''+'navpath'; -function stripPath(uri) -{ - return uri.substring(uri.lastIndexOf('/')+1); -} - -function stripPath2(uri) -{ - var i = uri.lastIndexOf('/'); - var s = uri.substring(i+1); - var m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/); - return m ? uri.substring(i-6) : s; -} - -function hashValue() -{ - return $(location).attr('hash').substring(1).replace(/[^\w\-]/g,''); -} - -function hashUrl() -{ - return '#'+hashValue(); -} - -function pathName() -{ - return $(location).attr('pathname').replace(/[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]/g, ''); -} - -function localStorageSupported() -{ - try { - return 'localStorage' in window && window['localStorage'] !== null && window.localStorage.getItem; + const getData = function(varName) { + const i = varName.lastIndexOf('/'); + const n = i>=0 ? varName.substring(i+1) : varName; + return eval(n.replace(/-/g,'_')); } - catch(e) { - return false; + + const stripPath = function(uri) { + return uri.substring(uri.lastIndexOf('/')+1); } -} -function storeLink(link) -{ - if (!$("#nav-sync").hasClass('sync') && localStorageSupported()) { - window.localStorage.setItem('navpath',link); + const stripPath2 = function(uri) { + const i = uri.lastIndexOf('/'); + const s = uri.substring(i+1); + const m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/); + return m ? uri.substring(i-6) : s; } -} -function deleteLink() -{ - if (localStorageSupported()) { - window.localStorage.setItem('navpath',''); + const hashValue = function() { + return $(location).attr('hash').substring(1).replace(/[^\w-]/g,''); } -} -function cachedLink() -{ - if (localStorageSupported()) { - return window.localStorage.getItem('navpath'); - } else { - return ''; + const hashUrl = function() { + return '#'+hashValue(); } -} -function getScript(scriptName,func,show) -{ - var head = document.getElementsByTagName("head")[0]; - var script = document.createElement('script'); - script.id = scriptName; - script.type = 'text/javascript'; - script.onload = func; - script.src = scriptName+'.js'; - head.appendChild(script); -} + const pathName = function() { + return $(location).attr('pathname').replace(/[^-A-Za-z0-9+&@#/%?=~_|!:,.;()]/g, ''); + } -function createIndent(o,domNode,node,level) -{ - var level=-1; - var n = node; - while (n.parentNode) { level++; n=n.parentNode; } - if (node.childrenData) { - var imgNode = document.createElement("span"); - imgNode.className = 'arrow'; - imgNode.style.paddingLeft=(16*level).toString()+'px'; - imgNode.innerHTML=arrowRight; - node.plus_img = imgNode; - node.expandToggle = document.createElement("a"); - node.expandToggle.href = "javascript:void(0)"; - node.expandToggle.onclick = function() { - if (node.expanded) { - $(node.getChildrenUL()).slideUp("fast"); - node.plus_img.innerHTML=arrowRight; - node.expanded = false; - } else { - expandNode(o, node, false, false); - } + const storeLink = function(link) { + if (!$("#nav-sync").hasClass('sync')) { + Cookie.writeSetting(NAVPATH_COOKIE_NAME,link,0); } - node.expandToggle.appendChild(imgNode); - domNode.appendChild(node.expandToggle); - } else { - var span = document.createElement("span"); - span.className = 'arrow'; - span.style.width = 16*(level+1)+'px'; - span.innerHTML = ' '; - domNode.appendChild(span); } -} -var animationInProgress = false; - -function gotoAnchor(anchor,aname,updateLocation) -{ - var pos, docContent = $('#doc-content'); - var ancParent = $(anchor.parent()); - if (ancParent.hasClass('memItemLeft') || - ancParent.hasClass('memtitle') || - ancParent.hasClass('fieldname') || - ancParent.hasClass('fieldtype') || - ancParent.is(':header')) - { - pos = ancParent.position().top; - } else if (anchor.position()) { - pos = anchor.position().top; + const deleteLink = function() { + Cookie.eraseSetting(NAVPATH_COOKIE_NAME); } - if (pos) { - var dist = Math.abs(Math.min( - pos-docContent.offset().top, - docContent[0].scrollHeight- - docContent.height()-docContent.scrollTop())); - animationInProgress=true; - docContent.animate({ - scrollTop: pos + docContent.scrollTop() - docContent.offset().top - },Math.max(50,Math.min(500,dist)),function(){ - if (updateLocation) window.location.href=aname; - animationInProgress=false; - }); + + const cachedLink = function() { + return Cookie.readSetting(NAVPATH_COOKIE_NAME,''); } -} -function newNode(o, po, text, link, childrenData, lastNode) -{ - var node = new Object(); - node.children = Array(); - node.childrenData = childrenData; - node.depth = po.depth + 1; - node.relpath = po.relpath; - node.isLast = lastNode; + const getScript = function(scriptName,func) { + const head = document.getElementsByTagName("head")[0]; + const script = document.createElement('script'); + script.id = scriptName; + script.type = 'text/javascript'; + script.onload = func; + script.src = scriptName+'.js'; + head.appendChild(script); + } - node.li = document.createElement("li"); - po.getChildrenUL().appendChild(node.li); - node.parentNode = po; - - node.itemDiv = document.createElement("div"); - node.itemDiv.className = "item"; - - node.labelSpan = document.createElement("span"); - node.labelSpan.className = "label"; - - createIndent(o,node.itemDiv,node,0); - node.itemDiv.appendChild(node.labelSpan); - node.li.appendChild(node.itemDiv); - - var a = document.createElement("a"); - node.labelSpan.appendChild(a); - node.label = document.createTextNode(text); - node.expanded = false; - a.appendChild(node.label); - if (link) { - var url; - if (link.substring(0,1)=='^') { - url = link.substring(1); - link = url; - } else { - url = node.relpath+link; - } - a.className = stripPath(link.replace('#',':')); - if (link.indexOf('#')!=-1) { - var aname = '#'+link.split('#')[1]; - var srcPage = stripPath(pathName()); - var targetPage = stripPath(link.split('#')[0]); - a.href = srcPage!=targetPage ? url : "javascript:void(0)"; - a.onclick = function(){ - storeLink(link); - if (!$(a).parent().parent().hasClass('selected')) - { - $('.item').removeClass('selected'); - $('.item').removeAttr('id'); - $(a).parent().parent().addClass('selected'); - $(a).parent().parent().attr('id','selected'); + const createIndent = function(o,domNode,node) { + let level=-1; + let n = node; + while (n.parentNode) { level++; n=n.parentNode; } + if (node.childrenData) { + const imgNode = document.createElement("span"); + imgNode.className = 'arrow'; + imgNode.style.paddingLeft=(16*level).toString()+'px'; + imgNode.innerHTML=ARROW_RIGHT; + node.plus_img = imgNode; + node.expandToggle = document.createElement("a"); + node.expandToggle.href = "javascript:void(0)"; + node.expandToggle.onclick = function() { + if (node.expanded) { + $(node.getChildrenUL()).slideUp("fast"); + node.plus_img.innerHTML=ARROW_RIGHT; + node.expanded = false; + } else { + expandNode(o, node, false, true); } - var anchor = $(aname); - gotoAnchor(anchor,aname,true); - }; + } + node.expandToggle.appendChild(imgNode); + domNode.appendChild(node.expandToggle); } else { - a.href = url; - a.onclick = function() { storeLink(link); } + let span = document.createElement("span"); + span.className = 'arrow'; + span.style.width = 16*(level+1)+'px'; + span.innerHTML = ' '; + domNode.appendChild(span); } - } else { - if (childrenData != null) - { + } + + let animationInProgress = false; + + const gotoAnchor = function(anchor,aname) { + let pos, docContent = $('#doc-content'); + let ancParent = $(anchor.parent()); + if (ancParent.hasClass('memItemLeft') || ancParent.hasClass('memtitle') || + ancParent.hasClass('fieldname') || ancParent.hasClass('fieldtype') || + ancParent.is(':header')) { + pos = ancParent.position().top; + } else if (anchor.position()) { + pos = anchor.position().top; + } + if (pos) { + const dcOffset = docContent.offset().top; + const dcHeight = docContent.height(); + const dcScrHeight = docContent[0].scrollHeight + const dcScrTop = docContent.scrollTop(); + let dist = Math.abs(Math.min(pos-dcOffset,dcScrHeight-dcHeight-dcScrTop)); + animationInProgress = true; + docContent.animate({ + scrollTop: pos + dcScrTop - dcOffset + },Math.max(50,Math.min(500,dist)),function() { + animationInProgress=false; + if (anchor.parent().attr('class')=='memItemLeft') { + let rows = $('.memberdecls tr[class$="'+hashValue()+'"]'); + glowEffect(rows.children(),300); // member without details + } else if (anchor.parent().attr('class')=='fieldname') { + glowEffect(anchor.parent().parent(),1000); // enum value + } else if (anchor.parent().attr('class')=='fieldtype') { + glowEffect(anchor.parent().parent(),1000); // struct field + } else if (anchor.parent().is(":header")) { + glowEffect(anchor.parent(),1000); // section header + } else { + glowEffect(anchor.next(),1000); // normal member + } + }); + } + } + + const newNode = function(o, po, text, link, childrenData, lastNode) { + const node = { + children : [], + childrenData : childrenData, + depth : po.depth + 1, + relpath : po.relpath, + isLast : lastNode, + li : document.createElement("li"), + parentNode : po, + itemDiv : document.createElement("div"), + labelSpan : document.createElement("span"), + label : document.createTextNode(text), + expanded : false, + childrenUL : null, + getChildrenUL : function() { + if (!this.childrenUL) { + this.childrenUL = document.createElement("ul"); + this.childrenUL.className = "children_ul"; + this.childrenUL.style.display = "none"; + this.li.appendChild(node.childrenUL); + } + return node.childrenUL; + }, + }; + + node.itemDiv.className = "item"; + node.labelSpan.className = "label"; + createIndent(o,node.itemDiv,node); + node.itemDiv.appendChild(node.labelSpan); + node.li.appendChild(node.itemDiv); + + const a = document.createElement("a"); + node.labelSpan.appendChild(a); + po.getChildrenUL().appendChild(node.li); + a.appendChild(node.label); + if (link) { + let url; + if (link.substring(0,1)=='^') { + url = link.substring(1); + link = url; + } else { + url = node.relpath+link; + } + a.className = stripPath(link.replace('#',':')); + if (link.indexOf('#')!=-1) { + const aname = '#'+link.split('#')[1]; + const srcPage = stripPath(pathName()); + const targetPage = stripPath(link.split('#')[0]); + a.href = srcPage!=targetPage ? url : aname; + a.onclick = function() { + storeLink(link); + aPPar = $(a).parent().parent(); + if (!aPPar.hasClass('selected')) { + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + aPPar.addClass('selected'); + aPPar.attr('id','selected'); + } + const anchor = $(aname); + gotoAnchor(anchor,aname); + }; + } else { + a.href = url; + a.onclick = () => storeLink(link); + } + } else if (childrenData != null) { a.className = "nolink"; a.href = "javascript:void(0)"; a.onclick = node.expandToggle.onclick; } + return node; } - node.childrenUL = null; - node.getChildrenUL = function() { - if (!node.childrenUL) { - node.childrenUL = document.createElement("ul"); - node.childrenUL.className = "children_ul"; - node.childrenUL.style.display = "none"; - node.li.appendChild(node.childrenUL); - } - return node.childrenUL; - }; - - return node; -} - -function showRoot() -{ - var headerHeight = $("#top").height(); - var footerHeight = $("#nav-path").height(); - var windowHeight = $(window).height() - headerHeight - footerHeight; - (function (){ // retry until we can scroll to the selected item - try { - var navtree=$('#nav-tree'); - navtree.scrollTo('#selected',100,{offset:-windowHeight/2}); - } catch (err) { - setTimeout(arguments.callee, 0); - } - })(); -} - -function expandNode(o, node, imm, showRoot) -{ - if (node.childrenData && !node.expanded) { - if (typeof(node.childrenData)==='string') { - var varName = node.childrenData; - getScript(node.relpath+varName,function(){ - node.childrenData = getData(varName); - expandNode(o, node, imm, showRoot); - }, showRoot); - } else { - if (!node.childrenVisited) { - getNode(o, node); + const showRoot = function() { + const headerHeight = $("#top").height(); + const footerHeight = $("#nav-path").height(); + const windowHeight = $(window).height() - headerHeight - footerHeight; + (function() { // retry until we can scroll to the selected item + try { + const navtree=$('#nav-tree'); + navtree.scrollTo('#selected',100,{offset:-windowHeight/2}); + } catch (err) { + setTimeout(arguments.callee, 0); } - $(node.getChildrenUL()).slideDown("fast"); - node.plus_img.innerHTML = arrowDown; - node.expanded = true; - } + })(); } -} -function glowEffect(n,duration) -{ - n.addClass('glow').delay(duration).queue(function(next){ - $(this).removeClass('glow');next(); - }); -} - -function highlightAnchor() -{ - var aname = hashUrl(); - var anchor = $(aname); - if (anchor.parent().attr('class')=='memItemLeft'){ - var rows = $('.memberdecls tr[class$="'+hashValue()+'"]'); - glowEffect(rows.children(),300); // member without details - } else if (anchor.parent().attr('class')=='fieldname'){ - glowEffect(anchor.parent().parent(),1000); // enum value - } else if (anchor.parent().attr('class')=='fieldtype'){ - glowEffect(anchor.parent().parent(),1000); // struct field - } else if (anchor.parent().is(":header")) { - glowEffect(anchor.parent(),1000); // section header - } else { - glowEffect(anchor.next(),1000); // normal member - } -} - -function selectAndHighlight(hash,n) -{ - var a; - if (hash) { - var link=stripPath(pathName())+':'+hash.substring(1); - a=$('.item a[class$="'+link+'"]'); - } - if (a && a.length) { - a.parent().parent().addClass('selected'); - a.parent().parent().attr('id','selected'); - highlightAnchor(); - } else if (n) { - $(n.itemDiv).addClass('selected'); - $(n.itemDiv).attr('id','selected'); - } - if ($('#nav-tree-contents .item:first').hasClass('selected')) { - $('#nav-sync').css('top','30px'); - } else { - $('#nav-sync').css('top','5px'); - } - showRoot(); -} - -function showNode(o, node, index, hash) -{ - if (node && node.childrenData) { - if (typeof(node.childrenData)==='string') { - var varName = node.childrenData; - getScript(node.relpath+varName,function(){ - node.childrenData = getData(varName); - showNode(o,node,index,hash); - },true); - } else { - if (!node.childrenVisited) { - getNode(o, node); - } - $(node.getChildrenUL()).css({'display':'block'}); - node.plus_img.innerHTML = arrowDown; - node.expanded = true; - var n = node.children[o.breadcrumbs[index]]; - if (index+11) hash = '#'+parts[1].replace(/[^\w\-]/g,''); - else hash=''; - } - if (hash.match(/^#l\d+$/)) { - var anchor=$('a[name='+hash.substring(1)+']'); - glowEffect(anchor.parent(),1000); // line number - hash=''; // strip line number anchors - } - var url=root+hash; - var i=-1; - while (NAVTREEINDEX[i+1]<=url) i++; - if (i==-1) { i=0; root=NAVTREE[0][1]; } // fallback: show index - if (navTreeSubIndices[i]) { - gotoNode(o,i,root,hash,relpath) - } else { - getScript(relpath+'navtreeindex'+i,function(){ - navTreeSubIndices[i] = eval('NAVTREEINDEX'+i); - if (navTreeSubIndices[i]) { - gotoNode(o,i,root,hash,relpath); + const removeToInsertLater = function(element) { + const parentNode = element.parentNode; + const nextSibling = element.nextSibling; + parentNode.removeChild(element); + return function() { + if (nextSibling) { + parentNode.insertBefore(element, nextSibling); + } else { + parentNode.appendChild(element); } - },true); + }; } -} -function showSyncOff(n,relpath) -{ - n.html(''); -} - -function showSyncOn(n,relpath) -{ - n.html(''); -} - -function toggleSyncButton(relpath) -{ - var navSync = $('#nav-sync'); - if (navSync.hasClass('sync')) { - navSync.removeClass('sync'); - showSyncOff(navSync,relpath); - storeLink(stripPath2(pathName())+hashUrl()); - } else { - navSync.addClass('sync'); - showSyncOn(navSync,relpath); - deleteLink(); - } -} - -var loadTriggered = false; -var readyTriggered = false; -var loadObject,loadToRoot,loadUrl,loadRelPath; - -$(window).on('load',function(){ - if (readyTriggered) { // ready first - navTo(loadObject,loadToRoot,loadUrl,loadRelPath); - showRoot(); - } - loadTriggered=true; -}); - -function initNavTree(toroot,relpath) -{ - var o = new Object(); - o.toroot = toroot; - o.node = new Object(); - o.node.li = document.getElementById("nav-tree-contents"); - o.node.childrenData = NAVTREE; - o.node.children = new Array(); - o.node.childrenUL = document.createElement("ul"); - o.node.getChildrenUL = function() { return o.node.childrenUL; }; - o.node.li.appendChild(o.node.childrenUL); - o.node.depth = 0; - o.node.relpath = relpath; - o.node.expanded = false; - o.node.isLast = true; - o.node.plus_img = document.createElement("span"); - o.node.plus_img.className = 'arrow'; - o.node.plus_img.innerHTML = arrowRight; - - if (localStorageSupported()) { - var navSync = $('#nav-sync'); - if (cachedLink()) { - showSyncOff(navSync,relpath); - navSync.removeClass('sync'); - } else { - showSyncOn(navSync,relpath); + const getNode = function(o, po) { + const insertFunction = removeToInsertLater(po.li); + po.childrenVisited = true; + const l = po.childrenData.length-1; + for (let i in po.childrenData) { + const nodeData = po.childrenData[i]; + po.children[i] = newNode(o, po, nodeData[0], nodeData[1], nodeData[2], i==l); } - navSync.click(function(){ toggleSyncButton(relpath); }); + insertFunction(); } - if (loadTriggered) { // load before ready - navTo(o,toroot,hashUrl(),relpath); - showRoot(); - } else { // ready before load - loadObject = o; - loadToRoot = toroot; - loadUrl = hashUrl(); - loadRelPath = relpath; - readyTriggered=true; + const gotoNode = function(o,subIndex,root,hash,relpath) { + const nti = navTreeSubIndices[subIndex][root+hash]; + o.breadcrumbs = $.extend(true, [], nti ? nti : navTreeSubIndices[subIndex][root]); + if (!o.breadcrumbs && root!=NAVTREE[0][1]) { // fallback: show index + navTo(o,NAVTREE[0][1],"",relpath); + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + } + if (o.breadcrumbs) { + o.breadcrumbs.unshift(0); // add 0 for root node + showNode(o, o.node, 0, hash); + } } - $(window).bind('hashchange', function(){ - if (window.location.hash && window.location.hash.length>1){ - var a; - if ($(location).attr('hash')){ - var clslink=stripPath(pathName())+':'+hashValue(); - a=$('.item a[class$="'+clslink.replace(/1 ? '#'+parts[1].replace(/[^\w-]/g,'') : ''; + } + if (hash.match(/^#l\d+$/)) { + const anchor=$('a[name='+hash.substring(1)+']'); + glowEffect(anchor.parent(),1000); // line number + hash=''; // strip line number anchors + } + const url=root+hash; + let i=-1; + while (NAVTREEINDEX[i+1]<=url) i++; + if (i==-1) { i=0; root=NAVTREE[0][1]; } // fallback: show index + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath) + } else { + getScript(relpath+'navtreeindex'+i,function() { + navTreeSubIndices[i] = eval('NAVTREEINDEX'+i); + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath); + } + }); + } + } + + const showSyncOff = function(n,relpath) { + n.html(''); + } + + const showSyncOn = function(n,relpath) { + n.html(''); + } + + const o = { + toroot : toroot, + node : { + childrenData : NAVTREE, + children : [], + childrenUL : document.createElement("ul"), + getChildrenUL : function() { return this.childrenUL }, + li : document.getElementById("nav-tree-contents"), + depth : 0, + relpath : relpath, + expanded : false, + isLast : true, + plus_img : document.createElement("span"), + }, + }; + o.node.li.appendChild(o.node.childrenUL); + o.node.plus_img.className = 'arrow'; + o.node.plus_img.innerHTML = ARROW_RIGHT; + + const navSync = $('#nav-sync'); + if (cachedLink()) { + showSyncOff(navSync,relpath); + navSync.removeClass('sync'); + } else { + showSyncOn(navSync,relpath); + } + + navSync.click(() => { + const navSync = $('#nav-sync'); + if (navSync.hasClass('sync')) { + navSync.removeClass('sync'); + showSyncOff(navSync,relpath); + storeLink(stripPath2(pathName())+hashUrl()); + } else { + navSync.addClass('sync'); + showSyncOn(navSync,relpath); + deleteLink(); + } + }); + + navTo(o,toroot,hashUrl(),relpath); + showRoot(); + + $(window).bind('hashchange', () => { + if (!animationInProgress) { + if (window.location.hash && window.location.hash.length>1) { + let a; + if ($(location).attr('hash')) { + const clslink=stripPath(pathName())+':'+hashValue(); + a=$('.item a[class$="'+clslink.replace(/ - + - - + + mi-malloc: Overriding Malloc + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html'); -
    @@ -88,43 +91,47 @@ $(document).ready(function(){initNavTree('overrides.html',''); initResizable();
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    -
    Overriding Malloc
    +
    +
    Overriding Malloc
    -

    Overriding the standard malloc can be done either dynamically or statically.

    +

    Overriding the standard malloc (and new) can be done either dynamically or statically.

    Dynamic override

    This is the recommended way to override the standard malloc interface.

    -

    Linux, BSD

    -

    On these systems we preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    -
      -
    • env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    • -
    -

    You can set extra environment variables to check that mimalloc is running, like:

    env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    -

    or run with the debug version to get detailed statistics:

    env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram
    -

    MacOS

    -

    On macOS we can also preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    -
      -
    • 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: macOS support for dynamic overriding is recent, please report any issues.)

    -

    Windows

    -

    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 without linking to the mimalloc library).

    +

    Dynamic Override on Linux, BSD

    +

    On these ELF-based systems we preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    > env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    +

    You can set extra environment variables to check that mimalloc is running, like:

    > env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram
    +

    or run with the debug version to get detailed statistics:

    > env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram
    +

    Dynamic Override on MacOS

    +

    On macOS we can also preload the mimalloc shared library so all calls to the standard malloc interface are resolved to the mimalloc library.

    > env DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram
    +

    Note that certain security restrictions may apply when doing this from the shell.

    +

    Dynamic Override on Windows

    +

    Dynamically overriding on mimalloc 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. As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. There are four requirements to make the overriding work robustly:

    +
      +
    1. Use the C-runtime library as a DLL (using the /MD or /MDd switch).
    2. +
    3. Link your program explicitly with mimalloc-override.dll library. To ensure the mimalloc-override.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.
    4. +
    5. The [mimalloc-redirect.dll](bin) (or mimalloc-redirect32.dll) must be put in the same folder as the main mimalloc-override.dll at runtime (as it is a dependency of that DLL). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc functions (which reside in mimalloc-override.dll).
    6. +
    7. Ensure the mimalloc-override.dll comes as early as possible in the import list of the final executable (so it can intercept all potential allocations).
    8. +
    +

    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 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).

    +

    We cannot always re-link an executable with mimalloc-override.dll, and similarly, we cannot always ensure the the DLL comes first in the import table of the final executable. In many cases though we can 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 or the [minject](bin) program.

    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:

    +

    On Unix-like 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.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.o myfile1.c ...
    +

    Another way to override statically that works on all platforms, is to link statically to mimalloc (as shown in the introduction) and include a header file in each source file that re-defines malloc etc. to mi_malloc. This is provided by mimalloc-override.h. This only works reliably though if all sources are under your control or otherwise mixing of pointers from different heaps may occur!

    +

    List of Overrides:

    The specific functions that get redirected to the mimalloc library are:

    // C
    void* malloc(size_t size);
    @@ -142,10 +149,10 @@ $(document).ready(function(){initNavTree('overrides.html',''); initResizable();
    void operator delete(void* p);
    void operator delete[](void* p);
    -
    void* operator new(std::size_t n) noexcept(false);
    -
    void* operator new[](std::size_t n) noexcept(false);
    -
    void* operator new( std::size_t n, std::align_val_t align) noexcept(false);
    -
    void* operator new[]( std::size_t n, std::align_val_t align) noexcept(false);
    +
    void* operator new(std::size_t n) noexcept(false);
    +
    void* operator new[](std::size_t n) noexcept(false);
    +
    void* operator new( std::size_t n, std::align_val_t align) noexcept(false);
    +
    void* operator new[]( std::size_t n, std::align_val_t align) noexcept(false);
    void* operator new ( std::size_t count, const std::nothrow_t& tag);
    void* operator new[]( std::size_t count, const std::nothrow_t& tag);
    @@ -191,7 +198,7 @@ $(document).ready(function(){initNavTree('overrides.html',''); initResizable(); diff --git a/docs/pages.html b/docs/pages.html index 60b7fc30..2fab5ac9 100644 --- a/docs/pages.html +++ b/docs/pages.html @@ -1,24 +1,26 @@ - + - - + + mi-malloc: Related Pages + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,22 +91,28 @@ $(document).ready(function(){initNavTree('pages.html',''); initResizable(); });
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    Related Pages
    +
    Related Pages
    Here is a list of all related documentation pages:
    @@ -112,7 +121,7 @@ $(document).ready(function(){initNavTree('pages.html',''); initResizable(); }); diff --git a/docs/resize.js b/docs/resize.js index e1ad0fe3..b6935298 100644 --- a/docs/resize.js +++ b/docs/resize.js @@ -22,119 +22,124 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -function initResizable() -{ - var cookie_namespace = 'doxygen'; - var sidenav,navtree,content,header,collapsed,collapsedWidth=0,barWidth=6,desktop_vp=768,titleHeight; - function readCookie(cookie) - { - var myCookie = cookie_namespace+"_"+cookie+"="; - if (document.cookie) { - var index = document.cookie.indexOf(myCookie); - if (index != -1) { - var valStart = index + myCookie.length; - var valEnd = document.cookie.indexOf(";", valStart); - if (valEnd == -1) { - valEnd = document.cookie.length; - } - var val = document.cookie.substring(valStart, valEnd); - return val; - } - } - return 0; - } +function initResizable(treeview) { + let sidenav,navtree,content,header,footer,barWidth=6; + const RESIZE_COOKIE_NAME = ''+'width'; - function writeCookie(cookie, val, expiration) - { - if (val==undefined) return; - if (expiration == null) { - var date = new Date(); - date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week - expiration = date.toGMTString(); - } - document.cookie = cookie_namespace + "_" + cookie + "=" + val + "; expires=" + expiration+"; path=/"; - } - - function resizeWidth() - { - var windowWidth = $(window).width() + "px"; - var sidenavWidth = $(sidenav).outerWidth(); + function resizeWidth() { + const sidenavWidth = $(sidenav).outerWidth(); content.css({marginLeft:parseInt(sidenavWidth)+"px"}); - writeCookie('width',sidenavWidth-barWidth, null); + if (typeof page_layout!=='undefined' && page_layout==1) { + footer.css({marginLeft:parseInt(sidenavWidth)+"px"}); + } + Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); } - function restoreWidth(navWidth) - { - var windowWidth = $(window).width() + "px"; + function restoreWidth(navWidth) { content.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + if (typeof page_layout!=='undefined' && page_layout==1) { + footer.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + } sidenav.css({width:navWidth + "px"}); } - function resizeHeight() - { - var headerHeight = header.outerHeight(); - var footerHeight = footer.outerHeight(); - var windowHeight = $(window).height() - headerHeight - footerHeight; - content.css({height:windowHeight + "px"}); - navtree.css({height:windowHeight + "px"}); - sidenav.css({height:windowHeight + "px"}); - var width=$(window).width(); - if (width!=collapsedWidth) { - if (width=desktop_vp) { - if (!collapsed) { - collapseExpand(); - } - } else if (width>desktop_vp && collapsedWidth0) { - restoreWidth(0); - collapsed=true; - } - else { - var width = readCookie('width'); - if (width>200 && width<$(window).width()) { restoreWidth(width); } else { restoreWidth(200); } - collapsed=false; + newWidth=0; + } else { + const width = Cookie.readSetting(RESIZE_COOKIE_NAME,180); + newWidth = (width>180 && width<$(window).width()) ? width : 180; } + restoreWidth(newWidth); + const sidenavWidth = $(sidenav).outerWidth(); + Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); } header = $("#top"); - sidenav = $("#side-nav"); content = $("#doc-content"); - navtree = $("#nav-tree"); footer = $("#nav-path"); - $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); - $(sidenav).resizable({ minWidth: 0 }); - $(window).resize(function() { resizeHeight(); }); - var device = navigator.userAgent.toLowerCase(); - var touch_device = device.match(/(iphone|ipod|ipad|android)/); - if (touch_device) { /* wider split bar for touch only devices */ - $(sidenav).css({ paddingRight:'20px' }); - $('.ui-resizable-e').css({ width:'20px' }); - $('#nav-sync').css({ right:'34px' }); - barWidth=20; + sidenav = $("#side-nav"); + if (!treeview) { +// title = $("#titlearea"); +// titleH = $(title).height(); +// let animating = false; +// content.on("scroll", function() { +// slideOpts = { duration: 200, +// step: function() { +// contentHeight = $(window).height() - header.outerHeight(); +// content.css({ height : contentHeight + "px" }); +// }, +// done: function() { animating=false; } +// }; +// if (content.scrollTop()>titleH && title.css('display')!='none' && !animating) { +// title.slideUp(slideOpts); +// animating=true; +// } else if (content.scrollTop()<=titleH && title.css('display')=='none' && !animating) { +// title.slideDown(slideOpts); +// animating=true; +// } +// }); + } else { + navtree = $("#nav-tree"); + $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); + $(sidenav).resizable({ minWidth: 0 }); } - var width = readCookie('width'); - if (width) { restoreWidth(width); } else { resizeWidth(); } - resizeHeight(); - var url = location.href; - var i=url.indexOf("#"); + $(window).resize(function() { resizeHeight(treeview); }); + if (treeview) + { + const device = navigator.userAgent.toLowerCase(); + const touch_device = device.match(/(iphone|ipod|ipad|android)/); + if (touch_device) { /* wider split bar for touch only devices */ + $(sidenav).css({ paddingRight:'20px' }); + $('.ui-resizable-e').css({ width:'20px' }); + $('#nav-sync').css({ right:'34px' }); + barWidth=20; + } + const width = Cookie.readSetting(RESIZE_COOKIE_NAME,180); + if (width) { restoreWidth(width); } else { resizeWidth(); } + } + resizeHeight(treeview); + const url = location.href; + const i=url.indexOf("#"); if (i>=0) window.location.hash=url.substr(i); - var _preventDefault = function(evt) { evt.preventDefault(); }; - $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); - $(".ui-resizable-handle").dblclick(collapseExpand); + const _preventDefault = function(evt) { evt.preventDefault(); }; + if (treeview) + { + $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); + $(".ui-resizable-handle").dblclick(collapseExpand); + } $(window).on('load',resizeHeight); } /* @license-end */ diff --git a/docs/search/all_1.js b/docs/search/all_1.js index 7f1097c0..d371a399 100644 --- a/docs/search/all_1.js +++ b/docs/search/all_1.js @@ -1,4 +1,6 @@ var searchData= [ - ['aligned_20allocation_1',['Aligned Allocation',['../group__aligned.html',1,'']]] + ['aligned_20allocation_0',['Aligned Allocation',['../group__aligned.html',1,'']]], + ['allocation_1',['Allocation',['../group__aligned.html',1,'Aligned Allocation'],['../group__malloc.html',1,'Basic Allocation'],['../group__heap.html',1,'Heap Allocation']]], + ['allocation_2',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] ]; diff --git a/docs/search/all_2.js b/docs/search/all_2.js index 00576d78..6a297a47 100644 --- a/docs/search/all_2.js +++ b/docs/search/all_2.js @@ -1,7 +1,7 @@ var searchData= [ - ['basic_20allocation_2',['Basic Allocation',['../group__malloc.html',1,'']]], - ['block_5fsize_3',['block_size',['../group__analysis.html#a332a6c14d736a99699d5453a1cb04b41',1,'mi_heap_area_t']]], - ['blocks_4',['blocks',['../group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8',1,'mi_heap_area_t']]], - ['building_5',['Building',['../build.html',1,'']]] + ['basic_20allocation_0',['Basic Allocation',['../group__malloc.html',1,'']]], + ['block_5fsize_1',['block_size',['../group__analysis.html#a332a6c14d736a99699d5453a1cb04b41',1,'mi_heap_area_t']]], + ['blocks_2',['blocks',['../group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8',1,'mi_heap_area_t']]], + ['building_3',['Building',['../build.html',1,'']]] ]; diff --git a/docs/search/all_3.js b/docs/search/all_3.js index 9a029ee0..76374a61 100644 --- a/docs/search/all_3.js +++ b/docs/search/all_3.js @@ -1,5 +1,5 @@ var searchData= [ - ['c_2b_2b_20wrappers_6',['C++ wrappers',['../group__cpp.html',1,'']]], - ['committed_7',['committed',['../group__analysis.html#ab47526df656d8837ec3e97f11b83f835',1,'mi_heap_area_t']]] + ['c_20wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]], + ['committed_1',['committed',['../group__analysis.html#ab47526df656d8837ec3e97f11b83f835',1,'mi_heap_area_t']]] ]; diff --git a/docs/search/all_4.js b/docs/search/all_4.js index 5dc51286..a2c108b7 100644 --- a/docs/search/all_4.js +++ b/docs/search/all_4.js @@ -1,5 +1,5 @@ var searchData= [ - ['environment_20options_8',['Environment Options',['../environment.html',1,'']]], - ['extended_20functions_9',['Extended Functions',['../group__extended.html',1,'']]] + ['environment_20options_0',['Environment Options',['../environment.html',1,'']]], + ['extended_20functions_1',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/docs/search/all_5.js b/docs/search/all_5.js index 7441d853..6f8d30e9 100644 --- a/docs/search/all_5.js +++ b/docs/search/all_5.js @@ -1,5 +1,5 @@ var searchData= [ - ['heap_20allocation_10',['Heap Allocation',['../group__heap.html',1,'']]], - ['heap_20introspection_11',['Heap Introspection',['../group__analysis.html',1,'']]] + ['full_5fblock_5fsize_0',['full_block_size',['../group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3',1,'mi_heap_area_t']]], + ['functions_1',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/docs/search/all_6.js b/docs/search/all_6.js index 6d32b7b1..3131f4a2 100644 --- a/docs/search/all_6.js +++ b/docs/search/all_6.js @@ -1,153 +1,5 @@ var searchData= [ - ['mi_5f_5fposix_5fmemalign_12',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], - ['mi_5faligned_5falloc_13',['mi_aligned_alloc',['../group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5',1,'mimalloc-doc.h']]], - ['mi_5falignment_5fmax_14',['MI_ALIGNMENT_MAX',['../group__aligned.html#ga83c03016066b438f51a8095e9140be06',1,'mimalloc-doc.h']]], - ['mi_5fblock_5fvisit_5ffun_15',['mi_block_visit_fun',['../group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_16',['mi_calloc',['../group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_17',['mi_calloc_aligned',['../group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_5fat_18',['mi_calloc_aligned_at',['../group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5ftp_19',['mi_calloc_tp',['../group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07',1,'mimalloc-doc.h']]], - ['mi_5fcfree_20',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], - ['mi_5fcheck_5fowned_21',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], - ['mi_5fcollect_22',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], - ['mi_5fdeferred_5ffree_5ffun_23',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]], - ['mi_5ferror_5ffun_24',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',1,'mimalloc-doc.h']]], - ['mi_5fexpand_25',['mi_expand',['../group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4',1,'mimalloc-doc.h']]], - ['mi_5ffree_26',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], - ['mi_5ffree_5faligned_27',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_28',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_5faligned_29',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], - ['mi_5fgood_5fsize_30',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], - ['mi_5fheap_5farea_5ft_31',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], - ['mi_5fheap_5fcalloc_32',['mi_heap_calloc',['../group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_33',['mi_heap_calloc_aligned',['../group__heap.html#ga4af03a6e2b93fae77424d93f889705c3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_5fat_34',['mi_heap_calloc_aligned_at',['../group__heap.html#ga08ca6419a5c057a4d965868998eef487',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5ftp_35',['mi_heap_calloc_tp',['../group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcheck_5fowned_36',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcollect_37',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcontains_5fblock_38',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdelete_39',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdestroy_40',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fbacking_41',['mi_heap_get_backing',['../group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fdefault_42',['mi_heap_get_default',['../group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_43',['mi_heap_malloc',['../group__heap.html#ga9cbed01e42c0647907295de92c3fa296',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_44',['mi_heap_malloc_aligned',['../group__heap.html#gab5b87e1805306f70df38789fcfcf6653',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_5fat_45',['mi_heap_malloc_aligned_at',['../group__heap.html#ga23acd7680fb0976dde3783254c6c874b',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5fsmall_46',['mi_heap_malloc_small',['../group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5ftp_47',['mi_heap_malloc_tp',['../group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_48',['mi_heap_mallocn',['../group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_5ftp_49',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_50',['mi_heap_new',['../group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_51',['mi_heap_realloc',['../group__heap.html#gaaef3395f66be48f37bdc8322509c5d81',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_52',['mi_heap_realloc_aligned',['../group__heap.html#gafc603b696bd14cae6da28658f950d98c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_5fat_53',['mi_heap_realloc_aligned_at',['../group__heap.html#gaf96c788a1bf553fe2d371de9365e047c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocf_54',['mi_heap_reallocf',['../group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_55',['mi_heap_reallocn',['../group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_5ftp_56',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealpath_57',['mi_heap_realpath',['../group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_58',['mi_heap_recalloc',['../group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_59',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_5fat_60',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5ftp_61',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_62',['mi_heap_rezalloc',['../group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_63',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_5fat_64',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fset_5fdefault_65',['mi_heap_set_default',['../group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrdup_66',['mi_heap_strdup',['../group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrndup_67',['mi_heap_strndup',['../group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5ft_68',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fvisit_5fblocks_69',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_70',['mi_heap_zalloc',['../group__heap.html#ga903104592c8ed53417a3762da6241133',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_71',['mi_heap_zalloc_aligned',['../group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_5fat_72',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga45fb43a62776fbebbdf1edd99b527954',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5ftp_73',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], - ['mi_5fis_5fin_5fheap_5fregion_74',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], - ['mi_5fis_5fredirected_75',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_76',['mi_malloc',['../group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_77',['mi_malloc_aligned',['../group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_5fat_78',['mi_malloc_aligned_at',['../group__aligned.html#ga5850da130c936bd77db039dcfbc8295d',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsize_79',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsmall_80',['mi_malloc_small',['../group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5ftp_81',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fusable_5fsize_82',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_83',['mi_mallocn',['../group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_5ftp_84',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_85',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], - ['mi_5fmemalign_86',['mi_memalign',['../group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e',1,'mimalloc-doc.h']]], - ['mi_5fnew_87',['mi_new',['../group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_88',['mi_new_aligned',['../group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_5fnothrow_89',['mi_new_aligned_nothrow',['../group__cpp.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fn_90',['mi_new_n',['../group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fnothrow_91',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]], - ['mi_5fnew_5frealloc_92',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]], - ['mi_5fnew_5freallocn_93',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisable_94',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_95',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_5fdelay_96',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fregion_5fcommit_97',['mi_option_eager_region_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_98',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_99',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fis_5fenabled_100',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], - ['mi_5foption_5flarge_5fos_5fpages_101',['mi_option_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e',1,'mimalloc-doc.h']]], - ['mi_5foption_5fos_5ftag_102',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpage_5freset_103',['mi_option_page_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_104',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_105',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdecommits_106',['mi_option_reset_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdelay_107',['mi_option_reset_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5fcache_108',['mi_option_segment_cache',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5freset_109',['mi_option_segment_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_110',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fdefault_111',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_112',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_5fdefault_113',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5ferrors_114',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5fstats_115',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], - ['mi_5foption_5ft_116',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fuse_5fnuma_5fnodes_117',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], - ['mi_5foption_5fverbose_118',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], - ['mi_5foutput_5ffun_119',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',1,'mimalloc-doc.h']]], - ['mi_5fposix_5fmemalign_120',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo_121',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], - ['mi_5fpvalloc_122',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], - ['mi_5frealloc_123',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_124',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_5fat_125',['mi_realloc_aligned_at',['../group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb',1,'mimalloc-doc.h']]], - ['mi_5freallocarr_126',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], - ['mi_5freallocarray_127',['mi_reallocarray',['../group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088',1,'mimalloc-doc.h']]], - ['mi_5freallocf_128',['mi_reallocf',['../group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0',1,'mimalloc-doc.h']]], - ['mi_5freallocn_129',['mi_reallocn',['../group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853',1,'mimalloc-doc.h']]], - ['mi_5freallocn_5ftp_130',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], - ['mi_5frealpath_131',['mi_realpath',['../group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_132',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_133',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_5fat_134',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]], - ['mi_5fregister_5fdeferred_5ffree_135',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], - ['mi_5fregister_5ferror_136',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], - ['mi_5fregister_5foutput_137',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_138',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_139',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_140',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_141',['mi_rezalloc',['../group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_142',['mi_rezalloc_aligned',['../group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_5fat_143',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], - ['mi_5fsmall_5fsize_5fmax_144',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fmerge_145',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_146',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_5fout_147',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset_148',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], - ['mi_5fstl_5fallocator_149',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], - ['mi_5fstrdup_150',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], - ['mi_5fstrndup_151',['mi_strndup',['../group__malloc.html#gaaabf971c2571891433477e2d21a35266',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone_152',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit_153',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint_5fout_154',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], - ['mi_5fusable_5fsize_155',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], - ['mi_5fvalloc_156',['mi_valloc',['../group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_157',['mi_zalloc',['../group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_158',['mi_zalloc_aligned',['../group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_5fat_159',['mi_zalloc_aligned_at',['../group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5fsmall_160',['mi_zalloc_small',['../group__extended.html#ga220f29f40a44404b0061c15bc1c31152',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5ftp_161',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] + ['heap_20allocation_0',['Heap Allocation',['../group__heap.html',1,'']]], + ['heap_20introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] ]; diff --git a/docs/search/all_7.js b/docs/search/all_7.js index 8f296aa5..6d208432 100644 --- a/docs/search/all_7.js +++ b/docs/search/all_7.js @@ -1,4 +1,5 @@ var searchData= [ - ['overriding_20malloc_162',['Overriding Malloc',['../overrides.html',1,'']]] + ['initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] ]; diff --git a/docs/search/all_8.js b/docs/search/all_8.js index a9caa77c..5071ed69 100644 --- a/docs/search/all_8.js +++ b/docs/search/all_8.js @@ -1,5 +1,4 @@ var searchData= [ - ['performance_163',['Performance',['../bench.html',1,'']]], - ['posix_164',['Posix',['../group__posix.html',1,'']]] + ['library_0',['Using the library',['../using.html',1,'']]] ]; diff --git a/docs/search/all_9.js b/docs/search/all_9.js index f6b4ba35..bac4217a 100644 --- a/docs/search/all_9.js +++ b/docs/search/all_9.js @@ -1,5 +1,192 @@ var searchData= [ - ['reserved_165',['reserved',['../group__analysis.html#ae848a3e6840414891035423948ca0383',1,'mi_heap_area_t']]], - ['runtime_20options_166',['Runtime Options',['../group__options.html',1,'']]] + ['macros_0',['Typed Macros',['../group__typed.html',1,'']]], + ['malloc_1',['Overriding Malloc',['../overrides.html',1,'']]], + ['malloc_2',['mi-malloc',['../index.html',1,'']]], + ['mi_20malloc_3',['mi-malloc',['../index.html',1,'']]], + ['mi_5f_5fexpand_4',['mi__expand',['../group__posix.html#ga66bcfeb4faedbb42b796bc680821ef84',1,'mimalloc-doc.h']]], + ['mi_5f_5fposix_5fmemalign_5',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], + ['mi_5fabandoned_5fvisit_5fblocks_6',['mi_abandoned_visit_blocks',['../group__analysis.html#ga6a4865a887b2ec5247854af61562503c',1,'mimalloc-doc.h']]], + ['mi_5faligned_5falloc_7',['mi_aligned_alloc',['../group__posix.html#ga430ed1513f0571ff83be00ec58a98ee0',1,'mimalloc-doc.h']]], + ['mi_5faligned_5foffset_5frecalloc_8',['mi_aligned_offset_recalloc',['../group__posix.html#ga16570deddd559001b44953eedbad0084',1,'mimalloc-doc.h']]], + ['mi_5faligned_5frecalloc_9',['mi_aligned_recalloc',['../group__posix.html#gaf82cbb4b4f24acf723348628451798d3',1,'mimalloc-doc.h']]], + ['mi_5farena_5farea_10',['mi_arena_area',['../group__extended.html#ga9a25a00a22151619a0be91a10af7787f',1,'mimalloc-doc.h']]], + ['mi_5farena_5fid_5ft_11',['mi_arena_id_t',['../group__extended.html#ga99fe38650d0b02e0e0f89ee024db91d3',1,'mimalloc-doc.h']]], + ['mi_5fblock_5falignment_5fmax_12',['MI_BLOCK_ALIGNMENT_MAX',['../group__aligned.html#ga2e3fc59317bd730a71788c4d56ac8bff',1,'mimalloc-doc.h']]], + ['mi_5fblock_5fvisit_5ffun_13',['mi_block_visit_fun',['../group__analysis.html#ga8255dc9371e6b299d9802a610c4e34ec',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_14',['mi_calloc',['../group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_15',['mi_calloc_aligned',['../group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_5fat_16',['mi_calloc_aligned_at',['../group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5ftp_17',['mi_calloc_tp',['../group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07',1,'mimalloc-doc.h']]], + ['mi_5fcfree_18',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], + ['mi_5fcheck_5fowned_19',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], + ['mi_5fcollect_20',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], + ['mi_5fdebug_5fshow_5farenas_21',['mi_debug_show_arenas',['../group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7',1,'mimalloc-doc.h']]], + ['mi_5fdeferred_5ffree_5ffun_22',['mi_deferred_free_fun',['../group__extended.html#ga292a45f7dbc7cd23c5352ce1f0002816',1,'mimalloc-doc.h']]], + ['mi_5fdupenv_5fs_23',['mi_dupenv_s',['../group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958',1,'mimalloc-doc.h']]], + ['mi_5ferror_5ffun_24',['mi_error_fun',['../group__extended.html#ga83fc6a688b322261e1c2deab000b0591',1,'mimalloc-doc.h']]], + ['mi_5fexpand_25',['mi_expand',['../group__malloc.html#ga19299856216cfbb08e2628593654dfb0',1,'mimalloc-doc.h']]], + ['mi_5ffree_26',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], + ['mi_5ffree_5faligned_27',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_28',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_5faligned_29',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], + ['mi_5fgood_5fsize_30',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], + ['mi_5fheap_5farea_5ft_31',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], + ['mi_5fheap_5fcalloc_32',['mi_heap_calloc',['../group__heap.html#gac0098aaf231d3e9586c73136d5df95da',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_33',['mi_heap_calloc_aligned',['../group__heap.html#gacafcc26df827c7a7de5e850217566108',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_5fat_34',['mi_heap_calloc_aligned_at',['../group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5ftp_35',['mi_heap_calloc_tp',['../group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcheck_5fowned_36',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcollect_37',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcontains_5fblock_38',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdelete_39',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdestroy_40',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fbacking_41',['mi_heap_get_backing',['../group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fdefault_42',['mi_heap_get_default',['../group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_43',['mi_heap_malloc',['../group__heap.html#gab374e206c7034e0d899fb934e4f4a863',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_44',['mi_heap_malloc_aligned',['../group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_5fat_45',['mi_heap_malloc_aligned_at',['../group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5fsmall_46',['mi_heap_malloc_small',['../group__heap.html#ga012c5c8abe22b10043de39ff95909541',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5ftp_47',['mi_heap_malloc_tp',['../group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_48',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_5ftp_49',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_50',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fin_5farena_51',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_52',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_53',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_5fat_54',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocf_55',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_56',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_5ftp_57',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealpath_58',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_59',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_60',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat_61',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5ftp_62',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_63',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_64',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat_65',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fset_5fdefault_66',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrdup_67',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrndup_68',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5ft_69',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fvisit_5fblocks_70',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_71',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_72',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_5fat_73',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5ftp_74',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion_75',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected_76',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_77',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_78',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_5fat_79',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fgood_5fsize_80',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsize_81',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsmall_82',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5ftp_83',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fusable_5fsize_84',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_85',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_5ftp_86',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_87',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_5fex_88',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], + ['mi_5fmbsdup_89',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], + ['mi_5fmemalign_90',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], + ['mi_5fnew_91',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_92',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_5fnothrow_93',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fn_94',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fnothrow_95',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], + ['mi_5fnew_5frealloc_96',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], + ['mi_5fnew_5freallocn_97',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5fpage_5fpurge_98',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_99',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], + ['mi_5foption_5fallow_5flarge_5fos_5fpages_100',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5feager_5fcommit_101',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5fpurge_5fmult_102',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5freserve_103',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdestroy_5fon_5fexit_104',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable_105',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5farena_5falloc_106',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5fos_5falloc_107',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_108',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay_109',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable_110',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_111',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fclamp_112',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fsize_113',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled_114',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], + ['mi_5foption_5flimit_5fos_5falloc_115',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5ferrors_116',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fsegment_5freclaim_117',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fwarnings_118',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag_119',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdecommits_120',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdelay_121',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fextend_5fdelay_122',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_123',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_124',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fos_5fmemory_125',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], + ['mi_5foption_5fretry_5fon_5foom_126',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_127',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fdefault_128',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_129',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault_130',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5ferrors_131',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5fstats_132',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], + ['mi_5foption_5ft_133',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fuse_5fnuma_5fnodes_134',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], + ['mi_5foption_5fverbose_135',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], + ['mi_5foption_5fvisit_5fabandoned_136',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]], + ['mi_5foutput_5ffun_137',['mi_output_fun',['../group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d',1,'mimalloc-doc.h']]], + ['mi_5fposix_5fmemalign_138',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo_139',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], + ['mi_5fpvalloc_140',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], + ['mi_5frealloc_141',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_142',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_5fat_143',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], + ['mi_5freallocarr_144',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], + ['mi_5freallocarray_145',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], + ['mi_5freallocf_146',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], + ['mi_5freallocn_147',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], + ['mi_5freallocn_5ftp_148',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], + ['mi_5frealpath_149',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_150',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_151',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat_152',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], + ['mi_5fregister_5fdeferred_5ffree_153',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], + ['mi_5fregister_5ferror_154',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput_155',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_156',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_157',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_158',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_159',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_5fex_160',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_161',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_162',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat_163',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], + ['mi_5fsmall_5fsize_5fmax_164',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge_165',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_166',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout_167',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset_168',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], + ['mi_5fstl_5fallocator_169',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], + ['mi_5fstrdup_170',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], + ['mi_5fstrndup_171',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fadd_5fcurrent_5fthread_172',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fdelete_173',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fid_5ft_174',['mi_subproc_id_t',['../group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fmain_175',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fnew_176',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone_177',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit_178',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint_5fout_179',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], + ['mi_5fusable_5fsize_180',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], + ['mi_5fvalloc_181',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], + ['mi_5fwcsdup_182',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], + ['mi_5fwdupenv_5fs_183',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_184',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_185',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_5fat_186',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5fsmall_187',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5ftp_188',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] ]; diff --git a/docs/search/all_a.js b/docs/search/all_a.js index 699b5456..dee0ab7c 100644 --- a/docs/search/all_a.js +++ b/docs/search/all_a.js @@ -1,4 +1,5 @@ var searchData= [ - ['typed_20macros_167',['Typed Macros',['../group__typed.html',1,'']]] + ['options_0',['Options',['../environment.html',1,'Environment Options'],['../group__options.html',1,'Runtime Options']]], + ['overriding_20malloc_1',['Overriding Malloc',['../overrides.html',1,'']]] ]; diff --git a/docs/search/all_b.js b/docs/search/all_b.js index 73a2671d..44ef0a69 100644 --- a/docs/search/all_b.js +++ b/docs/search/all_b.js @@ -1,5 +1,5 @@ var searchData= [ - ['used_168',['used',['../group__analysis.html#ab820302c5cd0df133eb8e51650a008b4',1,'mi_heap_area_t']]], - ['using_20the_20library_169',['Using the library',['../using.html',1,'']]] + ['performance_0',['Performance',['../bench.html',1,'']]], + ['posix_1',['Posix',['../group__posix.html',1,'']]] ]; diff --git a/docs/search/all_c.js b/docs/search/all_c.js index 192fb1cb..d0a080fe 100644 --- a/docs/search/all_c.js +++ b/docs/search/all_c.js @@ -1,4 +1,6 @@ var searchData= [ - ['zero_20initialized_20re_2dallocation_170',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] + ['re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['reserved_1',['reserved',['../group__analysis.html#ae848a3e6840414891035423948ca0383',1,'mi_heap_area_t']]], + ['runtime_20options_2',['Runtime Options',['../group__options.html',1,'']]] ]; diff --git a/docs/search/all_d.js b/docs/search/all_d.js index 2b9b4cea..2cce101a 100644 --- a/docs/search/all_d.js +++ b/docs/search/all_d.js @@ -1,4 +1,5 @@ var searchData= [ - ['zero_20initialized_20re_2dallocation',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] + ['the_20library_0',['Using the library',['../using.html',1,'']]], + ['typed_20macros_1',['Typed Macros',['../group__typed.html',1,'']]] ]; diff --git a/docs/search/classes_0.js b/docs/search/classes_0.js index e3770fb4..5ba18706 100644 --- a/docs/search/classes_0.js +++ b/docs/search/classes_0.js @@ -1,5 +1,5 @@ var searchData= [ - ['mi_5fheap_5farea_5ft_171',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], - ['mi_5fstl_5fallocator_172',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]] + ['mi_5fheap_5farea_5ft_0',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], + ['mi_5fstl_5fallocator_1',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]] ]; diff --git a/docs/search/enums_0.js b/docs/search/enums_0.js index 6f1f3833..9bc2f56b 100644 --- a/docs/search/enums_0.js +++ b/docs/search/enums_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['mi_5foption_5ft_296',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]] + ['mi_5foption_5ft_0',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]] ]; diff --git a/docs/search/enumvalues_0.js b/docs/search/enumvalues_0.js index 1aca63bb..cd7bb419 100644 --- a/docs/search/enumvalues_0.js +++ b/docs/search/enumvalues_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['_5fmi_5foption_5flast_297',['_mi_option_last',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a',1,'mimalloc-doc.h']]] + ['_5fmi_5foption_5flast_0',['_mi_option_last',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a',1,'mimalloc-doc.h']]] ]; diff --git a/docs/search/enumvalues_1.js b/docs/search/enumvalues_1.js index bd525bb8..d40f943b 100644 --- a/docs/search/enumvalues_1.js +++ b/docs/search/enumvalues_1.js @@ -1,19 +1,31 @@ var searchData= [ - ['mi_5foption_5feager_5fcommit_298',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_5fdelay_299',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fregion_5fcommit_300',['mi_option_eager_region_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad',1,'mimalloc-doc.h']]], - ['mi_5foption_5flarge_5fos_5fpages_301',['mi_option_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e',1,'mimalloc-doc.h']]], - ['mi_5foption_5fos_5ftag_302',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpage_5freset_303',['mi_option_page_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_304',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_305',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdecommits_306',['mi_option_reset_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdelay_307',['mi_option_reset_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5fcache_308',['mi_option_segment_cache',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsegment_5freset_309',['mi_option_segment_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5ferrors_310',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5fstats_311',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], - ['mi_5foption_5fuse_5fnuma_5fnodes_312',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], - ['mi_5foption_5fverbose_313',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]] + ['mi_5foption_5fabandoned_5fpage_5fpurge_0',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_1',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], + ['mi_5foption_5fallow_5flarge_5fos_5fpages_2',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5feager_5fcommit_3',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5fpurge_5fmult_4',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5freserve_5',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdestroy_5fon_5fexit_6',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5farena_5falloc_7',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5fos_5falloc_8',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_9',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay_10',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], + ['mi_5foption_5flimit_5fos_5falloc_11',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5ferrors_12',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fsegment_5freclaim_13',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fwarnings_14',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag_15',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdecommits_16',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdelay_17',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fextend_5fdelay_18',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_19',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_20',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fos_5fmemory_21',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], + ['mi_5foption_5fretry_5fon_5foom_22',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5ferrors_23',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5fstats_24',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], + ['mi_5foption_5fuse_5fnuma_5fnodes_25',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], + ['mi_5foption_5fverbose_26',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], + ['mi_5foption_5fvisit_5fabandoned_27',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]] ]; diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js index b44917a5..5a8d20d0 100644 --- a/docs/search/functions_0.js +++ b/docs/search/functions_0.js @@ -1,116 +1,137 @@ var searchData= [ - ['mi_5f_5fposix_5fmemalign_173',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], - ['mi_5faligned_5falloc_174',['mi_aligned_alloc',['../group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_175',['mi_calloc',['../group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_176',['mi_calloc_aligned',['../group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_5fat_177',['mi_calloc_aligned_at',['../group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3',1,'mimalloc-doc.h']]], - ['mi_5fcfree_178',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], - ['mi_5fcheck_5fowned_179',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], - ['mi_5fcollect_180',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], - ['mi_5fexpand_181',['mi_expand',['../group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4',1,'mimalloc-doc.h']]], - ['mi_5ffree_182',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], - ['mi_5ffree_5faligned_183',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_184',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_5faligned_185',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], - ['mi_5fgood_5fsize_186',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_187',['mi_heap_calloc',['../group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_188',['mi_heap_calloc_aligned',['../group__heap.html#ga4af03a6e2b93fae77424d93f889705c3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_5fat_189',['mi_heap_calloc_aligned_at',['../group__heap.html#ga08ca6419a5c057a4d965868998eef487',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcheck_5fowned_190',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcollect_191',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcontains_5fblock_192',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdelete_193',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdestroy_194',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fbacking_195',['mi_heap_get_backing',['../group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fdefault_196',['mi_heap_get_default',['../group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_197',['mi_heap_malloc',['../group__heap.html#ga9cbed01e42c0647907295de92c3fa296',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_198',['mi_heap_malloc_aligned',['../group__heap.html#gab5b87e1805306f70df38789fcfcf6653',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_5fat_199',['mi_heap_malloc_aligned_at',['../group__heap.html#ga23acd7680fb0976dde3783254c6c874b',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5fsmall_200',['mi_heap_malloc_small',['../group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_201',['mi_heap_mallocn',['../group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_202',['mi_heap_new',['../group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_203',['mi_heap_realloc',['../group__heap.html#gaaef3395f66be48f37bdc8322509c5d81',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_204',['mi_heap_realloc_aligned',['../group__heap.html#gafc603b696bd14cae6da28658f950d98c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_5fat_205',['mi_heap_realloc_aligned_at',['../group__heap.html#gaf96c788a1bf553fe2d371de9365e047c',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocf_206',['mi_heap_reallocf',['../group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_207',['mi_heap_reallocn',['../group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealpath_208',['mi_heap_realpath',['../group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_209',['mi_heap_recalloc',['../group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_210',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_5fat_211',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_212',['mi_heap_rezalloc',['../group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_213',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_5fat_214',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fset_5fdefault_215',['mi_heap_set_default',['../group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrdup_216',['mi_heap_strdup',['../group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrndup_217',['mi_heap_strndup',['../group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fvisit_5fblocks_218',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_219',['mi_heap_zalloc',['../group__heap.html#ga903104592c8ed53417a3762da6241133',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_220',['mi_heap_zalloc_aligned',['../group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_5fat_221',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga45fb43a62776fbebbdf1edd99b527954',1,'mimalloc-doc.h']]], - ['mi_5fis_5fin_5fheap_5fregion_222',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], - ['mi_5fis_5fredirected_223',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_224',['mi_malloc',['../group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_225',['mi_malloc_aligned',['../group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_5fat_226',['mi_malloc_aligned_at',['../group__aligned.html#ga5850da130c936bd77db039dcfbc8295d',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsize_227',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsmall_228',['mi_malloc_small',['../group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fusable_5fsize_229',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_230',['mi_mallocn',['../group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_231',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], - ['mi_5fmemalign_232',['mi_memalign',['../group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e',1,'mimalloc-doc.h']]], - ['mi_5fnew_233',['mi_new',['../group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_234',['mi_new_aligned',['../group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_5fnothrow_235',['mi_new_aligned_nothrow',['../group__cpp.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fn_236',['mi_new_n',['../group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fnothrow_237',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]], - ['mi_5fnew_5frealloc_238',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]], - ['mi_5fnew_5freallocn_239',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisable_240',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_241',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_242',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fis_5fenabled_243',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_244',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fdefault_245',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_246',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_5fdefault_247',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], - ['mi_5fposix_5fmemalign_248',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo_249',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], - ['mi_5fpvalloc_250',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], - ['mi_5frealloc_251',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_252',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_5fat_253',['mi_realloc_aligned_at',['../group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb',1,'mimalloc-doc.h']]], - ['mi_5freallocarr_254',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], - ['mi_5freallocarray_255',['mi_reallocarray',['../group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088',1,'mimalloc-doc.h']]], - ['mi_5freallocf_256',['mi_reallocf',['../group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0',1,'mimalloc-doc.h']]], - ['mi_5freallocn_257',['mi_reallocn',['../group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853',1,'mimalloc-doc.h']]], - ['mi_5frealpath_258',['mi_realpath',['../group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_259',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_260',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_5fat_261',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]], - ['mi_5fregister_5fdeferred_5ffree_262',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], - ['mi_5fregister_5ferror_263',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], - ['mi_5fregister_5foutput_264',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_265',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_266',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_267',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_268',['mi_rezalloc',['../group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_269',['mi_rezalloc_aligned',['../group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_5fat_270',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fmerge_271',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_272',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_5fout_273',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset_274',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], - ['mi_5fstrdup_275',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], - ['mi_5fstrndup_276',['mi_strndup',['../group__malloc.html#gaaabf971c2571891433477e2d21a35266',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone_277',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit_278',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint_5fout_279',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], - ['mi_5fusable_5fsize_280',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], - ['mi_5fvalloc_281',['mi_valloc',['../group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_282',['mi_zalloc',['../group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_283',['mi_zalloc_aligned',['../group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_5fat_284',['mi_zalloc_aligned_at',['../group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5fsmall_285',['mi_zalloc_small',['../group__extended.html#ga220f29f40a44404b0061c15bc1c31152',1,'mimalloc-doc.h']]] + ['mi_5f_5fexpand_0',['mi__expand',['../group__posix.html#ga66bcfeb4faedbb42b796bc680821ef84',1,'mimalloc-doc.h']]], + ['mi_5f_5fposix_5fmemalign_1',['mi__posix_memalign',['../group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a',1,'mimalloc-doc.h']]], + ['mi_5fabandoned_5fvisit_5fblocks_2',['mi_abandoned_visit_blocks',['../group__analysis.html#ga6a4865a887b2ec5247854af61562503c',1,'mimalloc-doc.h']]], + ['mi_5faligned_5falloc_3',['mi_aligned_alloc',['../group__posix.html#ga430ed1513f0571ff83be00ec58a98ee0',1,'mimalloc-doc.h']]], + ['mi_5faligned_5foffset_5frecalloc_4',['mi_aligned_offset_recalloc',['../group__posix.html#ga16570deddd559001b44953eedbad0084',1,'mimalloc-doc.h']]], + ['mi_5faligned_5frecalloc_5',['mi_aligned_recalloc',['../group__posix.html#gaf82cbb4b4f24acf723348628451798d3',1,'mimalloc-doc.h']]], + ['mi_5farena_5farea_6',['mi_arena_area',['../group__extended.html#ga9a25a00a22151619a0be91a10af7787f',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_7',['mi_calloc',['../group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_8',['mi_calloc_aligned',['../group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_5fat_9',['mi_calloc_aligned_at',['../group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3',1,'mimalloc-doc.h']]], + ['mi_5fcfree_10',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], + ['mi_5fcheck_5fowned_11',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], + ['mi_5fcollect_12',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], + ['mi_5fdebug_5fshow_5farenas_13',['mi_debug_show_arenas',['../group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7',1,'mimalloc-doc.h']]], + ['mi_5fdupenv_5fs_14',['mi_dupenv_s',['../group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958',1,'mimalloc-doc.h']]], + ['mi_5fexpand_15',['mi_expand',['../group__malloc.html#ga19299856216cfbb08e2628593654dfb0',1,'mimalloc-doc.h']]], + ['mi_5ffree_16',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], + ['mi_5ffree_5faligned_17',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_18',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_5faligned_19',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], + ['mi_5fgood_5fsize_20',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_21',['mi_heap_calloc',['../group__heap.html#gac0098aaf231d3e9586c73136d5df95da',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_22',['mi_heap_calloc_aligned',['../group__heap.html#gacafcc26df827c7a7de5e850217566108',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_5fat_23',['mi_heap_calloc_aligned_at',['../group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcheck_5fowned_24',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcollect_25',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcontains_5fblock_26',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdelete_27',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdestroy_28',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fbacking_29',['mi_heap_get_backing',['../group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fdefault_30',['mi_heap_get_default',['../group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_31',['mi_heap_malloc',['../group__heap.html#gab374e206c7034e0d899fb934e4f4a863',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_32',['mi_heap_malloc_aligned',['../group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_5fat_33',['mi_heap_malloc_aligned_at',['../group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5fsmall_34',['mi_heap_malloc_small',['../group__heap.html#ga012c5c8abe22b10043de39ff95909541',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_35',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_36',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fin_5farena_37',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_38',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_39',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_5fat_40',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocf_41',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_42',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealpath_43',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_44',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_45',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat_46',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_47',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_48',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat_49',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fset_5fdefault_50',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrdup_51',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrndup_52',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fvisit_5fblocks_53',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_54',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_55',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_5fat_56',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion_57',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected_58',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_59',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_60',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_5fat_61',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fgood_5fsize_62',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsize_63',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsmall_64',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fusable_5fsize_65',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_66',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_67',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_5fex_68',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], + ['mi_5fmbsdup_69',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], + ['mi_5fmemalign_70',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], + ['mi_5fnew_71',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_72',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_5fnothrow_73',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fn_74',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fnothrow_75',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], + ['mi_5fnew_5frealloc_76',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], + ['mi_5fnew_5freallocn_77',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable_78',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable_79',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_80',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fclamp_81',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fsize_82',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled_83',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_84',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fdefault_85',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_86',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault_87',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], + ['mi_5fposix_5fmemalign_88',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo_89',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], + ['mi_5fpvalloc_90',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], + ['mi_5frealloc_91',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_92',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_5fat_93',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], + ['mi_5freallocarr_94',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], + ['mi_5freallocarray_95',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], + ['mi_5freallocf_96',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], + ['mi_5freallocn_97',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], + ['mi_5frealpath_98',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_99',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_100',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat_101',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], + ['mi_5fregister_5fdeferred_5ffree_102',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], + ['mi_5fregister_5ferror_103',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput_104',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_105',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_106',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_107',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_108',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_5fex_109',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_110',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_111',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat_112',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge_113',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_114',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout_115',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset_116',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], + ['mi_5fstrdup_117',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], + ['mi_5fstrndup_118',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fadd_5fcurrent_5fthread_119',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fdelete_120',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fmain_121',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fnew_122',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone_123',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit_124',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint_5fout_125',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], + ['mi_5fusable_5fsize_126',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], + ['mi_5fvalloc_127',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], + ['mi_5fwcsdup_128',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], + ['mi_5fwdupenv_5fs_129',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_130',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_131',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_5fat_132',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5fsmall_133',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]] ]; diff --git a/docs/search/groups_0.js b/docs/search/groups_0.js index 0ed99b80..d371a399 100644 --- a/docs/search/groups_0.js +++ b/docs/search/groups_0.js @@ -1,4 +1,6 @@ var searchData= [ - ['aligned_20allocation_314',['Aligned Allocation',['../group__aligned.html',1,'']]] + ['aligned_20allocation_0',['Aligned Allocation',['../group__aligned.html',1,'']]], + ['allocation_1',['Allocation',['../group__aligned.html',1,'Aligned Allocation'],['../group__malloc.html',1,'Basic Allocation'],['../group__heap.html',1,'Heap Allocation']]], + ['allocation_2',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] ]; diff --git a/docs/search/groups_1.js b/docs/search/groups_1.js index f27c5847..8fca2717 100644 --- a/docs/search/groups_1.js +++ b/docs/search/groups_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['basic_20allocation_315',['Basic Allocation',['../group__malloc.html',1,'']]] + ['basic_20allocation_0',['Basic Allocation',['../group__malloc.html',1,'']]] ]; diff --git a/docs/search/groups_2.js b/docs/search/groups_2.js index 6da64b68..d260dec8 100644 --- a/docs/search/groups_2.js +++ b/docs/search/groups_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['c_2b_2b_20wrappers_316',['C++ wrappers',['../group__cpp.html',1,'']]] + ['c_20wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]] ]; diff --git a/docs/search/groups_3.js b/docs/search/groups_3.js index cdfbe640..7099da01 100644 --- a/docs/search/groups_3.js +++ b/docs/search/groups_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['extended_20functions_317',['Extended Functions',['../group__extended.html',1,'']]] + ['extended_20functions_0',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/docs/search/groups_4.js b/docs/search/groups_4.js index 687f1ea7..87efcce9 100644 --- a/docs/search/groups_4.js +++ b/docs/search/groups_4.js @@ -1,5 +1,4 @@ var searchData= [ - ['heap_20allocation_318',['Heap Allocation',['../group__heap.html',1,'']]], - ['heap_20introspection_319',['Heap Introspection',['../group__analysis.html',1,'']]] + ['functions_0',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/docs/search/groups_5.js b/docs/search/groups_5.js index 43c8b1fc..3131f4a2 100644 --- a/docs/search/groups_5.js +++ b/docs/search/groups_5.js @@ -1,4 +1,5 @@ var searchData= [ - ['posix_320',['Posix',['../group__posix.html',1,'']]] + ['heap_20allocation_0',['Heap Allocation',['../group__heap.html',1,'']]], + ['heap_20introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] ]; diff --git a/docs/search/groups_6.js b/docs/search/groups_6.js index 34631879..6d208432 100644 --- a/docs/search/groups_6.js +++ b/docs/search/groups_6.js @@ -1,4 +1,5 @@ var searchData= [ - ['runtime_20options_321',['Runtime Options',['../group__options.html',1,'']]] + ['initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] ]; diff --git a/docs/search/groups_7.js b/docs/search/groups_7.js index aa150e97..aafc4dae 100644 --- a/docs/search/groups_7.js +++ b/docs/search/groups_7.js @@ -1,4 +1,4 @@ var searchData= [ - ['typed_20macros_322',['Typed Macros',['../group__typed.html',1,'']]] + ['macros_0',['Typed Macros',['../group__typed.html',1,'']]] ]; diff --git a/docs/search/groups_8.js b/docs/search/groups_8.js index f9c29fe3..30681f7b 100644 --- a/docs/search/groups_8.js +++ b/docs/search/groups_8.js @@ -1,4 +1,4 @@ var searchData= [ - ['zero_20initialized_20re_2dallocation_323',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] + ['options_0',['Runtime Options',['../group__options.html',1,'']]] ]; diff --git a/docs/search/pages_0.js b/docs/search/pages_0.js index 07922dae..9c92133c 100644 --- a/docs/search/pages_0.js +++ b/docs/search/pages_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['building_324',['Building',['../build.html',1,'']]] + ['building_0',['Building',['../build.html',1,'']]] ]; diff --git a/docs/search/pages_1.js b/docs/search/pages_1.js index 6433daec..4e3b12ee 100644 --- a/docs/search/pages_1.js +++ b/docs/search/pages_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['environment_20options_325',['Environment Options',['../environment.html',1,'']]] + ['environment_20options_0',['Environment Options',['../environment.html',1,'']]] ]; diff --git a/docs/search/pages_2.js b/docs/search/pages_2.js index 7577377b..5071ed69 100644 --- a/docs/search/pages_2.js +++ b/docs/search/pages_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['overriding_20malloc_326',['Overriding Malloc',['../overrides.html',1,'']]] + ['library_0',['Using the library',['../using.html',1,'']]] ]; diff --git a/docs/search/pages_3.js b/docs/search/pages_3.js index d62a3cfd..4c761a08 100644 --- a/docs/search/pages_3.js +++ b/docs/search/pages_3.js @@ -1,4 +1,6 @@ var searchData= [ - ['performance_327',['Performance',['../bench.html',1,'']]] + ['malloc_0',['Overriding Malloc',['../overrides.html',1,'']]], + ['malloc_1',['mi-malloc',['../index.html',1,'']]], + ['mi_20malloc_2',['mi-malloc',['../index.html',1,'']]] ]; diff --git a/docs/search/pages_4.js b/docs/search/pages_4.js index 4e4e64dc..a0c748ac 100644 --- a/docs/search/pages_4.js +++ b/docs/search/pages_4.js @@ -1,4 +1,5 @@ var searchData= [ - ['using_20the_20library_328',['Using the library',['../using.html',1,'']]] + ['options_0',['Environment Options',['../environment.html',1,'']]], + ['overriding_20malloc_1',['Overriding Malloc',['../overrides.html',1,'']]] ]; diff --git a/docs/search/search.css b/docs/search/search.css index d30e0274..190ed7fd 100644 --- a/docs/search/search.css +++ b/docs/search/search.css @@ -1,100 +1,111 @@ /*---------------- Search Box */ -#FSearchBox { - float: left; +#MSearchBox { + position: absolute; + right: 5px; +} +/*---------------- Search box styling */ + +.SRPage * { + font-weight: normal; + line-height: normal; +} + +dark-mode-toggle { + margin-left: 5px; + display: flex; + float: right; } #MSearchBox { + display: inline-block; white-space : nowrap; - float: none; - margin-top: 0px; - right: 0px; - width: 170px; - height: 24px; + background: white; + border-radius: 0.65em; + box-shadow: inset 0.5px 0.5px 3px 0px #555; z-index: 102; - display: inline; - position: absolute; } -#MSearchBox .left -{ - display:block; - position:absolute; - left:10px; - width:20px; - height:19px; - background:url('search_l.png') no-repeat; - background-position:right; +#MSearchBox .left { + display: inline-block; + vertical-align: middle; + height: 1.4em; } #MSearchSelect { - display:block; - position:absolute; - width:20px; - height:19px; + display: inline-block; + vertical-align: middle; + width: 20px; + height: 19px; + background-image: url('mag_sel.svg'); + margin: 0 0 0 0.3em; + padding: 0; } -.left #MSearchSelect { - left:4px; +#MSearchSelectExt { + display: inline-block; + vertical-align: middle; + width: 10px; + height: 19px; + background-image: url('mag.svg'); + margin: 0 0 0 0.5em; + padding: 0; } -.right #MSearchSelect { - right:5px; -} #MSearchField { - display:block; - position:absolute; - height:19px; - background:url('search_m.png') repeat-x; + display: inline-block; + vertical-align: middle; + width: 7.5em; + height: 19px; + margin: 0 0.15em; + padding: 0; + line-height: 1em; border:none; - width:111px; - margin-left:20px; - padding-left:4px; color: #909090; outline: none; - font: 9pt Arial, Verdana, sans-serif; + font-family: Arial,Verdana,sans-serif; -webkit-border-radius: 0px; + border-radius: 0px; + background: none; } -#FSearchBox #MSearchField { - margin-left:15px; +@media(hover: none) { + /* to avoid zooming on iOS */ + #MSearchField { + font-size: 16px; + } } #MSearchBox .right { - display:block; - position:absolute; - right:10px; - top:0px; - width:20px; - height:19px; - background:url('search_r.png') no-repeat; - background-position:left; + display: inline-block; + vertical-align: middle; + width: 1.4em; + height: 1.4em; } #MSearchClose { display: none; - position: absolute; - top: 4px; + font-size: inherit; background : none; border: none; - margin: 0px 4px 0px 0px; - padding: 0px 0px; + margin: 0; + padding: 0; outline: none; + } -.left #MSearchClose { - left: 6px; -} - -.right #MSearchClose { - right: 2px; +#MSearchCloseImg { + padding: 0.3em; + margin: 0; } .MSearchBoxActive #MSearchField { - color: #000000; + color: black; } + + /*---------------- Search filter selection */ #MSearchSelectWindow { @@ -115,7 +126,7 @@ } .SelectItem { - font: 8pt Arial, Verdana, sans-serif; + font: 8pt Arial,Verdana,sans-serif; padding-left: 2px; padding-right: 12px; border: 0px; @@ -123,7 +134,7 @@ span.SelectionMark { margin-right: 4px; - font-family: monospace; + font-family: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; outline-style: none; text-decoration: none; } @@ -131,7 +142,7 @@ span.SelectionMark { a.SelectItem { display: block; outline-style: none; - color: #000000; + color: black; text-decoration: none; padding-left: 6px; padding-right: 12px; @@ -139,13 +150,13 @@ a.SelectItem { a.SelectItem:focus, a.SelectItem:active { - color: #000000; + color: black; outline-style: none; text-decoration: none; } a.SelectItem:hover { - color: #FFFFFF; + color: white; background-color: #0F1010; outline-style: none; text-decoration: none; @@ -156,7 +167,7 @@ a.SelectItem:hover { /*---------------- Search results window */ iframe#MSearchResults { - width: 60ex; + /*width: 60ex;*/ height: 15em; } @@ -164,17 +175,19 @@ iframe#MSearchResults { display: none; position: absolute; left: 0; top: 0; - border: 1px solid #000; + border: 1px solid black; background-color: #DADDDE; z-index:10000; + width: 300px; + height: 400px; + overflow: auto; } /* ----------------------------------- */ #SRIndex { - clear:both; - padding-bottom: 15px; + clear:both; } .SREntry { @@ -187,12 +200,13 @@ iframe#MSearchResults { padding: 1px 5px; } -body.SRPage { +div.SRPage { margin: 5px 2px; + background-color: #DADDDE; } .SRChildren { - padding-left: 3ex; padding-bottom: .5em + padding-left: 3ex; padding-bottom: .5em } .SRPage .SRChildren { @@ -202,7 +216,7 @@ body.SRPage { .SRSymbol { font-weight: bold; color: #121414; - font-family: Arial, Verdana, sans-serif; + font-family: Arial,Verdana,sans-serif; text-decoration: none; outline: none; } @@ -210,7 +224,8 @@ body.SRPage { a.SRScope { display: block; color: #121414; - font-family: Arial, Verdana, sans-serif; + font-family: Arial,Verdana,sans-serif; + font-size: 8pt; text-decoration: none; outline: none; } @@ -222,29 +237,27 @@ a.SRScope:focus, a.SRScope:active { span.SRScope { padding-left: 4px; + font-family: Arial,Verdana,sans-serif; } .SRPage .SRStatus { padding: 2px 5px; font-size: 8pt; font-style: italic; + font-family: Arial,Verdana,sans-serif; } .SRResult { display: none; } -DIV.searchresults { +div.searchresults { margin-left: 10px; margin-right: 10px; } /*---------------- External search page results */ -.searchresult { - background-color: #DFE1E2; -} - .pages b { color: white; padding: 5px 5px 3px 5px; @@ -270,3 +283,4 @@ DIV.searchresults { .searchpages { margin-top: 10px; } + diff --git a/docs/search/search.js b/docs/search/search.js index fb226f73..666af01e 100644 --- a/docs/search/search.js +++ b/docs/search/search.js @@ -22,56 +22,9 @@ @licend The above is the entire license notice for the JavaScript code in this file */ -function convertToId(search) -{ - var result = ''; - for (i=0;i document.getElementById("MSearchField"); + this.DOMSearchSelect = () => document.getElementById("MSearchSelect"); + this.DOMSearchSelectWindow = () => document.getElementById("MSearchSelectWindow"); + this.DOMPopupSearchResults = () => document.getElementById("MSearchResults"); + this.DOMPopupSearchResultsWindow = () => document.getElementById("MSearchResultsWindow"); + this.DOMSearchClose = () => document.getElementById("MSearchClose"); + this.DOMSearchBox = () => document.getElementById("MSearchBox"); // ------------ Event Handlers // Called when focus is added or removed from the search field. - this.OnSearchFieldFocus = function(isActive) - { + this.OnSearchFieldFocus = function(isActive) { this.Activate(isActive); } - this.OnSearchSelectShow = function() - { - var searchSelectWindow = this.DOMSearchSelectWindow(); - var searchField = this.DOMSearchSelect(); + this.OnSearchSelectShow = function() { + const searchSelectWindow = this.DOMSearchSelectWindow(); + const searchField = this.DOMSearchSelect(); - if (this.insideFrame) - { - var left = getXPos(searchField); - var top = getYPos(searchField); - left += searchField.offsetWidth + 6; - top += searchField.offsetHeight; + const left = getXPos(searchField); + const top = getYPos(searchField) + searchField.offsetHeight; - // show search selection popup - searchSelectWindow.style.display='block'; - left -= searchSelectWindow.offsetWidth; - searchSelectWindow.style.left = left + 'px'; - searchSelectWindow.style.top = top + 'px'; - } - else - { - var left = getXPos(searchField); - var top = getYPos(searchField); - top += searchField.offsetHeight; - - // show search selection popup - searchSelectWindow.style.display='block'; - searchSelectWindow.style.left = left + 'px'; - searchSelectWindow.style.top = top + 'px'; - } + // show search selection popup + searchSelectWindow.style.display='block'; + searchSelectWindow.style.left = left + 'px'; + searchSelectWindow.style.top = top + 'px'; // stop selection hide timer - if (this.hideTimeout) - { + if (this.hideTimeout) { clearTimeout(this.hideTimeout); this.hideTimeout=0; } return false; // to avoid "image drag" default event } - this.OnSearchSelectHide = function() - { - this.hideTimeout = setTimeout(this.name +".CloseSelectionWindow()", + this.OnSearchSelectHide = function() { + this.hideTimeout = setTimeout(this.CloseSelectionWindow.bind(this), this.closeSelectionTimeout); } // Called when the content of the search field is changed. - this.OnSearchFieldChange = function(evt) - { - if (this.keyTimeout) // kill running timer - { + this.OnSearchFieldChange = function(evt) { + if (this.keyTimeout) { // kill running timer clearTimeout(this.keyTimeout); this.keyTimeout = 0; } - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==40 || e.keyCode==13) - { - if (e.shiftKey==1) - { + const e = evt ? evt : window.event; // for IE + if (e.keyCode==40 || e.keyCode==13) { + if (e.shiftKey==1) { this.OnSearchSelectShow(); - var win=this.DOMSearchSelectWindow(); - for (i=0;i do a search - { + const searchValue = this.DOMSearchField().value.replace(/ +/g, ""); + if (searchValue!="" && this.searchActive) { // something was found -> do a search this.Search(); } } - this.OnSearchSelectKey = function(evt) - { - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==40 && this.searchIndex0) // Up - { + } else if (e.keyCode==38 && this.searchIndex>0) { // Up this.searchIndex--; this.OnSelectItem(this.searchIndex); - } - else if (e.keyCode==13 || e.keyCode==27) - { + } else if (e.keyCode==13 || e.keyCode==27) { + e.stopPropagation(); this.OnSelectItem(this.searchIndex); this.CloseSelectionWindow(); this.DOMSearchField().focus(); @@ -314,111 +239,108 @@ function SearchBox(name, resultsPath, inFrame, label, extension) // --------- Actions // Closes the results window. - this.CloseResultsWindow = function() - { + this.CloseResultsWindow = function() { this.DOMPopupSearchResultsWindow().style.display = 'none'; this.DOMSearchClose().style.display = 'none'; this.Activate(false); } - this.CloseSelectionWindow = function() - { + this.CloseSelectionWindow = function() { this.DOMSearchSelectWindow().style.display = 'none'; } // Performs a search. - this.Search = function() - { + this.Search = function() { this.keyTimeout = 0; // strip leading whitespace - var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + const searchValue = this.DOMSearchField().value.replace(/^ +/, ""); - var code = searchValue.toLowerCase().charCodeAt(0); - var idxChar = searchValue.substr(0, 1).toLowerCase(); - if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair - { + const code = searchValue.toLowerCase().charCodeAt(0); + let idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) { // surrogate pair idxChar = searchValue.substr(0, 2); } - var resultsPage; - var resultsPageWithSearch; - var hasResultsPage; - - var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); - if (idx!=-1) - { - var hexCode=idx.toString(16); - resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + this.extension; - resultsPageWithSearch = resultsPage+'?'+escape(searchValue); - hasResultsPage = true; - } - else // nothing available for this search term - { - resultsPage = this.resultsPath + '/nomatches' + this.extension; - resultsPageWithSearch = resultsPage; - hasResultsPage = false; + let jsFile; + let idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) { + const hexCode=idx.toString(16); + jsFile = this.resultsPath + indexSectionNames[this.searchIndex] + '_' + hexCode + '.js'; } - window.frames.MSearchResults.location = resultsPageWithSearch; - var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + const loadJS = function(url, impl, loc) { + const scriptTag = document.createElement('script'); + scriptTag.src = url; + scriptTag.onload = impl; + scriptTag.onreadystatechange = impl; + loc.appendChild(scriptTag); + } - if (domPopupSearchResultsWindow.style.display!='block') - { - var domSearchBox = this.DOMSearchBox(); - this.DOMSearchClose().style.display = 'inline-block'; - if (this.insideFrame) - { - var domPopupSearchResults = this.DOMPopupSearchResults(); - domPopupSearchResultsWindow.style.position = 'relative'; - domPopupSearchResultsWindow.style.display = 'block'; - var width = document.body.clientWidth - 8; // the -8 is for IE :-( - domPopupSearchResultsWindow.style.width = width + 'px'; - domPopupSearchResults.style.width = width + 'px'; - } - else - { - var domPopupSearchResults = this.DOMPopupSearchResults(); - var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; - var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; - domPopupSearchResultsWindow.style.display = 'block'; - left -= domPopupSearchResults.offsetWidth; - domPopupSearchResultsWindow.style.top = top + 'px'; - domPopupSearchResultsWindow.style.left = left + 'px'; - } + const domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + const domSearchBox = this.DOMSearchBox(); + const domPopupSearchResults = this.DOMPopupSearchResults(); + const domSearchClose = this.DOMSearchClose(); + const resultsPath = this.resultsPath; + + const handleResults = function() { + document.getElementById("Loading").style.display="none"; + if (typeof searchData !== 'undefined') { + createResults(resultsPath); + document.getElementById("NoMatches").style.display="none"; + } + + if (idx!=-1) { + searchResults.Search(searchValue); + } else { // no file with search results => force empty search results + searchResults.Search('===='); + } + + if (domPopupSearchResultsWindow.style.display!='block') { + domSearchClose.style.display = 'inline-block'; + let left = getXPos(domSearchBox) + 150; + let top = getYPos(domSearchBox) + 20; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + const maxWidth = document.body.clientWidth; + const maxHeight = document.body.clientHeight; + let width = 300; + if (left<10) left=10; + if (width+left+8>maxWidth) width=maxWidth-left-8; + let height = 400; + if (height+top+8>maxHeight) height=maxHeight-top-8; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResultsWindow.style.height = height + 'px'; + } + } + + if (jsFile) { + loadJS(jsFile, handleResults, this.DOMPopupSearchResultsWindow()); + } else { + handleResults(); } this.lastSearchValue = searchValue; - this.lastResultsPage = resultsPage; } // -------- Activation Functions // Activates or deactivates the search panel, resetting things to // their default values if necessary. - this.Activate = function(isActive) - { + this.Activate = function(isActive) { if (isActive || // open it - this.DOMPopupSearchResultsWindow().style.display == 'block' - ) - { + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) { this.DOMSearchBox().className = 'MSearchBoxActive'; - - var searchField = this.DOMSearchField(); - - if (searchField.value == this.searchLabel) // clear "Search" term upon entry - { - searchField.value = ''; - this.searchActive = true; - } - } - else if (!isActive) // directly remove the panel - { + this.searchActive = true; + } else if (!isActive) { // directly remove the panel this.DOMSearchBox().className = 'MSearchBoxInactive'; - this.DOMSearchField().value = this.searchLabel; this.searchActive = false; this.lastSearchValue = '' this.lastResultsPage = ''; + this.DOMSearchField().value = ''; } } } @@ -426,391 +348,347 @@ function SearchBox(name, resultsPath, inFrame, label, extension) // ----------------------------------------------------------------------- // The class that handles everything on the search results page. -function SearchResults(name) -{ - // The number of matches from the last run of . - this.lastMatchCount = 0; - this.lastKey = 0; - this.repeatOn = false; +function SearchResults() { - // Toggles the visibility of the passed element ID. - this.FindChildElement = function(id) - { - var parentElement = document.getElementById(id); - var element = parentElement.firstChild; + function convertToId(search) { + let result = ''; + for (let i=0;i. + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) { + const parentElement = document.getElementById(id); + let element = parentElement.firstChild; + + while (element && element!=parentElement) { + if (element.nodeName.toLowerCase() == 'div' && element.className == 'SRChildren') { + return element; + } + + if (element.nodeName.toLowerCase() == 'div' && element.hasChildNodes()) { + element = element.firstChild; + } else if (element.nextSibling) { + element = element.nextSibling; + } else { + do { + element = element.parentNode; } + while (element && element!=parentElement && !element.nextSibling); - if (element.nodeName.toLowerCase() == 'div' && element.hasChildNodes()) - { - element = element.firstChild; - } - else if (element.nextSibling) - { - element = element.nextSibling; - } - else - { - do - { - element = element.parentNode; - } - while (element && element!=parentElement && !element.nextSibling); - - if (element && element!=parentElement) - { - element = element.nextSibling; - } + if (element && element!=parentElement) { + element = element.nextSibling; } } } + } - this.Toggle = function(id) - { - var element = this.FindChildElement(id); - if (element) - { - if (element.style.display == 'block') - { - element.style.display = 'none'; - } - else - { - element.style.display = 'block'; - } + this.Toggle = function(id) { + const element = this.FindChildElement(id); + if (element) { + if (element.style.display == 'block') { + element.style.display = 'none'; + } else { + element.style.display = 'block'; } } + } - // Searches for the passed string. If there is no parameter, - // it takes it from the URL query. - // - // Always returns true, since other documents may try to call it - // and that may or may not be possible. - this.Search = function(search) - { - if (!search) // get search word from URL - { - search = window.location.search; - search = search.substring(1); // Remove the leading '?' - search = unescape(search); + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) { + if (!search) { // get search word from URL + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + const resultRows = document.getElementsByTagName("div"); + let matches = 0; + + let i = 0; + while (i < resultRows.length) { + const row = resultRows.item(i); + if (row.className == "SRResult") { + let rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) { + row.style.display = 'block'; + matches++; + } else { + row.style.display = 'none'; + } } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) { // no results + document.getElementById("NoMatches").style.display='block'; + } else { // at least one result + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } - search = search.replace(/^ +/, ""); // strip leading spaces - search = search.replace(/ +$/, ""); // strip trailing spaces - search = search.toLowerCase(); - search = convertToId(search); + // return the first item with index index or higher that is visible + this.NavNext = function(index) { + let focusItem; + for (;;) { + const focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { + break; + } else if (!focusItem) { // last element + break; + } + focusItem=null; + index++; + } + return focusItem; + } - var resultRows = document.getElementsByTagName("div"); - var matches = 0; + this.NavPrev = function(index) { + let focusItem; + for (;;) { + const focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { + break; + } else if (!focusItem) { // last element + break; + } + focusItem=null; + index--; + } + return focusItem; + } - var i = 0; - while (i < resultRows.length) - { - var row = resultRows.item(i); - if (row.className == "SRResult") - { - var rowMatchName = row.id.toLowerCase(); - rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + this.ProcessKeys = function(e) { + if (e.type == "keydown") { + this.repeatOn = false; + this.lastKey = e.keyCode; + } else if (e.type == "keypress") { + if (!this.repeatOn) { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } else if (e.type == "keyup") { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } - if (search.length<=rowMatchName.length && - rowMatchName.substr(0, search.length)==search) - { - row.style.display = 'block'; - matches++; - } - else - { - row.style.display = 'none'; + this.Nav = function(evt,itemIndex) { + const e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) { // Up + const newIndex = itemIndex-1; + let focusItem = this.NavPrev(newIndex); + if (focusItem) { + let child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') { // children visible + let n=0; + let tmpElem; + for (;;) { // search for last child + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) { + focusItem = tmpElem; + } else { // found it! + break; + } + n++; } } - i++; } - document.getElementById("Searching").style.display='none'; - if (matches == 0) // no results - { - document.getElementById("NoMatches").style.display='block'; + if (focusItem) { + focusItem.focus(); + } else { // return focus to search field + document.getElementById("MSearchField").focus(); } - else // at least one result - { - document.getElementById("NoMatches").style.display='none'; + } else if (this.lastKey==40) { // Down + const newIndex = itemIndex+1; + let focusItem; + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') { // children visible + focusItem = document.getElementById('Item'+itemIndex+'_c0'); } - this.lastMatchCount = matches; + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } else if (this.lastKey==39) { // Right + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } else if (this.lastKey==37) { // Left + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } else if (this.lastKey==27) { // Escape + e.stopPropagation(); + searchBox.CloseResultsWindow(); + document.getElementById("MSearchField").focus(); + } else if (this.lastKey==13) { // Enter return true; } + return false; + } - // return the first item with index index or higher that is visible - this.NavNext = function(index) - { - var focusItem; - while (1) - { - var focusName = 'Item'+index; - focusItem = document.getElementById(focusName); - if (focusItem && focusItem.parentNode.parentNode.style.display=='block') - { - break; - } - else if (!focusItem) // last element - { - break; - } - focusItem=null; - index++; + this.NavChild = function(evt,itemIndex,childIndex) { + const e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) { // Up + if (childIndex>0) { + const newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } else { // already at first child, jump to parent + document.getElementById('Item'+itemIndex).focus(); } - return focusItem; - } - - this.NavPrev = function(index) - { - var focusItem; - while (1) - { - var focusName = 'Item'+index; - focusItem = document.getElementById(focusName); - if (focusItem && focusItem.parentNode.parentNode.style.display=='block') - { - break; - } - else if (!focusItem) // last element - { - break; - } - focusItem=null; - index--; - } - return focusItem; - } - - this.ProcessKeys = function(e) - { - if (e.type == "keydown") - { - this.repeatOn = false; - this.lastKey = e.keyCode; - } - else if (e.type == "keypress") - { - if (!this.repeatOn) - { - if (this.lastKey) this.repeatOn = true; - return false; // ignore first keypress after keydown - } - } - else if (e.type == "keyup") - { - this.lastKey = 0; - this.repeatOn = false; - } - return this.lastKey!=0; - } - - this.Nav = function(evt,itemIndex) - { - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==13) return true; - if (!this.ProcessKeys(e)) return false; - - if (this.lastKey==38) // Up - { - var newIndex = itemIndex-1; - var focusItem = this.NavPrev(newIndex); - if (focusItem) - { - var child = this.FindChildElement(focusItem.parentNode.parentNode.id); - if (child && child.style.display == 'block') // children visible - { - var n=0; - var tmpElem; - while (1) // search for last child - { - tmpElem = document.getElementById('Item'+newIndex+'_c'+n); - if (tmpElem) - { - focusItem = tmpElem; - } - else // found it! - { - break; - } - n++; - } - } - } - if (focusItem) - { - focusItem.focus(); - } - else // return focus to search field - { - parent.document.getElementById("MSearchField").focus(); - } - } - else if (this.lastKey==40) // Down - { - var newIndex = itemIndex+1; - var focusItem; - var item = document.getElementById('Item'+itemIndex); - var elem = this.FindChildElement(item.parentNode.parentNode.id); - if (elem && elem.style.display == 'block') // children visible - { - focusItem = document.getElementById('Item'+itemIndex+'_c0'); - } - if (!focusItem) focusItem = this.NavNext(newIndex); - if (focusItem) focusItem.focus(); - } - else if (this.lastKey==39) // Right - { - var item = document.getElementById('Item'+itemIndex); - var elem = this.FindChildElement(item.parentNode.parentNode.id); - if (elem) elem.style.display = 'block'; - } - else if (this.lastKey==37) // Left - { - var item = document.getElementById('Item'+itemIndex); - var elem = this.FindChildElement(item.parentNode.parentNode.id); - if (elem) elem.style.display = 'none'; - } - else if (this.lastKey==27) // Escape - { - parent.searchBox.CloseResultsWindow(); - parent.document.getElementById("MSearchField").focus(); - } - else if (this.lastKey==13) // Enter - { - return true; - } - return false; - } - - this.NavChild = function(evt,itemIndex,childIndex) - { - var e = (evt) ? evt : window.event; // for IE - if (e.keyCode==13) return true; - if (!this.ProcessKeys(e)) return false; - - if (this.lastKey==38) // Up - { - if (childIndex>0) - { - var newIndex = childIndex-1; - document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); - } - else // already at first child, jump to parent - { - document.getElementById('Item'+itemIndex).focus(); - } - } - else if (this.lastKey==40) // Down - { - var newIndex = childIndex+1; - var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); - if (!elem) // last child, jump to parent next parent - { - elem = this.NavNext(itemIndex+1); - } - if (elem) - { - elem.focus(); - } - } - else if (this.lastKey==27) // Escape - { - parent.searchBox.CloseResultsWindow(); - parent.document.getElementById("MSearchField").focus(); - } - else if (this.lastKey==13) // Enter - { - return true; - } - return false; + } else if (this.lastKey==40) { // Down + const newIndex = childIndex+1; + let elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) { // last child, jump to parent next parent + elem = this.NavNext(itemIndex+1); + } + if (elem) { + elem.focus(); + } + } else if (this.lastKey==27) { // Escape + e.stopPropagation(); + searchBox.CloseResultsWindow(); + document.getElementById("MSearchField").focus(); + } else if (this.lastKey==13) { // Enter + return true; } + return false; + } } -function setKeyActions(elem,action) -{ - elem.setAttribute('onkeydown',action); - elem.setAttribute('onkeypress',action); - elem.setAttribute('onkeyup',action); -} +function createResults(resultsPath) { -function setClassAttr(elem,attr) -{ - elem.setAttribute('class',attr); - elem.setAttribute('className',attr); -} + function setKeyActions(elem,action) { + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); + } -function createResults() -{ - var results = document.getElementById("SRResults"); - for (var e=0; e { + const id = elem[0]; + const srResult = document.createElement('div'); srResult.setAttribute('id','SR_'+id); setClassAttr(srResult,'SRResult'); - var srEntry = document.createElement('div'); + const srEntry = document.createElement('div'); setClassAttr(srEntry,'SREntry'); - var srLink = document.createElement('a'); - srLink.setAttribute('id','Item'+e); - setKeyActions(srLink,'return searchResults.Nav(event,'+e+')'); + const srLink = document.createElement('a'); + srLink.setAttribute('id','Item'+index); + setKeyActions(srLink,'return searchResults.Nav(event,'+index+')'); setClassAttr(srLink,'SRSymbol'); - srLink.innerHTML = searchData[e][1][0]; + srLink.innerHTML = elem[1][0]; srEntry.appendChild(srLink); - if (searchData[e][1].length==2) // single result - { - srLink.setAttribute('href',searchData[e][1][1][0]); - if (searchData[e][1][1][1]) - { + if (elem[1].length==2) { // single result + srLink.setAttribute('href',resultsPath+elem[1][1][0]); + srLink.setAttribute('onclick','searchBox.CloseResultsWindow()'); + if (elem[1][1][1]) { srLink.setAttribute('target','_parent'); + } else { + srLink.setAttribute('target','_blank'); } - var srScope = document.createElement('span'); + const srScope = document.createElement('span'); setClassAttr(srScope,'SRScope'); - srScope.innerHTML = searchData[e][1][1][2]; + srScope.innerHTML = elem[1][1][2]; srEntry.appendChild(srScope); - } - else // multiple results - { + } else { // multiple results srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")'); - var srChildren = document.createElement('div'); + const srChildren = document.createElement('div'); setClassAttr(srChildren,'SRChildren'); - for (var c=0; c - + - - + + mi-malloc: Using the library + - + + @@ -29,22 +31,18 @@
    - + - -
    -
    mi-malloc -  1.7/2.0 +
    +
    mi-malloc 1.8/2.1
    +
    - -   + @@ -56,10 +54,15 @@
    - + +
    @@ -69,13 +72,13 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
    -
    @@ -88,24 +91,30 @@ $(document).ready(function(){initNavTree('using.html',''); initResizable(); });
    - +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    -
    -
    -
    Using the library
    +
    +
    Using the library

    Build

    The preferred usage is including <mimalloc.h>, linking with the shared- or static library, and using the mi_malloc API exclusively for allocation. For example,

    gcc -o myprogram -lmimalloc myfile.c
    -

    mimalloc uses only safe OS calls (mmap and VirtualAlloc) and can co-exist with other allocators linked to the same program. If you use cmake, you can simply use:

    find_package(mimalloc 1.0 REQUIRED)
    +

    mimalloc uses only safe OS calls (mmap and VirtualAlloc) and can co-exist with other allocators linked to the same program. If you use cmake, you can simply use:

    find_package(mimalloc 2.1 REQUIRED)

    in your CMakeLists.txt to find a locally installed mimalloc. Then use either:

    target_link_libraries(myapp PUBLIC mimalloc)

    to link with the shared (dynamic) library, or:

    target_link_libraries(myapp PUBLIC mimalloc-static)

    to link with the static library. See test\CMakeLists.txt for an example.

    C++

    -

    For best performance in C++ programs, it is also recommended to override the global new and delete operators. For convience, mimalloc provides mimalloc-new-delete.h which does this for you – just include it in a single(!) source file in your project without linking to the mimalloc's library.

    +

    For best performance in C++ programs, it is also recommended to override the global new and delete operators. For convience, mimalloc provides mimalloc-new-delete.h which does this for you – just include it in a single(!) source file in your project.

    In C++, mimalloc also provides the mi_stl_allocator struct which implements the std::allocator interface. For example:

    std::vector<some_struct, mi_stl_allocator<some_struct>> vec;
    vec.push_back(some_struct());

    Statistics

    @@ -148,7 +157,7 @@ $(document).ready(function(){initNavTree('using.html',''); initResizable(); }); From 20424dbfa215db01000364cd61d40823de6c76b9 Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 4 Jun 2024 14:38:23 -0700 Subject: [PATCH 045/305] update doxyfile --- doc/doxyfile | 696 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 466 insertions(+), 230 deletions(-) diff --git a/doc/doxyfile b/doc/doxyfile index d03a70f5..53f874cf 100644 --- a/doc/doxyfile +++ b/doc/doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.1 +# Doxyfile 1.11.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -53,6 +63,12 @@ PROJECT_BRIEF = PROJECT_LOGO = mimalloc-logo.svg +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If @@ -60,16 +76,28 @@ PROJECT_LOGO = mimalloc-logo.svg OUTPUT_DIRECTORY = .. -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,26 +109,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -258,16 +278,16 @@ TAB_SIZE = 2 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = @@ -312,8 +332,8 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files @@ -344,11 +364,22 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. +# Minimum value: 0, maximum value: 99, default value: 6. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -361,8 +392,8 @@ AUTOLINK_SUPPORT = YES # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO @@ -374,9 +405,9 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO @@ -460,7 +491,7 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing @@ -473,6 +504,14 @@ LOOKUP_CACHE_SIZE = 0 NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -554,7 +593,8 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO @@ -585,14 +625,15 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. -# The default value is: system dependent. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = NO @@ -610,6 +651,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -767,7 +814,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -813,27 +861,50 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -844,13 +915,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -871,10 +956,21 @@ INPUT = mimalloc-doc.h # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -886,12 +982,12 @@ INPUT_ENCODING = UTF-8 # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -973,10 +1069,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test EXCLUDE_SYMBOLS = @@ -1021,6 +1114,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -1062,6 +1160,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1076,7 +1183,8 @@ USE_MDFILE_AS_MAINPAGE = SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1159,9 +1267,11 @@ VERBATIM_HEADERS = YES CLANG_ASSISTED_PARSING = NO -# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to -# YES then doxygen will add the directory of each input to the include path. +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. # The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_ADD_INC_PATHS = YES @@ -1197,10 +1307,11 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1279,7 +1390,12 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = mimalloc-doxygen.css @@ -1294,9 +1410,22 @@ HTML_EXTRA_STYLESHEET = mimalloc-doxygen.css HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1306,7 +1435,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 189 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1324,15 +1453,6 @@ HTML_COLORSTYLE_SAT = 12 HTML_COLORSTYLE_GAMMA = 240 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1352,6 +1472,33 @@ HTML_DYNAMIC_MENUS = NO HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1388,6 +1535,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1413,8 +1567,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1471,6 +1629,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1573,16 +1741,28 @@ DISABLE_INDEX = YES # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1607,6 +1787,13 @@ TREEVIEW_WIDTH = 180 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for @@ -1627,17 +1814,6 @@ HTML_FORMULA_FORMAT = png FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. @@ -1655,11 +1831,29 @@ FORMULA_MACROFILE = USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1672,15 +1866,21 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = @@ -1860,29 +2060,31 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1925,10 +2127,16 @@ PDF_HYPERLINKS = YES USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1941,16 +2149,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1959,14 +2157,6 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2031,15 +2221,13 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. +# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the RTF_OUTPUT output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_SOURCE_CODE = NO +RTF_EXTRA_FILES = #--------------------------------------------------------------------------- # Configuration options related to the man page output @@ -2137,21 +2325,12 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. @@ -2162,6 +2341,28 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to Sqlite3 output #--------------------------------------------------------------------------- +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2236,7 +2437,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2303,15 +2505,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2325,25 +2527,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2352,7 +2538,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2369,49 +2555,77 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" + +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2453,8 +2667,8 @@ DOT_UML_DETAILS = NO # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters # to display on a single line. If the actual line length exceeds this threshold -# significantly it will wrapped across multiple lines. Some heuristics are apply -# to avoid ugly line breaks. +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. # Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2471,7 +2685,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2480,7 +2696,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2520,16 +2739,26 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2566,11 +2795,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2579,10 +2809,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2599,7 +2829,7 @@ PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized -# by representing a node as a red box. Note that doxygen if the number of direct +# by representing a node as a red box. Note that if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. @@ -2620,18 +2850,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2644,6 +2862,8 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2652,8 +2872,24 @@ GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. # -# Note: This setting is not only used for dot files but also for msc and -# plantuml temporary files. +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = From 272d3368a0757dc3237bc0ceccab6a1ffbcddb77 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 14:50:55 -0700 Subject: [PATCH 046/305] update aligned documentation --- doc/mimalloc-doc.h | 8 +- docs/group__aligned.html | 32 +-- docs/group__aligned.js | 1 - docs/mimalloc-doc_8h_source.html | 4 +- docs/navtreeindex0.js | 17 +- docs/search/all_9.js | 353 +++++++++++++++---------------- 6 files changed, 194 insertions(+), 221 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 42454e9f..1bb2a482 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -571,20 +571,20 @@ void mi_subproc_add_current_thread(mi_subproc_id_t subproc); /// \defgroup aligned Aligned Allocation /// /// Allocating aligned memory blocks. +/// Note that `alignment` always follows `size` for consistency with the unaligned +/// allocation API, but unfortunately this differs from `posix_memalign` and `aligned_alloc` in the C library. /// /// \{ -/// The maximum supported alignment size (currently 1MiB). -#define MI_BLOCK_ALIGNMENT_MAX (1024*1024UL) - /// Allocate \a size bytes aligned by \a alignment. /// @param size number of bytes to allocate. -/// @param alignment the minimal alignment of the allocated memory. Must be less than #MI_BLOCK_ALIGNMENT_MAX. +/// @param alignment the minimal alignment of the allocated memory. /// @returns pointer to the allocated memory or \a NULL if out of memory. /// The returned pointer is aligned by \a alignment, i.e. /// `(uintptr_t)p % alignment == 0`. /// /// Returns a unique pointer if called with \a size 0. +/// @see [aligned_alloc](https://en.cppreference.com/w/c/memory/aligned_alloc) (in the standard C11 library, with switched arguments!) /// @see [_aligned_malloc](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-malloc?view=vs-2017) (on Windows) /// @see [aligned_alloc](http://man.openbsd.org/reallocarray) (on BSD, with switched arguments!) /// @see [posix_memalign](https://linux.die.net/man/3/posix_memalign) (on Posix, with switched arguments!) diff --git a/docs/group__aligned.html b/docs/group__aligned.html index 93ecd920..d54957fa 100644 --- a/docs/group__aligned.html +++ b/docs/group__aligned.html @@ -105,18 +105,11 @@ $(function(){initNavTree('group__aligned.html',''); initResizable(true); });
    Aligned Allocation
    - - - - -

    -Macros

    #define MI_BLOCK_ALIGNMENT_MAX
     The maximum supported alignment size (currently 1MiB).
     
    @@ -139,24 +132,7 @@ Functions

    Functions

    void * mi_malloc_aligned (size_t size, size_t alignment)
     

    Detailed Description

    -

    Allocating aligned memory blocks.

    -

    Macro Definition Documentation

    - -

    ◆ MI_BLOCK_ALIGNMENT_MAX

    - -
    -
    - - - - -
    #define MI_BLOCK_ALIGNMENT_MAX
    -
    - -

    The maximum supported alignment size (currently 1MiB).

    - -
    -
    +

    Allocating aligned memory blocks. Note that alignment always follows size for consistency with the unaligned allocation API, but unfortunately this differs from posix_memalign and aligned_alloc in the C library.

    Function Documentation

    ◆ mi_calloc_aligned()

    @@ -238,12 +214,14 @@ Functions
    Parameters
    - +
    sizenumber of bytes to allocate.
    alignmentthe minimal alignment of the allocated memory. Must be less than MI_BLOCK_ALIGNMENT_MAX.
    alignmentthe minimal alignment of the allocated memory.
    Returns
    pointer to the allocated memory or NULL if out of memory. The returned pointer is aligned by alignment, i.e. (uintptr_t)p % alignment == 0.
    -

    Returns a unique pointer if called with size 0.

    See also
    _aligned_malloc (on Windows)
    +

    Returns a unique pointer if called with size 0.

    See also
    aligned_alloc (in the standard C11 library, with switched arguments!)
    +
    +_aligned_malloc (on Windows)
    aligned_alloc (on BSD, with switched arguments!)
    diff --git a/docs/group__aligned.js b/docs/group__aligned.js index 3bcc1d68..d77e5036 100644 --- a/docs/group__aligned.js +++ b/docs/group__aligned.js @@ -1,6 +1,5 @@ var group__aligned = [ - [ "MI_BLOCK_ALIGNMENT_MAX", "group__aligned.html#ga2e3fc59317bd730a71788c4d56ac8bff", null ], [ "mi_calloc_aligned", "group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1", null ], [ "mi_calloc_aligned_at", "group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3", null ], [ "mi_malloc_aligned", "group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c", null ], diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index 35c2674e..cd7cb8b8 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -235,9 +235,7 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    568// Aligned allocation
    569// ------------------------------------------------------
    570
    -
    576
    -
    578#define MI_BLOCK_ALIGNMENT_MAX (1024*1024UL)
    -
    579
    +
    578
    592void* mi_malloc_aligned(size_t size, size_t alignment);
    593void* mi_zalloc_aligned(size_t size, size_t alignment);
    594void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js index 34969a3c..885cdacf 100644 --- a/docs/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -8,15 +8,14 @@ var NAVTREEINDEX0 = "functions.html":[6,2,0], "functions_vars.html":[6,2,1], "group__aligned.html":[5,2], -"group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca":[5,2,4], -"group__aligned.html#ga2e3fc59317bd730a71788c4d56ac8bff":[5,2,0], -"group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1":[5,2,1], -"group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf":[5,2,5], -"group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c":[5,2,3], -"group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba":[5,2,8], -"group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3":[5,2,2], -"group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82":[5,2,7], -"group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6":[5,2,6], +"group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca":[5,2,3], +"group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1":[5,2,0], +"group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf":[5,2,4], +"group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c":[5,2,2], +"group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba":[5,2,7], +"group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3":[5,2,1], +"group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82":[5,2,6], +"group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6":[5,2,5], "group__analysis.html":[5,6], "group__analysis.html#a332a6c14d736a99699d5453a1cb04b41":[5,6,0,0], "group__analysis.html#ab47526df656d8837ec3e97f11b83f835":[5,6,0,2], diff --git a/docs/search/all_9.js b/docs/search/all_9.js index bac4217a..99613086 100644 --- a/docs/search/all_9.js +++ b/docs/search/all_9.js @@ -12,181 +12,180 @@ var searchData= ['mi_5faligned_5frecalloc_9',['mi_aligned_recalloc',['../group__posix.html#gaf82cbb4b4f24acf723348628451798d3',1,'mimalloc-doc.h']]], ['mi_5farena_5farea_10',['mi_arena_area',['../group__extended.html#ga9a25a00a22151619a0be91a10af7787f',1,'mimalloc-doc.h']]], ['mi_5farena_5fid_5ft_11',['mi_arena_id_t',['../group__extended.html#ga99fe38650d0b02e0e0f89ee024db91d3',1,'mimalloc-doc.h']]], - ['mi_5fblock_5falignment_5fmax_12',['MI_BLOCK_ALIGNMENT_MAX',['../group__aligned.html#ga2e3fc59317bd730a71788c4d56ac8bff',1,'mimalloc-doc.h']]], - ['mi_5fblock_5fvisit_5ffun_13',['mi_block_visit_fun',['../group__analysis.html#ga8255dc9371e6b299d9802a610c4e34ec',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_14',['mi_calloc',['../group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_15',['mi_calloc_aligned',['../group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5faligned_5fat_16',['mi_calloc_aligned_at',['../group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3',1,'mimalloc-doc.h']]], - ['mi_5fcalloc_5ftp_17',['mi_calloc_tp',['../group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07',1,'mimalloc-doc.h']]], - ['mi_5fcfree_18',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], - ['mi_5fcheck_5fowned_19',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], - ['mi_5fcollect_20',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], - ['mi_5fdebug_5fshow_5farenas_21',['mi_debug_show_arenas',['../group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7',1,'mimalloc-doc.h']]], - ['mi_5fdeferred_5ffree_5ffun_22',['mi_deferred_free_fun',['../group__extended.html#ga292a45f7dbc7cd23c5352ce1f0002816',1,'mimalloc-doc.h']]], - ['mi_5fdupenv_5fs_23',['mi_dupenv_s',['../group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958',1,'mimalloc-doc.h']]], - ['mi_5ferror_5ffun_24',['mi_error_fun',['../group__extended.html#ga83fc6a688b322261e1c2deab000b0591',1,'mimalloc-doc.h']]], - ['mi_5fexpand_25',['mi_expand',['../group__malloc.html#ga19299856216cfbb08e2628593654dfb0',1,'mimalloc-doc.h']]], - ['mi_5ffree_26',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], - ['mi_5ffree_5faligned_27',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_28',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], - ['mi_5ffree_5fsize_5faligned_29',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], - ['mi_5fgood_5fsize_30',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], - ['mi_5fheap_5farea_5ft_31',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], - ['mi_5fheap_5fcalloc_32',['mi_heap_calloc',['../group__heap.html#gac0098aaf231d3e9586c73136d5df95da',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_33',['mi_heap_calloc_aligned',['../group__heap.html#gacafcc26df827c7a7de5e850217566108',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5faligned_5fat_34',['mi_heap_calloc_aligned_at',['../group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcalloc_5ftp_35',['mi_heap_calloc_tp',['../group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcheck_5fowned_36',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcollect_37',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fcontains_5fblock_38',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdelete_39',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fdestroy_40',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fbacking_41',['mi_heap_get_backing',['../group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fget_5fdefault_42',['mi_heap_get_default',['../group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_43',['mi_heap_malloc',['../group__heap.html#gab374e206c7034e0d899fb934e4f4a863',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_44',['mi_heap_malloc_aligned',['../group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5faligned_5fat_45',['mi_heap_malloc_aligned_at',['../group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5fsmall_46',['mi_heap_malloc_small',['../group__heap.html#ga012c5c8abe22b10043de39ff95909541',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmalloc_5ftp_47',['mi_heap_malloc_tp',['../group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_48',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fmallocn_5ftp_49',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_50',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_5fin_5farena_51',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_52',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_53',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_5fat_54',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocf_55',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_56',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_5ftp_57',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealpath_58',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_59',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_60',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_5fat_61',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5ftp_62',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_63',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_64',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_5fat_65',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fset_5fdefault_66',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrdup_67',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrndup_68',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5ft_69',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fvisit_5fblocks_70',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_71',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_72',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_5fat_73',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5ftp_74',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], - ['mi_5fis_5fin_5fheap_5fregion_75',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], - ['mi_5fis_5fredirected_76',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_77',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_78',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_5fat_79',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fgood_5fsize_80',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsize_81',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsmall_82',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5ftp_83',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fusable_5fsize_84',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_85',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_5ftp_86',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_87',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_5fex_88',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], - ['mi_5fmbsdup_89',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], - ['mi_5fmemalign_90',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], - ['mi_5fnew_91',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_92',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_5fnothrow_93',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fn_94',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fnothrow_95',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], - ['mi_5fnew_5frealloc_96',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], - ['mi_5fnew_5freallocn_97',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], - ['mi_5foption_5fabandoned_5fpage_5fpurge_98',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_99',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], - ['mi_5foption_5fallow_5flarge_5fos_5fpages_100',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], - ['mi_5foption_5farena_5feager_5fcommit_101',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], - ['mi_5foption_5farena_5fpurge_5fmult_102',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], - ['mi_5foption_5farena_5freserve_103',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdestroy_5fon_5fexit_104',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisable_105',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisallow_5farena_5falloc_106',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisallow_5fos_5falloc_107',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_108',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_5fdelay_109',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_110',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_111',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_5fclamp_112',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_5fsize_113',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fis_5fenabled_114',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], - ['mi_5foption_5flimit_5fos_5falloc_115',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], - ['mi_5foption_5fmax_5ferrors_116',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fmax_5fsegment_5freclaim_117',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], - ['mi_5foption_5fmax_5fwarnings_118',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], - ['mi_5foption_5fos_5ftag_119',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpurge_5fdecommits_120',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpurge_5fdelay_121',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpurge_5fextend_5fdelay_122',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_123',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_124',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fos_5fmemory_125',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], - ['mi_5foption_5fretry_5fon_5foom_126',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_127',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fdefault_128',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_129',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_5fdefault_130',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5ferrors_131',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5fstats_132',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], - ['mi_5foption_5ft_133',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fuse_5fnuma_5fnodes_134',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], - ['mi_5foption_5fverbose_135',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], - ['mi_5foption_5fvisit_5fabandoned_136',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]], - ['mi_5foutput_5ffun_137',['mi_output_fun',['../group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d',1,'mimalloc-doc.h']]], - ['mi_5fposix_5fmemalign_138',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo_139',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], - ['mi_5fpvalloc_140',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], - ['mi_5frealloc_141',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_142',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_5fat_143',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], - ['mi_5freallocarr_144',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], - ['mi_5freallocarray_145',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], - ['mi_5freallocf_146',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], - ['mi_5freallocn_147',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], - ['mi_5freallocn_5ftp_148',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], - ['mi_5frealpath_149',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_150',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_151',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_5fat_152',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], - ['mi_5fregister_5fdeferred_5ffree_153',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], - ['mi_5fregister_5ferror_154',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], - ['mi_5fregister_5foutput_155',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_156',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_157',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_158',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_159',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_5fex_160',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_161',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_162',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_5fat_163',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], - ['mi_5fsmall_5fsize_5fmax_164',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fmerge_165',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_166',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_5fout_167',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset_168',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], - ['mi_5fstl_5fallocator_169',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], - ['mi_5fstrdup_170',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], - ['mi_5fstrndup_171',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fadd_5fcurrent_5fthread_172',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fdelete_173',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fid_5ft_174',['mi_subproc_id_t',['../group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fmain_175',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fnew_176',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone_177',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit_178',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint_5fout_179',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], - ['mi_5fusable_5fsize_180',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], - ['mi_5fvalloc_181',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], - ['mi_5fwcsdup_182',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], - ['mi_5fwdupenv_5fs_183',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_184',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_185',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_5fat_186',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5fsmall_187',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5ftp_188',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] + ['mi_5fblock_5fvisit_5ffun_12',['mi_block_visit_fun',['../group__analysis.html#ga8255dc9371e6b299d9802a610c4e34ec',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_13',['mi_calloc',['../group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_14',['mi_calloc_aligned',['../group__aligned.html#ga424ef386fb1f9f8e0a86ab53f16eaaf1',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5faligned_5fat_15',['mi_calloc_aligned_at',['../group__aligned.html#ga977f96bd2c5c141bcd70e6685c90d6c3',1,'mimalloc-doc.h']]], + ['mi_5fcalloc_5ftp_16',['mi_calloc_tp',['../group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07',1,'mimalloc-doc.h']]], + ['mi_5fcfree_17',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]], + ['mi_5fcheck_5fowned_18',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]], + ['mi_5fcollect_19',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]], + ['mi_5fdebug_5fshow_5farenas_20',['mi_debug_show_arenas',['../group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7',1,'mimalloc-doc.h']]], + ['mi_5fdeferred_5ffree_5ffun_21',['mi_deferred_free_fun',['../group__extended.html#ga292a45f7dbc7cd23c5352ce1f0002816',1,'mimalloc-doc.h']]], + ['mi_5fdupenv_5fs_22',['mi_dupenv_s',['../group__posix.html#gab41369c1a1da7504013a7a0b1d4dd958',1,'mimalloc-doc.h']]], + ['mi_5ferror_5ffun_23',['mi_error_fun',['../group__extended.html#ga83fc6a688b322261e1c2deab000b0591',1,'mimalloc-doc.h']]], + ['mi_5fexpand_24',['mi_expand',['../group__malloc.html#ga19299856216cfbb08e2628593654dfb0',1,'mimalloc-doc.h']]], + ['mi_5ffree_25',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]], + ['mi_5ffree_5faligned_26',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_27',['mi_free_size',['../group__posix.html#gae01389eedab8d67341ff52e2aad80ebb',1,'mimalloc-doc.h']]], + ['mi_5ffree_5fsize_5faligned_28',['mi_free_size_aligned',['../group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc',1,'mimalloc-doc.h']]], + ['mi_5fgood_5fsize_29',['mi_good_size',['../group__extended.html#gac057927cd06c854b45fe7847e921bd47',1,'mimalloc-doc.h']]], + ['mi_5fheap_5farea_5ft_30',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]], + ['mi_5fheap_5fcalloc_31',['mi_heap_calloc',['../group__heap.html#gac0098aaf231d3e9586c73136d5df95da',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_32',['mi_heap_calloc_aligned',['../group__heap.html#gacafcc26df827c7a7de5e850217566108',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5faligned_5fat_33',['mi_heap_calloc_aligned_at',['../group__heap.html#gaa42ec2079989c4374f2c331d9b35f4e4',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcalloc_5ftp_34',['mi_heap_calloc_tp',['../group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcheck_5fowned_35',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcollect_36',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcontains_5fblock_37',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdelete_38',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fdestroy_39',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fbacking_40',['mi_heap_get_backing',['../group__heap.html#gac6ac9f0e7be9ab4ff70acfc8dad1235a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fget_5fdefault_41',['mi_heap_get_default',['../group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_42',['mi_heap_malloc',['../group__heap.html#gab374e206c7034e0d899fb934e4f4a863',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_43',['mi_heap_malloc_aligned',['../group__heap.html#ga33f4f05b7fea7af2113c62a4bf882cc5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5faligned_5fat_44',['mi_heap_malloc_aligned_at',['../group__heap.html#gae7ffc045c3996497a7f3a5f6fe7b8aaa',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5fsmall_45',['mi_heap_malloc_small',['../group__heap.html#ga012c5c8abe22b10043de39ff95909541',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5ftp_46',['mi_heap_malloc_tp',['../group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_47',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmallocn_5ftp_48',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_49',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fin_5farena_50',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_51',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_52',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_5fat_53',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocf_54',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_55',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_5ftp_56',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealpath_57',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_58',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_59',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat_60',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5ftp_61',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_62',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_63',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat_64',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fset_5fdefault_65',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrdup_66',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrndup_67',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5ft_68',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fvisit_5fblocks_69',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_70',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_71',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_5fat_72',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5ftp_73',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion_74',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected_75',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_76',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_77',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_5fat_78',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fgood_5fsize_79',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsize_80',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsmall_81',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5ftp_82',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fusable_5fsize_83',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_84',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_5ftp_85',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_86',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_5fex_87',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], + ['mi_5fmbsdup_88',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], + ['mi_5fmemalign_89',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], + ['mi_5fnew_90',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_91',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_5fnothrow_92',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fn_93',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fnothrow_94',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], + ['mi_5fnew_5frealloc_95',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], + ['mi_5fnew_5freallocn_96',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5fpage_5fpurge_97',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_98',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], + ['mi_5foption_5fallow_5flarge_5fos_5fpages_99',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5feager_5fcommit_100',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5fpurge_5fmult_101',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5freserve_102',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdestroy_5fon_5fexit_103',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable_104',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5farena_5falloc_105',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5fos_5falloc_106',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_107',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay_108',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable_109',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_110',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fclamp_111',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fsize_112',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled_113',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], + ['mi_5foption_5flimit_5fos_5falloc_114',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5ferrors_115',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fsegment_5freclaim_116',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fwarnings_117',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag_118',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdecommits_119',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdelay_120',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fextend_5fdelay_121',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_122',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_123',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fos_5fmemory_124',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], + ['mi_5foption_5fretry_5fon_5foom_125',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_126',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fdefault_127',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_128',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault_129',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5ferrors_130',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5fstats_131',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], + ['mi_5foption_5ft_132',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fuse_5fnuma_5fnodes_133',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], + ['mi_5foption_5fverbose_134',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], + ['mi_5foption_5fvisit_5fabandoned_135',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]], + ['mi_5foutput_5ffun_136',['mi_output_fun',['../group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d',1,'mimalloc-doc.h']]], + ['mi_5fposix_5fmemalign_137',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo_138',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], + ['mi_5fpvalloc_139',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], + ['mi_5frealloc_140',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_141',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_5fat_142',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], + ['mi_5freallocarr_143',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], + ['mi_5freallocarray_144',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], + ['mi_5freallocf_145',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], + ['mi_5freallocn_146',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], + ['mi_5freallocn_5ftp_147',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], + ['mi_5frealpath_148',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_149',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_150',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat_151',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], + ['mi_5fregister_5fdeferred_5ffree_152',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], + ['mi_5fregister_5ferror_153',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput_154',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_155',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_156',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_157',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_158',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_5fex_159',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_160',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_161',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat_162',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], + ['mi_5fsmall_5fsize_5fmax_163',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge_164',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_165',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout_166',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset_167',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], + ['mi_5fstl_5fallocator_168',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], + ['mi_5fstrdup_169',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], + ['mi_5fstrndup_170',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fadd_5fcurrent_5fthread_171',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fdelete_172',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fid_5ft_173',['mi_subproc_id_t',['../group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fmain_174',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fnew_175',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone_176',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit_177',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint_5fout_178',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], + ['mi_5fusable_5fsize_179',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], + ['mi_5fvalloc_180',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], + ['mi_5fwcsdup_181',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], + ['mi_5fwdupenv_5fs_182',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_183',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_184',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_5fat_185',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5fsmall_186',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5ftp_187',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] ]; From dee7faa6d8953844295ee2eb020c25dc58c2fc2f Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 14:56:49 -0700 Subject: [PATCH 047/305] add js for docs --- docs/clipboard.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++ docs/cookie.js | 58 ++++++++++++++++++++++++++++++++++++++++++++ docs/topics.js | 13 ++++++++++ 3 files changed, 132 insertions(+) create mode 100644 docs/clipboard.js create mode 100644 docs/cookie.js create mode 100644 docs/topics.js diff --git a/docs/clipboard.js b/docs/clipboard.js new file mode 100644 index 00000000..42c1fb0e --- /dev/null +++ b/docs/clipboard.js @@ -0,0 +1,61 @@ +/** + +The code below is based on the Doxygen Awesome project, see +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +let clipboard_title = "Copy to clipboard" +let clipboard_icon = `` +let clipboard_successIcon = `` +let clipboard_successDuration = 1000 + +$(function() { + if(navigator.clipboard) { + const fragments = document.getElementsByClassName("fragment") + for(const fragment of fragments) { + const clipboard_div = document.createElement("div") + clipboard_div.classList.add("clipboard") + clipboard_div.innerHTML = clipboard_icon + clipboard_div.title = clipboard_title + $(clipboard_div).click(function() { + const content = this.parentNode.cloneNode(true) + // filter out line number and folded fragments from file listings + content.querySelectorAll(".lineno, .ttc, .foldclosed").forEach((node) => { node.remove() }) + let text = content.textContent + // remove trailing newlines and trailing spaces from empty lines + text = text.replace(/^\s*\n/gm,'\n').replace(/\n*$/,'') + navigator.clipboard.writeText(text); + this.classList.add("success") + this.innerHTML = clipboard_successIcon + window.setTimeout(() => { // switch back to normal icon after timeout + this.classList.remove("success") + this.innerHTML = clipboard_icon + }, clipboard_successDuration); + }) + fragment.insertBefore(clipboard_div, fragment.firstChild) + } + } +}) diff --git a/docs/cookie.js b/docs/cookie.js new file mode 100644 index 00000000..53ad21d9 --- /dev/null +++ b/docs/cookie.js @@ -0,0 +1,58 @@ +/*! + Cookie helper functions + Copyright (c) 2023 Dimitri van Heesch + Released under MIT license. +*/ +let Cookie = { + cookie_namespace: 'doxygen_', + + readSetting(cookie,defVal) { + if (window.chrome) { + const val = localStorage.getItem(this.cookie_namespace+cookie) || + sessionStorage.getItem(this.cookie_namespace+cookie); + if (val) return val; + } else { + let myCookie = this.cookie_namespace+cookie+"="; + if (document.cookie) { + const index = document.cookie.indexOf(myCookie); + if (index != -1) { + const valStart = index + myCookie.length; + let valEnd = document.cookie.indexOf(";", valStart); + if (valEnd == -1) { + valEnd = document.cookie.length; + } + return document.cookie.substring(valStart, valEnd); + } + } + } + return defVal; + }, + + writeSetting(cookie,val,days=10*365) { // default days='forever', 0=session cookie, -1=delete + if (window.chrome) { + if (days==0) { + sessionStorage.setItem(this.cookie_namespace+cookie,val); + } else { + localStorage.setItem(this.cookie_namespace+cookie,val); + } + } else { + let date = new Date(); + date.setTime(date.getTime()+(days*24*60*60*1000)); + const expiration = days!=0 ? "expires="+date.toGMTString()+";" : ""; + document.cookie = this.cookie_namespace + cookie + "=" + + val + "; SameSite=Lax;" + expiration + "path=/"; + } + }, + + eraseSetting(cookie) { + if (window.chrome) { + if (localStorage.getItem(this.cookie_namespace+cookie)) { + localStorage.removeItem(this.cookie_namespace+cookie); + } else if (sessionStorage.getItem(this.cookie_namespace+cookie)) { + sessionStorage.removeItem(this.cookie_namespace+cookie); + } + } else { + this.writeSetting(cookie,'',-1); + } + }, +} diff --git a/docs/topics.js b/docs/topics.js new file mode 100644 index 00000000..a9a23367 --- /dev/null +++ b/docs/topics.js @@ -0,0 +1,13 @@ +var topics = +[ + [ "Basic Allocation", "group__malloc.html", "group__malloc" ], + [ "Extended Functions", "group__extended.html", "group__extended" ], + [ "Aligned Allocation", "group__aligned.html", "group__aligned" ], + [ "Heap Allocation", "group__heap.html", "group__heap" ], + [ "Zero initialized re-allocation", "group__zeroinit.html", "group__zeroinit" ], + [ "Typed Macros", "group__typed.html", "group__typed" ], + [ "Heap Introspection", "group__analysis.html", "group__analysis" ], + [ "Runtime Options", "group__options.html", "group__options" ], + [ "Posix", "group__posix.html", "group__posix" ], + [ "C++ wrappers", "group__cpp.html", "group__cpp" ] +]; \ No newline at end of file From ab1cdbbde367e16045dbdcd1d3f97aefcdb1761e Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 14:58:58 -0700 Subject: [PATCH 048/305] add search js files for docs --- docs/search/all_10.js | 4 ++++ docs/search/all_e.js | 5 +++++ docs/search/all_f.js | 4 ++++ docs/search/groups_9.js | 4 ++++ docs/search/groups_a.js | 5 +++++ docs/search/groups_b.js | 4 ++++ docs/search/groups_c.js | 4 ++++ docs/search/groups_d.js | 4 ++++ docs/search/pages_5.js | 4 ++++ docs/search/pages_6.js | 4 ++++ docs/search/pages_7.js | 4 ++++ docs/search/variables_4.js | 4 ++++ 12 files changed, 50 insertions(+) create mode 100644 docs/search/all_10.js create mode 100644 docs/search/all_e.js create mode 100644 docs/search/all_f.js create mode 100644 docs/search/groups_9.js create mode 100644 docs/search/groups_a.js create mode 100644 docs/search/groups_b.js create mode 100644 docs/search/groups_c.js create mode 100644 docs/search/groups_d.js create mode 100644 docs/search/pages_5.js create mode 100644 docs/search/pages_6.js create mode 100644 docs/search/pages_7.js create mode 100644 docs/search/variables_4.js diff --git a/docs/search/all_10.js b/docs/search/all_10.js new file mode 100644 index 00000000..1437d04a --- /dev/null +++ b/docs/search/all_10.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['zero_20initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] +]; diff --git a/docs/search/all_e.js b/docs/search/all_e.js new file mode 100644 index 00000000..4c8c2e89 --- /dev/null +++ b/docs/search/all_e.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['used_0',['used',['../group__analysis.html#ab820302c5cd0df133eb8e51650a008b4',1,'mi_heap_area_t']]], + ['using_20the_20library_1',['Using the library',['../using.html',1,'']]] +]; diff --git a/docs/search/all_f.js b/docs/search/all_f.js new file mode 100644 index 00000000..8f445b9f --- /dev/null +++ b/docs/search/all_f.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]] +]; diff --git a/docs/search/groups_9.js b/docs/search/groups_9.js new file mode 100644 index 00000000..bc342946 --- /dev/null +++ b/docs/search/groups_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['posix_0',['Posix',['../group__posix.html',1,'']]] +]; diff --git a/docs/search/groups_a.js b/docs/search/groups_a.js new file mode 100644 index 00000000..5f2947aa --- /dev/null +++ b/docs/search/groups_a.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]], + ['runtime_20options_1',['Runtime Options',['../group__options.html',1,'']]] +]; diff --git a/docs/search/groups_b.js b/docs/search/groups_b.js new file mode 100644 index 00000000..56eb25ea --- /dev/null +++ b/docs/search/groups_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['typed_20macros_0',['Typed Macros',['../group__typed.html',1,'']]] +]; diff --git a/docs/search/groups_c.js b/docs/search/groups_c.js new file mode 100644 index 00000000..8f445b9f --- /dev/null +++ b/docs/search/groups_c.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['wrappers_0',['C++ wrappers',['../group__cpp.html',1,'']]] +]; diff --git a/docs/search/groups_d.js b/docs/search/groups_d.js new file mode 100644 index 00000000..1437d04a --- /dev/null +++ b/docs/search/groups_d.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['zero_20initialized_20re_20allocation_0',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]] +]; diff --git a/docs/search/pages_5.js b/docs/search/pages_5.js new file mode 100644 index 00000000..31424809 --- /dev/null +++ b/docs/search/pages_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['performance_0',['Performance',['../bench.html',1,'']]] +]; diff --git a/docs/search/pages_6.js b/docs/search/pages_6.js new file mode 100644 index 00000000..308a1780 --- /dev/null +++ b/docs/search/pages_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['the_20library_0',['Using the library',['../using.html',1,'']]] +]; diff --git a/docs/search/pages_7.js b/docs/search/pages_7.js new file mode 100644 index 00000000..4806a818 --- /dev/null +++ b/docs/search/pages_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['using_20the_20library_0',['Using the library',['../using.html',1,'']]] +]; diff --git a/docs/search/variables_4.js b/docs/search/variables_4.js new file mode 100644 index 00000000..230778b8 --- /dev/null +++ b/docs/search/variables_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['used_0',['used',['../group__analysis.html#ab820302c5cd0df133eb8e51650a008b4',1,'mi_heap_area_t']]] +]; From 8b7b3e37546de6206bafc0f78200af4e5ce7b5a0 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 14:59:42 -0700 Subject: [PATCH 049/305] add docs svg's --- docs/doxygen.svg | 28 ++++++++++++++++++++++++++++ docs/search/close.svg | 18 ++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 docs/doxygen.svg create mode 100644 docs/search/close.svg diff --git a/docs/doxygen.svg b/docs/doxygen.svg new file mode 100644 index 00000000..aeb5facb --- /dev/null +++ b/docs/doxygen.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/search/close.svg b/docs/search/close.svg new file mode 100644 index 00000000..337d6cc1 --- /dev/null +++ b/docs/search/close.svg @@ -0,0 +1,18 @@ + + + + + + From 98058eed1447aa15f37fea5151d74e50d4d845a4 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 16:54:06 -0700 Subject: [PATCH 050/305] add heap tag to area descriptor --- include/mimalloc.h | 1 + src/heap.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/mimalloc.h b/include/mimalloc.h index a315370e..bc743fd7 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -258,6 +258,7 @@ typedef struct mi_heap_area_s { size_t used; // number of allocated blocks size_t block_size; // size in bytes of each block size_t full_block_size; // size in bytes of a full block including padding and metadata. + int heap_tag; // heap tag associated with this area } mi_heap_area_t; typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg); diff --git a/src/heap.c b/src/heap.c index 0049abc3..0d716f91 100644 --- a/src/heap.c +++ b/src/heap.c @@ -530,6 +530,7 @@ void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page) { area->used = page->used; // number of blocks in use (#553) area->block_size = ubsize; area->full_block_size = bsize; + area->heap_tag = page->heap_tag; } From 8f481d34ddc2d202b3e65dbb128ef5e2e76bbfb7 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 16:54:22 -0700 Subject: [PATCH 051/305] update docs --- doc/mimalloc-doc.h | 58 +- docs/functions.html | 1 + docs/functions_vars.html | 1 + docs/group__aligned.html | 12 +- docs/group__analysis.html | 19 +- docs/group__analysis.js | 1 + ...group__analysis_structmi__heap__area__t.js | 1 + docs/group__extended.html | 44 +- docs/group__extended.js | 1 + docs/group__typed.html | 2 +- docs/mimalloc-doc_8h_source.html | 689 +++++++++--------- docs/navtreeindex0.js | 62 +- docs/search/all_6.js | 3 +- docs/search/all_9.js | 277 +++---- docs/search/functions_0.js | 195 ++--- docs/search/searchdata.js | 2 +- docs/search/variables_3.js | 2 +- docs/search/variables_4.js | 2 +- 18 files changed, 739 insertions(+), 633 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 1bb2a482..0c19e7b8 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -281,8 +281,7 @@ void* mi_zalloc_small(size_t size); /// The returned size can be /// used to call \a mi_expand successfully. /// The returned size is always at least equal to the -/// allocated size of \a p, and, in the current design, -/// should be less than 16.7% more. +/// allocated size of \a p. /// /// @see [_msize](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize?view=vs-2017) (Windows) /// @see [malloc_usable_size](http://man7.org/linux/man-pages/man3/malloc_usable_size.3.html) (Linux) @@ -307,7 +306,7 @@ size_t mi_good_size(size_t size); /// in very narrow circumstances; in particular, when a long running thread /// allocates a lot of blocks that are freed by other threads it may improve /// resource usage by calling this every once in a while. -void mi_collect(bool force); +void mi_collect(bool force); /// Deprecated /// @param out Ignored, outputs to the registered output function or stderr by default. @@ -540,6 +539,19 @@ bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool i /// @return The new heap or `NULL`. mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id); +/// @brief Create a new heap +/// @param heap_tag The heap tag associated with this heap; heaps only reclaim memory between heaps with the same tag. +/// @param allow_destroy Is \a mi_heap_destroy allowed? Not allowing this allows the heap to reclaim memory from terminated threads. +/// @param arena_id If not 0, the heap will only allocate from the specified arena. +/// @return A new heap or `NULL` on failure. +/// +/// The \a arena_id can be used by runtimes to allocate only in a specified pre-reserved arena. +/// This is used for example for a compressed pointer heap in Koka. +/// +/// The \a heap_tag enables heaps to keep objects of a certain type isolated to heaps with that tag. +/// This is used for example in the CPython integration. +mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); + /// A process can associate threads with sub-processes. /// A sub-process will not reclaim memory from (abandoned heaps/threads) /// other subprocesses. @@ -578,12 +590,16 @@ void mi_subproc_add_current_thread(mi_subproc_id_t subproc); /// Allocate \a size bytes aligned by \a alignment. /// @param size number of bytes to allocate. -/// @param alignment the minimal alignment of the allocated memory. -/// @returns pointer to the allocated memory or \a NULL if out of memory. -/// The returned pointer is aligned by \a alignment, i.e. -/// `(uintptr_t)p % alignment == 0`. -/// +/// @param alignment the minimal alignment of the allocated memory. +/// @returns pointer to the allocated memory or \a NULL if out of memory, +/// or if the alignment is not a power of 2 (including 0). The \a size is unrestricted +/// (and does not have to be an integral multiple of the \a alignment). +/// The returned pointer is aligned by \a alignment, i.e. `(uintptr_t)p % alignment == 0`. /// Returns a unique pointer if called with \a size 0. +/// +/// Note that `alignment` always follows `size` for consistency with the unaligned +/// allocation API, but unfortunately this differs from `posix_memalign` and `aligned_alloc` in the C library. +/// /// @see [aligned_alloc](https://en.cppreference.com/w/c/memory/aligned_alloc) (in the standard C11 library, with switched arguments!) /// @see [_aligned_malloc](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-malloc?view=vs-2017) (on Windows) /// @see [aligned_alloc](http://man.openbsd.org/reallocarray) (on BSD, with switched arguments!) @@ -598,11 +614,12 @@ void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment); /// @param size number of bytes to allocate. /// @param alignment the minimal alignment of the allocated memory at \a offset. /// @param offset the offset that should be aligned. -/// @returns pointer to the allocated memory or \a NULL if out of memory. -/// The returned pointer is aligned by \a alignment at \a offset, i.e. -/// `((uintptr_t)p + offset) % alignment == 0`. -/// +/// @returns pointer to the allocated memory or \a NULL if out of memory, +/// or if the alignment is not a power of 2 (including 0). The \a size is unrestricted +/// (and does not have to be an integral multiple of the \a alignment). +/// The returned pointer is aligned by \a alignment, i.e. `(uintptr_t)p % alignment == 0`. /// Returns a unique pointer if called with \a size 0. +/// /// @see [_aligned_offset_malloc](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-offset-malloc?view=vs-2017) (on Windows) void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset); void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset); @@ -841,6 +858,7 @@ typedef struct mi_heap_area_s { size_t used; ///< bytes in use by allocated blocks size_t block_size; ///< size in bytes of one block size_t full_block_size; ///< size in bytes of a full block including padding and metadata. + int heap_tag; ///< heap tag associated with this area (see \a mi_heap_new_ex) } mi_heap_area_t; /// Visitor function passed to mi_heap_visit_blocks() @@ -865,8 +883,20 @@ typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* a /// @returns \a true if all areas and blocks were visited. 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 abandoned heaps. -/// Note: requires the option `mi_option_allow_visit_abandoned` to be set +/// @brief Visit all areas and blocks in abandoned heaps. +/// @param subproc_id The sub-process id associated with the abandonded heaps. +/// @param heap_tag Visit only abandoned memory with the specified heap tag, use -1 to visit all abandoned memory. +/// @param visit_blocks If \a true visits all allocated blocks, otherwise +/// \a visitor is only called for every heap area. +/// @param visitor This function is called for every area in the heap +/// (with \a block as \a NULL). If \a visit_all_blocks is +/// \a true, \a visitor is also called for every allocated +/// block in every area (with `block!=NULL`). +/// return \a false from this function to stop visiting early. +/// @param arg extra argument passed to the \a visitor. +/// @return \a true if all areas and blocks were visited. +/// +/// Note: requires the option `mi_option_visit_abandoned` to be set /// at the start of the program. bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); diff --git a/docs/functions.html b/docs/functions.html index f04c90dd..02686e71 100644 --- a/docs/functions.html +++ b/docs/functions.html @@ -109,6 +109,7 @@ $(function(){initNavTree('functions.html',''); initResizable(true); });
  • blocks : mi_heap_area_t
  • committed : mi_heap_area_t
  • full_block_size : mi_heap_area_t
  • +
  • heap_tag : mi_heap_area_t
  • reserved : mi_heap_area_t
  • used : mi_heap_area_t
  • diff --git a/docs/functions_vars.html b/docs/functions_vars.html index afd66afc..6321e47c 100644 --- a/docs/functions_vars.html +++ b/docs/functions_vars.html @@ -109,6 +109,7 @@ $(function(){initNavTree('functions_vars.html',''); initResizable(true); });
  • blocks : mi_heap_area_t
  • committed : mi_heap_area_t
  • full_block_size : mi_heap_area_t
  • +
  • heap_tag : mi_heap_area_t
  • reserved : mi_heap_area_t
  • used : mi_heap_area_t
  • diff --git a/docs/group__aligned.html b/docs/group__aligned.html index d54957fa..63257804 100644 --- a/docs/group__aligned.html +++ b/docs/group__aligned.html @@ -214,12 +214,14 @@ Functions
    Parameters
    - +
    sizenumber of bytes to allocate.
    alignmentthe minimal alignment of the allocated memory.
    alignmentthe minimal alignment of the allocated memory.
    +
    -
    Returns
    pointer to the allocated memory or NULL if out of memory. The returned pointer is aligned by alignment, i.e. (uintptr_t)p % alignment == 0.
    -

    Returns a unique pointer if called with size 0.

    See also
    aligned_alloc (in the standard C11 library, with switched arguments!)
    +
    Returns
    pointer to the allocated memory or NULL if out of memory, or if the alignment is not a power of 2 (including 0). The size is unrestricted (and does not have to be an integral multiple of the alignment). The returned pointer is aligned by alignment, i.e. (uintptr_t)p % alignment == 0. Returns a unique pointer if called with size 0.
    +

    Note that alignment always follows size for consistency with the unaligned allocation API, but unfortunately this differs from posix_memalign and aligned_alloc in the C library.

    +
    See also
    aligned_alloc (in the standard C11 library, with switched arguments!)
    _aligned_malloc (on Windows)
    @@ -264,8 +266,8 @@ Functions
    -
    Returns
    pointer to the allocated memory or NULL if out of memory. The returned pointer is aligned by alignment at offset, i.e. ((uintptr_t)p + offset) % alignment == 0.
    -

    Returns a unique pointer if called with size 0.

    See also
    _aligned_offset_malloc (on Windows)
    +
    Returns
    pointer to the allocated memory or NULL if out of memory, or if the alignment is not a power of 2 (including 0). The size is unrestricted (and does not have to be an integral multiple of the alignment). The returned pointer is aligned by alignment, i.e. (uintptr_t)p % alignment == 0. Returns a unique pointer if called with size 0.
    +
    See also
    _aligned_offset_malloc (on Windows)
    diff --git a/docs/group__analysis.html b/docs/group__analysis.html index 9e9cee73..7bcfb1c5 100644 --- a/docs/group__analysis.html +++ b/docs/group__analysis.html @@ -185,6 +185,12 @@ full_block_size size in bytes of a full block including padding and metadata. +int + +heap_tag + +heap tag associated with this area (see mi_heap_new_ex) + size_t reserved @@ -255,7 +261,18 @@ bytes in use by allocated blocks

    Visit all areas and blocks in abandoned heaps.

    -

    Note: requires the option mi_option_allow_visit_abandoned to be set at the start of the program.

    +
    Parameters
    + + + + + + +
    subproc_idThe sub-process id associated with the abandonded heaps.
    heap_tagVisit only abandoned memory with the specified heap tag, use -1 to visit all abandoned memory.
    visit_blocksIf true visits all allocated blocks, otherwise visitor is only called for every heap area.
    visitorThis function is called for every area in the heap (with block as NULL). If visit_all_blocks is true, visitor is also called for every allocated block in every area (with block!=NULL). return false from this function to stop visiting early.
    argextra argument passed to the visitor.
    +
    +
    +
    Returns
    true if all areas and blocks were visited.
    +

    Note: requires the option mi_option_visit_abandoned to be set at the start of the program.

    diff --git a/docs/group__analysis.js b/docs/group__analysis.js index f60c7943..5e72b94a 100644 --- a/docs/group__analysis.js +++ b/docs/group__analysis.js @@ -5,6 +5,7 @@ var group__analysis = [ "blocks", "group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8", null ], [ "committed", "group__analysis.html#ab47526df656d8837ec3e97f11b83f835", null ], [ "full_block_size", "group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3", null ], + [ "heap_tag", "group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1", null ], [ "reserved", "group__analysis.html#ae848a3e6840414891035423948ca0383", null ], [ "used", "group__analysis.html#ab820302c5cd0df133eb8e51650a008b4", null ] ] ], diff --git a/docs/group__analysis_structmi__heap__area__t.js b/docs/group__analysis_structmi__heap__area__t.js index 6e40ef07..41a8e77a 100644 --- a/docs/group__analysis_structmi__heap__area__t.js +++ b/docs/group__analysis_structmi__heap__area__t.js @@ -4,6 +4,7 @@ var group__analysis_structmi__heap__area__t = [ "blocks", "group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8", null ], [ "committed", "group__analysis.html#ab47526df656d8837ec3e97f11b83f835", null ], [ "full_block_size", "group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3", null ], + [ "heap_tag", "group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1", null ], [ "reserved", "group__analysis.html#ae848a3e6840414891035423948ca0383", null ], [ "used", "group__analysis.html#ab820302c5cd0df133eb8e51650a008b4", null ] ]; \ No newline at end of file diff --git a/docs/group__extended.html b/docs/group__extended.html index 16ae2c5f..98aca4ec 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -225,6 +225,9 @@ Functions mi_heap_tmi_heap_new_in_arena (mi_arena_id_t arena_id)  Create a new heap that only allocates in the specified arena.
      +mi_heap_tmi_heap_new_ex (int heap_tag, bool allow_destroy, mi_arena_id_t arena_id) + Create a new heap.
    mi_subproc_id_t mi_subproc_main (void)  Get the main sub-process identifier.
      @@ -485,6 +488,45 @@ Functions

    Generally, mi_usable_size(mi_malloc(size)) == mi_good_size(size). This can be used to reduce internal wasted space when allocating buffers for example.

    See also
    mi_usable_size()
    +
    +
    + +

    ◆ mi_heap_new_ex()

    + +
    +
    + + + + + + + + + + + + + + + + +
    mi_heap_t * mi_heap_new_ex (int heap_tag,
    bool allow_destroy,
    mi_arena_id_t arena_id )
    +
    + +

    Create a new heap.

    +
    Parameters
    + + + + +
    heap_tagThe heap tag associated with this heap; heaps only reclaim memory between heaps with the same tag.
    allow_destroyIs mi_heap_destroy allowed? Not allowing this allows the heap to reclaim memory from terminated threads.
    arena_idIf not 0, the heap will only allocate from the specified arena.
    +
    +
    +
    Returns
    A new heap or NULL on failure.
    +

    The arena_id can be used by runtimes to allocate only in a specified pre-reserved arena. This is used for example for a compressed pointer heap in Koka.

    +

    The heap_tag enables heaps to keep objects of a certain type isolated to heaps with that tag. This is used for example in the CPython integration.

    +
    @@ -1358,7 +1400,7 @@ Functions
    Returns
    Returns the available bytes in the memory block, or 0 if p was NULL.
    -

    The returned size can be used to call mi_expand successfully. The returned size is always at least equal to the allocated size of p, and, in the current design, should be less than 16.7% more.

    +

    The returned size can be used to call mi_expand successfully. The returned size is always at least equal to the allocated size of p.

    See also
    _msize (Windows)
    malloc_usable_size (Linux)
    diff --git a/docs/group__extended.js b/docs/group__extended.js index cb7009f0..43d6378f 100644 --- a/docs/group__extended.js +++ b/docs/group__extended.js @@ -10,6 +10,7 @@ var group__extended = [ "mi_collect", "group__extended.html#ga421430e2226d7d468529cec457396756", null ], [ "mi_debug_show_arenas", "group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7", null ], [ "mi_good_size", "group__extended.html#gac057927cd06c854b45fe7847e921bd47", null ], + [ "mi_heap_new_ex", "group__extended.html#ga3ae360583f4351aa5267ee7e43008faf", null ], [ "mi_heap_new_in_arena", "group__extended.html#gaaf2d9976576d5efd5544be12848af949", null ], [ "mi_is_in_heap_region", "group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6", null ], [ "mi_is_redirected", "group__extended.html#gaad25050b19f30cd79397b227e0157a3f", null ], diff --git a/docs/group__typed.html b/docs/group__typed.html index 94efe409..aa91a12f 100644 --- a/docs/group__typed.html +++ b/docs/group__typed.html @@ -148,7 +148,7 @@ Macros

    Detailed Description

    Typed allocation macros. For example:

    int* p = mi_malloc_tp(int)
    -
    #define mi_malloc_tp(tp)
    Allocate a block of type tp.
    Definition mimalloc-doc.h:768
    +
    #define mi_malloc_tp(tp)
    Allocate a block of type tp.
    Definition mimalloc-doc.h:785

    Macro Definition Documentation

    ◆ mi_calloc_tp

    diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index cd7cb8b8..84549c54 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -158,320 +158,323 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    266
    274void* mi_zalloc_small(size_t size);
    275
    -
    290size_t mi_usable_size(void* p);
    -
    291
    -
    301size_t mi_good_size(size_t size);
    -
    302
    -
    310void mi_collect(bool force);
    -
    311
    -
    316void mi_stats_print(void* out);
    -
    317
    -
    323void mi_stats_print_out(mi_output_fun* out, void* arg);
    -
    324
    -
    326void mi_stats_reset(void);
    -
    327
    -
    329void mi_stats_merge(void);
    -
    330
    -
    334void mi_thread_init(void);
    -
    335
    -
    340void mi_thread_done(void);
    -
    341
    - -
    348
    -
    355typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    -
    356
    -
    372void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    -
    373
    -
    379typedef void (mi_output_fun)(const char* msg, void* arg);
    -
    380
    -
    387void mi_register_output(mi_output_fun* out, void* arg);
    -
    388
    -
    394typedef void (mi_error_fun)(int err, void* arg);
    -
    395
    -
    411void mi_register_error(mi_error_fun* errfun, void* arg);
    -
    412
    -
    417bool mi_is_in_heap_region(const void* p);
    -
    418
    -
    427int mi_reserve_os_memory(size_t size, bool commit, bool allow_large);
    -
    428
    -
    440bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node);
    -
    441
    -
    454int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    -
    455
    -
    468int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    +
    289size_t mi_usable_size(void* p);
    +
    290
    +
    300size_t mi_good_size(size_t size);
    +
    301
    +
    309void mi_collect(bool force);
    +
    310
    +
    315void mi_stats_print(void* out);
    +
    316
    +
    322void mi_stats_print_out(mi_output_fun* out, void* arg);
    +
    323
    +
    325void mi_stats_reset(void);
    +
    326
    +
    328void mi_stats_merge(void);
    +
    329
    +
    333void mi_thread_init(void);
    +
    334
    +
    339void mi_thread_done(void);
    +
    340
    + +
    347
    +
    354typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
    +
    355
    +
    371void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
    +
    372
    +
    378typedef void (mi_output_fun)(const char* msg, void* arg);
    +
    379
    +
    386void mi_register_output(mi_output_fun* out, void* arg);
    +
    387
    +
    393typedef void (mi_error_fun)(int err, void* arg);
    +
    394
    +
    410void mi_register_error(mi_error_fun* errfun, void* arg);
    +
    411
    +
    416bool mi_is_in_heap_region(const void* p);
    +
    417
    +
    426int mi_reserve_os_memory(size_t size, bool commit, bool allow_large);
    +
    427
    +
    439bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node);
    +
    440
    +
    453int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
    +
    454
    +
    467int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
    +
    468
    469
    -
    470
    - -
    476
    -
    490void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults);
    -
    491
    -
    496void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge);
    -
    497
    -
    500typedef int mi_arena_id_t;
    -
    501
    -
    506void* mi_arena_area(mi_arena_id_t arena_id, size_t* size);
    -
    507
    -
    515int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id);
    -
    516
    -
    524int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id);
    -
    525
    -
    536bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id);
    -
    537
    - -
    542
    -
    546typedef void* mi_subproc_id_t;
    -
    547
    - -
    550
    - + +
    475
    +
    489void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults);
    +
    490
    +
    495void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge);
    +
    496
    +
    499typedef int mi_arena_id_t;
    +
    500
    +
    505void* mi_arena_area(mi_arena_id_t arena_id, size_t* size);
    +
    506
    +
    514int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id);
    +
    515
    +
    523int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id);
    +
    524
    +
    535bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id);
    +
    536
    + +
    541
    +
    553mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id);
    554
    - +
    558typedef void* mi_subproc_id_t;
    559
    - -
    563
    -
    564
    + +
    562
    +
    566
    -
    567// ------------------------------------------------------
    -
    568// Aligned allocation
    -
    569// ------------------------------------------------------
    -
    570
    + +
    571
    + +
    575
    +
    576
    578
    -
    592void* mi_malloc_aligned(size_t size, size_t alignment);
    -
    593void* mi_zalloc_aligned(size_t size, size_t alignment);
    -
    594void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    -
    595void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    596
    -
    607void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    608void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    609void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    -
    610void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    611
    -
    613
    -
    619
    -
    624struct mi_heap_s;
    -
    625
    -
    630typedef struct mi_heap_s mi_heap_t;
    -
    631
    - -
    634
    - -
    643
    - -
    652
    - -
    657
    - -
    661
    - -
    668
    -
    670void mi_heap_collect(mi_heap_t* heap, bool force);
    -
    671
    -
    674void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    -
    675
    -
    679void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    -
    680
    -
    683void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    -
    684
    -
    687void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    +
    579// ------------------------------------------------------
    +
    580// Aligned allocation
    +
    581// ------------------------------------------------------
    +
    582
    +
    590
    +
    608void* mi_malloc_aligned(size_t size, size_t alignment);
    +
    609void* mi_zalloc_aligned(size_t size, size_t alignment);
    +
    610void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    +
    611void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    612
    +
    624void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    625void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    626void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    +
    627void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    628
    +
    630
    +
    636
    +
    641struct mi_heap_s;
    +
    642
    +
    647typedef struct mi_heap_s mi_heap_t;
    +
    648
    + +
    651
    + +
    660
    + +
    669
    + +
    674
    + +
    678
    + +
    685
    +
    687void mi_heap_collect(mi_heap_t* heap, bool force);
    688
    -
    691void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    +
    691void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    692
    -
    695char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    -
    696
    -
    699char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    -
    700
    -
    703char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    -
    704
    -
    705void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    706void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    -
    707void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    -
    708
    -
    709void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    710void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    711void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    712void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    713void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    -
    714void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    -
    715void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    716void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    696void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    +
    697
    +
    700void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    +
    701
    +
    704void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    +
    705
    +
    708void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    +
    709
    +
    712char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    +
    713
    +
    716char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    717
    -
    719
    -
    720
    -
    729
    -
    730void* mi_rezalloc(void* p, size_t newsize);
    -
    731void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    -
    732
    -
    733void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    734void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    735void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    -
    736void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    720char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    +
    721
    +
    722void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    723void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    +
    724void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    +
    725
    +
    726void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    727void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    728void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    729void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    730void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    +
    731void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    +
    732void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    733void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    734
    +
    736
    737
    -
    738void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    739void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    -
    740
    -
    741void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    742void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    -
    743void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    -
    744void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    745
    -
    747
    -
    756
    -
    768#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    -
    769
    -
    771#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    -
    772
    -
    774#define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    -
    775
    -
    777#define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    -
    778
    -
    780#define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    -
    781
    -
    783#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    -
    784
    -
    786#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    -
    787
    -
    789#define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    -
    790
    -
    792#define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    -
    793
    -
    795#define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    -
    796
    -
    798#define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    -
    799
    +
    746
    +
    747void* mi_rezalloc(void* p, size_t newsize);
    +
    748void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    +
    749
    +
    750void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    751void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    752void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    +
    753void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    754
    +
    755void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    756void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    +
    757
    +
    758void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    759void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    760void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    +
    761void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    762
    +
    764
    +
    773
    +
    785#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    +
    786
    +
    788#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    +
    789
    +
    791#define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    +
    792
    +
    794#define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    +
    795
    +
    797#define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    +
    798
    +
    800#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    801
    +
    803#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    +
    804
    +
    806#define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    807
    -
    814bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    -
    815
    -
    824bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    -
    825
    -
    833bool mi_check_owned(const void* p);
    -
    834
    -
    -
    837typedef struct mi_heap_area_s {
    -
    838 void* blocks;
    -
    839 size_t reserved;
    -
    840 size_t committed;
    -
    841 size_t used;
    -
    842 size_t block_size;
    - - +
    809#define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    +
    810
    +
    812#define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    +
    813
    +
    815#define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    +
    816
    +
    818
    +
    824
    +
    831bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    +
    832
    +
    841bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    +
    842
    +
    850bool mi_check_owned(const void* p);
    +
    851
    +
    +
    854typedef struct mi_heap_area_s {
    +
    855 void* blocks;
    +
    856 size_t reserved;
    +
    857 size_t committed;
    +
    858 size_t used;
    +
    859 size_t block_size;
    + + +
    -
    845
    -
    853typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    -
    854
    -
    866bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    -
    867
    -
    871bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    863
    +
    871typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    872
    -
    874
    -
    880
    - +
    884bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    885
    +
    901bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    902
    +
    904
    +
    910
    +
    +
    912typedef enum mi_option_e {
    +
    913 // stable options
    + + + + +
    919
    -
    920
    - - - -
    924void mi_option_set_enabled(mi_option_t option, bool enable);
    - -
    926
    - -
    928long mi_option_get_clamp(mi_option_t option, long min, long max);
    - -
    930
    -
    931void mi_option_set(mi_option_t option, long value);
    -
    932void mi_option_set_default(mi_option_t option, long value);
    -
    933
    -
    934
    -
    936
    -
    943
    -
    945void mi_cfree(void* p);
    -
    946void* mi__expand(void* p, size_t newsize);
    -
    947
    -
    948void* mi_recalloc(void* p, size_t count, size_t size);
    -
    949size_t mi_malloc_size(const void* p);
    -
    950size_t mi_malloc_good_size(size_t size);
    -
    951size_t mi_malloc_usable_size(const void *p);
    -
    952
    -
    953int mi_posix_memalign(void** p, size_t alignment, size_t size);
    -
    954int mi__posix_memalign(void** p, size_t alignment, size_t size);
    -
    955void* mi_memalign(size_t alignment, size_t size);
    -
    956void* mi_valloc(size_t size);
    -
    957void* mi_pvalloc(size_t size);
    -
    958void* mi_aligned_alloc(size_t alignment, size_t size);
    -
    959
    -
    960unsigned short* mi_wcsdup(const unsigned short* s);
    -
    961unsigned char* mi_mbsdup(const unsigned char* s);
    -
    962int mi_dupenv_s(char** buf, size_t* size, const char* name);
    -
    963int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name);
    +
    920 // advanced options
    + + + + + + + + +
    929
    +
    930 // experimental options
    + + + + + + + + + + + + + + + +
    946
    + + +
    +
    949
    +
    950
    + + + +
    954void mi_option_set_enabled(mi_option_t option, bool enable);
    + +
    956
    + +
    958long mi_option_get_clamp(mi_option_t option, long min, long max);
    + +
    960
    +
    961void mi_option_set(mi_option_t option, long value);
    +
    962void mi_option_set_default(mi_option_t option, long value);
    +
    963
    964
    -
    967void* mi_reallocarray(void* p, size_t count, size_t size);
    -
    968
    -
    970int mi_reallocarr(void* p, size_t count, size_t size);
    -
    971
    -
    972void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment);
    -
    973void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    974
    -
    975void mi_free_size(void* p, size_t size);
    -
    976void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    -
    977void mi_free_aligned(void* p, size_t alignment);
    -
    978
    -
    980
    -
    993
    -
    995void* mi_new(std::size_t n) noexcept(false);
    -
    996
    -
    998void* mi_new_n(size_t count, size_t size) noexcept(false);
    -
    999
    -
    1001void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    -
    1002
    -
    1004void* mi_new_nothrow(size_t n);
    -
    1005
    -
    1007void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    +
    966
    +
    973
    +
    975void mi_cfree(void* p);
    +
    976void* mi__expand(void* p, size_t newsize);
    +
    977
    +
    978void* mi_recalloc(void* p, size_t count, size_t size);
    +
    979size_t mi_malloc_size(const void* p);
    +
    980size_t mi_malloc_good_size(size_t size);
    +
    981size_t mi_malloc_usable_size(const void *p);
    +
    982
    +
    983int mi_posix_memalign(void** p, size_t alignment, size_t size);
    +
    984int mi__posix_memalign(void** p, size_t alignment, size_t size);
    +
    985void* mi_memalign(size_t alignment, size_t size);
    +
    986void* mi_valloc(size_t size);
    +
    987void* mi_pvalloc(size_t size);
    +
    988void* mi_aligned_alloc(size_t alignment, size_t size);
    +
    989
    +
    990unsigned short* mi_wcsdup(const unsigned short* s);
    +
    991unsigned char* mi_mbsdup(const unsigned char* s);
    +
    992int mi_dupenv_s(char** buf, size_t* size, const char* name);
    +
    993int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name);
    +
    994
    +
    997void* mi_reallocarray(void* p, size_t count, size_t size);
    +
    998
    +
    1000int mi_reallocarr(void* p, size_t count, size_t size);
    +
    1001
    +
    1002void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment);
    +
    1003void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    1004
    +
    1005void mi_free_size(void* p, size_t size);
    +
    1006void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    +
    1007void mi_free_aligned(void* p, size_t alignment);
    1008
    -
    1010void* mi_new_realloc(void* p, size_t newsize);
    -
    1011
    -
    1013void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    -
    1014
    -
    1022template<class T> struct mi_stl_allocator { }
    +
    1010
    1023
    -
    1025
    +
    1025void* mi_new(std::size_t n) noexcept(false);
    +
    1026
    +
    1028void* mi_new_n(size_t count, size_t size) noexcept(false);
    +
    1029
    +
    1031void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    +
    1032
    +
    1034void* mi_new_nothrow(size_t n);
    +
    1035
    +
    1037void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    +
    1038
    +
    1040void* mi_new_realloc(void* p, size_t newsize);
    +
    1041
    +
    1043void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    +
    1044
    +
    1052template<class T> struct mi_stl_allocator { }
    +
    1053
    +
    1055
    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_calloc_aligned(size_t count, size_t size, size_t alignment)
    void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
    @@ -480,19 +483,20 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
    void * mi_zalloc_aligned(size_t size, size_t alignment)
    void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    -
    size_t block_size
    size in bytes of one block
    Definition mimalloc-doc.h:842
    -
    size_t committed
    current committed bytes of this area
    Definition mimalloc-doc.h:840
    -
    size_t full_block_size
    size in bytes of a full block including padding and metadata.
    Definition mimalloc-doc.h:843
    -
    size_t used
    bytes in use by allocated blocks
    Definition mimalloc-doc.h:841
    -
    void * blocks
    start of the area containing heap blocks
    Definition mimalloc-doc.h:838
    -
    size_t reserved
    bytes reserved for this area
    Definition mimalloc-doc.h:839
    +
    int heap_tag
    heap tag associated with this area (see mi_heap_new_ex)
    Definition mimalloc-doc.h:861
    +
    size_t block_size
    size in bytes of one block
    Definition mimalloc-doc.h:859
    +
    size_t committed
    current committed bytes of this area
    Definition mimalloc-doc.h:857
    +
    size_t full_block_size
    size in bytes of a full block including padding and metadata.
    Definition mimalloc-doc.h:860
    +
    size_t used
    bytes in use by allocated blocks
    Definition mimalloc-doc.h:858
    +
    void * blocks
    start of the area containing heap blocks
    Definition mimalloc-doc.h:855
    +
    size_t reserved
    bytes reserved for this area
    Definition mimalloc-doc.h:856
    bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
    Check safely if any pointer is part of a heap.
    bool mi_check_owned(const void *p)
    Check safely if any pointer is part of the default heap of this thread.
    bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun *visitor, void *arg)
    Visit all areas and blocks in abandoned heaps.
    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.
    -
    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:853
    +
    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:871
    bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
    Does a heap contain a pointer to a previously allocated block?
    -
    An area of heap space contains blocks of a single size.
    Definition mimalloc-doc.h:837
    +
    An area of heap space contains blocks of a single size.
    Definition mimalloc-doc.h:854
    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_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...
    void * mi_new_realloc(void *p, size_t newsize)
    like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    @@ -500,16 +504,17 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    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_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_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...
    -
    std::allocator implementation for mimalloc for use in STL containers.
    Definition mimalloc-doc.h:1022
    +
    std::allocator implementation for mimalloc for use in STL containers.
    Definition mimalloc-doc.h:1052
    int mi_reserve_os_memory(size_t size, bool commit, bool allow_large)
    Reserve OS memory for use by mimalloc.
    size_t mi_usable_size(void *p)
    Return the available bytes in a memory block.
    void mi_thread_done(void)
    Uninitialize mimalloc on a thread.
    -
    void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition mimalloc-doc.h:355
    +
    void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
    Type of deferred free functions.
    Definition mimalloc-doc.h:354
    void mi_stats_print(void *out)
    Deprecated.
    mi_subproc_id_t mi_subproc_main(void)
    Get the main sub-process identifier.
    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...
    int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t *arena_id)
    Reserve OS memory to be managed in an arena.
    void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
    Register a deferred free function.
    +
    mi_heap_t * mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id)
    Create a new heap.
    void mi_stats_reset(void)
    Reset statistics.
    bool mi_manage_os_memory_ex(void *start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t *arena_id)
    Manage externally allocated memory as a mimalloc arena.
    void mi_collect(bool force)
    Eagerly free memory.
    @@ -522,10 +527,10 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    void mi_process_info(size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)
    Return process information (time and memory usage).
    void * mi_malloc_small(size_t size)
    Allocate a small object.
    mi_subproc_id_t mi_subproc_new(void)
    Create a fresh sub-process (with no associated threads yet).
    -
    void mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition mimalloc-doc.h:394
    +
    void mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition mimalloc-doc.h:393
    void mi_stats_merge(void)
    Merge thread local statistics with the main statistics and reset.
    -
    void * mi_subproc_id_t
    A process can associate threads with sub-processes.
    Definition mimalloc-doc.h:546
    -
    int mi_arena_id_t
    Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.
    Definition mimalloc-doc.h:500
    +
    void * mi_subproc_id_t
    A process can associate threads with sub-processes.
    Definition mimalloc-doc.h:558
    +
    int mi_arena_id_t
    Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.
    Definition mimalloc-doc.h:499
    void * mi_arena_area(mi_arena_id_t arena_id, size_t *size)
    Return the size of an arena.
    void mi_register_error(mi_error_fun *errfun, void *arg)
    Register an error callback function.
    void mi_subproc_delete(mi_subproc_id_t subproc)
    Delete a previously created sub-process.
    @@ -535,7 +540,7 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    size_t mi_good_size(size_t size)
    Return the used allocation size.
    void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge)
    Show all current arena's.
    void mi_subproc_add_current_thread(mi_subproc_id_t subproc)
    Add the current thread to the given sub-process.
    -
    void mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition mimalloc-doc.h:379
    +
    void mi_output_fun(const char *msg, void *arg)
    Type of output functions.
    Definition mimalloc-doc.h:378
    void mi_register_output(mi_output_fun *out, void *arg)
    Register an output function.
    void mi_thread_init(void)
    Initialize mimalloc on a thread.
    void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
    Allocate a small object in a specific heap.
    @@ -543,7 +548,7 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    void mi_heap_delete(mi_heap_t *heap)
    Delete a previously allocated heap.
    void * mi_heap_malloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
    Set the default heap to use in the current thread for mi_malloc() et al.
    -
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition mimalloc-doc.h:630
    +
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition mimalloc-doc.h:647
    void * mi_heap_zalloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    char * mi_heap_realpath(mi_heap_t *heap, const char *fname, char *resolved_name)
    Resolve a file path name using a specific heap to allocate the result.
    char * mi_heap_strdup(mi_heap_t *heap, const char *s)
    Duplicate a string in a specific heap.
    @@ -588,36 +593,36 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    void mi_option_set_enabled(mi_option_t option, bool enable)
    void mi_option_disable(mi_option_t option)
    void mi_option_set(mi_option_t option, long value)
    -
    mi_option_t
    Runtime options.
    Definition mimalloc-doc.h:882
    -
    @ mi_option_abandoned_reclaim_on_free
    allow to reclaim an abandoned segment on a free (=1)
    Definition mimalloc-doc.h:912
    -
    @ mi_option_purge_extend_delay
    extend purge delay on each subsequent delay (=1)
    Definition mimalloc-doc.h:913
    -
    @ mi_option_show_stats
    Print statistics on termination.
    Definition mimalloc-doc.h:885
    -
    @ mi_option_use_numa_nodes
    0 = use all available numa nodes, otherwise use at most N nodes.
    Definition mimalloc-doc.h:906
    -
    @ mi_option_abandoned_page_purge
    immediately purge delayed purges on thread termination
    Definition mimalloc-doc.h:904
    -
    @ mi_option_eager_commit_delay
    the first N segments per thread are not eagerly committed (but per page in the segment on demand)
    Definition mimalloc-doc.h:902
    -
    @ mi_option_eager_commit
    eager commit segments? (after eager_commit_delay segments) (enabled by default).
    Definition mimalloc-doc.h:901
    -
    @ mi_option_visit_abandoned
    allow visiting heap blocks from abandoned threads (=0)
    Definition mimalloc-doc.h:915
    -
    @ mi_option_os_tag
    tag used for OS logging (macOS only for now) (=100)
    Definition mimalloc-doc.h:897
    -
    @ _mi_option_last
    Definition mimalloc-doc.h:917
    -
    @ mi_option_destroy_on_exit
    if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe
    Definition mimalloc-doc.h:910
    -
    @ mi_option_verbose
    Print verbose messages.
    Definition mimalloc-doc.h:886
    -
    @ mi_option_allow_large_os_pages
    allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.
    Definition mimalloc-doc.h:894
    -
    @ mi_option_arena_purge_mult
    multiplier for purge_delay for the purging delay for arenas (=10)
    Definition mimalloc-doc.h:911
    -
    @ mi_option_retry_on_oom
    retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)
    Definition mimalloc-doc.h:898
    -
    @ mi_option_purge_decommits
    should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)
    Definition mimalloc-doc.h:895
    -
    @ mi_option_limit_os_alloc
    If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)
    Definition mimalloc-doc.h:908
    -
    @ mi_option_reserve_huge_os_pages_at
    Reserve N huge OS pages at a specific NUMA node N.
    Definition mimalloc-doc.h:892
    -
    @ mi_option_max_segment_reclaim
    max. percentage of the abandoned segments can be reclaimed per try (=10%)
    Definition mimalloc-doc.h:909
    -
    @ mi_option_arena_reserve
    initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use ...
    Definition mimalloc-doc.h:896
    -
    @ mi_option_reserve_huge_os_pages
    reserve N huge OS pages (1GiB pages) at startup
    Definition mimalloc-doc.h:891
    -
    @ mi_option_disallow_os_alloc
    1 = do not use OS memory for allocation (but only programmatically reserved arenas)
    Definition mimalloc-doc.h:907
    -
    @ mi_option_purge_delay
    memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all...
    Definition mimalloc-doc.h:905
    -
    @ mi_option_disallow_arena_alloc
    1 = do not use arena's for allocation (except if using specific arena id's)
    Definition mimalloc-doc.h:914
    -
    @ mi_option_max_errors
    issue at most N error messages
    Definition mimalloc-doc.h:887
    -
    @ mi_option_max_warnings
    issue at most N warning messages
    Definition mimalloc-doc.h:888
    -
    @ mi_option_show_errors
    Print error messages.
    Definition mimalloc-doc.h:884
    -
    @ mi_option_reserve_os_memory
    reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use m...
    Definition mimalloc-doc.h:893
    -
    @ mi_option_arena_eager_commit
    eager commit arenas? Use 2 to enable just on overcommit systems (=2)
    Definition mimalloc-doc.h:903
    +
    mi_option_t
    Runtime options.
    Definition mimalloc-doc.h:912
    +
    @ mi_option_abandoned_reclaim_on_free
    allow to reclaim an abandoned segment on a free (=1)
    Definition mimalloc-doc.h:942
    +
    @ mi_option_purge_extend_delay
    extend purge delay on each subsequent delay (=1)
    Definition mimalloc-doc.h:943
    +
    @ mi_option_show_stats
    Print statistics on termination.
    Definition mimalloc-doc.h:915
    +
    @ mi_option_use_numa_nodes
    0 = use all available numa nodes, otherwise use at most N nodes.
    Definition mimalloc-doc.h:936
    +
    @ mi_option_abandoned_page_purge
    immediately purge delayed purges on thread termination
    Definition mimalloc-doc.h:934
    +
    @ mi_option_eager_commit_delay
    the first N segments per thread are not eagerly committed (but per page in the segment on demand)
    Definition mimalloc-doc.h:932
    +
    @ mi_option_eager_commit
    eager commit segments? (after eager_commit_delay segments) (enabled by default).
    Definition mimalloc-doc.h:931
    +
    @ mi_option_visit_abandoned
    allow visiting heap blocks from abandoned threads (=0)
    Definition mimalloc-doc.h:945
    +
    @ mi_option_os_tag
    tag used for OS logging (macOS only for now) (=100)
    Definition mimalloc-doc.h:927
    +
    @ _mi_option_last
    Definition mimalloc-doc.h:947
    +
    @ mi_option_destroy_on_exit
    if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe
    Definition mimalloc-doc.h:940
    +
    @ mi_option_verbose
    Print verbose messages.
    Definition mimalloc-doc.h:916
    +
    @ mi_option_allow_large_os_pages
    allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.
    Definition mimalloc-doc.h:924
    +
    @ mi_option_arena_purge_mult
    multiplier for purge_delay for the purging delay for arenas (=10)
    Definition mimalloc-doc.h:941
    +
    @ mi_option_retry_on_oom
    retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)
    Definition mimalloc-doc.h:928
    +
    @ mi_option_purge_decommits
    should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)
    Definition mimalloc-doc.h:925
    +
    @ mi_option_limit_os_alloc
    If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)
    Definition mimalloc-doc.h:938
    +
    @ mi_option_reserve_huge_os_pages_at
    Reserve N huge OS pages at a specific NUMA node N.
    Definition mimalloc-doc.h:922
    +
    @ mi_option_max_segment_reclaim
    max. percentage of the abandoned segments can be reclaimed per try (=10%)
    Definition mimalloc-doc.h:939
    +
    @ mi_option_arena_reserve
    initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use ...
    Definition mimalloc-doc.h:926
    +
    @ mi_option_reserve_huge_os_pages
    reserve N huge OS pages (1GiB pages) at startup
    Definition mimalloc-doc.h:921
    +
    @ mi_option_disallow_os_alloc
    1 = do not use OS memory for allocation (but only programmatically reserved arenas)
    Definition mimalloc-doc.h:937
    +
    @ mi_option_purge_delay
    memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all...
    Definition mimalloc-doc.h:935
    +
    @ mi_option_disallow_arena_alloc
    1 = do not use arena's for allocation (except if using specific arena id's)
    Definition mimalloc-doc.h:944
    +
    @ mi_option_max_errors
    issue at most N error messages
    Definition mimalloc-doc.h:917
    +
    @ mi_option_max_warnings
    issue at most N warning messages
    Definition mimalloc-doc.h:918
    +
    @ mi_option_show_errors
    Print error messages.
    Definition mimalloc-doc.h:914
    +
    @ mi_option_reserve_os_memory
    reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use m...
    Definition mimalloc-doc.h:923
    +
    @ mi_option_arena_eager_commit
    eager commit arenas? Use 2 to enable just on overcommit systems (=2)
    Definition mimalloc-doc.h:933
    size_t mi_malloc_usable_size(const void *p)
    void mi_free_aligned(void *p, size_t alignment)
    void * mi_aligned_offset_recalloc(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js index 885cdacf..e3010d9e 100644 --- a/docs/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -17,12 +17,13 @@ var NAVTREEINDEX0 = "group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82":[5,2,6], "group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6":[5,2,5], "group__analysis.html":[5,6], +"group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1":[5,6,0,4], "group__analysis.html#a332a6c14d736a99699d5453a1cb04b41":[5,6,0,0], "group__analysis.html#ab47526df656d8837ec3e97f11b83f835":[5,6,0,2], "group__analysis.html#ab53664e31d7fe2564f8d42041ef75cb3":[5,6,0,3], -"group__analysis.html#ab820302c5cd0df133eb8e51650a008b4":[5,6,0,5], +"group__analysis.html#ab820302c5cd0df133eb8e51650a008b4":[5,6,0,6], "group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8":[5,6,0,1], -"group__analysis.html#ae848a3e6840414891035423948ca0383":[5,6,0,4], +"group__analysis.html#ae848a3e6840414891035423948ca0383":[5,6,0,5], "group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377":[5,6,4], "group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5":[5,6,3], "group__analysis.html#ga6a4865a887b2ec5247854af61562503c":[5,6,2], @@ -40,44 +41,45 @@ var NAVTREEINDEX0 = "group__cpp.html#gadd11b85c15d21d308386844b5233856c":[5,9,4], "group__cpp.html#structmi__stl__allocator":[5,9,0], "group__extended.html":[5,1], -"group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767":[5,1,23], -"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,36], -"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,33], +"group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767":[5,1,24], +"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,37], +"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,34], "group__extended.html#ga1ea64283508718d9d645c38efc2f4305":[5,1,0], "group__extended.html#ga292a45f7dbc7cd23c5352ce1f0002816":[5,1,2], -"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,26], -"group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806":[5,1,31], -"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,22], -"group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b":[5,1,24], -"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,17], -"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,28], -"group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e":[5,1,15], +"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,27], +"group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806":[5,1,32], +"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,23], +"group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b":[5,1,25], +"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,18], +"group__extended.html#ga3ae360583f4351aa5267ee7e43008faf":[5,1,10], +"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,29], +"group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e":[5,1,16], "group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,7], -"group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf":[5,1,14], -"group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e":[5,1,37], -"group__extended.html#ga537f13b299ddf801e49a5a94fde02c79":[5,1,27], -"group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52":[5,1,21], -"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,11], -"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,20], -"group__extended.html#ga7d862c2affd5790381da14eb102a364d":[5,1,16], -"group__extended.html#ga7f050bc6b897da82692174f5fce59cde":[5,1,13], -"group__extended.html#ga8068cac328e41fa2170faef707315243":[5,1,32], +"group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf":[5,1,15], +"group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e":[5,1,38], +"group__extended.html#ga537f13b299ddf801e49a5a94fde02c79":[5,1,28], +"group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52":[5,1,22], +"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,12], +"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,21], +"group__extended.html#ga7d862c2affd5790381da14eb102a364d":[5,1,17], +"group__extended.html#ga7f050bc6b897da82692174f5fce59cde":[5,1,14], +"group__extended.html#ga8068cac328e41fa2170faef707315243":[5,1,33], "group__extended.html#ga83fc6a688b322261e1c2deab000b0591":[5,1,3], -"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,25], +"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,26], "group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d":[5,1,5], "group__extended.html#ga99fe38650d0b02e0e0f89ee024db91d3":[5,1,1], "group__extended.html#ga9a25a00a22151619a0be91a10af7787f":[5,1,6], -"group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,18], -"group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e":[5,1,30], -"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,12], -"group__extended.html#gaaf2d9976576d5efd5544be12848af949":[5,1,10], -"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,35], +"group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,19], +"group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e":[5,1,31], +"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,13], +"group__extended.html#gaaf2d9976576d5efd5544be12848af949":[5,1,11], +"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,36], "group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,9], "group__extended.html#gad7439207f8f71fb6c382a9ea20b997e7":[5,1,8], -"group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c":[5,1,29], +"group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c":[5,1,30], "group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d":[5,1,4], -"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,19], -"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,34], +"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,20], +"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,35], "group__heap.html":[5,3], "group__heap.html#ga012c5c8abe22b10043de39ff95909541":[5,3,12], "group__heap.html#ga14c667a6e2c5d28762d8cb7d4e057909":[5,3,8], diff --git a/docs/search/all_6.js b/docs/search/all_6.js index 3131f4a2..5a38d848 100644 --- a/docs/search/all_6.js +++ b/docs/search/all_6.js @@ -1,5 +1,6 @@ var searchData= [ ['heap_20allocation_0',['Heap Allocation',['../group__heap.html',1,'']]], - ['heap_20introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]] + ['heap_20introspection_1',['Heap Introspection',['../group__analysis.html',1,'']]], + ['heap_5ftag_2',['heap_tag',['../group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1',1,'mi_heap_area_t']]] ]; diff --git a/docs/search/all_9.js b/docs/search/all_9.js index 99613086..400cd023 100644 --- a/docs/search/all_9.js +++ b/docs/search/all_9.js @@ -50,142 +50,143 @@ var searchData= ['mi_5fheap_5fmallocn_47',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmallocn_5ftp_48',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], ['mi_5fheap_5fnew_49',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_5fin_5farena_50',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_51',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_52',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_5fat_53',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocf_54',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_55',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_5ftp_56',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealpath_57',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_58',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_59',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_5fat_60',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5ftp_61',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_62',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_63',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_5fat_64',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fset_5fdefault_65',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrdup_66',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrndup_67',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5ft_68',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fvisit_5fblocks_69',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_70',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_71',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_5fat_72',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5ftp_73',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], - ['mi_5fis_5fin_5fheap_5fregion_74',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], - ['mi_5fis_5fredirected_75',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_76',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_77',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_5fat_78',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fgood_5fsize_79',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsize_80',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsmall_81',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5ftp_82',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fusable_5fsize_83',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_84',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_5ftp_85',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_86',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_5fex_87',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], - ['mi_5fmbsdup_88',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], - ['mi_5fmemalign_89',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], - ['mi_5fnew_90',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_91',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_5fnothrow_92',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fn_93',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fnothrow_94',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], - ['mi_5fnew_5frealloc_95',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], - ['mi_5fnew_5freallocn_96',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], - ['mi_5foption_5fabandoned_5fpage_5fpurge_97',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_98',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], - ['mi_5foption_5fallow_5flarge_5fos_5fpages_99',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], - ['mi_5foption_5farena_5feager_5fcommit_100',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], - ['mi_5foption_5farena_5fpurge_5fmult_101',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], - ['mi_5foption_5farena_5freserve_102',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdestroy_5fon_5fexit_103',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisable_104',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisallow_5farena_5falloc_105',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisallow_5fos_5falloc_106',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_107',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], - ['mi_5foption_5feager_5fcommit_5fdelay_108',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_109',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_110',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_5fclamp_111',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_5fsize_112',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fis_5fenabled_113',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], - ['mi_5foption_5flimit_5fos_5falloc_114',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], - ['mi_5foption_5fmax_5ferrors_115',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fmax_5fsegment_5freclaim_116',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], - ['mi_5foption_5fmax_5fwarnings_117',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], - ['mi_5foption_5fos_5ftag_118',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpurge_5fdecommits_119',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpurge_5fdelay_120',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], - ['mi_5foption_5fpurge_5fextend_5fdelay_121',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_122',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_123',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], - ['mi_5foption_5freserve_5fos_5fmemory_124',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], - ['mi_5foption_5fretry_5fon_5foom_125',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_126',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fdefault_127',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_128',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_5fdefault_129',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5ferrors_130',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], - ['mi_5foption_5fshow_5fstats_131',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], - ['mi_5foption_5ft_132',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fuse_5fnuma_5fnodes_133',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], - ['mi_5foption_5fverbose_134',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], - ['mi_5foption_5fvisit_5fabandoned_135',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]], - ['mi_5foutput_5ffun_136',['mi_output_fun',['../group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d',1,'mimalloc-doc.h']]], - ['mi_5fposix_5fmemalign_137',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo_138',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], - ['mi_5fpvalloc_139',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], - ['mi_5frealloc_140',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_141',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_5fat_142',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], - ['mi_5freallocarr_143',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], - ['mi_5freallocarray_144',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], - ['mi_5freallocf_145',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], - ['mi_5freallocn_146',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], - ['mi_5freallocn_5ftp_147',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], - ['mi_5frealpath_148',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_149',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_150',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_5fat_151',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], - ['mi_5fregister_5fdeferred_5ffree_152',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], - ['mi_5fregister_5ferror_153',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], - ['mi_5fregister_5foutput_154',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_155',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_156',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_157',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_158',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_5fex_159',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_160',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_161',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_5fat_162',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], - ['mi_5fsmall_5fsize_5fmax_163',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fmerge_164',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_165',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_5fout_166',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset_167',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], - ['mi_5fstl_5fallocator_168',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], - ['mi_5fstrdup_169',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], - ['mi_5fstrndup_170',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fadd_5fcurrent_5fthread_171',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fdelete_172',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fid_5ft_173',['mi_subproc_id_t',['../group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fmain_174',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fnew_175',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone_176',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit_177',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint_5fout_178',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], - ['mi_5fusable_5fsize_179',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], - ['mi_5fvalloc_180',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], - ['mi_5fwcsdup_181',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], - ['mi_5fwdupenv_5fs_182',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_183',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_184',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_5fat_185',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5fsmall_186',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5ftp_187',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] + ['mi_5fheap_5fnew_5fex_50',['mi_heap_new_ex',['../group__extended.html#ga3ae360583f4351aa5267ee7e43008faf',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fin_5farena_51',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_52',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_53',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_5fat_54',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocf_55',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_56',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_5ftp_57',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealpath_58',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_59',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_60',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat_61',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5ftp_62',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_63',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_64',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat_65',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fset_5fdefault_66',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrdup_67',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrndup_68',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5ft_69',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fvisit_5fblocks_70',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_71',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_72',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_5fat_73',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5ftp_74',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion_75',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected_76',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_77',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_78',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_5fat_79',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fgood_5fsize_80',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsize_81',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsmall_82',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5ftp_83',['mi_malloc_tp',['../group__typed.html#ga0619a62c5fd886f1016030abe91f0557',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fusable_5fsize_84',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_85',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_5ftp_86',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_87',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_5fex_88',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], + ['mi_5fmbsdup_89',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], + ['mi_5fmemalign_90',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], + ['mi_5fnew_91',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_92',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_5fnothrow_93',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fn_94',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fnothrow_95',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], + ['mi_5fnew_5frealloc_96',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], + ['mi_5fnew_5freallocn_97',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5fpage_5fpurge_98',['mi_option_abandoned_page_purge',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca11e62ed69200a489a5be955582078c0c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fabandoned_5freclaim_5fon_5ffree_99',['mi_option_abandoned_reclaim_on_free',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca009e4b5684922ce664d73d2a8e1698d9',1,'mimalloc-doc.h']]], + ['mi_5foption_5fallow_5flarge_5fos_5fpages_100',['mi_option_allow_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7cc4804ced69004fa42a9a136a9ba556',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5feager_5fcommit_101',['mi_option_arena_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafd0c5ddbc4b59fd8b5216871728167a5',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5fpurge_5fmult_102',['mi_option_arena_purge_mult',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8236501f1ab45d26e6fd885d191a2b5e',1,'mimalloc-doc.h']]], + ['mi_5foption_5farena_5freserve_103',['mi_option_arena_reserve',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab1c88e23ae290bbeec824038a97959de',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdestroy_5fon_5fexit_104',['mi_option_destroy_on_exit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca6364331e305e7d3c0218b058ff3afc88',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable_105',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5farena_5falloc_106',['mi_option_disallow_arena_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caeae1696100e4057ffc4182730cc04e40',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisallow_5fos_5falloc_107',['mi_option_disallow_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadcfb5a09580361b1be65901d2d812de6',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_108',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay_109',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable_110',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_111',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fclamp_112',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fsize_113',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled_114',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], + ['mi_5foption_5flimit_5fos_5falloc_115',['mi_option_limit_os_alloc',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9fa61bd9668479f8452d2195759444cc',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5ferrors_116',['mi_option_max_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caec6ecbe29d46a48205ed8823a8a52a6a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fsegment_5freclaim_117',['mi_option_max_segment_reclaim',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa9ad9005d7017c8c30ad2d6ba31db909',1,'mimalloc-doc.h']]], + ['mi_5foption_5fmax_5fwarnings_118',['mi_option_max_warnings',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caf9595921087e942602ee079158762665',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag_119',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdecommits_120',['mi_option_purge_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca9d15c5e3d2115eef681c17e4dd5ab9a4',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fdelay_121',['mi_option_purge_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cadd351e615acd8563529c20a347be7290',1,'mimalloc-doc.h']]], + ['mi_5foption_5fpurge_5fextend_5fdelay_122',['mi_option_purge_extend_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca02005f164bdf03f5f00c5be726adf487',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_123',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages_5fat_124',['mi_option_reserve_huge_os_pages_at',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caa13e7926d4339d2aa6fbf61d4473fd5c',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fos_5fmemory_125',['mi_option_reserve_os_memory',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4999c828cf79a0fb2de65d23f7333',1,'mimalloc-doc.h']]], + ['mi_5foption_5fretry_5fon_5foom_126',['mi_option_retry_on_oom',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca8f51df355bf6651db899e6085b54865e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_127',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fdefault_128',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_129',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault_130',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5ferrors_131',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], + ['mi_5foption_5fshow_5fstats_132',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], + ['mi_5foption_5ft_133',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fuse_5fnuma_5fnodes_134',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]], + ['mi_5foption_5fverbose_135',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], + ['mi_5foption_5fvisit_5fabandoned_136',['mi_option_visit_abandoned',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca38c67733a3956a1f4eeaca89fab9e78e',1,'mimalloc-doc.h']]], + ['mi_5foutput_5ffun_137',['mi_output_fun',['../group__extended.html#gadf31cea7d0332a81c8b882cbbdbadb8d',1,'mimalloc-doc.h']]], + ['mi_5fposix_5fmemalign_138',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo_139',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], + ['mi_5fpvalloc_140',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], + ['mi_5frealloc_141',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_142',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_5fat_143',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], + ['mi_5freallocarr_144',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], + ['mi_5freallocarray_145',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], + ['mi_5freallocf_146',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], + ['mi_5freallocn_147',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], + ['mi_5freallocn_5ftp_148',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], + ['mi_5frealpath_149',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_150',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_151',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat_152',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], + ['mi_5fregister_5fdeferred_5ffree_153',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], + ['mi_5fregister_5ferror_154',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput_155',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_156',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_157',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_158',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_159',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_5fex_160',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_161',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_162',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat_163',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], + ['mi_5fsmall_5fsize_5fmax_164',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge_165',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_166',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout_167',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset_168',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], + ['mi_5fstl_5fallocator_169',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], + ['mi_5fstrdup_170',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], + ['mi_5fstrndup_171',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fadd_5fcurrent_5fthread_172',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fdelete_173',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fid_5ft_174',['mi_subproc_id_t',['../group__extended.html#ga8c0bcd1fee27c7641e9c3c0d991b3b7d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fmain_175',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fnew_176',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone_177',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit_178',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint_5fout_179',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], + ['mi_5fusable_5fsize_180',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], + ['mi_5fvalloc_181',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], + ['mi_5fwcsdup_182',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], + ['mi_5fwdupenv_5fs_183',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_184',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_185',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_5fat_186',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5fsmall_187',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5ftp_188',['mi_zalloc_tp',['../group__typed.html#gac77a61bdaf680a803785fe307820b48c',1,'mimalloc-doc.h']]] ]; diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js index 5a8d20d0..8899d6e4 100644 --- a/docs/search/functions_0.js +++ b/docs/search/functions_0.js @@ -37,101 +37,102 @@ var searchData= ['mi_5fheap_5fmalloc_5fsmall_34',['mi_heap_malloc_small',['../group__heap.html#ga012c5c8abe22b10043de39ff95909541',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmallocn_35',['mi_heap_mallocn',['../group__heap.html#gab0f755c0b21c387fe8e9024200faa372',1,'mimalloc-doc.h']]], ['mi_5fheap_5fnew_36',['mi_heap_new',['../group__heap.html#gaa718bb226ec0546ba6d1b6cb32179f3a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fnew_5fin_5farena_37',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_38',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_39',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealloc_5faligned_5fat_40',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocf_41',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5freallocn_42',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frealpath_43',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_44',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_45',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frecalloc_5faligned_5fat_46',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_47',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_48',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], - ['mi_5fheap_5frezalloc_5faligned_5fat_49',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fset_5fdefault_50',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrdup_51',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fstrndup_52',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fvisit_5fblocks_53',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_54',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_55',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], - ['mi_5fheap_5fzalloc_5faligned_5fat_56',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], - ['mi_5fis_5fin_5fheap_5fregion_57',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], - ['mi_5fis_5fredirected_58',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_59',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_60',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5faligned_5fat_61',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fgood_5fsize_62',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsize_63',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fsmall_64',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], - ['mi_5fmalloc_5fusable_5fsize_65',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], - ['mi_5fmallocn_66',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_67',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], - ['mi_5fmanage_5fos_5fmemory_5fex_68',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], - ['mi_5fmbsdup_69',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], - ['mi_5fmemalign_70',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], - ['mi_5fnew_71',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_72',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], - ['mi_5fnew_5faligned_5fnothrow_73',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fn_74',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], - ['mi_5fnew_5fnothrow_75',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], - ['mi_5fnew_5frealloc_76',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], - ['mi_5fnew_5freallocn_77',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], - ['mi_5foption_5fdisable_78',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_79',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_80',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_5fclamp_81',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], - ['mi_5foption_5fget_5fsize_82',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], - ['mi_5foption_5fis_5fenabled_83',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_84',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fdefault_85',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_86',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], - ['mi_5foption_5fset_5fenabled_5fdefault_87',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], - ['mi_5fposix_5fmemalign_88',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo_89',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], - ['mi_5fpvalloc_90',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], - ['mi_5frealloc_91',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_92',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], - ['mi_5frealloc_5faligned_5fat_93',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], - ['mi_5freallocarr_94',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], - ['mi_5freallocarray_95',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], - ['mi_5freallocf_96',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], - ['mi_5freallocn_97',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], - ['mi_5frealpath_98',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_99',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_100',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], - ['mi_5frecalloc_5faligned_5fat_101',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], - ['mi_5fregister_5fdeferred_5ffree_102',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], - ['mi_5fregister_5ferror_103',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], - ['mi_5fregister_5foutput_104',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_105',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_106',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_107',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_108',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], - ['mi_5freserve_5fos_5fmemory_5fex_109',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_110',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_111',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], - ['mi_5frezalloc_5faligned_5fat_112',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fmerge_113',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_114',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint_5fout_115',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset_116',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], - ['mi_5fstrdup_117',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], - ['mi_5fstrndup_118',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fadd_5fcurrent_5fthread_119',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fdelete_120',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fmain_121',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], - ['mi_5fsubproc_5fnew_122',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone_123',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit_124',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint_5fout_125',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], - ['mi_5fusable_5fsize_126',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], - ['mi_5fvalloc_127',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], - ['mi_5fwcsdup_128',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], - ['mi_5fwdupenv_5fs_129',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_130',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_131',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5faligned_5fat_132',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], - ['mi_5fzalloc_5fsmall_133',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]] + ['mi_5fheap_5fnew_5fex_37',['mi_heap_new_ex',['../group__extended.html#ga3ae360583f4351aa5267ee7e43008faf',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fnew_5fin_5farena_38',['mi_heap_new_in_arena',['../group__extended.html#gaaf2d9976576d5efd5544be12848af949',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_39',['mi_heap_realloc',['../group__heap.html#gac5252d6a2e510bd349e4fcb452e6a93a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_40',['mi_heap_realloc_aligned',['../group__heap.html#gaccf8c249872f30bf1c2493a09197d734',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealloc_5faligned_5fat_41',['mi_heap_realloc_aligned_at',['../group__heap.html#ga6df988a7219d5707f010d5f3eb0dc3f5',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocf_42',['mi_heap_reallocf',['../group__heap.html#gae7cd171425bee04c683c65a3701f0b4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5freallocn_43',['mi_heap_reallocn',['../group__heap.html#gaccf7bfe10ce510a000d3547d9cf7fa29',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frealpath_44',['mi_heap_realpath',['../group__heap.html#ga55545a3ec6da29c5b4f62e540ecac1e2',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_45',['mi_heap_recalloc',['../group__zeroinit.html#gad1a0d325d930eeb80f25e3fea37aacde',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_46',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga87ddd674bf1c67237d780d0b9e0f0f32',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat_47',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga07b5bcbaf00d0d2e598c232982588496',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_48',['mi_heap_rezalloc',['../group__zeroinit.html#ga8d8b7ebb24b513cd84d1a696048da60d',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_49',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga5129f6dc46ee1613d918820a8a0533a7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat_50',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#ga2bafa79c3f98ea74882349d44cffa5d9',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fset_5fdefault_51',['mi_heap_set_default',['../group__heap.html#ga349b677dec7da5eacdbc7a385bd62a4a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrdup_52',['mi_heap_strdup',['../group__heap.html#ga5754e09ccc51dd6bc73885bb6ea21b7a',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fstrndup_53',['mi_heap_strndup',['../group__heap.html#gad224df78f1fbee942df8adf023e12cf3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fvisit_5fblocks_54',['mi_heap_visit_blocks',['../group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_55',['mi_heap_zalloc',['../group__heap.html#gabebc796399619d964d8db77aa835e8c1',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_56',['mi_heap_zalloc_aligned',['../group__heap.html#ga6466bde8b5712aa34e081a8317f9f471',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fzalloc_5faligned_5fat_57',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga484e3d01cd174f78c7e53370e5a7c819',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion_58',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected_59',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_60',['mi_malloc',['../group__malloc.html#gae1dd97b542420c87ae085e822b1229e8',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_61',['mi_malloc_aligned',['../group__aligned.html#ga69578ff1a98ca16e1dcd02c0995cd65c',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5faligned_5fat_62',['mi_malloc_aligned_at',['../group__aligned.html#ga2022f71b95a7cd6cce1b6e07752ae8ca',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fgood_5fsize_63',['mi_malloc_good_size',['../group__posix.html#ga9d23ac7885fed7413c11d8e0ffa31071',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsize_64',['mi_malloc_size',['../group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fsmall_65',['mi_malloc_small',['../group__extended.html#ga7f050bc6b897da82692174f5fce59cde',1,'mimalloc-doc.h']]], + ['mi_5fmalloc_5fusable_5fsize_66',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]], + ['mi_5fmallocn_67',['mi_mallocn',['../group__malloc.html#ga61f46bade3db76ca24aaafedc40de7b6',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_68',['mi_manage_os_memory',['../group__extended.html#ga4c6486a1fdcd7a423b5f25fe4be8e0cf',1,'mimalloc-doc.h']]], + ['mi_5fmanage_5fos_5fmemory_5fex_69',['mi_manage_os_memory_ex',['../group__extended.html#ga41ce8525d77bbb60f618fa1029994f6e',1,'mimalloc-doc.h']]], + ['mi_5fmbsdup_70',['mi_mbsdup',['../group__posix.html#ga7b82a44094fdec4d2084eb4288a979b0',1,'mimalloc-doc.h']]], + ['mi_5fmemalign_71',['mi_memalign',['../group__posix.html#ga726867f13fd29ca36064954c0285b1d8',1,'mimalloc-doc.h']]], + ['mi_5fnew_72',['mi_new',['../group__cpp.html#ga633d96e3bc7011f960df9f3b2731fc6a',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_73',['mi_new_aligned',['../group__cpp.html#ga79c54da0b4b4ce9fcc11d2f6ef6675f8',1,'mimalloc-doc.h']]], + ['mi_5fnew_5faligned_5fnothrow_74',['mi_new_aligned_nothrow',['../group__cpp.html#ga92ae00b6dd64406c7e64557711ec04b7',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fn_75',['mi_new_n',['../group__cpp.html#gadd11b85c15d21d308386844b5233856c',1,'mimalloc-doc.h']]], + ['mi_5fnew_5fnothrow_76',['mi_new_nothrow',['../group__cpp.html#ga5cb4f120d1f7296074256215aa9a9e54',1,'mimalloc-doc.h']]], + ['mi_5fnew_5frealloc_77',['mi_new_realloc',['../group__cpp.html#ga6867d89baf992728e0cc20a1f47db4d0',1,'mimalloc-doc.h']]], + ['mi_5fnew_5freallocn_78',['mi_new_reallocn',['../group__cpp.html#gaace912ce086682d56f3ce9f7638d9d67',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable_79',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable_80',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_81',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fclamp_82',['mi_option_get_clamp',['../group__options.html#ga96ad9c406338bd314cfe878cfc9bf723',1,'mimalloc-doc.h']]], + ['mi_5foption_5fget_5fsize_83',['mi_option_get_size',['../group__options.html#ga274db5a6ac87cc24ef0b23e7006ed02c',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled_84',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_85',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fdefault_86',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_87',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault_88',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], + ['mi_5fposix_5fmemalign_89',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo_90',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], + ['mi_5fpvalloc_91',['mi_pvalloc',['../group__posix.html#ga644bebccdbb2821542dd8c7e7641f476',1,'mimalloc-doc.h']]], + ['mi_5frealloc_92',['mi_realloc',['../group__malloc.html#ga0621af6a5e3aa384e6a1b548958bf583',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_93',['mi_realloc_aligned',['../group__aligned.html#ga5d7a46d054b4d7abe9d8d2474add2edf',1,'mimalloc-doc.h']]], + ['mi_5frealloc_5faligned_5fat_94',['mi_realloc_aligned_at',['../group__aligned.html#gad06dcf2bb8faadb2c8ea61ee5d24bbf6',1,'mimalloc-doc.h']]], + ['mi_5freallocarr_95',['mi_reallocarr',['../group__posix.html#ga7e1934d60a3e697950eeb48e042bfad5',1,'mimalloc-doc.h']]], + ['mi_5freallocarray_96',['mi_reallocarray',['../group__posix.html#gadfeccb72748a2f6305474a37d9d57bce',1,'mimalloc-doc.h']]], + ['mi_5freallocf_97',['mi_reallocf',['../group__malloc.html#ga4dc3a4067037b151a64629fe8a332641',1,'mimalloc-doc.h']]], + ['mi_5freallocn_98',['mi_reallocn',['../group__malloc.html#ga8bddfb4a1270a0854bbcf44cb3980467',1,'mimalloc-doc.h']]], + ['mi_5frealpath_99',['mi_realpath',['../group__malloc.html#ga94c3afcc086e85d75a57e9f76b9b71dd',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_100',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_101',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e2169b48683aa0ab64f813fd68d839e',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat_102',['mi_recalloc_aligned_at',['../group__zeroinit.html#gaae25e4ddedd4e0fb61b1a8bd5d452750',1,'mimalloc-doc.h']]], + ['mi_5fregister_5fdeferred_5ffree_103',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]], + ['mi_5fregister_5ferror_104',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput_105',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_106',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5fat_5fex_107',['mi_reserve_huge_os_pages_at_ex',['../group__extended.html#ga591aab1c2bc2ca920e33f0f9f9cb5c52',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages_5finterleave_108',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_109',['mi_reserve_os_memory',['../group__extended.html#ga00ec3324b6b2591c7fe3677baa30a767',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fos_5fmemory_5fex_110',['mi_reserve_os_memory_ex',['../group__extended.html#ga32f519797fd9a81acb4f52d36e6d751b',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_111',['mi_rezalloc',['../group__zeroinit.html#gadfd34cd7b4f2bbda7ae06367a6360756',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_112',['mi_rezalloc_aligned',['../group__zeroinit.html#ga4d02404fe1e7db00beb65f185e012caa',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat_113',['mi_rezalloc_aligned_at',['../group__zeroinit.html#ga6843a88285bbfcc3bdfccc60aafd1270',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge_114',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_115',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout_116',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset_117',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], + ['mi_5fstrdup_118',['mi_strdup',['../group__malloc.html#ga245ac90ebc2cfdd17de599e5fea59889',1,'mimalloc-doc.h']]], + ['mi_5fstrndup_119',['mi_strndup',['../group__malloc.html#ga486d0d26b3b3794f6d1cdb41a9aed92d',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fadd_5fcurrent_5fthread_120',['mi_subproc_add_current_thread',['../group__extended.html#gadbc53414eb68b275588ec001ce1ddc7c',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fdelete_121',['mi_subproc_delete',['../group__extended.html#gaa7d263e9429bac9ac8345c9d25de610e',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fmain_122',['mi_subproc_main',['../group__extended.html#ga2ecba0d7ebdc99e71bb985c4a1609806',1,'mimalloc-doc.h']]], + ['mi_5fsubproc_5fnew_123',['mi_subproc_new',['../group__extended.html#ga8068cac328e41fa2170faef707315243',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone_124',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit_125',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint_5fout_126',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',1,'mimalloc-doc.h']]], + ['mi_5fusable_5fsize_127',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], + ['mi_5fvalloc_128',['mi_valloc',['../group__posix.html#ga50cafb9722020402f065de93799f64ca',1,'mimalloc-doc.h']]], + ['mi_5fwcsdup_129',['mi_wcsdup',['../group__posix.html#gaa9fd7f25c9ac3a20e89b33bd6e383fcf',1,'mimalloc-doc.h']]], + ['mi_5fwdupenv_5fs_130',['mi_wdupenv_s',['../group__posix.html#ga6ac6a6a8f3c96f1af24bb8d0439cbbd1',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_131',['mi_zalloc',['../group__malloc.html#gae6e38c4403247a7b40d80419e093bfb8',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_132',['mi_zalloc_aligned',['../group__aligned.html#gaac7d0beb782f9b9ac31f47492b130f82',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5faligned_5fat_133',['mi_zalloc_aligned_at',['../group__aligned.html#ga7c1778805ce50ebbf02ccbd5e39d5dba',1,'mimalloc-doc.h']]], + ['mi_5fzalloc_5fsmall_134',['mi_zalloc_small',['../group__extended.html#ga51c47637e81df0e2f13a2d7a2dec123e',1,'mimalloc-doc.h']]] ]; diff --git a/docs/search/searchdata.js b/docs/search/searchdata.js index bab3d38b..5a777792 100644 --- a/docs/search/searchdata.js +++ b/docs/search/searchdata.js @@ -3,7 +3,7 @@ var indexSectionsWithContent = 0: "_abcefhilmoprtuwz", 1: "m", 2: "m", - 3: "bcfru", + 3: "bcfhru", 4: "m", 5: "m", 6: "_m", diff --git a/docs/search/variables_3.js b/docs/search/variables_3.js index 30cf0e0c..792ce772 100644 --- a/docs/search/variables_3.js +++ b/docs/search/variables_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['reserved_0',['reserved',['../group__analysis.html#ae848a3e6840414891035423948ca0383',1,'mi_heap_area_t']]] + ['heap_5ftag_0',['heap_tag',['../group__analysis.html#a2b7a0c92ece8daf46b558efc990ebdc1',1,'mi_heap_area_t']]] ]; diff --git a/docs/search/variables_4.js b/docs/search/variables_4.js index 230778b8..30cf0e0c 100644 --- a/docs/search/variables_4.js +++ b/docs/search/variables_4.js @@ -1,4 +1,4 @@ var searchData= [ - ['used_0',['used',['../group__analysis.html#ab820302c5cd0df133eb8e51650a008b4',1,'mi_heap_area_t']]] + ['reserved_0',['reserved',['../group__analysis.html#ae848a3e6840414891035423948ca0383',1,'mi_heap_area_t']]] ]; From d68a7fc3e6072f1f084a199aaf693acaa03026f4 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 17:04:33 -0700 Subject: [PATCH 052/305] update docs --- doc/mimalloc-doc.h | 1 - docs/group__extended.html | 3 +- docs/group__typed.html | 2 +- docs/mimalloc-doc_8h_source.html | 584 +++++++++++++++---------------- 4 files changed, 294 insertions(+), 296 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 0c19e7b8..e1c14b44 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -547,7 +547,6 @@ mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id); /// /// The \a arena_id can be used by runtimes to allocate only in a specified pre-reserved arena. /// This is used for example for a compressed pointer heap in Koka. -/// /// The \a heap_tag enables heaps to keep objects of a certain type isolated to heaps with that tag. /// This is used for example in the CPython integration. mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id); diff --git a/docs/group__extended.html b/docs/group__extended.html index 98aca4ec..6bc793f6 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -524,8 +524,7 @@ Functions
    Returns
    A new heap or NULL on failure.
    -

    The arena_id can be used by runtimes to allocate only in a specified pre-reserved arena. This is used for example for a compressed pointer heap in Koka.

    -

    The heap_tag enables heaps to keep objects of a certain type isolated to heaps with that tag. This is used for example in the CPython integration.

    +

    The arena_id can be used by runtimes to allocate only in a specified pre-reserved arena. This is used for example for a compressed pointer heap in Koka. The heap_tag enables heaps to keep objects of a certain type isolated to heaps with that tag. This is used for example in the CPython integration.

    diff --git a/docs/group__typed.html b/docs/group__typed.html index aa91a12f..69f5278f 100644 --- a/docs/group__typed.html +++ b/docs/group__typed.html @@ -148,7 +148,7 @@ Macros

    Detailed Description

    Typed allocation macros. For example:

    int* p = mi_malloc_tp(int)
    -
    #define mi_malloc_tp(tp)
    Allocate a block of type tp.
    Definition mimalloc-doc.h:785
    +
    #define mi_malloc_tp(tp)
    Allocate a block of type tp.
    Definition mimalloc-doc.h:784

    Macro Definition Documentation

    ◆ mi_calloc_tp

    diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index 84549c54..d4d17d26 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -219,262 +219,262 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    536
    541
    -
    553mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id);
    -
    554
    -
    558typedef void* mi_subproc_id_t;
    -
    559
    - -
    562
    - -
    566
    - -
    571
    - +
    552mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id);
    +
    553
    +
    557typedef void* mi_subproc_id_t;
    +
    558
    + +
    561
    + +
    565
    + +
    570
    + +
    574
    575
    -
    576
    -
    578
    -
    579// ------------------------------------------------------
    -
    580// Aligned allocation
    -
    581// ------------------------------------------------------
    -
    582
    -
    590
    -
    608void* mi_malloc_aligned(size_t size, size_t alignment);
    -
    609void* mi_zalloc_aligned(size_t size, size_t alignment);
    -
    610void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    -
    611void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    612
    -
    624void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    625void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    -
    626void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    -
    627void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    628
    -
    630
    -
    636
    -
    641struct mi_heap_s;
    -
    642
    -
    647typedef struct mi_heap_s mi_heap_t;
    -
    648
    - -
    651
    - -
    660
    - -
    669
    - -
    674
    - -
    678
    - -
    685
    -
    687void mi_heap_collect(mi_heap_t* heap, bool force);
    -
    688
    -
    691void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    -
    692
    -
    696void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    -
    697
    -
    700void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    -
    701
    -
    704void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    -
    705
    -
    708void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    -
    709
    -
    712char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    -
    713
    -
    716char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    -
    717
    -
    720char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    -
    721
    -
    722void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    723void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    -
    724void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    -
    725
    -
    726void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    727void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    728void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    -
    729void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    -
    730void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    -
    731void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    -
    732void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    733void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    -
    734
    +
    577
    +
    578// ------------------------------------------------------
    +
    579// Aligned allocation
    +
    580// ------------------------------------------------------
    +
    581
    +
    589
    +
    607void* mi_malloc_aligned(size_t size, size_t alignment);
    +
    608void* mi_zalloc_aligned(size_t size, size_t alignment);
    +
    609void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
    +
    610void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    611
    +
    623void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    624void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
    +
    625void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
    +
    626void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    627
    +
    629
    +
    635
    +
    640struct mi_heap_s;
    +
    641
    +
    646typedef struct mi_heap_s mi_heap_t;
    +
    647
    + +
    650
    + +
    659
    + +
    668
    + +
    673
    + +
    677
    + +
    684
    +
    686void mi_heap_collect(mi_heap_t* heap, bool force);
    +
    687
    +
    690void* mi_heap_malloc(mi_heap_t* heap, size_t size);
    +
    691
    +
    695void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
    +
    696
    +
    699void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
    +
    700
    +
    703void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
    +
    704
    +
    707void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
    +
    708
    +
    711char* mi_heap_strdup(mi_heap_t* heap, const char* s);
    +
    712
    +
    715char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
    +
    716
    +
    719char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
    +
    720
    +
    721void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    722void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
    +
    723void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
    +
    724
    +
    725void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    726void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    727void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
    +
    728void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
    +
    729void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
    +
    730void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
    +
    731void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    732void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    733
    +
    735
    736
    -
    737
    -
    746
    -
    747void* mi_rezalloc(void* p, size_t newsize);
    -
    748void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    -
    749
    -
    750void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    -
    751void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    -
    752void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    -
    753void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    754
    -
    755void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    -
    756void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    -
    757
    -
    758void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    -
    759void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    -
    760void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    -
    761void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    762
    -
    764
    -
    773
    -
    785#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    -
    786
    -
    788#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    -
    789
    -
    791#define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    -
    792
    -
    794#define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    -
    795
    -
    797#define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    -
    798
    -
    800#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    -
    801
    -
    803#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    -
    804
    -
    806#define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    -
    807
    -
    809#define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    -
    810
    -
    812#define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    -
    813
    -
    815#define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    -
    816
    -
    818
    -
    824
    -
    831bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    -
    832
    -
    841bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    -
    842
    -
    850bool mi_check_owned(const void* p);
    -
    851
    -
    -
    854typedef struct mi_heap_area_s {
    -
    855 void* blocks;
    -
    856 size_t reserved;
    -
    857 size_t committed;
    -
    858 size_t used;
    -
    859 size_t block_size;
    - - - +
    745
    +
    746void* mi_rezalloc(void* p, size_t newsize);
    +
    747void* mi_recalloc(void* p, size_t newcount, size_t size) ;
    +
    748
    +
    749void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
    +
    750void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
    +
    751void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
    +
    752void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    753
    +
    754void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
    +
    755void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
    +
    756
    +
    757void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
    +
    758void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
    +
    759void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
    +
    760void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    761
    +
    763
    +
    772
    +
    784#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
    +
    785
    +
    787#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
    +
    788
    +
    790#define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
    +
    791
    +
    793#define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
    +
    794
    +
    796#define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
    +
    797
    +
    799#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
    +
    800
    +
    802#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
    +
    803
    +
    805#define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
    +
    806
    +
    808#define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
    +
    809
    +
    811#define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
    +
    812
    +
    814#define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
    +
    815
    +
    817
    +
    823
    +
    830bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
    +
    831
    +
    840bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
    +
    841
    +
    849bool mi_check_owned(const void* p);
    +
    850
    +
    +
    853typedef struct mi_heap_area_s {
    +
    854 void* blocks;
    +
    855 size_t reserved;
    +
    856 size_t committed;
    +
    857 size_t used;
    +
    858 size_t block_size;
    + + +
    -
    863
    -
    871typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    -
    872
    -
    884bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    -
    885
    -
    901bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
    -
    902
    -
    904
    -
    910
    -
    -
    912typedef enum mi_option_e {
    -
    913 // stable options
    - - - - - -
    919
    -
    920 // advanced options
    - - - - - - - - -
    929
    -
    930 // experimental options
    - - - - - - - - - - - - - - - -
    946
    - - +
    862
    +
    870typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
    +
    871
    +
    883bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    884
    +
    900bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
    +
    901
    +
    903
    +
    909
    + +
    948
    949
    -
    950
    - - - -
    954void mi_option_set_enabled(mi_option_t option, bool enable);
    - -
    956
    - -
    958long mi_option_get_clamp(mi_option_t option, long min, long max);
    - -
    960
    -
    961void mi_option_set(mi_option_t option, long value);
    -
    962void mi_option_set_default(mi_option_t option, long value);
    + + + +
    953void mi_option_set_enabled(mi_option_t option, bool enable);
    + +
    955
    + +
    957long mi_option_get_clamp(mi_option_t option, long min, long max);
    + +
    959
    +
    960void mi_option_set(mi_option_t option, long value);
    +
    961void mi_option_set_default(mi_option_t option, long value);
    +
    962
    963
    -
    964
    -
    966
    -
    973
    -
    975void mi_cfree(void* p);
    -
    976void* mi__expand(void* p, size_t newsize);
    -
    977
    -
    978void* mi_recalloc(void* p, size_t count, size_t size);
    -
    979size_t mi_malloc_size(const void* p);
    -
    980size_t mi_malloc_good_size(size_t size);
    -
    981size_t mi_malloc_usable_size(const void *p);
    -
    982
    -
    983int mi_posix_memalign(void** p, size_t alignment, size_t size);
    -
    984int mi__posix_memalign(void** p, size_t alignment, size_t size);
    -
    985void* mi_memalign(size_t alignment, size_t size);
    -
    986void* mi_valloc(size_t size);
    -
    987void* mi_pvalloc(size_t size);
    -
    988void* mi_aligned_alloc(size_t alignment, size_t size);
    -
    989
    -
    990unsigned short* mi_wcsdup(const unsigned short* s);
    -
    991unsigned char* mi_mbsdup(const unsigned char* s);
    -
    992int mi_dupenv_s(char** buf, size_t* size, const char* name);
    -
    993int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name);
    -
    994
    -
    997void* mi_reallocarray(void* p, size_t count, size_t size);
    -
    998
    -
    1000int mi_reallocarr(void* p, size_t count, size_t size);
    -
    1001
    -
    1002void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment);
    -
    1003void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    -
    1004
    -
    1005void mi_free_size(void* p, size_t size);
    -
    1006void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    -
    1007void mi_free_aligned(void* p, size_t alignment);
    -
    1008
    -
    1010
    -
    1023
    -
    1025void* mi_new(std::size_t n) noexcept(false);
    -
    1026
    -
    1028void* mi_new_n(size_t count, size_t size) noexcept(false);
    -
    1029
    -
    1031void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    -
    1032
    -
    1034void* mi_new_nothrow(size_t n);
    -
    1035
    -
    1037void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    -
    1038
    -
    1040void* mi_new_realloc(void* p, size_t newsize);
    -
    1041
    -
    1043void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    -
    1044
    -
    1052template<class T> struct mi_stl_allocator { }
    -
    1053
    -
    1055
    +
    965
    +
    972
    +
    974void mi_cfree(void* p);
    +
    975void* mi__expand(void* p, size_t newsize);
    +
    976
    +
    977void* mi_recalloc(void* p, size_t count, size_t size);
    +
    978size_t mi_malloc_size(const void* p);
    +
    979size_t mi_malloc_good_size(size_t size);
    +
    980size_t mi_malloc_usable_size(const void *p);
    +
    981
    +
    982int mi_posix_memalign(void** p, size_t alignment, size_t size);
    +
    983int mi__posix_memalign(void** p, size_t alignment, size_t size);
    +
    984void* mi_memalign(size_t alignment, size_t size);
    +
    985void* mi_valloc(size_t size);
    +
    986void* mi_pvalloc(size_t size);
    +
    987void* mi_aligned_alloc(size_t alignment, size_t size);
    +
    988
    +
    989unsigned short* mi_wcsdup(const unsigned short* s);
    +
    990unsigned char* mi_mbsdup(const unsigned char* s);
    +
    991int mi_dupenv_s(char** buf, size_t* size, const char* name);
    +
    992int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name);
    +
    993
    +
    996void* mi_reallocarray(void* p, size_t count, size_t size);
    +
    997
    +
    999int mi_reallocarr(void* p, size_t count, size_t size);
    +
    1000
    +
    1001void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment);
    +
    1002void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
    +
    1003
    +
    1004void mi_free_size(void* p, size_t size);
    +
    1005void mi_free_size_aligned(void* p, size_t size, size_t alignment);
    +
    1006void mi_free_aligned(void* p, size_t alignment);
    +
    1007
    +
    1009
    +
    1022
    +
    1024void* mi_new(std::size_t n) noexcept(false);
    +
    1025
    +
    1027void* mi_new_n(size_t count, size_t size) noexcept(false);
    +
    1028
    +
    1030void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
    +
    1031
    +
    1033void* mi_new_nothrow(size_t n);
    +
    1034
    +
    1036void* mi_new_aligned_nothrow(size_t n, size_t alignment);
    +
    1037
    +
    1039void* mi_new_realloc(void* p, size_t newsize);
    +
    1040
    +
    1042void* mi_new_reallocn(void* p, size_t newcount, size_t size);
    +
    1043
    +
    1051template<class T> struct mi_stl_allocator { }
    +
    1052
    +
    1054
    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_calloc_aligned(size_t count, size_t size, size_t alignment)
    void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
    @@ -483,20 +483,20 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
    void * mi_zalloc_aligned(size_t size, size_t alignment)
    void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
    -
    int heap_tag
    heap tag associated with this area (see mi_heap_new_ex)
    Definition mimalloc-doc.h:861
    -
    size_t block_size
    size in bytes of one block
    Definition mimalloc-doc.h:859
    -
    size_t committed
    current committed bytes of this area
    Definition mimalloc-doc.h:857
    -
    size_t full_block_size
    size in bytes of a full block including padding and metadata.
    Definition mimalloc-doc.h:860
    -
    size_t used
    bytes in use by allocated blocks
    Definition mimalloc-doc.h:858
    -
    void * blocks
    start of the area containing heap blocks
    Definition mimalloc-doc.h:855
    -
    size_t reserved
    bytes reserved for this area
    Definition mimalloc-doc.h:856
    +
    int heap_tag
    heap tag associated with this area (see mi_heap_new_ex)
    Definition mimalloc-doc.h:860
    +
    size_t block_size
    size in bytes of one block
    Definition mimalloc-doc.h:858
    +
    size_t committed
    current committed bytes of this area
    Definition mimalloc-doc.h:856
    +
    size_t full_block_size
    size in bytes of a full block including padding and metadata.
    Definition mimalloc-doc.h:859
    +
    size_t used
    bytes in use by allocated blocks
    Definition mimalloc-doc.h:857
    +
    void * blocks
    start of the area containing heap blocks
    Definition mimalloc-doc.h:854
    +
    size_t reserved
    bytes reserved for this area
    Definition mimalloc-doc.h:855
    bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
    Check safely if any pointer is part of a heap.
    bool mi_check_owned(const void *p)
    Check safely if any pointer is part of the default heap of this thread.
    bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun *visitor, void *arg)
    Visit all areas and blocks in abandoned heaps.
    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.
    -
    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:871
    +
    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:870
    bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
    Does a heap contain a pointer to a previously allocated block?
    -
    An area of heap space contains blocks of a single size.
    Definition mimalloc-doc.h:854
    +
    An area of heap space contains blocks of a single size.
    Definition mimalloc-doc.h:853
    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_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...
    void * mi_new_realloc(void *p, size_t newsize)
    like mi_realloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
    @@ -504,7 +504,7 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    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_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_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...
    -
    std::allocator implementation for mimalloc for use in STL containers.
    Definition mimalloc-doc.h:1052
    +
    std::allocator implementation for mimalloc for use in STL containers.
    Definition mimalloc-doc.h:1051
    int mi_reserve_os_memory(size_t size, bool commit, bool allow_large)
    Reserve OS memory for use by mimalloc.
    size_t mi_usable_size(void *p)
    Return the available bytes in a memory block.
    void mi_thread_done(void)
    Uninitialize mimalloc on a thread.
    @@ -529,7 +529,7 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    mi_subproc_id_t mi_subproc_new(void)
    Create a fresh sub-process (with no associated threads yet).
    void mi_error_fun(int err, void *arg)
    Type of error callback functions.
    Definition mimalloc-doc.h:393
    void mi_stats_merge(void)
    Merge thread local statistics with the main statistics and reset.
    -
    void * mi_subproc_id_t
    A process can associate threads with sub-processes.
    Definition mimalloc-doc.h:558
    +
    void * mi_subproc_id_t
    A process can associate threads with sub-processes.
    Definition mimalloc-doc.h:557
    int mi_arena_id_t
    Mimalloc uses large (virtual) memory areas, called "arena"s, from the OS to manage its memory.
    Definition mimalloc-doc.h:499
    void * mi_arena_area(mi_arena_id_t arena_id, size_t *size)
    Return the size of an arena.
    void mi_register_error(mi_error_fun *errfun, void *arg)
    Register an error callback function.
    @@ -548,7 +548,7 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    void mi_heap_delete(mi_heap_t *heap)
    Delete a previously allocated heap.
    void * mi_heap_malloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
    mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
    Set the default heap to use in the current thread for mi_malloc() et al.
    -
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition mimalloc-doc.h:647
    +
    struct mi_heap_s mi_heap_t
    Type of first-class heaps.
    Definition mimalloc-doc.h:646
    void * mi_heap_zalloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
    char * mi_heap_realpath(mi_heap_t *heap, const char *fname, char *resolved_name)
    Resolve a file path name using a specific heap to allocate the result.
    char * mi_heap_strdup(mi_heap_t *heap, const char *s)
    Duplicate a string in a specific heap.
    @@ -593,36 +593,36 @@ $(function(){initNavTree('mimalloc-doc_8h_source.html',''); initResizable(true);
    void mi_option_set_enabled(mi_option_t option, bool enable)
    void mi_option_disable(mi_option_t option)
    void mi_option_set(mi_option_t option, long value)
    -
    mi_option_t
    Runtime options.
    Definition mimalloc-doc.h:912
    -
    @ mi_option_abandoned_reclaim_on_free
    allow to reclaim an abandoned segment on a free (=1)
    Definition mimalloc-doc.h:942
    -
    @ mi_option_purge_extend_delay
    extend purge delay on each subsequent delay (=1)
    Definition mimalloc-doc.h:943
    -
    @ mi_option_show_stats
    Print statistics on termination.
    Definition mimalloc-doc.h:915
    -
    @ mi_option_use_numa_nodes
    0 = use all available numa nodes, otherwise use at most N nodes.
    Definition mimalloc-doc.h:936
    -
    @ mi_option_abandoned_page_purge
    immediately purge delayed purges on thread termination
    Definition mimalloc-doc.h:934
    -
    @ mi_option_eager_commit_delay
    the first N segments per thread are not eagerly committed (but per page in the segment on demand)
    Definition mimalloc-doc.h:932
    -
    @ mi_option_eager_commit
    eager commit segments? (after eager_commit_delay segments) (enabled by default).
    Definition mimalloc-doc.h:931
    -
    @ mi_option_visit_abandoned
    allow visiting heap blocks from abandoned threads (=0)
    Definition mimalloc-doc.h:945
    -
    @ mi_option_os_tag
    tag used for OS logging (macOS only for now) (=100)
    Definition mimalloc-doc.h:927
    -
    @ _mi_option_last
    Definition mimalloc-doc.h:947
    -
    @ mi_option_destroy_on_exit
    if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe
    Definition mimalloc-doc.h:940
    -
    @ mi_option_verbose
    Print verbose messages.
    Definition mimalloc-doc.h:916
    -
    @ mi_option_allow_large_os_pages
    allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.
    Definition mimalloc-doc.h:924
    -
    @ mi_option_arena_purge_mult
    multiplier for purge_delay for the purging delay for arenas (=10)
    Definition mimalloc-doc.h:941
    -
    @ mi_option_retry_on_oom
    retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)
    Definition mimalloc-doc.h:928
    -
    @ mi_option_purge_decommits
    should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)
    Definition mimalloc-doc.h:925
    -
    @ mi_option_limit_os_alloc
    If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)
    Definition mimalloc-doc.h:938
    -
    @ mi_option_reserve_huge_os_pages_at
    Reserve N huge OS pages at a specific NUMA node N.
    Definition mimalloc-doc.h:922
    -
    @ mi_option_max_segment_reclaim
    max. percentage of the abandoned segments can be reclaimed per try (=10%)
    Definition mimalloc-doc.h:939
    -
    @ mi_option_arena_reserve
    initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use ...
    Definition mimalloc-doc.h:926
    -
    @ mi_option_reserve_huge_os_pages
    reserve N huge OS pages (1GiB pages) at startup
    Definition mimalloc-doc.h:921
    -
    @ mi_option_disallow_os_alloc
    1 = do not use OS memory for allocation (but only programmatically reserved arenas)
    Definition mimalloc-doc.h:937
    -
    @ mi_option_purge_delay
    memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all...
    Definition mimalloc-doc.h:935
    -
    @ mi_option_disallow_arena_alloc
    1 = do not use arena's for allocation (except if using specific arena id's)
    Definition mimalloc-doc.h:944
    -
    @ mi_option_max_errors
    issue at most N error messages
    Definition mimalloc-doc.h:917
    -
    @ mi_option_max_warnings
    issue at most N warning messages
    Definition mimalloc-doc.h:918
    -
    @ mi_option_show_errors
    Print error messages.
    Definition mimalloc-doc.h:914
    -
    @ mi_option_reserve_os_memory
    reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use m...
    Definition mimalloc-doc.h:923
    -
    @ mi_option_arena_eager_commit
    eager commit arenas? Use 2 to enable just on overcommit systems (=2)
    Definition mimalloc-doc.h:933
    +
    mi_option_t
    Runtime options.
    Definition mimalloc-doc.h:911
    +
    @ mi_option_abandoned_reclaim_on_free
    allow to reclaim an abandoned segment on a free (=1)
    Definition mimalloc-doc.h:941
    +
    @ mi_option_purge_extend_delay
    extend purge delay on each subsequent delay (=1)
    Definition mimalloc-doc.h:942
    +
    @ mi_option_show_stats
    Print statistics on termination.
    Definition mimalloc-doc.h:914
    +
    @ mi_option_use_numa_nodes
    0 = use all available numa nodes, otherwise use at most N nodes.
    Definition mimalloc-doc.h:935
    +
    @ mi_option_abandoned_page_purge
    immediately purge delayed purges on thread termination
    Definition mimalloc-doc.h:933
    +
    @ mi_option_eager_commit_delay
    the first N segments per thread are not eagerly committed (but per page in the segment on demand)
    Definition mimalloc-doc.h:931
    +
    @ mi_option_eager_commit
    eager commit segments? (after eager_commit_delay segments) (enabled by default).
    Definition mimalloc-doc.h:930
    +
    @ mi_option_visit_abandoned
    allow visiting heap blocks from abandoned threads (=0)
    Definition mimalloc-doc.h:944
    +
    @ mi_option_os_tag
    tag used for OS logging (macOS only for now) (=100)
    Definition mimalloc-doc.h:926
    +
    @ _mi_option_last
    Definition mimalloc-doc.h:946
    +
    @ mi_option_destroy_on_exit
    if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe
    Definition mimalloc-doc.h:939
    +
    @ mi_option_verbose
    Print verbose messages.
    Definition mimalloc-doc.h:915
    +
    @ mi_option_allow_large_os_pages
    allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.
    Definition mimalloc-doc.h:923
    +
    @ mi_option_arena_purge_mult
    multiplier for purge_delay for the purging delay for arenas (=10)
    Definition mimalloc-doc.h:940
    +
    @ mi_option_retry_on_oom
    retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)
    Definition mimalloc-doc.h:927
    +
    @ mi_option_purge_decommits
    should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)
    Definition mimalloc-doc.h:924
    +
    @ mi_option_limit_os_alloc
    If set to 1, do not use OS memory for allocation (but only pre-reserved arenas)
    Definition mimalloc-doc.h:937
    +
    @ mi_option_reserve_huge_os_pages_at
    Reserve N huge OS pages at a specific NUMA node N.
    Definition mimalloc-doc.h:921
    +
    @ mi_option_max_segment_reclaim
    max. percentage of the abandoned segments can be reclaimed per try (=10%)
    Definition mimalloc-doc.h:938
    +
    @ mi_option_arena_reserve
    initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use ...
    Definition mimalloc-doc.h:925
    +
    @ mi_option_reserve_huge_os_pages
    reserve N huge OS pages (1GiB pages) at startup
    Definition mimalloc-doc.h:920
    +
    @ mi_option_disallow_os_alloc
    1 = do not use OS memory for allocation (but only programmatically reserved arenas)
    Definition mimalloc-doc.h:936
    +
    @ mi_option_purge_delay
    memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all...
    Definition mimalloc-doc.h:934
    +
    @ mi_option_disallow_arena_alloc
    1 = do not use arena's for allocation (except if using specific arena id's)
    Definition mimalloc-doc.h:943
    +
    @ mi_option_max_errors
    issue at most N error messages
    Definition mimalloc-doc.h:916
    +
    @ mi_option_max_warnings
    issue at most N warning messages
    Definition mimalloc-doc.h:917
    +
    @ mi_option_show_errors
    Print error messages.
    Definition mimalloc-doc.h:913
    +
    @ mi_option_reserve_os_memory
    reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use m...
    Definition mimalloc-doc.h:922
    +
    @ mi_option_arena_eager_commit
    eager commit arenas? Use 2 to enable just on overcommit systems (=2)
    Definition mimalloc-doc.h:932
    size_t mi_malloc_usable_size(const void *p)
    void mi_free_aligned(void *p, size_t alignment)
    void * mi_aligned_offset_recalloc(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
    From 03020fbf81541651e24289d2f7033a772a50f480 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 4 Jun 2024 17:28:04 -0700 Subject: [PATCH 053/305] fix count/size order in mi_heap_alloc_new_n, issue #906 --- src/alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc.c b/src/alloc.c index 267fab0c..1eee1f2f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -530,7 +530,7 @@ mi_decl_nodiscard mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, si } mi_decl_nodiscard mi_decl_restrict void* mi_new_n(size_t count, size_t size) { - return mi_heap_alloc_new_n(mi_prim_get_default_heap(), size, count); + return mi_heap_alloc_new_n(mi_prim_get_default_heap(), count, size); } From e8b5e51b00aa0a10279f71b53412239de9eeb2dd Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Mon, 10 Jun 2024 15:06:39 -0700 Subject: [PATCH 054/305] Change macOS mmap tag to fix conflict with IOAccelerator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tag 100 is assigned to "IOAccelerator" (the GPU driver stack on Apple silicon), which makes for confusing output when debugging. To avoid conflicts, use a tag in the reserved application-specific range from 240–255 (inclusive). All assigned tags: https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/mach/vm_statistics.h#L773-L775 --- src/prim/unix/prim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 63a36f25..c3f36e2a 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -240,7 +240,7 @@ static int unix_mmap_fd(void) { #if defined(VM_MAKE_TAG) // macOS: tracking anonymous page with a specific ID. (All up to 98 are taken officially but LLVM sanitizers had taken 99) int os_tag = (int)mi_option_get(mi_option_os_tag); - if (os_tag < 100 || os_tag > 255) { os_tag = 100; } + if (os_tag < 100 || os_tag > 255) { os_tag = 254; } return VM_MAKE_TAG(os_tag); #else return -1; From b7dd5d6564567f39ce5111ddbe5064a22259bd94 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 17 Jun 2024 16:17:03 -0700 Subject: [PATCH 055/305] add extra assertions to check that blocks are always aligned to MI_MAX_ALIGN_SIZE --- src/alloc.c | 1 + src/segment.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/alloc.c b/src/alloc.c index 1eee1f2f..7be1a6e9 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -40,6 +40,7 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_ page->free = mi_block_next(page, block); page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); + mi_assert_internal(_mi_is_aligned(block, MI_MAX_ALIGN_SIZE)); #if MI_DEBUG>3 if (page->free_is_zero) { mi_assert_expensive(mi_mem_is_zero(block+1,size - sizeof(*block))); diff --git a/src/segment.c b/src/segment.c index 54a917ea..d9631d48 100644 --- a/src/segment.c +++ b/src/segment.c @@ -436,6 +436,8 @@ uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* pa mi_assert_internal((uintptr_t)p % block_size == 0); } } + mi_assert_internal(_mi_is_aligned(p, MI_MAX_ALIGN_SIZE)); + mi_assert_internal(block_size > MI_MAX_ALIGN_GUARANTEE || _mi_is_aligned(p,block_size)); if (page_size != NULL) *page_size = psize; mi_assert_internal(_mi_ptr_page(p) == page); From 3c5e480ce73b02cd8bd8eca0846b2baf930c265d Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 17 Jun 2024 16:21:46 -0700 Subject: [PATCH 056/305] fix alignment test --- src/segment.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/segment.c b/src/segment.c index 869e05a8..bea43210 100644 --- a/src/segment.c +++ b/src/segment.c @@ -332,6 +332,8 @@ static uint8_t* _mi_segment_page_start_from_slice(const mi_segment_t* segment, c if (block_size <= 64) { start_offset += 3*block_size; } else if (block_size <= 512) { start_offset += block_size; } } + mi_assert_internal(_mi_is_aligned(pstart + start_offset, MI_MAX_ALIGN_SIZE)); + mi_assert_internal(block_size == 0 || block_size > MI_MAX_ALIGN_GUARANTEE || _mi_is_aligned(pstart + start_offset,block_size)); if (page_size != NULL) { *page_size = psize - start_offset; } return (pstart + start_offset); } @@ -360,8 +362,6 @@ static size_t mi_segment_calculate_slices(size_t required, size_t* info_slices) required = _mi_align_up(required, MI_SEGMENT_SLICE_SIZE) + page_size; } } - mi_assert_internal(_mi_is_aligned(p, MI_MAX_ALIGN_SIZE)); - mi_assert_internal(block_size > MI_MAX_ALIGN_GUARANTEE || _mi_is_aligned(p,block_size)); isize = _mi_align_up(isize + guardsize, MI_SEGMENT_SLICE_SIZE); if (info_slices != NULL) *info_slices = isize / MI_SEGMENT_SLICE_SIZE; From 265767766bffda929c31a49e6e30ea812f7088f0 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 17 Jun 2024 16:22:07 -0700 Subject: [PATCH 057/305] fix alignment test --- src/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index d9631d48..7646c94c 100644 --- a/src/segment.c +++ b/src/segment.c @@ -437,7 +437,7 @@ uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* pa } } mi_assert_internal(_mi_is_aligned(p, MI_MAX_ALIGN_SIZE)); - mi_assert_internal(block_size > MI_MAX_ALIGN_GUARANTEE || _mi_is_aligned(p,block_size)); + mi_assert_internal(block_size == 0 || block_size > MI_MAX_ALIGN_GUARANTEE || _mi_is_aligned(p,block_size)); if (page_size != NULL) *page_size = psize; mi_assert_internal(_mi_ptr_page(p) == page); From 632421da3a6e0e769c6f09539d04007c627ac878 Mon Sep 17 00:00:00 2001 From: QuarticCat Date: Wed, 19 Jun 2024 10:49:03 +0800 Subject: [PATCH 058/305] fix typos --- doc/mimalloc-doc.h | 6 +-- docker/alpine-arm32v7/Dockerfile | 4 +- include/mimalloc/atomic.h | 2 +- include/mimalloc/internal.h | 2 +- include/mimalloc/types.h | 4 +- readme.md | 68 ++++++++++++++++---------------- src/arena.c | 4 +- src/options.c | 10 ++--- src/prim/unix/prim.c | 2 +- src/prim/windows/prim.c | 3 +- src/segment.c | 10 ++--- test/test-stress.c | 6 +-- 12 files changed, 59 insertions(+), 62 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index e1c14b44..698c5dbb 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -589,7 +589,7 @@ void mi_subproc_add_current_thread(mi_subproc_id_t subproc); /// Allocate \a size bytes aligned by \a alignment. /// @param size number of bytes to allocate. -/// @param alignment the minimal alignment of the allocated memory. +/// @param alignment the minimal alignment of the allocated memory. /// @returns pointer to the allocated memory or \a NULL if out of memory, /// or if the alignment is not a power of 2 (including 0). The \a size is unrestricted /// (and does not have to be an integral multiple of the \a alignment). @@ -883,7 +883,7 @@ typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* a bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg); /// @brief Visit all areas and blocks in abandoned heaps. -/// @param subproc_id The sub-process id associated with the abandonded heaps. +/// @param subproc_id The sub-process id associated with the abandoned heaps. /// @param heap_tag Visit only abandoned memory with the specified heap tag, use -1 to visit all abandoned memory. /// @param visit_blocks If \a true visits all allocated blocks, otherwise /// \a visitor is only called for every heap area. @@ -1139,7 +1139,7 @@ to link with the static library. See `test\CMakeLists.txt` for an example. ### C++ For best performance in C++ programs, it is also recommended to override the -global `new` and `delete` operators. For convience, mimalloc provides +global `new` and `delete` operators. For convenience, mimalloc provides [`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project. In C++, mimalloc also provides the `mi_stl_allocator` struct which implements the `std::allocator` diff --git a/docker/alpine-arm32v7/Dockerfile b/docker/alpine-arm32v7/Dockerfile index 56f071db..1d7fd48b 100644 --- a/docker/alpine-arm32v7/Dockerfile +++ b/docker/alpine-arm32v7/Dockerfile @@ -1,10 +1,10 @@ # install from an image -# download first an appropiate tar.gz image into the current directory +# download first an appropriate tar.gz image into the current directory # from: FROM scratch # Substitute the image name that was downloaded -ADD alpine-minirootfs-20240329-armv7.tar.gz / +ADD alpine-minirootfs-20240329-armv7.tar.gz / # Install tools RUN apk add build-base make cmake diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index 3a0d4892..530cca01 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -22,7 +22,7 @@ terms of the MIT license. A copy of the license can be found in the file // -------------------------------------------------------------------------------------------- // Atomics // We need to be portable between C, C++, and MSVC. -// We base the primitives on the C/C++ atomics and create a mimimal wrapper for MSVC in C compilation mode. +// We base the primitives on the C/C++ atomics and create a minimal wrapper for MSVC in C compilation mode. // This is why we try to use only `uintptr_t` and `*` as atomic types. // To gain better insight in the range of used atomics, we use explicitly named memory order operations // instead of passing the memory order as a parameter. diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 6e87d5ae..94e394c2 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -10,7 +10,7 @@ terms of the MIT license. A copy of the license can be found in the file // -------------------------------------------------------------------------- -// This file contains the interal API's of mimalloc and various utility +// This file contains the internal API's of mimalloc and various utility // functions and macros. // -------------------------------------------------------------------------- diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 31ed35f8..2545c6d2 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -231,7 +231,7 @@ typedef enum mi_delayed_e { MI_USE_DELAYED_FREE = 0, // push on the owning heap thread delayed list MI_DELAYED_FREEING = 1, // temporary: another thread is accessing the owning heap MI_NO_DELAYED_FREE = 2, // optimize: push on page local thread free queue if another block is already in the heap thread delayed free list - MI_NEVER_DELAYED_FREE = 3 // sticky: used for abondoned pages without a owning heap; this only resets on page reclaim + MI_NEVER_DELAYED_FREE = 3 // sticky: used for abandoned pages without a owning heap; this only resets on page reclaim } mi_delayed_t; @@ -338,7 +338,7 @@ typedef enum mi_page_kind_e { MI_PAGE_MEDIUM, // medium blocks go into 512KiB pages inside a segment MI_PAGE_LARGE, // larger blocks go into a single page spanning a whole segment MI_PAGE_HUGE // a huge page is a single page in a segment of variable size (but still 2MiB aligned) - // used for blocks `> MI_LARGE_OBJ_SIZE_MAX` or an aligment `> MI_BLOCK_ALIGNMENT_MAX`. + // used for blocks `> MI_LARGE_OBJ_SIZE_MAX` or an alignment `> MI_BLOCK_ALIGNMENT_MAX`. } mi_page_kind_t; diff --git a/readme.md b/readme.md index a0296b43..44e4c261 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ is a general purpose allocator with excellent [performance](#performance) charac Initially developed by Daan Leijen for the runtime systems of the [Koka](https://koka-lang.github.io) and [Lean](https://github.com/leanprover/lean) languages. -Latest release tag: `v2.1.7` (2024-05-21). +Latest release tag: `v2.1.7` (2024-05-21). Latest v1 tag: `v1.8.7` (2024-05-21). mimalloc is a drop-in replacement for `malloc` and can be used in other programs @@ -77,7 +77,7 @@ Enjoy! ### Releases -Note: the `v2.x` version has a different algorithm for managing internal mimalloc pages (as slices) that tends to use reduce +Note: the `v2.x` version has a different algorithm for managing internal mimalloc pages (as slices) that tends to use reduce memory usage and fragmentation compared to mimalloc `v1.x` (especially for large workloads). Should otherwise have similar performance (see [below](#performance)); please report if you observe any significant performance regression. @@ -87,18 +87,18 @@ memory usage * 2024-05-13, `v1.8.6`, `v2.1.6`: Fix build errors on various (older) platforms. Refactored aligned allocation. * 2024-04-22, `v1.8.4`, `v2.1.4`: Fixes various bugs and build issues. Add `MI_LIBC_MUSL` cmake flag for musl builds. Free-ing code is refactored into a separate module (`free.c`). Mimalloc page info is simplified with the block size - directly available (and new `block_size_shift` to improve aligned block free-ing). + directly available (and new `block_size_shift` to improve aligned block free-ing). New approach to collection of abandoned segments: When a thread terminates the segments it owns are abandoned (containing still live objects) and these can be - reclaimed by other threads. We no longer use a list of abandoned segments but this is now done using bitmaps in arena's + reclaimed by other threads. We no longer use a list of abandoned segments but this is now done using bitmaps in arena's which is more concurrent (and more aggressive). Abandoned memory can now also be reclaimed if a thread frees an object in an abandoned page (which can be disabled using `mi_option_abandoned_reclaim_on_free`). The option `mi_option_max_segment_reclaim` gives a maximum percentage of abandoned segments that can be reclaimed per try (=10%). -* 2023-04-24, `v1.8.2`, `v2.1.2`: Fixes build issues on freeBSD, musl, and C17 (UE 5.1.1). Reduce code size/complexity +* 2023-04-24, `v1.8.2`, `v2.1.2`: Fixes build issues on freeBSD, musl, and C17 (UE 5.1.1). Reduce code size/complexity by removing regions and segment-cache's and only use arenas with improved memory purging -- this may improve memory usage as well for larger services. Renamed options for consistency. Improved Valgrind and ASAN checking. - + * 2023-04-03, `v1.8.1`, `v2.1.1`: Fixes build issues on some platforms. * 2023-03-29, `v1.8.0`, `v2.1.0`: Improved support dynamic overriding on Windows 11. Improved tracing precision @@ -106,14 +106,14 @@ memory usage abstraction layer to make it easier to port and separate platform dependent code (in `src/prim`). Fixed C++ STL compilation on older Microsoft C++ compilers, and various small bug fixes. * 2022-12-23, `v1.7.9`, `v2.0.9`: Supports building with [asan](#asan) and improved [Valgrind](#valgrind) support. - Support arbitrary large alignments (in particular for `std::pmr` pools). - Added C++ STL allocators attached to a specific heap (thanks @vmarkovtsev). - Heap walks now visit all object (including huge objects). Support Windows nano server containers (by Johannes Schindelin,@dscho). + Support arbitrary large alignments (in particular for `std::pmr` pools). + Added C++ STL allocators attached to a specific heap (thanks @vmarkovtsev). + Heap walks now visit all object (including huge objects). Support Windows nano server containers (by Johannes Schindelin,@dscho). Various small bug fixes. * 2022-11-03, `v1.7.7`, `v2.0.7`: Initial support for [Valgrind](#valgrind) for leak testing and heap block overflow detection. Initial - support for attaching heaps to a speficic memory area (only in v2). Fix `realloc` behavior for zero size blocks, remove restriction to integral multiple of the alignment in `alloc_align`, improved aligned allocation performance, reduced contention with many threads on few processors (thank you @dposluns!), vs2022 support, support `pkg-config`, . + support for attaching heaps to a specific memory area (only in v2). Fix `realloc` behavior for zero size blocks, remove restriction to integral multiple of the alignment in `alloc_align`, improved aligned allocation performance, reduced contention with many threads on few processors (thank you @dposluns!), vs2022 support, support `pkg-config`, . * 2022-04-14, `v1.7.6`, `v2.0.6`: fix fallback path for aligned OS allocation on Windows, improve Windows aligned allocation even when compiling with older SDK's, fix dynamic overriding on macOS Monterey, fix MSVC C++ dynamic overriding, fix @@ -295,14 +295,14 @@ You can set further options either programmatically (using [`mi_option_set`](htt Advanced options: -- `MIMALLOC_ARENA_EAGER_COMMIT=2`: turns on eager commit for the large arenas (usually 1GiB) from which mimalloc - allocates segments and pages. Set this to 2 (default) to - only enable this on overcommit systems (e.g. Linux). Set this to 1 to enable explicitly on other systems - as well (like Windows or macOS) which may improve performance (as the whole arena is committed at once). - Note that eager commit only increases the commit but not the actual the peak resident set +- `MIMALLOC_ARENA_EAGER_COMMIT=2`: turns on eager commit for the large arenas (usually 1GiB) from which mimalloc + allocates segments and pages. Set this to 2 (default) to + only enable this on overcommit systems (e.g. Linux). Set this to 1 to enable explicitly on other systems + as well (like Windows or macOS) which may improve performance (as the whole arena is committed at once). + Note that eager commit only increases the commit but not the actual the peak resident set (rss) so it is generally ok to enable this. -- `MIMALLOC_PURGE_DELAY=N`: the delay in `N` milli-seconds (by default `10`) after which mimalloc will purge - OS pages that are not in use. This signals to the OS that the underlying physical memory can be reused which +- `MIMALLOC_PURGE_DELAY=N`: the delay in `N` milli-seconds (by default `10`) after which mimalloc will purge + OS pages that are not in use. This signals to the OS that the underlying physical memory can be reused which can reduce memory fragmentation especially in long running (server) programs. Setting `N` to `0` purges immediately when a page becomes unused which can improve memory usage but also decreases performance. Setting `N` to a higher value like `100` can improve performance (sometimes by a lot) at the cost of potentially using more memory at times. @@ -310,7 +310,7 @@ Advanced options: - `MIMALLOC_PURGE_DECOMMITS=1`: By default "purging" memory means unused memory is decommitted (`MEM_DECOMMIT` on Windows, `MADV_DONTNEED` (which decresease rss immediately) on `mmap` systems). Set this to 0 to instead "reset" unused memory on a purge (`MEM_RESET` on Windows, generally `MADV_FREE` (which does not decrease rss immediately) on `mmap` systems). - Mimalloc generally does not "free" OS memory but only "purges" OS memory, in other words, it tries to keep virtual + Mimalloc generally does not "free" OS memory but only "purges" OS memory, in other words, it tries to keep virtual address ranges and decommits within those ranges (to make the underlying physical memory available to other processes). Further options for large workloads and services: @@ -320,14 +320,14 @@ Further options for large workloads and services: 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_ALLOW_LARGE_OS_PAGES=1`: use large OS pages (2 or 4MiB) when available; for some workloads this can significantly - improve performance. When this option is disabled, it also disables transparent huge pages (THP) for the process + improve performance. When this option is disabled, it also disables transparent huge pages (THP) for the process (on Linux and Android). Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs to explicitly give permissions for 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 whenever possible). + can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead whenever 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_ALLOW_LARGE_OS_PAGES=1` in combination with this setting. Just like large + Usually it is better to not use `MIMALLOC_ALLOW_LARGE_OS_PAGES=1` 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). @@ -417,10 +417,10 @@ the [shell](https://stackoverflow.com/questions/43941322/dyld-insert-libraries-i ### Dynamic Override on Windows -Dynamically overriding on mimalloc on Windows +Dynamically overriding on mimalloc 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. -As it intercepts all allocation calls on a low level, it can be used reliably +As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. There are four requirements to make the overriding work robustly: @@ -429,7 +429,7 @@ There are four requirements to make the overriding work robustly: To ensure the `mimalloc-override.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 an example on how to use this. 3. The [`mimalloc-redirect.dll`](bin) (or `mimalloc-redirect32.dll`) must be put in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to @@ -439,7 +439,7 @@ There are four requirements to make the overriding work robustly: For best performance on Windows with C++, it is also recommended to also override the `new`/`delete` operations (by including -[`mimalloc-new-delete.h`](include/mimalloc-new-delete.h) +[`mimalloc-new-delete.h`](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 @@ -476,9 +476,9 @@ under your control or otherwise mixing of pointers from different heaps may occu # Tools Generally, we recommend using the standard allocator with memory tracking tools, but mimalloc -can also be build to support the [address sanitizer][asan] or the excellent [Valgrind] tool. +can also be build to support the [address sanitizer][asan] or the excellent [Valgrind] tool. Moreover, it can be build to support Windows event tracing ([ETW]). -This has a small performance overhead but does allow detecting memory leaks and byte-precise +This has a small performance overhead but does allow detecting memory leaks and byte-precise buffer overflows directly on final executables. See also the `test/test-wrong.c` file to test with various tools. ## Valgrind @@ -523,7 +523,7 @@ To build with the address sanitizer, use the `-DMI_TRACK_ASAN=ON` cmake option: > cmake ../.. -DMI_TRACK_ASAN=ON ``` -This can also be combined with secure mode or debug mode. +This can also be combined with secure mode or debug mode. You can then run your programs as:' ``` @@ -531,7 +531,7 @@ You can then run your programs as:' ``` When you link a program with an address sanitizer build of mimalloc, you should -generally compile that program too with the address sanitizer enabled. +generally compile that program too with the address sanitizer enabled. For example, assuming you build mimalloc in `out/debug`: ``` @@ -540,23 +540,23 @@ clang -g -o test-wrong -Iinclude test/test-wrong.c out/debug/libmimalloc-asan-de Since the address sanitizer redirects the standard allocation functions, on some platforms (macOSX for example) it is required to compile mimalloc with `-DMI_OVERRIDE=OFF`. -Adress sanitizer support is in its initial development -- please report any issues. +Address sanitizer support is in its initial development -- please report any issues. [asan]: https://github.com/google/sanitizers/wiki/AddressSanitizer ## ETW Event tracing for Windows ([ETW]) provides a high performance way to capture all allocations though -mimalloc and analyze them later. To build with ETW support, use the `-DMI_TRACK_ETW=ON` cmake option. +mimalloc and analyze them later. To build with ETW support, use the `-DMI_TRACK_ETW=ON` cmake option. -You can then capture an allocation trace using the Windows performance recorder (WPR), using the +You can then capture an allocation trace using the Windows performance recorder (WPR), using the `src/prim/windows/etw-mimalloc.wprp` profile. In an admin prompt, you can use: ``` > wpr -start src\prim\windows\etw-mimalloc.wprp -filemode > > wpr -stop .etl -``` -and then open `.etl` in the Windows Performance Analyzer (WPA), or +``` +and then open `.etl` in the Windows Performance Analyzer (WPA), or use a tool like [TraceControl] that is specialized for analyzing mimalloc traces. [ETW]: https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows diff --git a/src/arena.c b/src/arena.c index 3bb8f502..e0223e7f 100644 --- a/src/arena.c +++ b/src/arena.c @@ -284,7 +284,7 @@ static mi_decl_noinline void* mi_arena_try_alloc_at(mi_arena_t* arena, size_t ar return p; } -// allocate in a speficic arena +// allocate in a specific arena static void* mi_arena_try_alloc_at_id(mi_arena_id_t arena_id, bool match_numa_node, int numa_node, size_t size, size_t alignment, bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld ) { @@ -984,5 +984,3 @@ int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserv if (err==0 && pages_reserved!=NULL) *pages_reserved = pages; return err; } - - diff --git a/src/options.c b/src/options.c index 462a7c71..71c43e9c 100644 --- a/src/options.c +++ b/src/options.c @@ -94,10 +94,10 @@ static mi_option_desc_t options[_mi_option_last] = { 1, UNINIT, MI_OPTION(abandoned_reclaim_on_free) },// reclaim an abandoned segment on a free { 0, UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) { 400, UNINIT, MI_OPTION(retry_on_oom) }, // windows only: retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. -#if defined(MI_VISIT_ABANDONED) - { 1, INITIALIZED, MI_OPTION(visit_abandoned) }, // allow visiting heap blocks in abandonded segments; requires taking locks during reclaim. +#if defined(MI_VISIT_ABANDONED) + { 1, INITIALIZED, MI_OPTION(visit_abandoned) }, // allow visiting heap blocks in abandoned segments; requires taking locks during reclaim. #else - { 0, UNINIT, MI_OPTION(visit_abandoned) }, + { 0, UNINIT, MI_OPTION(visit_abandoned) }, #endif }; @@ -286,7 +286,7 @@ static _Atomic(size_t) warning_count; // = 0; // when >= max_warning_count stop // (recursively) invoke malloc again to allocate space for the thread local // variables on demand. This is why we use a _mi_preloading test on such // platforms. However, C code generator may move the initial thread local address -// load before the `if` and we therefore split it out in a separate funcion. +// load before the `if` and we therefore split it out in a separate function. static mi_decl_thread bool recurse = false; static mi_decl_noinline bool mi_recurse_enter_prim(void) { @@ -491,7 +491,7 @@ static void mi_option_init(mi_option_desc_t* desc) { char* end = buf; long value = strtol(buf, &end, 10); if (mi_option_has_size_in_kib(desc->option)) { - // this option is interpreted in KiB to prevent overflow of `long` for large allocations + // this option is interpreted in KiB to prevent overflow of `long` for large allocations // (long is 32-bit on 64-bit windows, which allows for 4TiB max.) size_t size = (value < 0 ? 0 : (size_t)value); bool overflow = false; diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 63a36f25..78080e88 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -763,7 +763,7 @@ bool _mi_prim_getenv(const char* name, char* result, size_t result_size) { #include bool _mi_prim_random_buf(void* buf, size_t buf_len) { - // We prefere CCRandomGenerateBytes as it returns an error code while arc4random_buf + // We prefer CCRandomGenerateBytes as it returns an error code while arc4random_buf // may fail silently on macOS. See PR #390, and return (CCRandomGenerateBytes(buf, buf_len) == kCCSuccess); } diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index bd874f9b..22f787de 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -50,7 +50,7 @@ typedef NTSTATUS (__stdcall *PNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, SIZE_T* static PVirtualAlloc2 pVirtualAlloc2 = NULL; static PNtAllocateVirtualMemoryEx pNtAllocateVirtualMemoryEx = NULL; -// Similarly, GetNumaProcesorNodeEx is only supported since Windows 7 +// Similarly, GetNumaProcessorNodeEx is only supported since Windows 7 typedef struct MI_PROCESSOR_NUMBER_S { WORD Group; BYTE Number; BYTE Reserved; } MI_PROCESSOR_NUMBER; typedef VOID (__stdcall *PGetCurrentProcessorNumberEx)(MI_PROCESSOR_NUMBER* ProcNumber); @@ -658,4 +658,3 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { } #endif - diff --git a/src/segment.c b/src/segment.c index 54a917ea..b9bdb9b7 100644 --- a/src/segment.c +++ b/src/segment.c @@ -32,7 +32,7 @@ static uint8_t* mi_segment_raw_page_start(const mi_segment_t* segment, const mi_ (i.e. we are careful to not touch the memory until we actually allocate a block there) If a thread ends, it "abandons" pages that still contain live blocks. - Such segments are abondoned and these can be reclaimed by still running threads, + Such segments are abandoned and these can be reclaimed by still running threads, (much like work-stealing). -------------------------------------------------------------------------------- */ @@ -276,7 +276,7 @@ static bool mi_page_ensure_committed(mi_segment_t* segment, mi_page_t* page, mi_ // we re-use the `free` field for the expiration counter. Since this is a // a pointer size field while the clock is always 64-bit we need to guard -// against overflow, we use substraction to check for expiry which works +// against overflow, we use subtraction to check for expiry which works // as long as the reset delay is under (2^30 - 1) milliseconds (~12 days) static uint32_t mi_page_get_expire( mi_page_t* page ) { return (uint32_t)((uintptr_t)page->free); @@ -294,7 +294,7 @@ static void mi_page_purge_set_expire(mi_page_t* page) { // we re-use the `free` field for the expiration counter. Since this is a // a pointer size field while the clock is always 64-bit we need to guard -// against overflow, we use substraction to check for expiry which work +// against overflow, we use subtraction to check for expiry which work // as long as the reset delay is under (2^30 - 1) milliseconds (~12 days) static bool mi_page_purge_is_expired(mi_page_t* page, mi_msecs_t now) { int32_t expire = (int32_t)mi_page_get_expire(page); @@ -778,7 +778,7 @@ When a block is freed in an abandoned segment, the segment is reclaimed into that thread. Moreover, if threads are looking for a fresh segment, they -will first consider abondoned segments -- these can be found +will first consider abandoned segments -- these can be found by scanning the arena memory (segments outside arena memoryare only reclaimed by a free). ----------------------------------------------------------- */ @@ -995,7 +995,7 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, { mi_assert(segment->subproc == heap->tld->segments.subproc); // cursor only visits segments in our sub-process segment->abandoned_visits++; - // todo: should we respect numa affinity for abondoned reclaim? perhaps only for the first visit? + // todo: should we respect numa affinity for abandoned reclaim? perhaps only for the first visit? // todo: an arena exclusive heap will potentially visit many abandoned unsuitable segments and use many tries // Perhaps we can skip non-suitable ones in a better way? bool is_suitable = _mi_heap_memid_is_suitable(heap, segment->memid); diff --git a/test/test-stress.c b/test/test-stress.c index f9b3c9d6..58d6a6a1 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -26,11 +26,11 @@ terms of the MIT license. // // argument defaults #if defined(MI_TSAN) // with thread-sanitizer reduce the threads to test within the azure pipeline limits -static int THREADS = 8; +static int THREADS = 8; static int SCALE = 25; static int ITER = 200; -#elif defined(MI_UBSAN) // with undefined behavious sanitizer reduce parameters to stay within the azure pipeline limits -static int THREADS = 8; +#elif defined(MI_UBSAN) // with undefined behaviours sanitizer reduce parameters to stay within the azure pipeline limits +static int THREADS = 8; static int SCALE = 25; static int ITER = 20; #else From 7b5df14beaeff29b9cee3e8de08b034879dca7fb Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 16 Jul 2024 09:15:59 -0700 Subject: [PATCH 059/305] initial work on guarded objects --- CMakeLists.txt | 10 ++++++++++ include/mimalloc.h | 2 ++ include/mimalloc/internal.h | 1 + src/options.c | 14 ++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a730557..e78ba9fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ option(MI_BUILD_OBJECT "Build object library" ON) option(MI_BUILD_TESTS "Build test executables" ON) option(MI_DEBUG_TSAN "Build with thread sanitizer (needs clang)" OFF) option(MI_DEBUG_UBSAN "Build with undefined-behavior sanitizer (needs clang++)" OFF) +option(MI_DEBUG_GUARDED "Build with guard pages behind certain object allocations (implies MI_NO_PADDING=ON)" OFF) option(MI_SKIP_COLLECT_ON_EXIT "Skip collecting memory on program exit" OFF) option(MI_NO_PADDING "Force no use of padding even in DEBUG mode etc." OFF) option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) @@ -199,6 +200,15 @@ if(MI_TRACK_ETW) endif() endif() +if(MI_DEBUG_GUARDED) + message(STATUS "Compile guard pages behind certain object allocations (MI_DEBUG_GUARDED=ON)") + list(APPEND mi_defines MI_DEBUG_GUARDED=1) + if(NOT MI_NO_PADDING) + message(STATUS " Disabling padding due to guard pages (MI_NO_PADDING=ON)") + set(MI_NO_PADDING ON) + endif() +endif() + if(MI_SEE_ASM) message(STATUS "Generate assembly listings (MI_SEE_ASM=ON)") list(APPEND mi_cflags -save-temps) diff --git a/include/mimalloc.h b/include/mimalloc.h index bc743fd7..a56f9b82 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -366,6 +366,8 @@ typedef enum mi_option_e { mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's) mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) + mi_option_debug_guarded_min, // only when build with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) + mi_option_debug_guarded_max, // only when build with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 6e87d5ae..05efa86f 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -61,6 +61,7 @@ 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); +long _mi_option_get_fast(mi_option_t option); void _mi_error_message(int err, const char* fmt, ...); // random.c diff --git a/src/options.c b/src/options.c index 462a7c71..ca931855 100644 --- a/src/options.c +++ b/src/options.c @@ -99,6 +99,8 @@ static mi_option_desc_t options[_mi_option_last] = #else { 0, UNINIT, MI_OPTION(visit_abandoned) }, #endif + { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only when build with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) + { 0, UNINIT, MI_OPTION(debug_guarded_max) }, // only when build with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) }; static void mi_option_init(mi_option_desc_t* desc); @@ -124,6 +126,15 @@ void _mi_options_init(void) { mi_max_warning_count = mi_option_get(mi_option_max_warnings); } +long _mi_option_get_fast(mi_option_t option) { + mi_assert(option >= 0 && option < _mi_option_last); + mi_option_desc_t* desc = &options[option]; + mi_assert(desc->option == option); // index should match the option + //mi_assert(desc->init != UNINIT); + return desc->value; +} + + mi_decl_nodiscard long mi_option_get(mi_option_t option) { mi_assert(option >= 0 && option < _mi_option_last); if (option < 0 || option >= _mi_option_last) return 0; @@ -508,6 +519,9 @@ static void mi_option_init(mi_option_desc_t* desc) { if (*end == 0) { desc->value = value; desc->init = INITIALIZED; + if (desc->option == mi_option_debug_guarded_min && _mi_option_get_fast(mi_option_debug_guarded_max) < value) { + mi_option_set(mi_option_debug_guarded_max,value); + } } else { // set `init` first to avoid recursion through _mi_warning_message on mimalloc_verbose. From 566b2c51fc42b476adf176063e84222e832a7d57 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 22 Jul 2024 09:43:43 +0900 Subject: [PATCH 060/305] Add a missing #include This change fixes the "implicit declaration of function 'getenv'" warning. Since stdlib.h is completely portable, as it is defined by the C standard, we can safely include it unconditionally. --- src/prim/unix/prim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 63a36f25..c48b4cbd 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -27,6 +27,7 @@ terms of the MIT license. A copy of the license can be found in the file #include // mmap #include // sysconf #include // open, close, read, access +#include // getenv, arc4random_buf #if defined(__linux__) #include @@ -773,7 +774,6 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) { defined(__sun) || \ (defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)) -#include bool _mi_prim_random_buf(void* buf, size_t buf_len) { arc4random_buf(buf, buf_len); return true; From 9c9efc417dbe275cfa0b542b7298494d889fc84a Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Fri, 26 Jul 2024 12:11:21 +0200 Subject: [PATCH 061/305] Fix build on FreeBSD-derivate DragonFly --- src/alloc-override.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc-override.c b/src/alloc-override.c index 12837cdd..dde37786 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -248,7 +248,7 @@ extern "C" { // Forward Posix/Unix calls as well void* reallocf(void* p, size_t newsize) MI_FORWARD2(mi_reallocf,p,newsize) size_t malloc_size(const void* p) MI_FORWARD1(mi_usable_size,p) - #if !defined(__ANDROID__) && !defined(__FreeBSD__) + #if !defined(__ANDROID__) && !defined(__FreeBSD__) && !defined(__DragonFly__) 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) From 01503df7f3bb9bc46c74d67bc5060552f9f66ded Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 12 Aug 2024 13:51:39 -0700 Subject: [PATCH 062/305] move declaration to avoid gcc warning, see issue #919 --- src/segment.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/segment.c b/src/segment.c index bea43210..f8e98655 100644 --- a/src/segment.c +++ b/src/segment.c @@ -663,8 +663,7 @@ static void mi_segment_span_remove_from_queue(mi_slice_t* slice, mi_segments_tld static mi_slice_t* mi_segment_span_free_coalesce(mi_slice_t* slice, mi_segments_tld_t* tld) { mi_assert_internal(slice != NULL && slice->slice_count > 0 && slice->slice_offset == 0); mi_segment_t* const segment = _mi_ptr_segment(slice); - const bool is_abandoned = (segment->thread_id == 0); // mi_segment_is_abandoned(segment); - + // for huge pages, just mark as free but don't add to the queues if (segment->kind == MI_SEGMENT_HUGE) { // issue #691: segment->used can be 0 if the huge page block was freed while abandoned (reclaim will get here in that case) @@ -676,6 +675,7 @@ static mi_slice_t* mi_segment_span_free_coalesce(mi_slice_t* slice, mi_segments_ } // otherwise coalesce the span and add to the free span queues + const bool is_abandoned = (segment->thread_id == 0); // mi_segment_is_abandoned(segment); size_t slice_count = slice->slice_count; mi_slice_t* next = slice + slice->slice_count; mi_assert_internal(next <= mi_segment_slices_end(segment)); From 5eb8c752f7dc2aaef5080831b1f8ff8092bc25af Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 13 Aug 2024 16:36:53 -0700 Subject: [PATCH 063/305] fix UINT32_MAX constant (see issue #913) --- src/segment-map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment-map.c b/src/segment-map.c index 8927a8bd..2c3964fe 100644 --- a/src/segment-map.c +++ b/src/segment-map.c @@ -22,7 +22,7 @@ terms of the MIT license. A copy of the license can be found in the file #elif (MI_INTPTR_SIZE > 4) #define MI_SEGMENT_MAP_MAX_ADDRESS (48*1024ULL*MI_GiB) // 48 TiB #else -#define MI_SEGMENT_MAP_MAX_ADDRESS (MAX_UINT32) +#define MI_SEGMENT_MAP_MAX_ADDRESS (UINT32_MAX) #endif #define MI_SEGMENT_MAP_PART_SIZE (MI_INTPTR_SIZE*MI_KiB - 128) // 128 > sizeof(mi_memid_t) ! From 0c19eb60cf9b70926a388b668bab574ca225afec Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 19 Aug 2024 21:21:40 -0700 Subject: [PATCH 064/305] initial working guarded pages --- include/mimalloc.h | 4 +- include/mimalloc/internal.h | 10 +++++ include/mimalloc/types.h | 10 ++++- src/alloc-aligned.c | 20 +++++++--- src/alloc.c | 75 +++++++++++++++++++++++++++++++++++-- src/free.c | 25 +++++++++++-- src/heap.c | 23 ++++++++---- src/options.c | 28 +++++++++----- src/page.c | 8 +++- src/segment.c | 9 ++++- test/main-override-static.c | 8 ++++ test/test-api.c | 13 ++++++- 12 files changed, 196 insertions(+), 37 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index a56f9b82..867c5c97 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -366,8 +366,8 @@ typedef enum mi_option_e { mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's) mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) - mi_option_debug_guarded_min, // only when build with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) - mi_option_debug_guarded_max, // only when build with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) + mi_option_debug_guarded_min, // only used when build with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) + mi_option_debug_guarded_max, // only used when build with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 05efa86f..6d9f25cb 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -323,6 +323,7 @@ static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) { } } + // Align a pointer upwards static inline void* mi_align_up_ptr(void* p, size_t alignment) { return (void*)_mi_align_up((uintptr_t)p, alignment); @@ -594,6 +595,15 @@ static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { page->flags.x.has_aligned = has_aligned; } +#if MI_DEBUG_GUARDED +static inline bool mi_page_has_guarded(const mi_page_t* page) { + return page->flags.x.has_guarded; +} + +static inline void mi_page_set_has_guarded(mi_page_t* page, bool has_guarded) { + page->flags.x.has_guarded = has_guarded; +} +#endif /* ------------------------------------------------------------------- Encoding/Decoding the free list next pointers diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 31ed35f8..ffe095a5 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -72,6 +72,12 @@ terms of the MIT license. A copy of the license can be found in the file #endif #endif +// Use guard pages behind objects of a certain size +#define MI_DEBUG_GUARDED 1 +#if defined(MI_DEBUG_GUARDED) || defined(MI_DEBUG_GUARDEDX) +#define MI_PADDING 0 +#endif + // Reserve extra padding at the end of each block to be more resilient against heap block overflows. // The padding can detect buffer overflow on free. #if !defined(MI_PADDING) && (MI_SECURE>=3 || MI_DEBUG>=1 || (MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_TRACK_ETW)) @@ -243,15 +249,17 @@ typedef union mi_page_flags_s { struct { uint8_t in_full : 1; uint8_t has_aligned : 1; + uint8_t has_guarded : 1; // only used with MI_DEBUG_GUARDED } x; } mi_page_flags_t; #else // under thread sanitizer, use a byte for each flag to suppress warning, issue #130 typedef union mi_page_flags_s { - uint16_t full_aligned; + uint32_t full_aligned; struct { uint8_t in_full; uint8_t has_aligned; + uint8_t has_guarded; // only used with MI_DEBUG_GUARDED } x; } mi_page_flags_t; #endif diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 20c36044..248c932d 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -20,8 +20,12 @@ static bool mi_malloc_is_naturally_aligned( size_t size, size_t alignment ) { mi_assert_internal(_mi_is_power_of_two(alignment) && (alignment > 0)); if (alignment > size) return false; if (alignment <= MI_MAX_ALIGN_SIZE) return true; + #if MI_DEBUG_GUARDED + return false; + #else const size_t bsize = mi_good_size(size); return (bsize <= MI_MAX_ALIGN_GUARANTEE && (bsize & (alignment-1)) == 0); + #endif } // Fallback aligned allocation that over-allocates -- split out for better codegen @@ -38,9 +42,9 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t // first (and single) page such that the segment info is `MI_SEGMENT_SIZE` bytes before it (so it can be found by aligning the pointer down) if mi_unlikely(offset != 0) { // todo: cannot support offset alignment for very large alignments yet - #if MI_DEBUG > 0 +#if MI_DEBUG > 0 _mi_error_message(EOVERFLOW, "aligned allocation with a very large alignment cannot be used with an alignment offset (size %zu, alignment %zu, offset %zu)\n", size, alignment, offset); - #endif +#endif return NULL; } oversize = (size <= MI_SMALL_SIZE_MAX ? MI_SMALL_SIZE_MAX + 1 /* ensure we use generic malloc path */ : size); @@ -54,7 +58,8 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t p = _mi_heap_malloc_zero(heap, oversize, zero); if (p == NULL) return NULL; } - + mi_page_t* page = _mi_ptr_page(p); + // .. and align within the allocation const uintptr_t align_mask = alignment - 1; // for any x, `(x & align_mask) == (x % alignment)` const uintptr_t poffset = ((uintptr_t)p + offset) & align_mask; @@ -62,17 +67,18 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t mi_assert_internal(adjust < alignment); void* aligned_p = (void*)((uintptr_t)p + adjust); if (aligned_p != p) { - mi_page_t* page = _mi_ptr_page(p); mi_page_set_has_aligned(page, true); _mi_padding_shrink(page, (mi_block_t*)p, adjust + size); } // todo: expand padding if overallocated ? - mi_assert_internal(mi_page_usable_block_size(_mi_ptr_page(p)) >= adjust + size); - mi_assert_internal(p == _mi_page_ptr_unalign(_mi_ptr_page(aligned_p), aligned_p)); + mi_assert_internal(mi_page_usable_block_size(page) >= adjust + size); mi_assert_internal(((uintptr_t)aligned_p + offset) % alignment == 0); mi_assert_internal(mi_usable_size(aligned_p)>=size); mi_assert_internal(mi_usable_size(p) == mi_usable_size(aligned_p)+adjust); + #if !MI_DEBUG_GUARDED + mi_assert_internal(p == _mi_page_ptr_unalign(_mi_ptr_page(aligned_p), aligned_p)); + #endif // now zero the block if needed if (alignment > MI_BLOCK_ALIGNMENT_MAX) { @@ -133,6 +139,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t return NULL; } + #if !MI_DEBUG_GUARDED // try first if there happens to be a small block available with just the right alignment if mi_likely(size <= MI_SMALL_SIZE_MAX && alignment <= size) { const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` @@ -153,6 +160,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t } } } + #endif // fallback to generic aligned allocation return mi_heap_malloc_zero_aligned_at_generic(heap, size, alignment, offset, zero); diff --git a/src/alloc.c b/src/alloc.c index 7be1a6e9..ec008318 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -40,9 +40,9 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_ page->free = mi_block_next(page, block); page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); - mi_assert_internal(_mi_is_aligned(block, MI_MAX_ALIGN_SIZE)); + mi_assert_internal(page->block_size < MI_MAX_ALIGN_SIZE || _mi_is_aligned(block, MI_MAX_ALIGN_SIZE)); #if MI_DEBUG>3 - if (page->free_is_zero) { + if (page->free_is_zero && size > sizeof(*block)) { mi_assert_expensive(mi_mem_is_zero(block+1,size - sizeof(*block))); } #endif @@ -56,6 +56,7 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_ if mi_unlikely(zero) { mi_assert_internal(page->block_size != 0); // do not call with zero'ing for huge blocks (see _mi_malloc_generic) mi_assert_internal(page->block_size >= MI_PADDING_SIZE); + mi_assert_internal(!mi_page_is_huge(page)); if (page->free_is_zero) { block->next = 0; mi_track_mem_defined(block, page->block_size - MI_PADDING_SIZE); @@ -114,6 +115,11 @@ extern void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t siz return _mi_page_malloc_zero(heap,page,size,true); } +#if MI_DEBUG_GUARDED +// forward declaration +static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept; +#endif + static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { mi_assert(heap != NULL); #if MI_DEBUG @@ -121,9 +127,14 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, mi_assert(heap->thread_id == 0 || heap->thread_id == tid); // heaps are thread local #endif mi_assert(size <= MI_SMALL_SIZE_MAX); - #if (MI_PADDING) + #if (MI_PADDING || MI_DEBUG_GUARDED) if (size == 0) { size = sizeof(void*); } #endif + #if MI_DEBUG_GUARDED + if (size >= _mi_option_get_fast(mi_option_debug_guarded_min) && size <= _mi_option_get_fast(mi_option_debug_guarded_max)) { + return mi_heap_malloc_guarded(heap, size, zero, 0); + } + #endif mi_page_t* page = _mi_heap_get_free_small_page(heap, size + MI_PADDING_SIZE); void* const p = _mi_page_malloc_zero(heap, page, size + MI_PADDING_SIZE, zero); @@ -158,6 +169,14 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z mi_assert_internal(huge_alignment == 0); return mi_heap_malloc_small_zero(heap, size, zero); } + #if MI_DEBUG_GUARDED + else if ( huge_alignment == 0 && // guarded pages do not work with huge aligments at the moment + ((size >= _mi_option_get_fast(mi_option_debug_guarded_min) && size <= _mi_option_get_fast(mi_option_debug_guarded_max)) + || ((size & (_mi_os_page_size()-1)) == 0)) ) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. + { + return mi_heap_malloc_guarded(heap, size, zero, 0); + } + #endif else { mi_assert(heap!=NULL); mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local @@ -578,6 +597,56 @@ mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) { } } +#if MI_DEBUG_GUARDED +static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept +{ + #if defined(MI_PADDING_SIZE) + mi_assert(MI_PADDING_SIZE==0); + #endif + // allocate multiple of page size ending in a guard page + const size_t bsize = _mi_align_up(size, MI_MAX_ALIGN_SIZE); // ensure minimal alignment requirement + const size_t psize = _mi_os_page_size(); + const size_t gsize = _mi_align_up(bsize + psize, psize); + void* const base = _mi_malloc_generic(heap, gsize, zero, huge_alignment); + if (base==NULL) return NULL; + mi_page_t* page = _mi_ptr_page(base); + mi_segment_t* segment = _mi_page_segment(page); + + const size_t fullsize = mi_page_block_size(page); // must use `block_size` to match `mi_free_local` + void* const gpage = (uint8_t*)base + (fullsize - psize); + mi_assert_internal(_mi_is_aligned(gpage, psize)); + void* const p = (uint8_t*)base + (fullsize - psize - bsize); + mi_assert_internal(p >= base); + + // set page flags + if (p > base) { mi_page_set_has_aligned(page, true); } + + // set guard page + if (segment->allow_decommit) { + mi_page_set_has_guarded(page, true); + _mi_os_protect(gpage, psize); + } + else { + _mi_warning_message("unable to set a guard page behind an object due to pinned memory (large OS pages?) (object %p of size %zu)\n", p, size); + } + + // stats + mi_track_malloc(p, size, zero); + #if MI_STAT>1 + if (p != NULL) { + if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); } + mi_heap_stat_increase(heap, malloc, mi_usable_size(p)); + } + #endif + #if MI_DEBUG>3 + if (p != NULL && zero) { + mi_assert_expensive(mi_mem_is_zero(p, size)); + } + #endif + return p; +} +#endif + // ------------------------------------------------------ // ensure explicit external inline definitions are emitted! // ------------------------------------------------------ diff --git a/src/free.c b/src/free.c index c6221fe7..07c06899 100644 --- a/src/free.c +++ b/src/free.c @@ -34,11 +34,21 @@ static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool if mi_unlikely(mi_check_is_double_free(page, block)) return; mi_check_padding(page, block); if (track_stats) { mi_stat_free(page, block); } - #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN + #if MI_DEBUG_GUARDED + if (mi_page_has_guarded(page)) { + const size_t bsize = mi_page_block_size(page); + const size_t psize = _mi_os_page_size(); + mi_assert_internal(bsize > psize); + mi_assert_internal(_mi_page_segment(page)->allow_decommit); + void* gpage = (uint8_t*)block + (bsize - psize); + _mi_os_unprotect(gpage, psize); + } + #endif + #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN && !MI_DEBUG_GUARDED memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); #endif if (track_stats) { mi_track_free_size(block, mi_page_usable_size_of(page, block)); } // faster then mi_usable_size as we already know the page and that p is unaligned - + // actual free: push on the local free list mi_block_set_next(page, block, page->local_free); page->local_free = block; @@ -51,8 +61,8 @@ static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool } // Adjust a block that was allocated aligned, to the actual start of the block in the page. -// note: this can be called from `mi_free_generic_mt` where a non-owning thread accesses the -// `page_start` and `block_size` fields; however these are constant and the page won't be +// note: this can be called from `mi_free_generic_mt` where a non-owning thread accesses the +// `page_start` and `block_size` fields; however these are constant and the page won't be // deallocated (as the block we are freeing keeps it alive) and thus safe to read concurrently. mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p) { mi_assert_internal(page!=NULL && p!=NULL); @@ -298,6 +308,13 @@ static inline size_t _mi_usable_size(const void* p, const char* msg) mi_attr_noe const mi_segment_t* const segment = mi_checked_ptr_segment(p, msg); if mi_unlikely(segment==NULL) return 0; const mi_page_t* const page = _mi_segment_page_of(segment, p); + #if MI_DEBUG_GUARDED + if (mi_page_has_guarded(page)) { + const size_t bsize = mi_page_usable_aligned_size_of(page, p); + mi_assert_internal(bsize > _mi_os_page_size()); + return (bsize > _mi_os_page_size() ? bsize - _mi_os_page_size() : bsize); + } else + #endif if mi_likely(!mi_page_has_aligned(page)) { const mi_block_t* block = (const mi_block_t*)p; return mi_page_usable_size_of(page, block); diff --git a/src/heap.c b/src/heap.c index 0d716f91..a3aaaf6b 100644 --- a/src/heap.c +++ b/src/heap.c @@ -32,7 +32,7 @@ static bool mi_heap_visit_pages(mi_heap_t* heap, heap_page_visitor_fun* fn, void #if MI_DEBUG>1 size_t total = heap->page_count; size_t count = 0; - #endif + #endif for (size_t i = 0; i <= MI_BIN_FULL; i++) { mi_page_queue_t* pq = &heap->pages[i]; @@ -164,9 +164,9 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) if (force && is_main_thread && mi_heap_is_backing(heap)) { _mi_thread_data_collect(); // collect thread data cache } - + // collect arenas (this is program wide so don't force purges on abandonment of threads) - _mi_arenas_collect(collect == MI_FORCE /* force purge? */, &heap->tld->stats); + _mi_arenas_collect(collect == MI_FORCE /* force purge? */, &heap->tld->stats); } void _mi_heap_collect_abandon(mi_heap_t* heap) { @@ -240,7 +240,7 @@ mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id) { } mi_decl_nodiscard mi_heap_t* mi_heap_new(void) { - // don't reclaim abandoned memory or otherwise destroy is unsafe + // don't reclaim abandoned memory or otherwise destroy is unsafe return mi_heap_new_ex(0 /* default heap tag */, true /* no reclaim */, _mi_arena_id_none()); } @@ -369,7 +369,13 @@ void mi_heap_destroy(mi_heap_t* heap) { mi_assert(heap->no_reclaim); mi_assert_expensive(mi_heap_is_valid(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return; + #if MI_DEBUG_GUARDED + _mi_warning_message("'mi_heap_destroy' called but ignored as MI_DEBUG_GUARDED is enabled (heap at %p)\n", heap); + mi_heap_delete(heap); + return; + #else if (!heap->no_reclaim) { + _mi_warning_message("'mi_heap_destroy' called but ignored as the heap was not created with 'allow_destroy' (heap at %p)\n", heap); // don't free in case it may contain reclaimed pages mi_heap_delete(heap); } @@ -382,6 +388,7 @@ void mi_heap_destroy(mi_heap_t* heap) { _mi_heap_destroy_pages(heap); mi_heap_free(heap); } + #endif } // forcefully destroy all heaps in the current thread @@ -537,7 +544,7 @@ void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page) { static void mi_get_fast_divisor(size_t divisor, uint64_t* magic, size_t* shift) { mi_assert_internal(divisor > 0 && divisor <= UINT32_MAX); *shift = 64 - mi_clz(divisor - 1); - *magic = ((((uint64_t)1 << 32) * (((uint64_t)1 << *shift) - divisor)) / divisor + 1); + *magic = ((((uint64_t)1 << 32) * (((uint64_t)1 << *shift) - divisor)) / divisor + 1); } static size_t mi_fast_divide(size_t n, uint64_t magic, size_t shift) { @@ -581,7 +588,7 @@ bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_ // create a bitmap of free blocks. #define MI_MAX_BLOCKS (MI_SMALL_PAGE_SIZE / sizeof(void*)) uintptr_t free_map[MI_MAX_BLOCKS / MI_INTPTR_BITS]; - const uintptr_t bmapsize = _mi_divide_up(page->capacity, MI_INTPTR_BITS); + const uintptr_t bmapsize = _mi_divide_up(page->capacity, MI_INTPTR_BITS); memset(free_map, 0, bmapsize * sizeof(intptr_t)); if (page->capacity % MI_INTPTR_BITS != 0) { // mark left-over bits at the end as free @@ -591,7 +598,7 @@ bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_ } // fast repeated division by the block size - uint64_t magic; + uint64_t magic; size_t shift; mi_get_fast_divisor(bsize, &magic, &shift); @@ -665,7 +672,7 @@ static bool mi_heap_visit_areas_page(mi_heap_t* heap, mi_page_queue_t* pq, mi_pa mi_heap_area_visit_fun* fun = (mi_heap_area_visit_fun*)vfun; mi_heap_area_ex_t xarea; xarea.page = page; - _mi_heap_area_init(&xarea.area, page); + _mi_heap_area_init(&xarea.area, page); return fun(heap, &xarea, arg); } diff --git a/src/options.c b/src/options.c index ca931855..b8859235 100644 --- a/src/options.c +++ b/src/options.c @@ -99,8 +99,8 @@ static mi_option_desc_t options[_mi_option_last] = #else { 0, UNINIT, MI_OPTION(visit_abandoned) }, #endif - { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only when build with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) - { 0, UNINIT, MI_OPTION(debug_guarded_max) }, // only when build with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) + { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only used when built with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) + { 0, UNINIT, MI_OPTION(debug_guarded_max) }, // only used when built with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) }; static void mi_option_init(mi_option_desc_t* desc); @@ -110,8 +110,7 @@ static bool mi_option_has_size_in_kib(mi_option_t option) { } void _mi_options_init(void) { - // called on process load; should not be called before the CRT is initialized! - // (e.g. do not call this from process_init as that may run before CRT initialization) + // called on process load mi_add_stderr_output(); // now it safe to use stderr for output for(int i = 0; i < _mi_option_last; i++ ) { mi_option_t option = (mi_option_t)i; @@ -124,6 +123,14 @@ void _mi_options_init(void) { } mi_max_error_count = mi_option_get(mi_option_max_errors); mi_max_warning_count = mi_option_get(mi_option_max_warnings); + #if MI_DEBUG_GUARDED + if (mi_option_get(mi_option_debug_guarded_max) > 0) { + if (mi_option_is_enabled(mi_option_allow_large_os_pages)) { + mi_option_disable(mi_option_allow_large_os_pages); + _mi_warning_message("option 'allow_large_os_pages' is disabled to allow for guarded objects\n"); + } + } + #endif } long _mi_option_get_fast(mi_option_t option) { @@ -168,6 +175,13 @@ void mi_option_set(mi_option_t option, long value) { mi_assert(desc->option == option); // index should match the option desc->value = value; desc->init = INITIALIZED; + // ensure min/max range; be careful to not recurse. + if (desc->option == mi_option_debug_guarded_min && _mi_option_get_fast(mi_option_debug_guarded_max) < value) { + mi_option_set(mi_option_debug_guarded_max, value); + } + else if (desc->option == mi_option_debug_guarded_max && _mi_option_get_fast(mi_option_debug_guarded_min) > value) { + mi_option_set(mi_option_debug_guarded_min, value); + } } void mi_option_set_default(mi_option_t option, long value) { @@ -517,11 +531,7 @@ static void mi_option_init(mi_option_desc_t* desc) { value = (size > LONG_MAX ? LONG_MAX : (long)size); } if (*end == 0) { - desc->value = value; - desc->init = INITIALIZED; - if (desc->option == mi_option_debug_guarded_min && _mi_option_get_fast(mi_option_debug_guarded_max) < value) { - mi_option_set(mi_option_debug_guarded_max,value); - } + mi_option_set(desc->option, value); } else { // set `init` first to avoid recursion through _mi_warning_message on mimalloc_verbose. diff --git a/src/page.c b/src/page.c index 96d1b24c..49f9ed52 100644 --- a/src/page.c +++ b/src/page.c @@ -414,6 +414,9 @@ void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force) { // no more aligned blocks in here mi_page_set_has_aligned(page, false); + #if MI_DEBUG_GUARDED + mi_page_set_has_guarded(page, false); + #endif // remove from the page list // (no need to do _mi_heap_delayed_free first as all blocks are already free) @@ -440,6 +443,9 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept { mi_assert_internal(mi_page_all_free(page)); mi_page_set_has_aligned(page, false); + #if MI_DEBUG_GUARDED + mi_page_set_has_guarded(page, false); + #endif // don't retire too often.. // (or we end up retiring and re-allocating most of the time) @@ -912,7 +918,7 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero, size_t huge_al mi_assert_internal(mi_page_block_size(page) >= size); // and try again, this time succeeding! (i.e. this should never recurse through _mi_page_malloc) - if mi_unlikely(zero && page->block_size == 0) { + if mi_unlikely(zero && mi_page_is_huge(page)) { // note: we cannot call _mi_page_malloc with zeroing for huge blocks; we zero it afterwards in that case. void* p = _mi_page_malloc(heap, page, size); mi_assert_internal(p != NULL); diff --git a/src/segment.c b/src/segment.c index 7646c94c..ead8bb98 100644 --- a/src/segment.c +++ b/src/segment.c @@ -448,13 +448,18 @@ uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* pa static size_t mi_segment_calculate_sizes(size_t capacity, size_t required, size_t* pre_size, size_t* info_size) { - const size_t minsize = sizeof(mi_segment_t) + ((capacity - 1) * sizeof(mi_page_t)) + 16 /* padding */; + const size_t minsize = sizeof(mi_segment_t) + ((capacity - 1) * sizeof(mi_page_t)) + 16 /* padding */; size_t guardsize = 0; size_t isize = 0; + if (MI_SECURE == 0) { // normally no guard pages + #if MI_DEBUG_GUARDED + isize = _mi_align_up(minsize, _mi_os_page_size()); + #else isize = _mi_align_up(minsize, 16 * MI_MAX_ALIGN_SIZE); + #endif } else { // in secure mode, we set up a protected page in between the segment info @@ -462,7 +467,7 @@ static size_t mi_segment_calculate_sizes(size_t capacity, size_t required, size_ const size_t page_size = _mi_os_page_size(); isize = _mi_align_up(minsize, page_size); guardsize = page_size; - required = _mi_align_up(required, page_size); + //required = _mi_align_up(required, isize + guardsize); } if (info_size != NULL) *info_size = isize; diff --git a/test/main-override-static.c b/test/main-override-static.c index bf1cc416..9cddb98d 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -11,6 +11,7 @@ static void double_free1(); static void double_free2(); static void corrupt_free(); static void block_overflow1(); +static void block_overflow2(); static void invalid_free(); static void test_aslr(void); static void test_process_info(void); @@ -28,6 +29,7 @@ int main() { // double_free2(); // corrupt_free(); // block_overflow1(); + block_overflow2(); // test_aslr(); // invalid_free(); // test_reserved(); @@ -76,6 +78,12 @@ static void block_overflow1() { free(p); } +static void block_overflow2() { + uint8_t* p = (uint8_t*)mi_malloc(16); + p[17] = 0; + free(p); +} + // The double free samples come ArcHeap [1] by Insu Yun (issue #161) // [1]: https://arxiv.org/pdf/1903.00503.pdf diff --git a/test/test-api.c b/test/test-api.c index 76101980..15484544 100644 --- a/test/test-api.c +++ b/test/test-api.c @@ -65,6 +65,15 @@ bool mem_is_zero(uint8_t* p, size_t size) { int main(void) { mi_option_disable(mi_option_verbose); + CHECK_BODY("malloc-aligned9a") { // test large alignments + void* p = mi_zalloc_aligned(1024 * 1024, 2); + mi_free(p); + p = mi_zalloc_aligned(1024 * 1024, 2); + mi_free(p); + result = true; + }; + + // --------------------------------------------------- // Malloc // --------------------------------------------------- @@ -157,6 +166,7 @@ int main(void) { printf("malloc_aligned5: usable size: %zi\n", usable); mi_free(p); }; + /* CHECK_BODY("malloc-aligned6") { bool ok = true; for (size_t align = 1; align <= MI_BLOCK_ALIGNMENT_MAX && ok; align *= 2) { @@ -174,6 +184,7 @@ int main(void) { } result = ok; }; + */ CHECK_BODY("malloc-aligned7") { void* p = mi_malloc_aligned(1024,MI_BLOCK_ALIGNMENT_MAX); mi_free(p); @@ -189,7 +200,7 @@ int main(void) { } result = ok; }; - CHECK_BODY("malloc-aligned9") { + CHECK_BODY("malloc-aligned9") { // test large alignments bool ok = true; void* p[8]; size_t sizes[8] = { 8, 512, 1024 * 1024, MI_BLOCK_ALIGNMENT_MAX, MI_BLOCK_ALIGNMENT_MAX + 1, 2 * MI_BLOCK_ALIGNMENT_MAX, 8 * MI_BLOCK_ALIGNMENT_MAX, 0 }; From 635cf7af6acae8d03767e5c158b79b94690813fa Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 20 Aug 2024 09:55:57 -0700 Subject: [PATCH 065/305] fix multi-threaded free to unprotect guarded blocks --- include/mimalloc/types.h | 2 +- src/alloc.c | 26 +++++++++++++++++++------- src/free.c | 33 ++++++++++++++++++++++----------- src/segment.c | 1 + test/test-api-fill.c | 2 +- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index ffe095a5..bf75f8c7 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -74,7 +74,7 @@ terms of the MIT license. A copy of the license can be found in the file // Use guard pages behind objects of a certain size #define MI_DEBUG_GUARDED 1 -#if defined(MI_DEBUG_GUARDED) || defined(MI_DEBUG_GUARDEDX) +#if defined(MI_DEBUG_GUARDED) #define MI_PADDING 0 #endif diff --git a/src/alloc.c b/src/alloc.c index ec008318..8f47e541 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -55,8 +55,10 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_ // zero the block? note: we need to zero the full block size (issue #63) if mi_unlikely(zero) { mi_assert_internal(page->block_size != 0); // do not call with zero'ing for huge blocks (see _mi_malloc_generic) - mi_assert_internal(page->block_size >= MI_PADDING_SIZE); mi_assert_internal(!mi_page_is_huge(page)); + #if MI_PADDING_SIZE > 0 + mi_assert_internal(page->block_size >= MI_PADDING_SIZE); + #endif if (page->free_is_zero) { block->next = 0; mi_track_mem_defined(block, page->block_size - MI_PADDING_SIZE); @@ -131,7 +133,7 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, if (size == 0) { size = sizeof(void*); } #endif #if MI_DEBUG_GUARDED - if (size >= _mi_option_get_fast(mi_option_debug_guarded_min) && size <= _mi_option_get_fast(mi_option_debug_guarded_max)) { + if (size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max) && size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min)) { return mi_heap_malloc_guarded(heap, size, zero, 0); } #endif @@ -171,8 +173,9 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z } #if MI_DEBUG_GUARDED else if ( huge_alignment == 0 && // guarded pages do not work with huge aligments at the moment - ((size >= _mi_option_get_fast(mi_option_debug_guarded_min) && size <= _mi_option_get_fast(mi_option_debug_guarded_max)) - || ((size & (_mi_os_page_size()-1)) == 0)) ) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. + _mi_option_get_fast(mi_option_debug_guarded_max) > 0 && // guarded must be enabled + ((size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min) && size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max)) + || ((mi_good_size(size) & (_mi_os_page_size()-1)) == 0)) ) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. { return mi_heap_malloc_guarded(heap, size, zero, 0); } @@ -611,15 +614,24 @@ static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t siz if (base==NULL) return NULL; mi_page_t* page = _mi_ptr_page(base); mi_segment_t* segment = _mi_page_segment(page); - + const size_t fullsize = mi_page_block_size(page); // must use `block_size` to match `mi_free_local` void* const gpage = (uint8_t*)base + (fullsize - psize); mi_assert_internal(_mi_is_aligned(gpage, psize)); - void* const p = (uint8_t*)base + (fullsize - psize - bsize); + + // place block in front of the guard page + size_t offset = fullsize - psize - bsize; + if (offset > MI_BLOCK_ALIGNMENT_MAX) { + // give up to place it right in front of the guard page if the offset is too large for unalignment + offset = MI_BLOCK_ALIGNMENT_MAX; + } + void* const p = (uint8_t*)base + offset; mi_assert_internal(p >= base); // set page flags - if (p > base) { mi_page_set_has_aligned(page, true); } + if (offset > 0) { + mi_page_set_has_aligned(page, true); + } // set guard page if (segment->allow_decommit) { diff --git a/src/free.c b/src/free.c index 07c06899..2137f7c9 100644 --- a/src/free.c +++ b/src/free.c @@ -26,6 +26,25 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block); // forward declaration of multi-threaded free (`_mt`) (or free in huge block if compiled with MI_HUGE_PAGE_ABANDON) static mi_decl_noinline void mi_free_block_mt(mi_page_t* page, mi_segment_t* segment, mi_block_t* block); +#if !MI_DEBUG_GUARDED +static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { + MI_UNUSED(page); + MI_UNUSED(block); +} +#else +static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { + if (mi_page_has_guarded(page)) { + const size_t bsize = mi_page_block_size(page); + const size_t psize = _mi_os_page_size(); + mi_assert_internal(bsize > psize); + mi_assert_internal(_mi_page_segment(page)->allow_decommit); + void* gpage = (uint8_t*)block + (bsize - psize); + mi_assert_internal(_mi_is_aligned(gpage, psize)); + _mi_os_unprotect(gpage, psize); + } +} +#endif + // regular free of a (thread local) block pointer // fast path written carefully to prevent spilling on the stack static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool track_stats, bool check_full) @@ -33,17 +52,7 @@ static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool // checks if mi_unlikely(mi_check_is_double_free(page, block)) return; mi_check_padding(page, block); - if (track_stats) { mi_stat_free(page, block); } - #if MI_DEBUG_GUARDED - if (mi_page_has_guarded(page)) { - const size_t bsize = mi_page_block_size(page); - const size_t psize = _mi_os_page_size(); - mi_assert_internal(bsize > psize); - mi_assert_internal(_mi_page_segment(page)->allow_decommit); - void* gpage = (uint8_t*)block + (bsize - psize); - _mi_os_unprotect(gpage, psize); - } - #endif + if (track_stats) { mi_stat_free(page, block); } #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN && !MI_DEBUG_GUARDED memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); #endif @@ -83,12 +92,14 @@ mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p) { static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept { MI_UNUSED(segment); mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(page, p) : (mi_block_t*)p); + mi_block_unguard(page,block); mi_free_block_local(page, block, true /* track stats */, true /* check for a full page */); } // free a pointer owned by another thread (page parameter comes first for better codegen) static void mi_decl_noinline mi_free_generic_mt(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept { mi_block_t* const block = _mi_page_ptr_unalign(page, p); // don't check `has_aligned` flag to avoid a race (issue #865) + mi_block_unguard(page, block); mi_free_block_mt(page, segment, block); } diff --git a/src/segment.c b/src/segment.c index ead8bb98..b03c7e85 100644 --- a/src/segment.c +++ b/src/segment.c @@ -745,6 +745,7 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, mi_seg void _mi_segment_page_free(mi_page_t* page, bool force, mi_segments_tld_t* tld) { mi_assert(page != NULL); + mi_assert_internal(!mi_page_has_guarded(page)); mi_segment_t* segment = _mi_page_segment(page); mi_assert_expensive(mi_segment_is_valid(segment,tld)); mi_pages_try_purge(false /*force?*/, tld); diff --git a/test/test-api-fill.c b/test/test-api-fill.c index 3fca3b9d..3baee83d 100644 --- a/test/test-api-fill.c +++ b/test/test-api-fill.c @@ -271,7 +271,7 @@ int main(void) { mi_free(p); }; - #if !(MI_TRACK_VALGRIND || MI_TRACK_ASAN) + #if !(MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_DEBUG_GUARDED) CHECK_BODY("fill-freed-small") { size_t malloc_size = MI_SMALL_SIZE_MAX / 2; uint8_t* p = (uint8_t*)mi_malloc(malloc_size); From 8899a11c70e94a7cb92aa57c3c8919d90a873f61 Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 20 Aug 2024 11:09:17 -0700 Subject: [PATCH 066/305] clean up guarded pages code --- include/mimalloc.h | 4 ++-- include/mimalloc/types.h | 5 +++-- src/alloc.c | 26 ++++++++++++------------ src/free.c | 44 +++++++++++++++++++++++----------------- src/options.c | 5 +++-- 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 867c5c97..e5133c96 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -366,8 +366,8 @@ typedef enum mi_option_e { mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's) mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) - mi_option_debug_guarded_min, // only used when build with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) - mi_option_debug_guarded_max, // only used when build with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) + mi_option_debug_guarded_min, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) + mi_option_debug_guarded_max, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index bf75f8c7..d1e6e5d8 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -72,8 +72,9 @@ terms of the MIT license. A copy of the license can be found in the file #endif #endif -// Use guard pages behind objects of a certain size -#define MI_DEBUG_GUARDED 1 +// Use guard pages behind objects of a certain size (set by the MIMALLOC_DEBUG_GUARDED_MIN/MAX options) +// Padding should be disabled when using guard pages +// #define MI_DEBUG_GUARDED 1 #if defined(MI_DEBUG_GUARDED) #define MI_PADDING 0 #endif diff --git a/src/alloc.c b/src/alloc.c index 8f47e541..6fc85952 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -607,26 +607,26 @@ static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t siz mi_assert(MI_PADDING_SIZE==0); #endif // allocate multiple of page size ending in a guard page - const size_t bsize = _mi_align_up(size, MI_MAX_ALIGN_SIZE); // ensure minimal alignment requirement - const size_t psize = _mi_os_page_size(); - const size_t gsize = _mi_align_up(bsize + psize, psize); - void* const base = _mi_malloc_generic(heap, gsize, zero, huge_alignment); - if (base==NULL) return NULL; - mi_page_t* page = _mi_ptr_page(base); + const size_t obj_size = _mi_align_up(size, MI_MAX_ALIGN_SIZE); // ensure minimal alignment requirement + const size_t os_page_size = _mi_os_page_size(); + const size_t req_size = _mi_align_up(obj_size + os_page_size, os_page_size); + void* const block = _mi_malloc_generic(heap, req_size, zero, huge_alignment); + if (block==NULL) return NULL; + mi_page_t* page = _mi_ptr_page(block); mi_segment_t* segment = _mi_page_segment(page); - const size_t fullsize = mi_page_block_size(page); // must use `block_size` to match `mi_free_local` - void* const gpage = (uint8_t*)base + (fullsize - psize); - mi_assert_internal(_mi_is_aligned(gpage, psize)); + const size_t block_size = mi_page_block_size(page); // must use `block_size` to match `mi_free_local` + void* const guard_page = (uint8_t*)block + (block_size - os_page_size); + mi_assert_internal(_mi_is_aligned(guard_page, os_page_size)); // place block in front of the guard page - size_t offset = fullsize - psize - bsize; + size_t offset = block_size - os_page_size - obj_size; if (offset > MI_BLOCK_ALIGNMENT_MAX) { // give up to place it right in front of the guard page if the offset is too large for unalignment offset = MI_BLOCK_ALIGNMENT_MAX; } - void* const p = (uint8_t*)base + offset; - mi_assert_internal(p >= base); + void* const p = (uint8_t*)block + offset; + mi_assert_internal(p>=block); // set page flags if (offset > 0) { @@ -636,7 +636,7 @@ static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t siz // set guard page if (segment->allow_decommit) { mi_page_set_has_guarded(page, true); - _mi_os_protect(gpage, psize); + _mi_os_protect(guard_page, os_page_size); } else { _mi_warning_message("unable to set a guard page behind an object due to pinned memory (large OS pages?) (object %p of size %zu)\n", p, size); diff --git a/src/free.c b/src/free.c index 2137f7c9..f2e5f8e3 100644 --- a/src/free.c +++ b/src/free.c @@ -26,25 +26,6 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block); // forward declaration of multi-threaded free (`_mt`) (or free in huge block if compiled with MI_HUGE_PAGE_ABANDON) static mi_decl_noinline void mi_free_block_mt(mi_page_t* page, mi_segment_t* segment, mi_block_t* block); -#if !MI_DEBUG_GUARDED -static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { - MI_UNUSED(page); - MI_UNUSED(block); -} -#else -static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { - if (mi_page_has_guarded(page)) { - const size_t bsize = mi_page_block_size(page); - const size_t psize = _mi_os_page_size(); - mi_assert_internal(bsize > psize); - mi_assert_internal(_mi_page_segment(page)->allow_decommit); - void* gpage = (uint8_t*)block + (bsize - psize); - mi_assert_internal(_mi_is_aligned(gpage, psize)); - _mi_os_unprotect(gpage, psize); - } -} -#endif - // regular free of a (thread local) block pointer // fast path written carefully to prevent spilling on the stack static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool track_stats, bool check_full) @@ -88,6 +69,9 @@ mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p) { return (mi_block_t*)((uintptr_t)p - adjust); } +// forward declaration for a MI_DEBUG_GUARDED build +static void mi_block_unguard(mi_page_t* page, mi_block_t* block); + // free a local pointer (page parameter comes first for better codegen) static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept { MI_UNUSED(segment); @@ -546,3 +530,25 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { MI_UNUSED(page); MI_UNUSED(block); } #endif + + +// Remove guard page when building with MI_DEBUG_GUARDED +#if !MI_DEBUG_GUARDED +static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { + MI_UNUSED(page); + MI_UNUSED(block); + // do nothing +} +#else +static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { + if (mi_page_has_guarded(page)) { + const size_t bsize = mi_page_block_size(page); + const size_t psize = _mi_os_page_size(); + mi_assert_internal(bsize > psize); + mi_assert_internal(_mi_page_segment(page)->allow_decommit); + void* gpage = (uint8_t*)block + (bsize - psize); + mi_assert_internal(_mi_is_aligned(gpage, psize)); + _mi_os_unprotect(gpage, psize); + } +} +#endif diff --git a/src/options.c b/src/options.c index b8859235..27122c78 100644 --- a/src/options.c +++ b/src/options.c @@ -99,8 +99,8 @@ static mi_option_desc_t options[_mi_option_last] = #else { 0, UNINIT, MI_OPTION(visit_abandoned) }, #endif - { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only used when built with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) - { 0, UNINIT, MI_OPTION(debug_guarded_max) }, // only used when built with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) + { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects + { 0, UNINIT, MI_OPTION(debug_guarded_max) }, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects }; static void mi_option_init(mi_option_desc_t* desc); @@ -130,6 +130,7 @@ void _mi_options_init(void) { _mi_warning_message("option 'allow_large_os_pages' is disabled to allow for guarded objects\n"); } } + _mi_verbose_message("guarded build: %s\n", mi_option_get(mi_option_debug_guarded_max) > 0 ? "enabled" : "disabled"); #endif } From f130808b5ce7c947b58343f780a67a07ccbcca32 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Tue, 20 Aug 2024 12:58:49 -0700 Subject: [PATCH 067/305] fix warnings --- src/alloc.c | 10 +++++----- src/segment.c | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 6fc85952..7c1284fb 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -56,7 +56,7 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_ if mi_unlikely(zero) { mi_assert_internal(page->block_size != 0); // do not call with zero'ing for huge blocks (see _mi_malloc_generic) mi_assert_internal(!mi_page_is_huge(page)); - #if MI_PADDING_SIZE > 0 + #if MI_PADDING mi_assert_internal(page->block_size >= MI_PADDING_SIZE); #endif if (page->free_is_zero) { @@ -173,7 +173,7 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z } #if MI_DEBUG_GUARDED else if ( huge_alignment == 0 && // guarded pages do not work with huge aligments at the moment - _mi_option_get_fast(mi_option_debug_guarded_max) > 0 && // guarded must be enabled + _mi_option_get_fast(mi_option_debug_guarded_max) > 0 && // guarded must be enabled ((size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min) && size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max)) || ((mi_good_size(size) & (_mi_os_page_size()-1)) == 0)) ) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. { @@ -620,7 +620,7 @@ static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t siz mi_assert_internal(_mi_is_aligned(guard_page, os_page_size)); // place block in front of the guard page - size_t offset = block_size - os_page_size - obj_size; + size_t offset = block_size - os_page_size - obj_size; if (offset > MI_BLOCK_ALIGNMENT_MAX) { // give up to place it right in front of the guard page if the offset is too large for unalignment offset = MI_BLOCK_ALIGNMENT_MAX; @@ -629,8 +629,8 @@ static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t siz mi_assert_internal(p>=block); // set page flags - if (offset > 0) { - mi_page_set_has_aligned(page, true); + if (offset > 0) { + mi_page_set_has_aligned(page, true); } // set guard page diff --git a/src/segment.c b/src/segment.c index b03c7e85..837a65e9 100644 --- a/src/segment.c +++ b/src/segment.c @@ -452,14 +452,14 @@ static size_t mi_segment_calculate_sizes(size_t capacity, size_t required, size_ size_t guardsize = 0; size_t isize = 0; - + if (MI_SECURE == 0) { // normally no guard pages #if MI_DEBUG_GUARDED isize = _mi_align_up(minsize, _mi_os_page_size()); #else isize = _mi_align_up(minsize, 16 * MI_MAX_ALIGN_SIZE); - #endif + #endif } else { // in secure mode, we set up a protected page in between the segment info @@ -745,7 +745,6 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, mi_seg void _mi_segment_page_free(mi_page_t* page, bool force, mi_segments_tld_t* tld) { mi_assert(page != NULL); - mi_assert_internal(!mi_page_has_guarded(page)); mi_segment_t* segment = _mi_page_segment(page); mi_assert_expensive(mi_segment_is_valid(segment,tld)); mi_pages_try_purge(false /*force?*/, tld); From f163164d364557e341b8e32684502fcb0ee60b58 Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 20 Aug 2024 13:12:51 -0700 Subject: [PATCH 068/305] ensure start-offset in a segment respects minimal alignment --- src/segment.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/segment.c b/src/segment.c index f8e98655..1906e8ac 100644 --- a/src/segment.c +++ b/src/segment.c @@ -332,6 +332,7 @@ static uint8_t* _mi_segment_page_start_from_slice(const mi_segment_t* segment, c if (block_size <= 64) { start_offset += 3*block_size; } else if (block_size <= 512) { start_offset += block_size; } } + start_offset = _mi_align_up(start_offset, MI_MAX_ALIGN_SIZE); mi_assert_internal(_mi_is_aligned(pstart + start_offset, MI_MAX_ALIGN_SIZE)); mi_assert_internal(block_size == 0 || block_size > MI_MAX_ALIGN_GUARANTEE || _mi_is_aligned(pstart + start_offset,block_size)); if (page_size != NULL) { *page_size = psize - start_offset; } From b5c6495f69fa0d642aa40211df61274b801c8915 Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 20 Aug 2024 15:58:36 -0700 Subject: [PATCH 069/305] don't consider memory as large OS pages if only madvise'd --- ide/vs2022/mimalloc-override.vcxproj | 8 +++--- src/prim/unix/prim.c | 9 ++++--- test/main-override-static.c | 39 +++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index e895fa3c..4383d886 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -98,7 +98,7 @@ MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); MultiThreadedDebugDLL false - Default + CompileAsCpp $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) @@ -126,7 +126,7 @@ MI_DEBUG=4;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); MultiThreadedDebugDLL false - Default + CompileAsCpp $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) @@ -157,7 +157,7 @@ $(IntDir) false MultiThreadedDLL - Default + CompileAsCpp false @@ -189,7 +189,7 @@ $(IntDir) false MultiThreadedDLL - Default + CompileAsCpp false diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 63a36f25..0ea8189c 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -181,10 +181,11 @@ int _mi_prim_free(void* addr, size_t size ) { static int unix_madvise(void* addr, size_t size, int advice) { #if defined(__sun) - return madvise((caddr_t)addr, size, advice); // Solaris needs cast (issue #520) + int res = madvise((caddr_t)addr, size, advice); // Solaris needs cast (issue #520) #else - return madvise(addr, size, advice); + int res = madvise(addr, size, advice); #endif + return (res==0 ? 0 : errno); } static void* unix_mmap_prim(void* addr, size_t size, size_t try_alignment, int protect_flags, int flags, int fd) { @@ -331,7 +332,7 @@ static void* unix_mmap(void* addr, size_t size, size_t try_alignment, int protec // when large OS pages are enabled for mimalloc, we call `madvise` anyways. if (allow_large && _mi_os_use_large_page(size, try_alignment)) { if (unix_madvise(p, size, MADV_HUGEPAGE) == 0) { - *is_large = true; // possibly + // *is_large = true; // possibly }; } #elif defined(__sun) @@ -340,7 +341,7 @@ static void* unix_mmap(void* addr, size_t size, size_t try_alignment, int protec cmd.mha_pagesize = _mi_os_large_page_size(); cmd.mha_cmd = MHA_MAPSIZE_VA; if (memcntl((caddr_t)p, size, MC_HAT_ADVISE, (caddr_t)&cmd, 0, 0) == 0) { - *is_large = true; + // *is_large = true; // possibly } } #endif diff --git a/test/main-override-static.c b/test/main-override-static.c index bf1cc416..535a9aaf 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -18,11 +18,13 @@ static void test_reserved(void); static void negative_stat(void); static void alloc_huge(void); static void test_heap_walk(void); +// static void test_large_pages(void); int main() { mi_version(); mi_stats_reset(); + // test_large_pages(); // detect double frees and heap corruption // double_free1(); // double_free2(); @@ -61,7 +63,7 @@ int main() { //mi_stats_print(NULL); // test_process_info(); - + return 0; } @@ -216,6 +218,41 @@ static void test_heap_walk(void) { mi_heap_visit_blocks(heap, true, &test_visit, NULL); } +// Experiment with huge OS pages +#if 0 + +#include +#include +#include +#include + +static void test_large_pages(void) { + mi_memid_t memid; + + #if 0 + size_t pages_reserved; + size_t page_size; + uint8_t* p = (uint8_t*)_mi_os_alloc_huge_os_pages(1, -1, 30000, &pages_reserved, &page_size, &memid); + const size_t req_size = pages_reserved * page_size; + #else + const size_t req_size = 64*MI_MiB; + uint8_t* p = (uint8_t*)_mi_os_alloc(req_size,&memid,NULL); + #endif + + p[0] = 1; + + //_mi_os_protect(p, _mi_os_page_size()); + //_mi_os_unprotect(p, _mi_os_page_size()); + //_mi_os_decommit(p, _mi_os_page_size(), NULL); + if (madvise(p, req_size, MADV_HUGEPAGE) == 0) { + printf("advised huge pages\n"); + _mi_os_decommit(p, _mi_os_page_size(), NULL); + }; + _mi_os_free(p, req_size, memid, NULL); +} + +#endif + // ---------------------------- // bin size experiments // ------------------------------ From b9b529de2817ccaddbab814d5636f2569464cb1b Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Wed, 21 Aug 2024 10:45:19 -0700 Subject: [PATCH 070/305] shuffle for 128 bit --- include/mimalloc/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 6e87d5ae..9d1f6e51 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -731,7 +731,7 @@ static inline mi_memid_t _mi_memid_create_os(bool committed, bool is_zero, bool 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) +#if (MI_INTPTR_SIZE>=8) // by Sebastiano Vigna, see: x ^= x >> 30; x *= 0xbf58476d1ce4e5b9UL; From 631ff581afb36d132c9157dc176d5dd94eff9e81 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Wed, 21 Aug 2024 10:47:38 -0700 Subject: [PATCH 071/305] set compile as C++ in VS IDE --- ide/vs2022/mimalloc-override.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index e895fa3c..4383d886 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -98,7 +98,7 @@ MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); MultiThreadedDebugDLL false - Default + CompileAsCpp $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) @@ -126,7 +126,7 @@ MI_DEBUG=4;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); MultiThreadedDebugDLL false - Default + CompileAsCpp $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) @@ -157,7 +157,7 @@ $(IntDir) false MultiThreadedDLL - Default + CompileAsCpp false @@ -189,7 +189,7 @@ $(IntDir) false MultiThreadedDLL - Default + CompileAsCpp false From 96f7cc4ef2c1f03a1775c9a3fa3a08a1e572b7b2 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Wed, 21 Aug 2024 11:21:25 -0700 Subject: [PATCH 072/305] clean up guarded allocation --- src/alloc.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 7c1284fb..34adc861 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -118,8 +118,9 @@ extern void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t siz } #if MI_DEBUG_GUARDED -// forward declaration -static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept; +static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; +static inline bool mi_heap_malloc_use_guarded(size_t size, bool huge_alignment); +static inline bool mi_heap_malloc_small_use_guarded(size_t size); #endif static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { @@ -133,9 +134,7 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, if (size == 0) { size = sizeof(void*); } #endif #if MI_DEBUG_GUARDED - if (size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max) && size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min)) { - return mi_heap_malloc_guarded(heap, size, zero, 0); - } + if (mi_heap_malloc_small_use_guarded(size)) { return mi_heap_malloc_guarded(heap, size, zero); } #endif mi_page_t* page = _mi_heap_get_free_small_page(heap, size + MI_PADDING_SIZE); @@ -172,13 +171,7 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z return mi_heap_malloc_small_zero(heap, size, zero); } #if MI_DEBUG_GUARDED - else if ( huge_alignment == 0 && // guarded pages do not work with huge aligments at the moment - _mi_option_get_fast(mi_option_debug_guarded_max) > 0 && // guarded must be enabled - ((size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min) && size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max)) - || ((mi_good_size(size) & (_mi_os_page_size()-1)) == 0)) ) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. - { - return mi_heap_malloc_guarded(heap, size, zero, 0); - } + else if (mi_use_guarded(size,huge_alignment)) { return mi_heap_malloc_guarded(heap, size, zero); } #endif else { mi_assert(heap!=NULL); @@ -601,7 +594,20 @@ mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) { } #if MI_DEBUG_GUARDED -static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept +static inline bool mi_heap_malloc_small_use_guarded(size_t size) { + return (size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max) + && size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min)); +} + +static inline bool mi_heap_malloc_use_guarded(size_t size, bool huge_alignment) { + return (huge_alignment == 0 // guarded pages do not work with huge aligments at the moment + && _mi_option_get_fast(mi_option_debug_guarded_max) > 0 // guarded must be enabled + && (mi_heap_malloc_small_use_guarded(size) + || ((mi_good_size(size) & (_mi_os_page_size() - 1)) == 0)) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. + ); +} + +static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { #if defined(MI_PADDING_SIZE) mi_assert(MI_PADDING_SIZE==0); @@ -610,7 +616,7 @@ static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t siz const size_t obj_size = _mi_align_up(size, MI_MAX_ALIGN_SIZE); // ensure minimal alignment requirement const size_t os_page_size = _mi_os_page_size(); const size_t req_size = _mi_align_up(obj_size + os_page_size, os_page_size); - void* const block = _mi_malloc_generic(heap, req_size, zero, huge_alignment); + void* const block = _mi_malloc_generic(heap, req_size, zero, 0 /* huge_alignment */); if (block==NULL) return NULL; mi_page_t* page = _mi_ptr_page(block); mi_segment_t* segment = _mi_page_segment(page); From cc4dc1bb53017da9862e1b4d3e74853fc9b6ec27 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Wed, 21 Aug 2024 11:26:12 -0700 Subject: [PATCH 073/305] add comments --- src/alloc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 34adc861..c91de62d 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -31,18 +31,22 @@ terms of the MIT license. A copy of the license can be found in the file extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept { mi_assert_internal(page->block_size == 0 /* empty heap */ || mi_page_block_size(page) >= size); + + // check the free list mi_block_t* const block = page->free; if mi_unlikely(block == NULL) { return _mi_malloc_generic(heap, size, zero, 0); } mi_assert_internal(block != NULL && _mi_ptr_page(block) == page); + // pop from the free list page->free = mi_block_next(page, block); page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); mi_assert_internal(page->block_size < MI_MAX_ALIGN_SIZE || _mi_is_aligned(block, MI_MAX_ALIGN_SIZE)); + #if MI_DEBUG>3 - if (page->free_is_zero && size > sizeof(*block)) { + if (page->free_is_zero && size > sizeof(*block)) { mi_assert_expensive(mi_mem_is_zero(block+1,size - sizeof(*block))); } #endif @@ -125,11 +129,11 @@ static inline bool mi_heap_malloc_small_use_guarded(size_t size); static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { mi_assert(heap != NULL); + mi_assert(size <= MI_SMALL_SIZE_MAX); #if MI_DEBUG const uintptr_t tid = _mi_thread_id(); mi_assert(heap->thread_id == 0 || heap->thread_id == tid); // heaps are thread local #endif - mi_assert(size <= MI_SMALL_SIZE_MAX); #if (MI_PADDING || MI_DEBUG_GUARDED) if (size == 0) { size = sizeof(void*); } #endif @@ -137,6 +141,7 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, if (mi_heap_malloc_small_use_guarded(size)) { return mi_heap_malloc_guarded(heap, size, zero); } #endif + // get page in constant time, and allocate from it mi_page_t* page = _mi_heap_get_free_small_page(heap, size + MI_PADDING_SIZE); void* const p = _mi_page_malloc_zero(heap, page, size + MI_PADDING_SIZE, zero); mi_track_malloc(p,size,zero); @@ -166,6 +171,7 @@ mi_decl_nodiscard extern inline mi_decl_restrict void* mi_malloc_small(size_t si // The main allocation function extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept { + // fast path for small objects if mi_likely(size <= MI_SMALL_SIZE_MAX) { mi_assert_internal(huge_alignment == 0); return mi_heap_malloc_small_zero(heap, size, zero); @@ -174,10 +180,12 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z else if (mi_use_guarded(size,huge_alignment)) { return mi_heap_malloc_guarded(heap, size, zero); } #endif else { + // regular allocation mi_assert(heap!=NULL); mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local void* const p = _mi_malloc_generic(heap, size + MI_PADDING_SIZE, zero, huge_alignment); // note: size can overflow but it is detected in malloc_generic mi_track_malloc(p,size,zero); + #if MI_STAT>1 if (p != NULL) { if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); } From 58e743b83f0949ecfa4732eaec0288672c55123f Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Wed, 21 Aug 2024 11:30:00 -0700 Subject: [PATCH 074/305] fix use_guarded signature --- src/alloc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index c91de62d..ca60c11a 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -123,7 +123,7 @@ extern void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t siz #if MI_DEBUG_GUARDED static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; -static inline bool mi_heap_malloc_use_guarded(size_t size, bool huge_alignment); +static inline bool mi_heap_malloc_use_guarded(size_t size, bool has_huge_alignment); static inline bool mi_heap_malloc_small_use_guarded(size_t size); #endif @@ -177,7 +177,7 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z return mi_heap_malloc_small_zero(heap, size, zero); } #if MI_DEBUG_GUARDED - else if (mi_use_guarded(size,huge_alignment)) { return mi_heap_malloc_guarded(heap, size, zero); } + else if (mi_heap_malloc_use_guarded(size,huge_alignment>0)) { return mi_heap_malloc_guarded(heap, size, zero); } #endif else { // regular allocation @@ -607,8 +607,8 @@ static inline bool mi_heap_malloc_small_use_guarded(size_t size) { && size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min)); } -static inline bool mi_heap_malloc_use_guarded(size_t size, bool huge_alignment) { - return (huge_alignment == 0 // guarded pages do not work with huge aligments at the moment +static inline bool mi_heap_malloc_use_guarded(size_t size, bool has_huge_alignment) { + return (!has_huge_alignment // guarded pages do not work with huge aligments at the moment && _mi_option_get_fast(mi_option_debug_guarded_max) > 0 // guarded must be enabled && (mi_heap_malloc_small_use_guarded(size) || ((mi_good_size(size) & (_mi_os_page_size() - 1)) == 0)) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. From 51025f1ac218811fb443dedea978af1551c52131 Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 21 Aug 2024 15:29:32 -0700 Subject: [PATCH 075/305] set lower parameters for guarded test --- test/test-stress.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-stress.c b/test/test-stress.c index f9b3c9d6..25942299 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -33,6 +33,10 @@ static int ITER = 200; static int THREADS = 8; static int SCALE = 25; static int ITER = 20; +#elif defined(MI_DEBUG_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits +static int THREADS = 8; +static int SCALE = 10; +static int ITER = 10; #else static int THREADS = 32; // more repeatable if THREADS <= #processors static int SCALE = 25; // scaling factor From bb3976760fa97b92f39580da7566a9ccd34378f5 Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 21 Aug 2024 15:34:22 -0700 Subject: [PATCH 076/305] add guarded build to test pipeline --- azure-pipelines.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e3689407..235b2bf5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -113,6 +113,11 @@ jobs: CXX: clang++ BuildType: debug-tsan-clang-cxx cmakeExtraArgs: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMI_USE_CXX=ON -DMI_DEBUG_TSAN=ON + Debug Guarded Clang: + CC: clang + CXX: clang + BuildType: debug-guarded-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMI_DEBUG_FULL=ON -DMI_DEBUG_GUARDED=ON steps: - task: CMake@1 @@ -124,6 +129,8 @@ jobs: - script: ctest --verbose --timeout 180 workingDirectory: $(BuildType) displayName: CTest + env: + MIMALLOC_DEBUG_GUARDED_MAX: 1024 # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-ubuntu-$(BuildType) From d8e0cb1a37e2b65551d4bf10558774c1ac5ef17c Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 21 Aug 2024 17:01:05 -0700 Subject: [PATCH 077/305] increase test timeout for azure pipeline --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 235b2bf5..256f7088 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,7 +43,7 @@ jobs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' msbuildArguments: -m - - script: ctest --verbose --timeout 120 -C $(MSBuildConfiguration) + - script: ctest --verbose --timeout 240 -C $(MSBuildConfiguration) workingDirectory: $(BuildType) displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress @@ -126,7 +126,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(nproc) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 180 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest env: @@ -157,7 +157,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 120 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest # - upload: $(Build.SourcesDirectory)/$(BuildType) @@ -193,5 +193,5 @@ jobs: # configuration: '$(MSBuildConfiguration)' # - script: | # cd $(BuildType) -# ctest --verbose --timeout 120 +# ctest --verbose --timeout 240 # displayName: CTest From ad02086d3b45de030680b895762fa8a018edd07e Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 21 Aug 2024 17:07:01 -0700 Subject: [PATCH 078/305] remove default MI_DEBUG_GUARDED --- include/mimalloc/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 4540998f..69f737b3 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -75,7 +75,7 @@ terms of the MIT license. A copy of the license can be found in the file // Use guard pages behind objects of a certain size (set by the MIMALLOC_DEBUG_GUARDED_MIN/MAX options) // Padding should be disabled when using guard pages -#define MI_DEBUG_GUARDED 1 +// #define MI_DEBUG_GUARDED 1 #if defined(MI_DEBUG_GUARDED) #define MI_PADDING 0 #endif From db3d8485d2f45a6f179d784f602f9eff4f60795c Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 21 Aug 2024 17:13:51 -0700 Subject: [PATCH 079/305] increase TSAN test to 400 iterations --- azure-pipelines.yml | 8 ++++---- test/test-stress.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 256f7088..4455dfeb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,7 +43,7 @@ jobs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' msbuildArguments: -m - - script: ctest --verbose --timeout 240 -C $(MSBuildConfiguration) + - script: ctest --verbose --timeout 180 -C $(MSBuildConfiguration) workingDirectory: $(BuildType) displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress @@ -126,7 +126,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(nproc) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 240 + - script: ctest --verbose --timeout 180 workingDirectory: $(BuildType) displayName: CTest env: @@ -157,7 +157,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 240 + - script: ctest --verbose --timeout 180 workingDirectory: $(BuildType) displayName: CTest # - upload: $(Build.SourcesDirectory)/$(BuildType) @@ -193,5 +193,5 @@ jobs: # configuration: '$(MSBuildConfiguration)' # - script: | # cd $(BuildType) -# ctest --verbose --timeout 240 +# ctest --verbose --timeout 180 # displayName: CTest diff --git a/test/test-stress.c b/test/test-stress.c index 25942299..30ad0e77 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -28,7 +28,7 @@ terms of the MIT license. #if defined(MI_TSAN) // with thread-sanitizer reduce the threads to test within the azure pipeline limits static int THREADS = 8; static int SCALE = 25; -static int ITER = 200; +static int ITER = 400; #elif defined(MI_UBSAN) // with undefined behavious sanitizer reduce parameters to stay within the azure pipeline limits static int THREADS = 8; static int SCALE = 25; From cd0c4ab67c06900dab2a01d96700b32bfc81e8b4 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Fri, 23 Aug 2024 00:31:14 +0900 Subject: [PATCH 080/305] docs: update readme.md speficic -> specific --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a0296b43..3ee2b280 100644 --- a/readme.md +++ b/readme.md @@ -113,7 +113,7 @@ memory usage * 2022-11-03, `v1.7.7`, `v2.0.7`: Initial support for [Valgrind](#valgrind) for leak testing and heap block overflow detection. Initial - support for attaching heaps to a speficic memory area (only in v2). Fix `realloc` behavior for zero size blocks, remove restriction to integral multiple of the alignment in `alloc_align`, improved aligned allocation performance, reduced contention with many threads on few processors (thank you @dposluns!), vs2022 support, support `pkg-config`, . + support for attaching heaps to a specific memory area (only in v2). Fix `realloc` behavior for zero size blocks, remove restriction to integral multiple of the alignment in `alloc_align`, improved aligned allocation performance, reduced contention with many threads on few processors (thank you @dposluns!), vs2022 support, support `pkg-config`, . * 2022-04-14, `v1.7.6`, `v2.0.6`: fix fallback path for aligned OS allocation on Windows, improve Windows aligned allocation even when compiling with older SDK's, fix dynamic overriding on macOS Monterey, fix MSVC C++ dynamic overriding, fix From 95f8fda113808e724dc63611da6b4e837426a32d Mon Sep 17 00:00:00 2001 From: Zhihua Lai Date: Fri, 30 Aug 2024 19:58:57 +0100 Subject: [PATCH 081/305] Fix typo --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a0296b43..79d07ca2 100644 --- a/readme.md +++ b/readme.md @@ -540,7 +540,7 @@ clang -g -o test-wrong -Iinclude test/test-wrong.c out/debug/libmimalloc-asan-de Since the address sanitizer redirects the standard allocation functions, on some platforms (macOSX for example) it is required to compile mimalloc with `-DMI_OVERRIDE=OFF`. -Adress sanitizer support is in its initial development -- please report any issues. +Address sanitizer support is in its initial development -- please report any issues. [asan]: https://github.com/google/sanitizers/wiki/AddressSanitizer From f38816d4ed3fb4af588c6addf8ec11ec47b79c55 Mon Sep 17 00:00:00 2001 From: Philip Brown <122590765+asdf-bro@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:42:46 -0500 Subject: [PATCH 082/305] Musl needs __libc* functions too --- src/alloc-override.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/alloc-override.c b/src/alloc-override.c index 12837cdd..82a98b80 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -289,8 +289,8 @@ mi_decl_weak int reallocarr(void* p, size_t count, size_t size) { return mi_r void __libc_free(void* p) MI_FORWARD0(mi_free, p) void* __libc_memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); } -#elif defined(__GLIBC__) && defined(__linux__) - // forward __libc interface (needed for glibc-based Linux distributions) +#elif defined(__linux__) + // forward __libc interface (needed for glibc-based and musl-based Linux distributions) void* __libc_malloc(size_t size) MI_FORWARD1(mi_malloc,size) void* __libc_calloc(size_t count, size_t size) MI_FORWARD2(mi_calloc,count,size) void* __libc_realloc(void* p, size_t size) MI_FORWARD2(mi_realloc,p,size) From ffa8bce58165a044c7e29c025dfa6c53e4d4b00c Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 9 Oct 2024 11:27:57 -0700 Subject: [PATCH 083/305] prefer pages that do not expand --- src/page.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/page.c b/src/page.c index 49f9ed52..29f08b49 100644 --- a/src/page.c +++ b/src/page.c @@ -715,6 +715,14 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi Find pages with free blocks -------------------------------------------------------------*/ +#define MI_MAX_CANDIDATE_SEARCH (16) + +static inline bool mi_page_is_expandable(const mi_page_t* page) { + mi_assert_internal(page != NULL); + mi_assert_internal(page->capacity <= page->reserved); + return (page->capacity < page->reserved); +} + // Find a page with free blocks of `page->block_size`. static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* pq, bool first_try) { @@ -722,6 +730,8 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p #if MI_STAT size_t count = 0; #endif + size_t candidate_count = 0; // we reset this on the first candidate to limit the search + mi_page_t* page_candidate = NULL; // a page with free space mi_page_t* page = pq->first; while (page != NULL) { @@ -729,10 +739,36 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p #if MI_STAT count++; #endif - + candidate_count++; +#if defined(MI_MAX_CANDIDATE_SEARCH) // 0. collect freed blocks by us and other threads - _mi_page_free_collect(page, false); + _mi_page_free_collect(page, false); // todo: should we free empty pages? + // is the local free list non-empty? + const bool immediate_available = mi_page_immediate_available(page); + + // 1. If the page is completely full, move it to the `mi_pages_full` + // queue so we don't visit long-lived pages too often. + if (!immediate_available && !mi_page_is_expandable(page)) { + mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page)); + mi_page_to_full(page, pq); + } + else { + // the page has free space, make it a candidate + // we prefer non-expandable pages with high usage as candidates (to reduce commit, and increase chances of free-ing up pages) + if (page_candidate == NULL) { + page_candidate = page; + candidate_count = 0; + } + else if (!mi_page_is_expandable(page) && page->used > page_candidate->used) { + page_candidate = page; + } + if (immediate_available || candidate_count > MI_MAX_CANDIDATE_SEARCH) { + mi_assert_internal(page_candidate!=NULL); + break; + } + } +#else // 1. if the page contains free blocks, we are done if (mi_page_immediate_available(page)) { break; // pick this one @@ -749,12 +785,22 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p // queue so we don't visit long-lived pages too often. mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page)); mi_page_to_full(page, pq); +#endif page = next; } // for each page mi_heap_stat_counter_increase(heap, searches, count); + // set the page to the best candidate + if (page_candidate != NULL) { + page = page_candidate; + } + if (page != NULL && !mi_page_immediate_available(page)) { + mi_assert_internal(mi_page_is_expandable(page)); + mi_page_extend_free(heap, page, heap->tld); + } + if (page == NULL) { _mi_heap_collect_retired(heap, false); // perhaps make a page available page = mi_page_fresh(heap, pq); From a05b5ab0a1ab94372c3db1b4580a16aee7821e0d Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 9 Oct 2024 14:21:50 -0700 Subject: [PATCH 084/305] search N pages for a best fit --- src/page.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/page.c b/src/page.c index 29f08b49..e3c2d643 100644 --- a/src/page.c +++ b/src/page.c @@ -715,14 +715,17 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi Find pages with free blocks -------------------------------------------------------------*/ +// search for a best next page to use for at most N pages (often cut short if immediate blocks are available) #define MI_MAX_CANDIDATE_SEARCH (16) -static inline bool mi_page_is_expandable(const mi_page_t* page) { +// is the page not yet used up to its reserved space? +static bool mi_page_is_expandable(const mi_page_t* page) { mi_assert_internal(page != NULL); mi_assert_internal(page->capacity <= page->reserved); return (page->capacity < page->reserved); } + // Find a page with free blocks of `page->block_size`. static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* pq, bool first_try) { @@ -740,14 +743,17 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p count++; #endif candidate_count++; -#if defined(MI_MAX_CANDIDATE_SEARCH) - // 0. collect freed blocks by us and other threads - _mi_page_free_collect(page, false); // todo: should we free empty pages? + // collect freed blocks by us and other threads + _mi_page_free_collect(page, false); + +#if defined(MI_MAX_CANDIDATE_SEARCH) + // search up to N pages for a best candidate + // is the local free list non-empty? const bool immediate_available = mi_page_immediate_available(page); - // 1. If the page is completely full, move it to the `mi_pages_full` + // if the page is completely full, move it to the `mi_pages_full` // queue so we don't visit long-lived pages too often. if (!immediate_available && !mi_page_is_expandable(page)) { mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page)); @@ -763,25 +769,20 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p else if (!mi_page_is_expandable(page) && page->used > page_candidate->used) { page_candidate = page; } + // if we find a non-expandable candidate, or searched for N pages, return with the best candidate if (immediate_available || candidate_count > MI_MAX_CANDIDATE_SEARCH) { mi_assert_internal(page_candidate!=NULL); break; } } #else - // 1. if the page contains free blocks, we are done - if (mi_page_immediate_available(page)) { + // first-fit algorithm + // If the page contains free blocks, we are done + if (mi_page_immediate_available(page) || mi_page_is_expandable(page)) { break; // pick this one } - // 2. Try to extend - if (page->capacity < page->reserved) { - mi_page_extend_free(heap, page, heap->tld); - mi_assert_internal(mi_page_immediate_available(page)); - break; - } - - // 3. If the page is completely full, move it to the `mi_pages_full` + // If the page is completely full, move it to the `mi_pages_full` // queue so we don't visit long-lived pages too often. mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page)); mi_page_to_full(page, pq); From 96877159c24d09a58fd7c7126261c177d15a5485 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 9 Oct 2024 14:35:33 -0700 Subject: [PATCH 085/305] insert full pages that became unfull, at the start of the page queue to increase potential reuse --- src/page-queue.c | 58 +++++++++++++++++++++++++++++++++++++++--------- src/page.c | 2 +- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/page-queue.c b/src/page-queue.c index 02a8008d..71e439d6 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -260,7 +260,7 @@ static void mi_page_queue_push(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_ } -static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { +static void mi_page_queue_enqueue_from_ex(mi_page_queue_t* to, mi_page_queue_t* from, bool enqueue_at_end, mi_page_t* page) { mi_assert_internal(page != NULL); mi_assert_expensive(mi_page_queue_contains(from, page)); mi_assert_expensive(!mi_page_queue_contains(to, page)); @@ -273,6 +273,8 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro (mi_page_is_huge(page) && mi_page_queue_is_full(to))); mi_heap_t* heap = mi_page_heap(page); + + // delete from `from` if (page->prev != NULL) page->prev->next = page->next; if (page->next != NULL) page->next->prev = page->prev; if (page == from->last) from->last = page->prev; @@ -283,22 +285,58 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro mi_heap_queue_first_update(heap, from); } - page->prev = to->last; - page->next = NULL; - if (to->last != NULL) { - mi_assert_internal(heap == mi_page_heap(to->last)); - to->last->next = page; - to->last = page; + // insert into `to` + if (enqueue_at_end) { + // enqueue at the end + page->prev = to->last; + page->next = NULL; + if (to->last != NULL) { + mi_assert_internal(heap == mi_page_heap(to->last)); + to->last->next = page; + to->last = page; + } + else { + to->first = page; + to->last = page; + mi_heap_queue_first_update(heap, to); + } } else { - to->first = page; - to->last = page; - mi_heap_queue_first_update(heap, to); + if (to->first != NULL) { + // enqueue at 2nd place + mi_assert_internal(heap == mi_page_heap(to->first)); + mi_page_t* next = to->first->next; + page->prev = to->first; + page->next = next; + to->first->next = page; + if (next != NULL) { + next->prev = page; + } + else { + to->last = page; + } + } + else { + // enqueue at the head (singleton list) + page->prev = NULL; + page->next = NULL; + to->first = page; + to->last = page; + mi_heap_queue_first_update(heap, to); + } } mi_page_set_in_full(page, mi_page_queue_is_full(to)); } +static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { + mi_page_queue_enqueue_from_ex(to, from, true, page); +} + +static void mi_page_queue_enqueue_from_at_start(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { + mi_page_queue_enqueue_from_ex(to, from, false, page); +} + // Only called from `mi_heap_absorb`. size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append) { mi_assert_internal(mi_heap_contains_queue(heap,pq)); diff --git a/src/page.c b/src/page.c index e3c2d643..fdc2c612 100644 --- a/src/page.c +++ b/src/page.c @@ -357,7 +357,7 @@ void _mi_page_unfull(mi_page_t* page) { mi_page_set_in_full(page, false); // to get the right queue mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); mi_page_set_in_full(page, true); - mi_page_queue_enqueue_from(pq, pqfull, page); + mi_page_queue_enqueue_from_at_start(pq, pqfull, page); // insert at the start to increase the chance of reusing full pages (?) } static void mi_page_to_full(mi_page_t* page, mi_page_queue_t* pq) { From cbc0e1980950949fbc0587a12eaad02f6c90317a Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 9 Oct 2024 14:41:12 -0700 Subject: [PATCH 086/305] revert back to unfull at the end of queues as it slows down some benchmarks (like alloc-test1) --- src/page.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/page.c b/src/page.c index fdc2c612..ab9152be 100644 --- a/src/page.c +++ b/src/page.c @@ -357,7 +357,9 @@ void _mi_page_unfull(mi_page_t* page) { mi_page_set_in_full(page, false); // to get the right queue mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); mi_page_set_in_full(page, true); - mi_page_queue_enqueue_from_at_start(pq, pqfull, page); // insert at the start to increase the chance of reusing full pages (?) + mi_page_queue_enqueue_from(pq, pqfull, page); + // we may instead insert at the front to increase reuse but it slows down some benchmarks like `alloc-test1` + // mi_page_queue_enqueue_from_at_start(pq, pqfull, page); } static void mi_page_to_full(mi_page_t* page, mi_page_queue_t* pq) { From 0316cb1d882034fad7f1b6521ac7e81441a87513 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 9 Oct 2024 15:05:35 -0700 Subject: [PATCH 087/305] reduce page search to 8 --- src/page-queue.c | 6 +++--- src/page.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/page-queue.c b/src/page-queue.c index 71e439d6..54496222 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -333,9 +333,9 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro mi_page_queue_enqueue_from_ex(to, from, true, page); } -static void mi_page_queue_enqueue_from_at_start(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { - mi_page_queue_enqueue_from_ex(to, from, false, page); -} +// static void mi_page_queue_enqueue_from_at_start(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { +// mi_page_queue_enqueue_from_ex(to, from, false, page); +// } // Only called from `mi_heap_absorb`. size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append) { diff --git a/src/page.c b/src/page.c index ab9152be..a0224e41 100644 --- a/src/page.c +++ b/src/page.c @@ -358,7 +358,7 @@ void _mi_page_unfull(mi_page_t* page) { mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); mi_page_set_in_full(page, true); mi_page_queue_enqueue_from(pq, pqfull, page); - // we may instead insert at the front to increase reuse but it slows down some benchmarks like `alloc-test1` + // we could insert at the front to increase reuse, but it slows down certain benchmarks (like alloc-test) // mi_page_queue_enqueue_from_at_start(pq, pqfull, page); } @@ -718,7 +718,7 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi -------------------------------------------------------------*/ // search for a best next page to use for at most N pages (often cut short if immediate blocks are available) -#define MI_MAX_CANDIDATE_SEARCH (16) +#define MI_MAX_CANDIDATE_SEARCH (8) // is the page not yet used up to its reserved space? static bool mi_page_is_expandable(const mi_page_t* page) { @@ -768,7 +768,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p page_candidate = page; candidate_count = 0; } - else if (!mi_page_is_expandable(page) && page->used > page_candidate->used) { + else if (!mi_page_is_expandable(page) && page->capacity < page_candidate->capacity) { page_candidate = page; } // if we find a non-expandable candidate, or searched for N pages, return with the best candidate From a7e7cbac89d4dbacee9e184b450ca5bfc31e0a19 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Wed, 9 Oct 2024 15:15:57 -0700 Subject: [PATCH 088/305] use enqueue_from_full, and keep inserting at the end --- src/page-queue.c | 9 +++++---- src/page.c | 4 +--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/page-queue.c b/src/page-queue.c index 54496222..3034e15d 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -330,12 +330,13 @@ static void mi_page_queue_enqueue_from_ex(mi_page_queue_t* to, mi_page_queue_t* } static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { - mi_page_queue_enqueue_from_ex(to, from, true, page); + mi_page_queue_enqueue_from_ex(to, from, true /* enqueue at the end */, page); } -// static void mi_page_queue_enqueue_from_at_start(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { -// mi_page_queue_enqueue_from_ex(to, from, false, page); -// } +static void mi_page_queue_enqueue_from_full(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { + // note: we could insert at the front to increase reuse, but it slows down certain benchmarks (like `alloc-test`) + mi_page_queue_enqueue_from_ex(to, from, true /* enqueue at the end of the `to` queue? */, page); +} // Only called from `mi_heap_absorb`. size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append) { diff --git a/src/page.c b/src/page.c index a0224e41..acc72253 100644 --- a/src/page.c +++ b/src/page.c @@ -357,9 +357,7 @@ void _mi_page_unfull(mi_page_t* page) { mi_page_set_in_full(page, false); // to get the right queue mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); mi_page_set_in_full(page, true); - mi_page_queue_enqueue_from(pq, pqfull, page); - // we could insert at the front to increase reuse, but it slows down certain benchmarks (like alloc-test) - // mi_page_queue_enqueue_from_at_start(pq, pqfull, page); + mi_page_queue_enqueue_from_full(pq, pqfull, page); } static void mi_page_to_full(mi_page_t* page, mi_page_queue_t* pq) { From 723869014ff71b12c585bf9b9b51ee4128d1b71f Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 9 Oct 2024 21:24:20 -0700 Subject: [PATCH 089/305] add ability to abandon segments after a threshold --- include/mimalloc.h | 1 + include/mimalloc/internal.h | 2 + include/mimalloc/types.h | 2 +- src/arena-abandon.c | 2 +- src/options.c | 1 + src/page.c | 21 ++++++++++ src/segment.c | 83 ++++++++++++++++++++++++++++++++++++- 7 files changed, 108 insertions(+), 4 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index a5b3cc9d..df85a2c0 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -369,6 +369,7 @@ typedef enum mi_option_e { mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) mi_option_debug_guarded_min, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) mi_option_debug_guarded_max, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) + mi_option_target_segments_per_thread, // experimental (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index aff6a1bd..b4e74789 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -175,6 +175,8 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept; / 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_page_force_abandon(mi_page_t* page); + void _mi_heap_delayed_free_all(mi_heap_t* heap); bool _mi_heap_delayed_free_partial(mi_heap_t* heap); void _mi_heap_collect_retired(mi_heap_t* heap, bool force); diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 69f737b3..044d6eae 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -200,7 +200,7 @@ typedef int32_t mi_ssize_t; #define MI_SMALL_OBJ_SIZE_MAX (MI_SMALL_PAGE_SIZE/4) // 8KiB on 64-bit #define MI_MEDIUM_OBJ_SIZE_MAX (MI_MEDIUM_PAGE_SIZE/4) // 128KiB on 64-bit #define MI_MEDIUM_OBJ_WSIZE_MAX (MI_MEDIUM_OBJ_SIZE_MAX/MI_INTPTR_SIZE) -#define MI_LARGE_OBJ_SIZE_MAX (MI_SEGMENT_SIZE/2) // 32MiB on 64-bit +#define MI_LARGE_OBJ_SIZE_MAX (MI_SEGMENT_SIZE/2) // 16MiB on 64-bit #define MI_LARGE_OBJ_WSIZE_MAX (MI_LARGE_OBJ_SIZE_MAX/MI_INTPTR_SIZE) // Maximum number of size classes. (spaced exponentially in 12.5% increments) diff --git a/src/arena-abandon.c b/src/arena-abandon.c index eaa8c7c9..84b9f72c 100644 --- a/src/arena-abandon.c +++ b/src/arena-abandon.c @@ -192,7 +192,7 @@ void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, bool vi else { // otherwise visit all starting at a random location if (abandoned_count > abandoned_list_count && max_arena > 0) { - current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); + current->start = 0; // (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); current->end = current->start + max_arena; } else { diff --git a/src/options.c b/src/options.c index 1cfb2f17..c97b9abe 100644 --- a/src/options.c +++ b/src/options.c @@ -100,6 +100,7 @@ static mi_option_desc_t options[_mi_option_last] = #endif { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects { 0, UNINIT, MI_OPTION(debug_guarded_max) }, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects + { 0, UNINIT, MI_OPTION(target_segments_per_thread) }, // abandon segments beyond this point, or 0 to disable. }; static void mi_option_init(mi_option_desc_t* desc); diff --git a/src/page.c b/src/page.c index 99ef3835..5671c7d4 100644 --- a/src/page.c +++ b/src/page.c @@ -405,6 +405,27 @@ void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) { } +// force abandon a page; this is safe to call +void _mi_page_force_abandon(mi_page_t* page) { + mi_heap_t* heap = mi_page_heap(page); + // mark page as not using delayed free + _mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false); + + // ensure this page is no longer in the heap delayed free list + _mi_heap_delayed_free_all(heap); + if (page->block_size == 0) return; // it may have been freed now + + // and now unlink it from the page queue and abandon (or free) + mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); + if (mi_page_all_free(page)) { + _mi_page_free(page, pq, false); + } + else { + _mi_page_abandon(page, pq); + } +} + + // Free a page with no more free blocks void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force) { mi_assert_internal(page != NULL); diff --git a/src/segment.c b/src/segment.c index 1f1dc006..bb7483f1 100644 --- a/src/segment.c +++ b/src/segment.c @@ -693,6 +693,8 @@ static mi_slice_t* mi_segment_span_free_coalesce(mi_slice_t* slice, mi_segments_ // free previous slice -- remove it from free and merge mi_assert_internal(prev->slice_count > 0 && prev->slice_offset==0); slice_count += prev->slice_count; + slice->slice_count = 0; + slice->slice_offset = (uint32_t)((uint8_t*)slice - (uint8_t*)prev); // set the slice offset for `segment_force_abandon` (in case the previous free block is very large). if (!is_abandoned) { mi_segment_span_remove_from_queue(prev, tld); } slice = prev; } @@ -1329,7 +1331,7 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t needed_slice result = mi_segment_reclaim(segment, heap, block_size, reclaimed, tld); break; } - else if (segment->abandoned_visits > 3 && is_suitable) { + else if (segment->abandoned_visits > 3 && is_suitable && !mi_option_is_enabled(mi_option_target_segments_per_thread)) { // always reclaim on 3rd visit to limit the abandoned queue length. mi_segment_reclaim(segment, heap, 0, NULL, tld); } @@ -1343,7 +1345,7 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t needed_slice return result; } - +// collect abandoned segments void _mi_abandoned_collect(mi_heap_t* heap, bool force, mi_segments_tld_t* tld) { mi_segment_t* segment; @@ -1367,6 +1369,80 @@ void _mi_abandoned_collect(mi_heap_t* heap, bool force, mi_segments_tld_t* tld) _mi_arena_field_cursor_done(¤t); } +/* ----------------------------------------------------------- + Force abandon a segment that is in use by our thread +----------------------------------------------------------- */ + +// force abandon a segment +static void mi_segment_force_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) +{ + mi_assert_internal(!mi_segment_is_abandoned(segment)); + + // for all slices + const mi_slice_t* end; + mi_slice_t* slice = mi_slices_start_iterate(segment, &end); + while (slice < end) { + mi_assert_internal(slice->slice_count > 0); + mi_assert_internal(slice->slice_offset == 0); + if (mi_slice_is_used(slice)) { + // ensure used count is up to date and collect potential concurrent frees + mi_page_t* const page = mi_slice_to_page(slice); + _mi_page_free_collect(page, false); + { + // abandon the page if it is still in-use (this will free it if possible as well) + mi_assert_internal(segment->used > 0); + if (segment->used == segment->abandoned+1) { + // the last page.. abandon and return as the segment will be abandoned after this + // and we should no longer access it. + _mi_page_force_abandon(page); + return; + } + else { + // abandon and continue + _mi_page_force_abandon(page); + // it might be freed, reset the slice (note: relies on coalesce setting the slice_offset) + slice = mi_slice_first(slice); + } + } + } + slice = slice + slice->slice_count; + } + mi_assert(segment->used == segment->abandoned); + mi_assert(segment->used == 0); + if (segment->used == 0) { + // all free now + mi_segment_free(segment, false, tld); + } + else { + // perform delayed purges + mi_segment_try_purge(segment, false /* force? */, tld->stats); + } +} + + +// try abandon segments. +// this should be called from `reclaim_or_alloc` so we know all segments are (about) fully in use. +static void mi_segments_try_abandon(mi_heap_t* heap, mi_segments_tld_t* tld) { + const size_t target = (size_t)mi_option_get_clamp(mi_option_target_segments_per_thread,0,1024); + if (target == 0 || tld->count <= target) return; + + const size_t min_target = (target > 4 ? (target*3)/4 : target); // 75% + + // todo: we should maintain a list of segments per thread; for now, only consider segments from the heap full pages + for (int i = 0; i < 16 && tld->count >= min_target; i++) { + mi_page_t* page = heap->pages[MI_BIN_FULL].first; + while (page != NULL && mi_page_block_size(page) > MI_LARGE_OBJ_SIZE_MAX) { + page = page->next; + } + if (page==NULL) { + break; + } + mi_segment_t* segment = _mi_page_segment(page); + mi_segment_force_abandon(segment, tld); + mi_assert_internal(page != heap->pages[MI_BIN_FULL].first); // as it is just abandoned + } +} + /* ----------------------------------------------------------- Reclaim or allocate ----------------------------------------------------------- */ @@ -1375,6 +1451,9 @@ static mi_segment_t* mi_segment_reclaim_or_alloc(mi_heap_t* heap, size_t needed_ { mi_assert_internal(block_size <= MI_LARGE_OBJ_SIZE_MAX); + // try to abandon some segments to increase reuse between threads + mi_segments_try_abandon(heap,tld); + // 1. try to reclaim an abandoned segment bool reclaimed; mi_segment_t* segment = mi_segment_try_reclaim(heap, needed_slices, block_size, &reclaimed, tld); From 19ce2c6461ffa63583f57c2558e9c7f9979dadaa Mon Sep 17 00:00:00 2001 From: Daan Date: Fri, 11 Oct 2024 10:44:43 -0700 Subject: [PATCH 090/305] restore randomization when trying to reclaim abandoned segments --- src/arena-abandon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arena-abandon.c b/src/arena-abandon.c index 84b9f72c..eaa8c7c9 100644 --- a/src/arena-abandon.c +++ b/src/arena-abandon.c @@ -192,7 +192,7 @@ void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_subproc_t* subproc, bool vi else { // otherwise visit all starting at a random location if (abandoned_count > abandoned_list_count && max_arena > 0) { - current->start = 0; // (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); + current->start = (heap == NULL || max_arena == 0 ? 0 : (mi_arena_id_t)(_mi_heap_random_next(heap) % max_arena)); current->end = current->start + max_arena; } else { From 81da26d7d30c87bc0f094c91fbbae39513d2d35a Mon Sep 17 00:00:00 2001 From: Daan Date: Fri, 11 Oct 2024 10:52:35 -0700 Subject: [PATCH 091/305] make target test for stealing one less since we are about to reclaim_or_alloc a fresh segment --- src/segment.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/segment.c b/src/segment.c index bb7483f1..3d411f9c 100644 --- a/src/segment.c +++ b/src/segment.c @@ -1424,9 +1424,10 @@ static void mi_segment_force_abandon(mi_segment_t* segment, mi_segments_tld_t* t // this should be called from `reclaim_or_alloc` so we know all segments are (about) fully in use. static void mi_segments_try_abandon(mi_heap_t* heap, mi_segments_tld_t* tld) { const size_t target = (size_t)mi_option_get_clamp(mi_option_target_segments_per_thread,0,1024); - if (target == 0 || tld->count <= target) return; + // we call this when we are about to add a fresh segment so we should be under our target segment count. + if (target == 0 || tld->count < target) return; - const size_t min_target = (target > 4 ? (target*3)/4 : target); // 75% + const size_t min_target = (target > 4 ? (target*3)/4 : target); // 75% // todo: we should maintain a list of segments per thread; for now, only consider segments from the heap full pages for (int i = 0; i < 16 && tld->count >= min_target; i++) { From bf251b27b187d36bec964e9d6e830dcf0e5b75a4 Mon Sep 17 00:00:00 2001 From: ArtSin Date: Tue, 15 Oct 2024 13:39:28 +0400 Subject: [PATCH 092/305] Fix int and long handling and the use of (u)intptr_t in _mi_vsnprintf 'va_arg' with type 'long' was used for both 'int' and 'long' arguments, but x86_64 Linux has 64-bit 'long', so passing an 'int' argument to '_mi_vsnprintf` results in undefined behaviour. 'intptr_t' was used as the largest integer type, but on 32-bit systems it is 32-bit wide, while 'long long' is 64-bit. 'intmax_t' can be used instead. --- src/libc.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libc.c b/src/libc.c index dd6b4007..ce541f1b 100644 --- a/src/libc.c +++ b/src/libc.c @@ -130,7 +130,7 @@ static void mi_out_alignright(char fill, char* start, size_t len, size_t extra, } -static void mi_out_num(uintptr_t x, size_t base, char prefix, char** out, char* end) +static void mi_out_num(uintmax_t x, size_t base, char prefix, char** out, char* end) { if (x == 0 || base == 0 || base > 16) { if (prefix != 0) { mi_outc(prefix, out, end); } @@ -206,12 +206,13 @@ void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { } else if (c == 'p' || c == 'x' || c == 'u') { // unsigned - uintptr_t x = 0; + uintmax_t x = 0; if (c == 'x' || c == 'u') { if (numtype == 'z') x = va_arg(args, size_t); else if (numtype == 't') x = va_arg(args, uintptr_t); // unsigned ptrdiff_t - else if (numtype == 'L') x = (uintptr_t)va_arg(args, unsigned long long); - else x = va_arg(args, unsigned long); + else if (numtype == 'L') x = va_arg(args, unsigned long long); + else if (numtype == 'l') x = va_arg(args, unsigned long); + else x = va_arg(args, unsigned int); } else if (c == 'p') { x = va_arg(args, uintptr_t); @@ -228,20 +229,21 @@ void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { } else if (c == 'i' || c == 'd') { // signed - intptr_t x = 0; + intmax_t x = 0; if (numtype == 'z') x = va_arg(args, intptr_t ); else if (numtype == 't') x = va_arg(args, ptrdiff_t); - else if (numtype == 'L') x = (intptr_t)va_arg(args, long long); - else x = va_arg(args, long); + else if (numtype == 'L') x = va_arg(args, long long); + else if (numtype == 'l') x = va_arg(args, long); + else x = va_arg(args, int); char pre = 0; if (x < 0) { pre = '-'; - if (x > INTPTR_MIN) { x = -x; } + if (x > INTMAX_MIN) { x = -x; } } else if (numplus != 0) { pre = numplus; } - mi_out_num((uintptr_t)x, 10, pre, &out, end); + mi_out_num((uintmax_t)x, 10, pre, &out, end); } else if (c >= ' ' && c <= '~') { // unknown format From 394e8c27d8b924e8b0248adc2835f65451c4f2ab Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 05:02:24 -0700 Subject: [PATCH 093/305] add cmake option to add C pre processor definitions more easily --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e78ba9fd..b32542ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ option(MI_SKIP_COLLECT_ON_EXIT "Skip collecting memory on program exit" OFF) option(MI_NO_PADDING "Force no use of padding even in DEBUG mode etc." OFF) option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) option(MI_NO_THP "Disable transparent huge pages support on Linux/Android for the mimalloc process only" OFF) +option(MI_EXTRA_CPPDEFS "Extra pre-processor definitions (use as `-DMI_EXTRA_CPPDEFS=\"opt1=val1;opt2=val2\"`)" "") # deprecated options option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) @@ -62,8 +63,8 @@ set(mi_sources set(mi_cflags "") set(mi_cflags_static "") # extra flags for a static library build set(mi_cflags_dynamic "") # extra flags for a shared-object library build -set(mi_defines "") set(mi_libraries "") +set(mi_defines ${MI_EXTRA_CPPDEFS}) # ----------------------------------------------------------------------------- # Convenience: set default build type depending on the build directory From 638ea539de088390b36f646e6c342dd230d0c93a Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 05:04:01 -0700 Subject: [PATCH 094/305] allow certain options to have defaults set via the pre-processor at build time -- see issue #945 --- src/options.c | 62 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/src/options.c b/src/options.c index 27122c78..76d2cf82 100644 --- a/src/options.c +++ b/src/options.c @@ -47,6 +47,47 @@ typedef struct mi_option_desc_s { #define MI_OPTION(opt) mi_option_##opt, #opt, NULL #define MI_OPTION_LEGACY(opt,legacy) mi_option_##opt, #opt, #legacy +// Some options can be set at build time for statically linked libraries (use `-DMI_EXTRA_CPPDEFS="opt1=val1;opt2=val2"`) +// This is useful if we cannot pass them as environment variables +// (and setting them programmatically would be too late) + +#ifndef MI_DEFAULT_VERBOSE +#define MI_DEFAULT_VERBOSE 0 +#endif + +#ifndef MI_DEFAULT_EAGER_COMMIT +#define MI_DEFAULT_EAGER_COMMIT 1 +#endif + +#ifndef MI_DEFAULT_ARENA_EAGER_COMMIT +#define MI_DEFAULT_ARENA_EAGER_COMMIT 2 +#endif + +#ifndef MI_DEFAULT_ARENA_RESERVE + #if (MI_INTPTR_SIZE>4) + #define MI_DEFAULT_ARENA_RESERVE 1024L*1024L + #else + #define MI_DEFAULT_ARENA_RESERVE 128L*1024L + #endif +#endif + +#ifndef MI_DEFAULT_DISALLOW_ARENA_ALLOC +#define MI_DEFAULT_DISALLOW_ARENA_ALLOC 0 +#endif + +#ifndef MI_DEFAULT_ALLOW_LARGE_OS_PAGES +#define MI_DEFAULT_ALLOW_LARGE_OS_PAGES 0 +#endif + +#ifndef MI_DEFAULT_RESERVE_HUGE_OS_PAGES +#define MI_DEFAULT_RESERVE_HUGE_OS_PAGES 0 +#endif + +#ifndef MI_DEFAULT_RESERVE_OS_MEMORY +#define MI_DEFAULT_RESERVE_OS_MEMORY 0 +#endif + + static mi_option_desc_t options[_mi_option_last] = { // stable options @@ -56,16 +97,16 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(show_errors) }, #endif { 0, UNINIT, MI_OPTION(show_stats) }, - { 0, UNINIT, MI_OPTION(verbose) }, + { MI_DEFAULT_VERBOSE, UNINIT, MI_OPTION(verbose) }, // the following options are experimental and not all combinations make sense. - { 1, UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`) - { 2, UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux) + { MI_DEFAULT_EAGER_COMMIT, UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`) + { MI_DEFAULT_ARENA_EAGER_COMMIT, UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux) { 1, UNINIT, MI_OPTION_LEGACY(purge_decommits,reset_decommits) }, // purge decommits memory (instead of reset) (note: on linux this uses MADV_DONTNEED for decommit) - { 0, UNINIT, MI_OPTION_LEGACY(allow_large_os_pages,large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's - { 0, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages + { MI_DEFAULT_ALLOW_LARGE_OS_PAGES, UNINIT, MI_OPTION_LEGACY(allow_large_os_pages,large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's + { MI_DEFAULT_RESERVE_HUGE_OS_PAGES, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages {-1, UNINIT, MI_OPTION(reserve_huge_os_pages_at) }, // reserve huge pages at node N - { 0, UNINIT, MI_OPTION(reserve_os_memory) }, // reserve N KiB OS memory in advance (use `option_get_size`) + { MI_DEFAULT_RESERVE_OS_MEMORY, UNINIT, MI_OPTION(reserve_os_memory) }, // reserve N KiB OS memory in advance (use `option_get_size`) { 0, UNINIT, MI_OPTION(deprecated_segment_cache) }, // cache N segments per thread { 0, UNINIT, MI_OPTION(deprecated_page_reset) }, // reset page memory on free { 0, UNINIT, MI_OPTION(abandoned_page_purge) }, // purge free page memory when a thread terminates @@ -83,16 +124,11 @@ static mi_option_desc_t options[_mi_option_last] = { 32, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output { 10, UNINIT, MI_OPTION(max_segment_reclaim)}, // max. percentage of the abandoned segments to be reclaimed per try. { 0, UNINIT, MI_OPTION(destroy_on_exit)}, // release all OS memory on process exit; careful with dangling pointer or after-exit frees! - #if (MI_INTPTR_SIZE>4) - { 1024L*1024L, UNINIT, MI_OPTION(arena_reserve) }, // reserve memory N KiB at a time (=1GiB) (use `option_get_size`) - #else - { 128L*1024L, UNINIT, MI_OPTION(arena_reserve) }, // =128MiB on 32-bit - #endif - + { MI_DEFAULT_ARENA_RESERVE, UNINIT, MI_OPTION(arena_reserve) }, // reserve memory N KiB at a time (=1GiB) (use `option_get_size`) { 10, UNINIT, MI_OPTION(arena_purge_mult) }, // purge delay multiplier for arena's { 1, UNINIT, MI_OPTION_LEGACY(purge_extend_delay, decommit_extend_delay) }, { 1, UNINIT, MI_OPTION(abandoned_reclaim_on_free) },// reclaim an abandoned segment on a free - { 0, UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) + { MI_DEFAULT_DISALLOW_ARENA_ALLOC, UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) { 400, UNINIT, MI_OPTION(retry_on_oom) }, // windows only: retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. #if defined(MI_VISIT_ABANDONED) { 1, INITIALIZED, MI_OPTION(visit_abandoned) }, // allow visiting heap blocks in abandonded segments; requires taking locks during reclaim. From 50d3525a8c948a5943c89590629e869fc7cdbe0d Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 05:04:27 -0700 Subject: [PATCH 095/305] add test for issue #944 --- test/main-override.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index fc7f70f0..50eb0267 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -37,6 +37,7 @@ static void tsan_numa_test(); // issue #414 static void strdup_test(); // issue #445 static void heap_thread_free_huge(); static void test_std_string(); // issue #697 +static void test_thread_local(); // issue #944 static void test_stl_allocators(); @@ -44,7 +45,8 @@ static void test_stl_allocators(); int main() { // mi_stats_reset(); // ignore earlier allocations - test_std_string(); + //test_std_string(); + test_thread_local(); // heap_thread_free_huge(); /* heap_thread_free_large(); @@ -312,3 +314,31 @@ static void tsan_numa_test() { dummy_worker(); t1.join(); } + + +class MTest +{ + char *data; +public: + MTest() { data = (char*)malloc(1024); } + ~MTest() { free(data); }; +}; + +thread_local MTest tlVariable; + +void threadFun( int i ) +{ + printf( "Thread %d\n", i ); + std::this_thread::sleep_for( std::chrono::milliseconds(100) ); +} + +void test_thread_local() +{ + for( int i=1; i < 100; ++i ) + { + std::thread t( threadFun, i ); + t.join(); + mi_stats_print(NULL); + } + return; +} \ No newline at end of file From 34e66778ecc40c58164c14ada56c15e8f38cf1f7 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 05:10:09 -0700 Subject: [PATCH 096/305] fix MI_EXTRA_CPPDEFS setting --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b32542ef..adf45bbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,12 @@ set(mi_cflags "") set(mi_cflags_static "") # extra flags for a static library build set(mi_cflags_dynamic "") # extra flags for a shared-object library build set(mi_libraries "") -set(mi_defines ${MI_EXTRA_CPPDEFS}) + +if(MI_EXTRA_CPPDEFS) + set(mi_defines ${MI_EXTRA_CPPDEFS}) +else() + set(mi_defines "") +endif() # ----------------------------------------------------------------------------- # Convenience: set default build type depending on the build directory From aa881733d7830e44b39bd16080fab803e468828c Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 22:56:59 -0700 Subject: [PATCH 097/305] reorganize primitives for process initialization; use special data segment on Windows for thread termination by default on Windows now (issue #869) --- include/mimalloc/internal.h | 5 + src/init.c | 114 ++------------------- src/prim/prim.c | 44 ++++++++ src/prim/windows/prim.c | 197 ++++++++++++++++++++++++++++-------- 4 files changed, 209 insertions(+), 151 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 2f21d88e..63a1e6f0 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -77,6 +77,11 @@ static inline uintptr_t _mi_random_shuffle(uintptr_t x); // init.c extern mi_decl_cache_align mi_stats_t _mi_stats_main; extern mi_decl_cache_align const mi_page_t _mi_page_empty; +void _mi_process_load(void); +void mi_cdecl _mi_process_done(void); +bool _mi_is_redirected(void); +bool _mi_allocator_init(const char** message); +void _mi_allocator_done(void); bool _mi_is_main_thread(void); size_t _mi_current_thread_count(void); bool _mi_preloading(void); // true while the C runtime is not initialized yet diff --git a/src/init.c b/src/init.c index ead5a147..eaa7f5be 100644 --- a/src/init.c +++ b/src/init.c @@ -459,10 +459,6 @@ void mi_thread_init(void) mi_attr_noexcept //_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); } -void mi_thread_done(void) mi_attr_noexcept { - _mi_thread_done(NULL); -} - void _mi_thread_done(mi_heap_t* heap) { // calling with NULL implies using the default heap @@ -508,54 +504,15 @@ void _mi_heap_set_default_direct(mi_heap_t* heap) { // -------------------------------------------------------- // Run functions on process init/done, and thread init/done // -------------------------------------------------------- -static void mi_cdecl mi_process_done(void); - static bool os_preloading = true; // true until this module is initialized -static bool mi_redirected = false; // true if malloc redirects to mi_malloc // Returns true if this module has not been initialized; Don't use C runtime routines until it returns false. bool mi_decl_noinline _mi_preloading(void) { return os_preloading; } -mi_decl_nodiscard bool mi_is_redirected(void) mi_attr_noexcept { - return mi_redirected; -} - -// Communicate with the redirection module on Windows -#if defined(_WIN32) && defined(MI_SHARED_LIB) && !defined(MI_WIN_NOREDIRECT) -#ifdef __cplusplus -extern "C" { -#endif -mi_decl_export void _mi_redirect_entry(DWORD reason) { - // called on redirection; careful as this may be called before DllMain - if (reason == DLL_PROCESS_ATTACH) { - mi_redirected = true; - } - else if (reason == DLL_PROCESS_DETACH) { - mi_redirected = false; - } - else if (reason == DLL_THREAD_DETACH) { - mi_thread_done(); - } -} -__declspec(dllimport) bool mi_cdecl mi_allocator_init(const char** message); -__declspec(dllimport) void mi_cdecl mi_allocator_done(void); -#ifdef __cplusplus -} -#endif -#else -static bool mi_allocator_init(const char** message) { - if (message != NULL) *message = NULL; - return true; -} -static void mi_allocator_done(void) { - // nothing to do -} -#endif - -// Called once by the process loader -static void mi_process_load(void) { +// Called once by the process loader from `src/prim/prim.c` +void _mi_process_load(void) { mi_heap_main_init(); #if defined(__APPLE__) || defined(MI_TLS_RECURSE_GUARD) volatile mi_heap_t* dummy = _mi_heap_default; // access TLS to allocate it before setting tls_initialized to true; @@ -563,17 +520,14 @@ static void mi_process_load(void) { #endif os_preloading = false; mi_assert_internal(_mi_is_main_thread()); - #if !(defined(_WIN32) && defined(MI_SHARED_LIB)) // use Dll process detach (see below) instead of atexit (issue #521) - atexit(&mi_process_done); - #endif _mi_options_init(); mi_process_setup_auto_thread_done(); mi_process_init(); - if (mi_redirected) _mi_verbose_message("malloc is redirected.\n"); + if (_mi_is_redirected()) _mi_verbose_message("malloc is redirected.\n"); // show message from the redirector (if present) const char* msg = NULL; - mi_allocator_init(&msg); + _mi_allocator_init(&msg); if (msg != NULL && (mi_option_is_enabled(mi_option_verbose) || mi_option_is_enabled(mi_option_show_errors))) { _mi_fputs(NULL,NULL,NULL,msg); } @@ -651,7 +605,7 @@ void mi_process_init(void) mi_attr_noexcept { } // Called when the process is done (through `at_exit`) -static void mi_cdecl mi_process_done(void) { +void mi_cdecl _mi_process_done(void) { // only shutdown if we were initialized if (!_mi_process_is_initialized) return; // ensure we are called once @@ -683,64 +637,8 @@ static void mi_cdecl mi_process_done(void) { if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) { mi_stats_print(NULL); } - mi_allocator_done(); + _mi_allocator_done(); _mi_verbose_message("process done: 0x%zx\n", _mi_heap_main.thread_id); os_preloading = true; // don't call the C runtime anymore } - - -#if defined(_WIN32) && defined(MI_SHARED_LIB) - // Windows DLL: easy to hook into process_init and thread_done - __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { - MI_UNUSED(reserved); - MI_UNUSED(inst); - if (reason==DLL_PROCESS_ATTACH) { - mi_process_load(); - } - else if (reason==DLL_PROCESS_DETACH) { - mi_process_done(); - } - else if (reason==DLL_THREAD_DETACH) { - if (!mi_is_redirected()) { - mi_thread_done(); - } - } - return TRUE; - } - -#elif defined(_MSC_VER) - // MSVC: use data section magic for static libraries - // See - static int _mi_process_init(void) { - mi_process_load(); - return 0; - } - typedef int(*_mi_crt_callback_t)(void); - #if defined(_M_X64) || defined(_M_ARM64) - __pragma(comment(linker, "/include:" "_mi_msvc_initu")) - #pragma section(".CRT$XIU", long, read) - #else - __pragma(comment(linker, "/include:" "__mi_msvc_initu")) - #endif - #pragma data_seg(".CRT$XIU") - mi_decl_externc _mi_crt_callback_t _mi_msvc_initu[] = { &_mi_process_init }; - #pragma data_seg() - -#elif defined(__cplusplus) - // C++: use static initialization to detect process start - static bool _mi_process_init(void) { - mi_process_load(); - return (_mi_heap_main.thread_id != 0); - } - static bool mi_initialized = _mi_process_init(); - -#elif defined(__GNUC__) || defined(__clang__) - // GCC,Clang: use the constructor attribute - static void __attribute__((constructor)) _mi_process_init(void) { - mi_process_load(); - } - -#else -#pragma message("define a way to call mi_process_load on your platform") -#endif diff --git a/src/prim/prim.c b/src/prim/prim.c index 3b7d3736..242cd618 100644 --- a/src/prim/prim.c +++ b/src/prim/prim.c @@ -25,3 +25,47 @@ terms of the MIT license. A copy of the license can be found in the file #include "unix/prim.c" // mmap() (Linux, macOSX, BSD, Illumnos, Haiku, DragonFly, etc.) #endif + +// Generic process initialization +#ifndef MI_PRIM_HAS_PROCESS_ATTACH +#if defined(__GNUC__) || defined(__clang__) + // GCC,Clang: use the constructor attribute + #if defined(__clang__) + #define mi_attr_constructor __attribute__((constructor(101))) + #define mi_attr_destructor __attribute__((destructor(101))) + #else + #define mi_attr_constructor __attribute__((constructor)) + #define mi_attr_destructor __attribute__((destructor)) + #endif + static void mi_attr_constructor mi_process_attach(void) { + _mi_process_load(); + } + static void mi_attr_destructor mi_process_detach(void) { + _mi_process_done(); + } +#elif defined(__cplusplus) + // C++: use static initialization to detect process start + static bool mi_process_attach(void) { + _mi_process_load(); + atexit(&_mi_process_done); + return (_mi_heap_main.thread_id != 0); + } + static bool mi_initialized = mi_process_attach(); +#else + #pragma message("define a way to call _mi_process_load/done on your platform") +#endif +#endif + +// Generic allocator init/done callback +#ifndef MI_PRIM_HAS_ALLOCATOR_INIT +bool _mi_is_redirected(void) { + return false; +} +bool _mi_allocator_init(const char** message) { + if (message != NULL) *message = NULL; + return true; +} +void _mi_allocator_done(void) { + // nothing to do +} +#endif diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index bd874f9b..c62ea497 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -499,8 +499,7 @@ void _mi_prim_process_info(mi_process_info_t* pinfo) } // get process info - PROCESS_MEMORY_COUNTERS info; - memset(&info, 0, sizeof(info)); + PROCESS_MEMORY_COUNTERS info; _mi_memzero_var(info); if (pGetProcessMemoryInfo != NULL) { pGetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); } @@ -602,60 +601,172 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) { #endif // MI_USE_RTLGENRANDOM + + //---------------------------------------------------------------- -// Thread init/done +// Process & Thread Init/Done //---------------------------------------------------------------- -#if !defined(MI_SHARED_LIB) - -// use thread local storage keys to detect thread ending -// note: another design could be to use special linker sections (see issue #869) -#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) { - mi_heap_t* heap = (mi_heap_t*)value; - if (heap != NULL) { - _mi_thread_done(heap); - FlsSetValue(mi_fls_key, NULL); // prevent recursion as _mi_thread_done may set it back to the main heap, issue #672 +static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { + MI_UNUSED(reserved); + MI_UNUSED(module); + if (reason==DLL_PROCESS_ATTACH) { + _mi_process_load(); } + else if (reason==DLL_PROCESS_DETACH) { + _mi_process_done(); + } + else if (reason==DLL_THREAD_DETACH && !_mi_is_redirected()) { + _mi_thread_done(NULL); + } } -void _mi_prim_thread_init_auto_done(void) { - mi_fls_key = FlsAlloc(&mi_fls_done); -} -void _mi_prim_thread_done_auto_done(void) { - // call thread-done on all threads (except the main thread) to prevent - // dangling callback pointer if statically linked with a DLL; Issue #208 - FlsFree(mi_fls_key); -} +#if defined(MI_SHARED_LIB) + #define MI_PRIM_HAS_PROCESS_INIT 1 -void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { - mi_assert_internal(mi_fls_key != (DWORD)(-1)); - FlsSetValue(mi_fls_key, heap); -} + // Windows DLL: easy to hook into process_init and thread_done + __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { + win_main((PVOID)inst,reason,reserved); + return TRUE; + } -#else + // nothing to do since `_mi_thread_done` is handled through the DLL_THREAD_DETACH event. + void _mi_prim_thread_init_auto_done(void) { } + void _mi_prim_thread_done_auto_done(void) { } + void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + MI_UNUSED(heap); + } -// Dll; nothing to do as in that case thread_done is handled through the DLL_THREAD_DETACH event. +#elif !defined(MI_WIN_USE_FLS) + #define MI_PRIM_HAS_PROCESS_INIT 1 -void _mi_prim_thread_init_auto_done(void) { -} + // Set up TLS callbacks in a statically linked library by using special data sections. + // See + // We may use ".CRT$XLY" instead of "B" -- see also issue #869. + #if defined(__cplusplus) + extern "C" { + #endif -void _mi_prim_thread_done_auto_done(void) { -} + #if defined(_WIN64) + #pragma comment(linker, "/INCLUDE:_tls_used") + #pragma comment(linker, "/INCLUDE:_mi_tls_callback") + #pragma const_seg(".CRT$XLB") + extern const PIMAGE_TLS_CALLBACK _mi_tls_callback[]; + const PIMAGE_TLS_CALLBACK _mi_tls_callback[] = { &mi_win_main }; + #pragma const_seg() + #else + #pragma comment(linker, "/INCLUDE:__tls_used") + #pragma comment(linker, "/INCLUDE:__mi_tls_callback") + #pragma data_seg(".CRT$XLB") + const PIMAGE_TLS_CALLBACK _mi_tls_callback[] = { &mi_win_main }; + #pragma data_seg() + #endif -void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { - MI_UNUSED(heap); -} + #if defined(__cplusplus) + } + #endif + // nothing to do since `_mi_thread_done` is handled through the DLL_THREAD_DETACH event. + void _mi_prim_thread_init_auto_done(void) { } + void _mi_prim_thread_done_auto_done(void) { } + void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + MI_UNUSED(heap); + } + +#else // statically linked, use fiber api + + #if defined(_MSC_VER) // on clang/gcc use the constructor attribute (in `src/prim/prim.c`) + // MSVC: use data section magic for static libraries + // See + #define MI_PRIM_HAS_PROCESS_INIT 1 + + static int mi_process_attach(void) { + mi_win_main(NULL,DLL_PROCESS_ATTACH,NULL); + atexit(&_mi_process_done); + return 0; + } + typedef int(*_mi_crt_callback_t)(void); + #if defined(_M_X64) || defined(_M_ARM64) + __pragma(comment(linker, "/include:" "_mi_msvc_initu")) + #pragma section(".CRT$XIU", long, read) + #else + __pragma(comment(linker, "/include:" "__mi_msvc_initu")) + #endif + #pragma data_seg(".CRT$XIU") + mi_decl_externc _mi_crt_callback_t _mi_msvc_initu[] = { &mi_process_attach }; + #pragma data_seg() + #endif + + // use the fiber api for calling `_mi_thread_done`. + #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) { + mi_heap_t* heap = (mi_heap_t*)value; + if (heap != NULL) { + _mi_thread_done(heap); + FlsSetValue(mi_fls_key, NULL); // prevent recursion as _mi_thread_done may set it back to the main heap, issue #672 + } + } + + void _mi_prim_thread_init_auto_done(void) { + mi_fls_key = FlsAlloc(&mi_fls_done); + } + + void _mi_prim_thread_done_auto_done(void) { + // call thread-done on all threads (except the main thread) to prevent + // dangling callback pointer if statically linked with a DLL; Issue #208 + FlsFree(mi_fls_key); + } + + void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) { + mi_assert_internal(mi_fls_key != (DWORD)(-1)); + FlsSetValue(mi_fls_key, heap); + } #endif +// ---------------------------------------------------- +// Communicate with the redirection module on Windows +// ---------------------------------------------------- +#if defined(MI_SHARED_LIB) && !defined(MI_WIN_NOREDIRECT) + static bool mi_redirected = false; // true if malloc redirects to mi_malloc + + bool _mi_is_redirected(void) { + return mi_redirected; + } + + #ifdef __cplusplus + extern "C" { + #endif + mi_decl_export void _mi_redirect_entry(DWORD reason) { + // called on redirection; careful as this may be called before DllMain + if (reason == DLL_PROCESS_ATTACH) { + mi_redirected = true; + } + else if (reason == DLL_PROCESS_DETACH) { + mi_redirected = false; + } + else if (reason == DLL_THREAD_DETACH) { + _mi_thread_done(NULL); + } + } + __declspec(dllimport) bool mi_cdecl mi_allocator_init(const char** message); + __declspec(dllimport) void mi_cdecl mi_allocator_done(void); + #ifdef __cplusplus + } + #endif + bool _mi_allocator_init(const char** message) { + return mi_allocator_init(message); + } + void _mi_allocator_done(void) { + mi_allocator_done(); + } +#endif \ No newline at end of file From 4377abe017d59796845ec0266531d62e5873a917 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 22:59:41 -0700 Subject: [PATCH 098/305] add cmake option to fall back on the fiber api do detect thread termination on windows --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index adf45bbf..e0aa59b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ option(MI_NO_THP "Disable transparent huge pages support on Linux/And option(MI_EXTRA_CPPDEFS "Extra pre-processor definitions (use as `-DMI_EXTRA_CPPDEFS=\"opt1=val1;opt2=val2\"`)" "") # deprecated options +option(MI_WIN_USE_FLS "Use Fiber local storage on Windows to detect thread termination" OFF) option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) option(MI_USE_LIBATOMIC "Explicitly link with -latomic (on older systems) (deprecated and detected automatically)" OFF) @@ -313,6 +314,11 @@ if(MI_LIBC_MUSL) list(APPEND mi_defines MI_LIBC_MUSL=1) endif() +if(MI_WIN_USE_FLS) + message(STATUS "Use the Fiber API to detect thread termination") + list(APPEND mi_defines MI_WIN_USE_FLS=1) +endif() + # On Haiku use `-DCMAKE_INSTALL_PREFIX` instead, issue #788 # if(CMAKE_SYSTEM_NAME MATCHES "Haiku") # SET(CMAKE_INSTALL_LIBDIR ~/config/non-packaged/lib) From f971bd6d749ccdea5b3622ef6272896b2d45ab28 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 23:05:51 -0700 Subject: [PATCH 099/305] fix build on windows --- src/prim/prim.c | 1 + src/prim/windows/prim.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/prim/prim.c b/src/prim/prim.c index 242cd618..8a2400c8 100644 --- a/src/prim/prim.c +++ b/src/prim/prim.c @@ -45,6 +45,7 @@ terms of the MIT license. A copy of the license can be found in the file } #elif defined(__cplusplus) // C++: use static initialization to detect process start + extern mi_heap_t _mi_heap_main; static bool mi_process_attach(void) { _mi_process_load(); atexit(&_mi_process_done); diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index c62ea497..ed160541 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -623,11 +623,11 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { #if defined(MI_SHARED_LIB) - #define MI_PRIM_HAS_PROCESS_INIT 1 + #define MI_PRIM_HAS_PROCESS_ATTACH 1 // Windows DLL: easy to hook into process_init and thread_done __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { - win_main((PVOID)inst,reason,reserved); + mi_win_main((PVOID)inst,reason,reserved); return TRUE; } @@ -639,7 +639,7 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { } #elif !defined(MI_WIN_USE_FLS) - #define MI_PRIM_HAS_PROCESS_INIT 1 + #define MI_PRIM_HAS_PROCESS_ATTACH 1 // Set up TLS callbacks in a statically linked library by using special data sections. // See @@ -679,7 +679,7 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { #if defined(_MSC_VER) // on clang/gcc use the constructor attribute (in `src/prim/prim.c`) // MSVC: use data section magic for static libraries // See - #define MI_PRIM_HAS_PROCESS_INIT 1 + #define MI_PRIM_HAS_PROCESS_ATTACH 1 static int mi_process_attach(void) { mi_win_main(NULL,DLL_PROCESS_ATTACH,NULL); From e55ae0aeb76f5205edce57b97031be6aa80f962a Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 21 Oct 2024 23:09:14 -0700 Subject: [PATCH 100/305] fix duplicate definition on windows --- src/prim/windows/prim.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index ed160541..90fab080 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -737,6 +737,8 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { // Communicate with the redirection module on Windows // ---------------------------------------------------- #if defined(MI_SHARED_LIB) && !defined(MI_WIN_NOREDIRECT) + #define MI_PRIM_HAS_ALLOCATOR_INIT 1 + static bool mi_redirected = false; // true if malloc redirects to mi_malloc bool _mi_is_redirected(void) { From 46e9e7fdd08f017eded0c88538647c82752c668f Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 22 Oct 2024 06:06:15 -0700 Subject: [PATCH 101/305] fix win32 compilation --- src/prim/windows/prim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 90fab080..7ba1f1de 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -659,7 +659,7 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { #pragma comment(linker, "/INCLUDE:__tls_used") #pragma comment(linker, "/INCLUDE:__mi_tls_callback") #pragma data_seg(".CRT$XLB") - const PIMAGE_TLS_CALLBACK _mi_tls_callback[] = { &mi_win_main }; + PIMAGE_TLS_CALLBACK _mi_tls_callback[] = { &mi_win_main }; #pragma data_seg() #endif @@ -738,7 +738,7 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { // ---------------------------------------------------- #if defined(MI_SHARED_LIB) && !defined(MI_WIN_NOREDIRECT) #define MI_PRIM_HAS_ALLOCATOR_INIT 1 - + static bool mi_redirected = false; // true if malloc redirects to mi_malloc bool _mi_is_redirected(void) { From 104e82170912bffdc7228202abc897204ca747be Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 22 Oct 2024 06:08:56 -0700 Subject: [PATCH 102/305] fix fast divisor for 32-bit platforms --- src/heap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/heap.c b/src/heap.c index a3aaaf6b..206d3a36 100644 --- a/src/heap.c +++ b/src/heap.c @@ -543,13 +543,14 @@ void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page) { static void mi_get_fast_divisor(size_t divisor, uint64_t* magic, size_t* shift) { mi_assert_internal(divisor > 0 && divisor <= UINT32_MAX); - *shift = 64 - mi_clz(divisor - 1); + *shift = MI_INTPTR_BITS - mi_clz(divisor - 1); *magic = ((((uint64_t)1 << 32) * (((uint64_t)1 << *shift) - divisor)) / divisor + 1); } static size_t mi_fast_divide(size_t n, uint64_t magic, size_t shift) { mi_assert_internal(n <= UINT32_MAX); - return ((((uint64_t)n * magic) >> 32) + n) >> shift; + const uint64_t hi = ((uint64_t)n * magic) >> 32; + return (size_t)((hi + n) >> shift); } bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg) { From dfdb9cb8772f8fabf63ce81aaa7e2aac9621a1e3 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 22 Oct 2024 06:52:34 -0700 Subject: [PATCH 103/305] cleanup process init/done --- src/prim/prim.c | 20 ++++++++++++++++---- src/prim/windows/prim.c | 12 ++++++------ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/prim/prim.c b/src/prim/prim.c index 8a2400c8..a4d3814f 100644 --- a/src/prim/prim.c +++ b/src/prim/prim.c @@ -29,7 +29,8 @@ terms of the MIT license. A copy of the license can be found in the file // Generic process initialization #ifndef MI_PRIM_HAS_PROCESS_ATTACH #if defined(__GNUC__) || defined(__clang__) - // GCC,Clang: use the constructor attribute + // gcc,clang: use the constructor/destructor attribute + // which for both seem to run before regular constructors/destructors #if defined(__clang__) #define mi_attr_constructor __attribute__((constructor(101))) #define mi_attr_destructor __attribute__((destructor(101))) @@ -44,7 +45,17 @@ terms of the MIT license. A copy of the license can be found in the file _mi_process_done(); } #elif defined(__cplusplus) - // C++: use static initialization to detect process start + // C++: use static initialization to detect process start/end + struct mi_init_done_t { + mi_init_done_t() { + _mi_process_load(); + } + ~mi_init_done_t() { + _mi_process_done(); + } + }; + static mi_init_done_t mi_init_done; + /* extern mi_heap_t _mi_heap_main; static bool mi_process_attach(void) { _mi_process_load(); @@ -52,7 +63,8 @@ terms of the MIT license. A copy of the license can be found in the file return (_mi_heap_main.thread_id != 0); } static bool mi_initialized = mi_process_attach(); -#else + */ + #else #pragma message("define a way to call _mi_process_load/done on your platform") #endif #endif @@ -63,7 +75,7 @@ bool _mi_is_redirected(void) { return false; } bool _mi_allocator_init(const char** message) { - if (message != NULL) *message = NULL; + if (message != NULL) { *message = NULL; } return true; } void _mi_allocator_done(void) { diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 7ba1f1de..b0631b81 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -674,7 +674,7 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { MI_UNUSED(heap); } -#else // statically linked, use fiber api +#else // deprecated: statically linked, use fiber api #if defined(_MSC_VER) // on clang/gcc use the constructor attribute (in `src/prim/prim.c`) // MSVC: use data section magic for static libraries @@ -686,15 +686,15 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { atexit(&_mi_process_done); return 0; } - typedef int(*_mi_crt_callback_t)(void); - #if defined(_M_X64) || defined(_M_ARM64) - __pragma(comment(linker, "/include:" "_mi_msvc_initu")) + typedef int(*mi_crt_callback_t)(void); + #if defined(_WIN64) + #pragma comment(linker, "/INCLUDE:_mi_tls_callback") #pragma section(".CRT$XIU", long, read) #else - __pragma(comment(linker, "/include:" "__mi_msvc_initu")) + #pragma comment(linker, "/INCLUDE:__mi_tls_callback") #endif #pragma data_seg(".CRT$XIU") - mi_decl_externc _mi_crt_callback_t _mi_msvc_initu[] = { &mi_process_attach }; + mi_decl_externc mi_crt_callback_t _mi_tls_callback[] = { &mi_process_attach }; #pragma data_seg() #endif From 6e9b38ac126c301f6e6c3e47a642c2c8388c333d Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 22 Oct 2024 18:58:55 -0700 Subject: [PATCH 104/305] fix issue where searching for abandoned blocks would skip the first one --- src/arena-abandon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/arena-abandon.c b/src/arena-abandon.c index eaa8c7c9..c40d3ce3 100644 --- a/src/arena-abandon.c +++ b/src/arena-abandon.c @@ -237,7 +237,7 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_at(mi_arena_t* arena, mi_s static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_cursor_t* previous) { const size_t max_arena = mi_arena_get_count(); size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx); - size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1; + size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx); // visit arena's (from the previous cursor) for (; previous->start < previous->end; previous->start++, field_idx = 0, bit_idx = 0) { // index wraps around @@ -266,11 +266,12 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_ // pre-check if the bit is set size_t mask = ((size_t)1 << bit_idx); if mi_unlikely((field & mask) == mask) { - previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); - mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, previous->bitmap_idx); + mi_bitmap_index_t bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx); + mi_segment_t* const segment = mi_arena_segment_clear_abandoned_at(arena, previous->subproc, bitmap_idx); if (segment != NULL) { //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } + previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx + 1); // start at next one for the next iteration return segment; } } From d951b4dd234c165552521419ef2365a55fdcd454 Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 23 Oct 2024 00:53:17 -0700 Subject: [PATCH 105/305] add missing mi_thread_done definition --- src/init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/init.c b/src/init.c index eaa7f5be..75458a1f 100644 --- a/src/init.c +++ b/src/init.c @@ -459,6 +459,10 @@ void mi_thread_init(void) mi_attr_noexcept //_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); } +void mi_thread_done(void) mi_attr_noexcept { + _mi_thread_done(NULL); +} + void _mi_thread_done(mi_heap_t* heap) { // calling with NULL implies using the default heap From 925efaeac93f15408f001484e9ea4fa0fe3b8aec Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 23 Oct 2024 01:10:00 -0700 Subject: [PATCH 106/305] improve windows static library initialization to account for thread local destructors (issue #944) --- src/prim/windows/prim.c | 45 ++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index b0631b81..385354fc 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -641,26 +641,47 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { #elif !defined(MI_WIN_USE_FLS) #define MI_PRIM_HAS_PROCESS_ATTACH 1 + static void NTAPI mi_win_main_attach(PVOID module, DWORD reason, LPVOID reserved) { + if (reason == DLL_PROCESS_ATTACH || reason == DLL_THREAD_ATTACH) { + mi_win_main(module, reason, reserved); + } + } + static void NTAPI mi_win_main_detach(PVOID module, DWORD reason, LPVOID reserved) { + if (reason == DLL_PROCESS_DETACH || reason == DLL_THREAD_DETACH) { + mi_win_main(module, reason, reserved); + } + } + // Set up TLS callbacks in a statically linked library by using special data sections. // See - // We may use ".CRT$XLY" instead of "B" -- see also issue #869. + // We use 2 entries to ensure we call attach events before constructors + // are called, and detach events after destructors are called. #if defined(__cplusplus) extern "C" { #endif #if defined(_WIN64) - #pragma comment(linker, "/INCLUDE:_tls_used") - #pragma comment(linker, "/INCLUDE:_mi_tls_callback") - #pragma const_seg(".CRT$XLB") - extern const PIMAGE_TLS_CALLBACK _mi_tls_callback[]; - const PIMAGE_TLS_CALLBACK _mi_tls_callback[] = { &mi_win_main }; - #pragma const_seg() + #pragma comment(linker, "/INCLUDE:_tls_used") + #pragma comment(linker, "/INCLUDE:_mi_tls_callback_pre") + #pragma comment(linker, "/INCLUDE:_mi_tls_callback_post") + #pragma const_seg(".CRT$XLB") + extern const PIMAGE_TLS_CALLBACK _mi_tls_callback_pre[]; + const PIMAGE_TLS_CALLBACK _mi_tls_callback_pre[] = { &mi_win_main_attach }; + #pragma const_seg() + #pragma const_seg(".CRT$XLY") + extern const PIMAGE_TLS_CALLBACK _mi_tls_callback_post[]; + const PIMAGE_TLS_CALLBACK _mi_tls_callback_post[] = { &mi_win_main_detach }; + #pragma const_seg() #else - #pragma comment(linker, "/INCLUDE:__tls_used") - #pragma comment(linker, "/INCLUDE:__mi_tls_callback") - #pragma data_seg(".CRT$XLB") - PIMAGE_TLS_CALLBACK _mi_tls_callback[] = { &mi_win_main }; - #pragma data_seg() + #pragma comment(linker, "/INCLUDE:__tls_used") + #pragma comment(linker, "/INCLUDE:__mi_tls_callback_pre") + #pragma comment(linker, "/INCLUDE:__mi_tls_callback_post") + #pragma data_seg(".CRT$XLB") + PIMAGE_TLS_CALLBACK _mi_tls_callback_pre[] = { &mi_win_main_attach }; + #pragma data_seg() + #pragma data_seg(".CRT$XLY") + PIMAGE_TLS_CALLBACK _mi_tls_callback_post[] = { &mi_win_main_detach }; + #pragma data_seg() #endif #if defined(__cplusplus) From 2b0d039cf3cf6df8b5269814344626e10565eb04 Mon Sep 17 00:00:00 2001 From: Daan Date: Wed, 23 Oct 2024 01:21:41 -0700 Subject: [PATCH 107/305] fix assertion check --- src/arena-abandon.c | 2 +- src/bitmap.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/arena-abandon.c b/src/arena-abandon.c index c40d3ce3..9c3356fc 100644 --- a/src/arena-abandon.c +++ b/src/arena-abandon.c @@ -271,7 +271,7 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_ if (segment != NULL) { //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); if (has_lock) { mi_lock_release(&arena->abandoned_visit_lock); } - previous->bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx + 1); // start at next one for the next iteration + previous->bitmap_idx = mi_bitmap_index_create_ex(field_idx, bit_idx + 1); // start at next one for the next iteration return segment; } } diff --git a/src/bitmap.h b/src/bitmap.h index a1e7686a..f8898935 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -35,9 +35,13 @@ typedef mi_bitmap_field_t* mi_bitmap_t; typedef size_t mi_bitmap_index_t; // Create a bit index. +static inline mi_bitmap_index_t mi_bitmap_index_create_ex(size_t idx, size_t bitidx) { + mi_assert_internal(bitidx <= MI_BITMAP_FIELD_BITS); + return (idx*MI_BITMAP_FIELD_BITS) + bitidx; +} static inline mi_bitmap_index_t mi_bitmap_index_create(size_t idx, size_t bitidx) { mi_assert_internal(bitidx < MI_BITMAP_FIELD_BITS); - return (idx*MI_BITMAP_FIELD_BITS) + bitidx; + return mi_bitmap_index_create_ex(idx,bitidx); } // Get the field index from a bit index. From ee92b337b9e0f68f28a5eb374e5852c5e60baee3 Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 24 Oct 2024 00:13:07 -0700 Subject: [PATCH 108/305] do not reclaim segments if free-ing from a thread with an already abandoned heap (issue #944) --- src/free.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/free.c b/src/free.c index f2e5f8e3..a85baa55 100644 --- a/src/free.c +++ b/src/free.c @@ -236,11 +236,12 @@ static void mi_decl_noinline mi_free_block_delayed_mt( mi_page_t* page, mi_block static void mi_decl_noinline mi_free_block_mt(mi_page_t* page, mi_segment_t* segment, mi_block_t* block) { // first see if the segment was abandoned and if we can reclaim it into our thread - if (mi_option_is_enabled(mi_option_abandoned_reclaim_on_free) && + if (_mi_option_get_fast(mi_option_abandoned_reclaim_on_free) != 0 && #if MI_HUGE_PAGE_ABANDON segment->page_kind != MI_PAGE_HUGE && #endif - mi_atomic_load_relaxed(&segment->thread_id) == 0) + mi_atomic_load_relaxed(&segment->thread_id) == 0 && // segment is abandoned? + mi_prim_get_default_heap() != (mi_heap_t*)&_mi_heap_empty) // and we did not already exit this thread (without this check, a fresh heap will be initalized (issue #944)) { // the segment is abandoned, try to reclaim it into our heap if (_mi_segment_attempt_reclaim(mi_heap_get_default(), segment)) { From 532904c85c23f777f29650eb48bd61f1115e2bab Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 24 Oct 2024 01:01:53 -0700 Subject: [PATCH 109/305] update mimalloc redirect to v1.2 to handle static destructors that free memory (issue #944) --- bin/mimalloc-redirect.dll | Bin 68096 -> 70144 bytes bin/mimalloc-redirect.lib | Bin 2874 -> 2874 bytes bin/mimalloc-redirect32.dll | Bin 41984 -> 47616 bytes bin/mimalloc-redirect32.lib | Bin 2928 -> 2928 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index a3a3591ff9b07edada16ad83ca1391963a126b2d..dec318976ca1b881bb5d165eef8d762533ed9b6f 100644 GIT binary patch delta 10362 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 A>i_@% delta 8766 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 delta 100 zcmdlbwo7b-1PjaM`aORp%dqTVQDo?=o}9&@Joz_^15;o1W?NQWMwavsuD>Sdu}wh8 lc5?6lWhdLRN=^1)7GiwV{%mH*$0`0RTALBn$um diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index 522723e5017b71b458afb4152bd6c7eec55e9e62..049c298189737481a44fbf45c1ed71ce86eb1d40 100644 GIT binary patch delta 8480 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 S8HbG{#!=%tMpSiUvi|{u)nG*c delta 6930 zcmb7JeOy#!zCULiWTa6JItnWCq9~HA&O0;1yr4418guVJVs^8F#CCkSN;tZ-!45XC z3l7|iKJG3R6}5Di%r?5PMjN%G7nSWp8?BUV;f6(Z5Hf11rkb4lea@U?c0c!zd-;66 z&pFTc_xij)bEut>)egv7Y734&R6F_B2UmL~oNoB^rMHFpr@f83Q@GfJR z*+TXECsRwbZ05o;(2#C%v&?F$QOYt_`O)+R$_kd5fq=R(k{m&Y)9Ys<^LG|=X^QB(kSU@Ni9mdqQYG2oh^E{>D? zWT|tIg5ao?{2LVZPyvz=sK>ic$=s~(*9#eD;>md^3SmC+yBHK3DEA3kIpI;DSU`(? z*(mOqgQA~G-=lhQYf+q~X6jTFHzlJuM2pi@uPF(|$0`)Xu_)$JGad;{Tv&|a?qw); zExj3K1~QuPQS!C9D88VsYZswdvjoNLL=;6(A*bapklGkkOa;U7a`JFYuDULp<<8aC zo<#roZM4F87rX>jX3v{U{HqU9L4EL`To;^->7^BNIw83`ZFUW75tM5g=D>=8Q!&dK z4$P&@5w77V)q9dw{6Y4&^f~!*RCw;N5Qwm`S;rK1SzR{CQ|w$sHP$$%8=W%&*G#S} z=|IL|WI|q6*i2DT=tzSPE*o6e0t*GEBouH?&vJsN{u+)@X`p0!R!QiH^I8LvCh9pm z4OEpuf|at#EFqmEE=7Z25q0A~!!`>31fkdoXx}0-HfK-L*I!2>{(gBhtD-=OvKY;D z^OwkuI5m5OB&d?RgK@bmdj|>Mv?{edM70%-&al5G%y?4+&X7CcQo=4=%yXgc^~w-C z>xeUqrmILWZuZSFRmd4VE1S%2b}1WOVX8?Zc;s|&axen^e&y~sei^Bqx1N2OoSBzN zJ8W{EjrDeC#qVR;4@oPxQ5ed{$Qb8lM~NokCz;+aX(p=4x$&n;BE|d{UkS~a$owu6 z`9V9^XWc`FhRO)8xoaa_s}an^JjSIw#;Lu(W?aZ)j8g*Yk+4|M{%{(JAB9Y59%0 zj7sLCQF9E`+C|H^k4UjbsN7#OBE%Y&l!pan=kQZ>qC{KUOuN0v6QU75`t*j@4oOBs zf>Fs3Ik_lvZ_@qHD;4y_<_$_A2csbeg^&Z1^+42mprIuEgYI2T9o=?gz<$Z3Uodg? z6GvjEFOTZIew8LB1`J98gVBINAz+_m-50g)YnZFv#EOml6>Vg($4z~`BKT59=T@&| z)hk#zdmEe>Qdgw@&tAhHDMda^O!RrEUCxa;^hi1MM04m7a_Ex0bw#~(H8{WXRKeI& zM?HM>iO`Dk&Q7X#-g%Nfnq4Q0noBy1`RS;%(b*bsp2Rxu#5!*+_O#s3=sEtRAmq;1 zS4Sd|E;u{ytPKi}x)I^gFeN;i6qQugl3YoiPg>;bs-k5r2KoNa**?>eJoy6<;xWl61qLFQenULj)()(M+)Dp{veM0pv% z^hVy7oW;7yGsy;a1$i&Ioa|VZG^cbGx{BfX<)m(zS+svH<;SwL?yXnihsfbGlj9kxIPjD^-3R<;|{X%#~2_Ze}+V zS*UcA=h8RGGE>QC>A#RYGfo~@-b9{Wu|lRyA+N0{j1`WSW#goImG?((mTPoQ`D><_ znwW_f=-@Yb(T~+1&~e0h#5b3W;iTZ*k%eh)vNm%xHjT>b-zN#HlVra4$(q$Ei?cxq zJEtBmfs(0WPd-&z^gg+Fwa>JaVFIqPK#~6N`wXLC=ng!(O|%#-rxwmpcXM+;-EIOU zGsPY+HNNLES)BE_A_hmDn?Jmy`%hUD58G#u-9C23&ljYi4(hkfq$skKu^K&gBoqRR4dDB3p9 zr(>vdG%ggqIBY~`q7NqLBcLlp^DpMtMLA(Z+cUsG_nbU#BH)~XAK?;q`Z6UO<#AZG z5xQ!{t62LjIZ%6JNg>JDrE8ql?Q7 zKmIPUugzck@Vi1<*kb472I4;h$?ezeCg{=RnHDAlhOzQp(zUj5P3jFMxbFn#;a2pG z6l$`}6Q=rD+Wfcgkj!?PtPghe|B9zfSXh*E+SjV^t$=6y98Bw$xI~f zm9xnzb)u~39pX^y$%R$RovQQB8DzvvVr*w{xy0pcmusepj&2F(x5i<&EJq`EIR$Q( z6ALLUUP{mf@|wkaT%lx=u373^4z&Q1c|gS++>eWa3U`X11aOH}U}VIr-bMwE<$k5O z7`+>*G5Y9yejG07xF9=GrT4a}#w~0bMgX%u94Mm3Q*;5qQ8*xTd#r~rv)RAVK1iB4 zL34G5<7wddy2nt%{;A$Xu4-1x)?Xt@+Dwi*J)h4e({pK03G)4C?V5NGby7S+og`2A zt`SF889FV2aJmJuM=z3a8&ufQ1-eUoDg zJtuG^&Fn^ciKI&(%O-dC>QyY8OkOwSupEgoTGM_#Og+-;Zwl?C4RYFFfrMg@{2=_c z50f&ZN_NW^Disrdqtn{G?g<6OvfDh|eWu@ga| zZxxMm^_$2()3Ov{UbvKgE6aE@=z6<8FVLvt_dV8Sm+&y3J7^lk{iSEKF^(J}VEu)8sb=oOCb6QgXaWe3nGtUNoI< zm;BKoArH99@Kl5JG*Ai6c2+c&o8LSms9*_99`YQgVi#A$Z@a;;of>vh3EdE0i%Q&l z!uN(YPnY1AbMvVX-zQw`5Hd(D2dIc9Cnn?ONB(g=ByEa~{uVl@_Y4Uku;0m}A>vO3 zkvQf#Cv1bBG01tFAXA=;!D@Igw<00Bsxf+TjJJB1Gt@-Fxhb-z-XO`==f z4(kfpzr4|1Zk?H(XvI`uyo;nRqoWvEXx&8iZ@fJ*?|+l!Z6cR8J}SF%j{Gb?Z)v`u zvLxVCp~q=r(On?2Fn<$yD}S2~$8uyPK0BaP2&Gae@w*F*N+^?rGFd3oP~sv}oItK@ zt<*}NN$BT=J%D=$a2sCmC&`rb9q5Cs@3!vKcc!qLaf6IdofBmYL-zyx0uxY$dK1tN zlyeNT7}y8I06D-J@Wa4Iz&F6$d%GXM;}n~|=9}*H;MLnU{GmFq|CJMaKB4(+v}`Xq zu(R^O_VTi_ePs8Yo4dR3TrWFzcSZO3-3s=m&1L)2bec4+TB{>p-E)=%ORumR@@!e5 zOp}E#F;9@*dk4DPcWhz1Gj@7q3QsG;RRj1wB%fZ7?**T2^(Y!Zw2EYlM0SAa5y>uz z41yRE$svgx1u-R(>J6gL84&V^qk%Yy@QP%GL^grw5Xmly z>;*9-l0y0^qD>^-64?tP2%yXA6oYsf7AvYT zyzsybfDvQV`GQuJO7SSeaX=D41=CSqRjSn>)PPkKxFriWi0yz!6y!;QY7lk6aZykz z3KSh6dH^A<0lbVzl_|W0rHY~rX#iABm4O#MkO%xA;VmFa0gouSo^Tb22A~aSK`Vk% zUOgcCfe|1G!L%fp1`!67k1<>Y1nr_AIRk_mpnxa0GI;zJp8-Z+q3a&TS3c?MP zi-LB^q83C8&;gWgLc2tPq7TF{AOxJki~I?OO9rUlF3CI(#CD)c6a+;9*9M|fB-5ON zn`*8X#DGYaO5`XAUL^A*G6X{29t~D2k}4I5G(ZgmL8c*Jq*tXX0I?0&3$#PPNP;>L zEtCYtAjlI1Tn~r=fHtN!N>;1JK!gC*ldu3eB(+ixq5yCM)Z%)#mV)pC4L~U@q~24t zgXjf@fgl89QoqcA;GPoQNP*QL3W2=<2hC|wJK;Ep9$*B>1Idu}yBC+`w+&7eGf5i|)}ZsD_U8_bPaNZ$6s-e>P_e$>kFZ*h}P#6RGS7 zS@^7G=^*=0UU%hw@6H|Gt-C6{2g~-lcK+-B$_E%Gjg&oWV3p)I&*pT$|7^DG*zFl) z-tTi`%2=j`#R;>V?XGyfRqi{W>CyaAb6RsjGp4E0{k!frx;9;h?xgNNbt(FK{loeZ z{bl_X{nz@4exBi=;UPo7aMbXK;R(ajhD=MI&1inCA)3Ev-qU1h@6+zlKCOLG`>OV=c2Ijk`;Jfhxt7zV>oRp4b$fIV z=zght48i}P>(^b-UD93Ac@1@j-x*?!zcl9NWLh4zj9LF-RobrDvg}%WuKg|h-|e5% zPxxwl+sC6@vqJwXz0%;$xj!e8^C#1wY0Ts_KVp6@_mVZoR%mOopR&Je|JHuU5pc9P zo_F*+e1CTEj_(}Q8a^1AdX4&4^&RRYjmhLP{fFsg(9X}|yusmiI&smozZa+AWOG;yXTQ;W%W+|+7nGbNdm&1vQg^J;U4xzpTb?lt$B z)fPQknr|tv^jU(I0n3nO*iw*Nm^++1k~^9^o?B`yw|cA<)+y_>b;cUDR@tg;wYEB2 zgH3K%*jwz!?XC89d$J?Vk>SX8bUIEtdg$C}!8*r7uQsXk)WQAge)XWbP~+BY(~M|F zF$u>tyrx|1(eBk&XuaBL?Tj|04Qm-)wXRmzpi}6TdQPv>C+UytTlH=F4t<&-!?4qpDfR6$K>6*IiA&!k<&tj_194b1_q|d z_AJtqx3Cq#l<5PNOpa%jnq0~r%Xuc!`Nc!1DznLg9Q80&(v#P7a6naVzRWR~2>=MW BA`Som delta 118 zcmew$_Caie84F7UkK4D&RxG<%6dC%eCu^~*PnKu3W9qBk9M5XV$Qe;K{r^!01_q|d z_AJtqx3Cq#l<5PNOpa%jnq0~r%ejdy_Sr+IDznLg9Q80&(v#P7a6naVzRWR~2>^ga BBijG~ From 3cba10e51060e2dd5399ea44b499d741ee58355b Mon Sep 17 00:00:00 2001 From: Daan Date: Sun, 27 Oct 2024 01:02:13 -0700 Subject: [PATCH 110/305] update mimalloc-redirect --- bin/mimalloc-redirect.dll | Bin 70144 -> 70656 bytes bin/mimalloc-redirect32.dll | Bin 47616 -> 47616 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index dec318976ca1b881bb5d165eef8d762533ed9b6f..ed001d64f7f70516577b3f3724b9a1279b73d51c 100644 GIT binary patch delta 6805 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 ZPiK8+EEo^=2K$5L_}SsKSfe52e*od*3grL* diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index 049c298189737481a44fbf45c1ed71ce86eb1d40..ec4ff1d521292a6fd1403d35c825e1cd1b060b3b 100644 GIT binary patch delta 5053 zcmZu#4^&fEntv}OBx-1aMuCbDOR!L}=Kudc)RI%TlKPdpYAbfq4m0Oj*t2PyZJBLG_jg~yv}boY z=ezHIzwgie?)QE7zDK$eqOOFfkI(4;X4#SHU(YMaU>K%_VXWlq4Q1pV_Ce9VKS{o1 zpAaqi1JR52uxBH0i4L%jHX9k{PVYPnCkrwBrvk%Qc^Ljnf`Kt(xFy1{Vg-it1`Npu zFl;Nr@Fg`{mQP*~=a?IoVZL62;RN+#VlgNwHl2lGNhSuCx*eg|EB9mA3>9)d?>*8b zsnJ%hW0hCB)?R0nOwdIcCa~xoC@_Eh0i$^L7gTT{+9ozcrzOLbA(ylBBkIf!)-EV_ zG0g6wkXM%BO@^{4a!}cGgzCLUnP8NCoj#{8rG!`Z3kwleT6$FG7FDhz<+8>lRAZ$# z-s??-dT1YtS}*x!;!Y~IhsqVntHsr&j6 zWMuljYoZ0z+nmlLrO%UbaVzOtxM#sk1FJmnVZa!4#Yy&}huAoAE_zx_QR*tQHZ7wWGh}cvf5&TD9T=F2xCL{llQ^Zo~)!bFmI1H()A99ycC^yf@&JbVT zYIY{lk=M@J6Of}sA+M4P`Q%lhT3PkI#T4udcE~f@mcUlf$O?Jo+`YwuyHWA8@5vdm zD>GN=O4%0c^Sq;Scd6Da*vNrDV5-N7cv1NoOkrc&~|{BAvp{OoUT zr2nw1D*o*fhUxVtgB?jmXb{D)7{-@lOvslERj^`|c_~q6N=W0fWuoUwNcXZ$ovIB8 zlL^d2bXTFwKv!19XWzSbFE}dh^~O=fYQ9>^Fanzhb|jcKsUdpjC{^_)B(r$-dS?yS zw)Xmx(~Gx;YLi=0$F04!$&hz87%hQNG1QhsCn<)iGOPJF?h39ILs3V(!&kXO;;%e_ zX7SBd@$3FTMRK&aQ3y&ELSL?-s!1I^wYA7l z(9Q(bg@Cpr^=oK#s+86I{FHfycLq75$+I$n`;nMXwxc%DCIK>?E94Y)nVtR|X2HuU zn)S1!N?wTmFDB~cIjn|Qm)k{R4GAnSW`9pkEMM1IMtkqDZ=#BS8MhT}QGVjT)3GLY z&^mH_2JSW?*4bdkEKQPcHn>-v%Et#nK2Qra$G?;^%V~u4pknhDo}d%rG62JLi!X zf0S-8G?`8Tf4DY=Gsfdu)R0vV-j>!-@v&PZyChfi%Ufh+NkLvcplRtE{)099=MjO3O6J^PQ5;nM4@wECuyTlyj( z{VNSp+226r$|vNrmFuK~pQL18sEveMDU0~a9$}^BRN<44$>6Hsf_lt_PEAY@_rn#U zwQ|6+m+K3pkUJwfh1TrfXCVHA~LKvt}_iEeyEHm!b5+Vc@zguaP# z2v?j*R%mlXEgun&_U8}0`5_hIvOuTLAT3ke-223T;blZ|?n81@`|Sf$bpG}SR5$m| zDdAuxgL_qsqMJ6W;^N{Y`48RUOl1$$GD(;IbG#Q`!J%&u)WnL5V+XDUO3^;m{yr++l``MKrf1?E z4BseVL~Y}6C*?#2jYn9u_P2By`sGqUTXKyUo0EmItNr_Ef<3<_o6I{!uiqf!<{(=@ zYAhDfAFqQkkf_Bay+C!s*NNErWDe8FDji-~n{<%96BTwZ>&;>sBh6Mft5fwtapIb= zBYJLp%8+V*H6IfY9LdD=kZ^}*`^%{2Z?2KswgOY!gZY(|74o3C=)H$Hmnts$RM@P- z&r#iQ%EvUl9WroX;^dX%driDx?#0hPagB7^b2_JJ-SO_=kBkX%z?H_I0O)5>IiXP& zrq<$k`?rD$Zl38qemNEUlvRA)PYiPb`qflIugFhR5{_qoG<5k(1iwm-FN8QZb%kpD zR%%&JMYIX~$H*#2!RobwCtUycr93GvMiE~=U6#HT{B@A?m4ZxuMUo^hI{HQDuabOc zzOyB_^nj{N_V$s5V-M_&~s-X$+q zlrL2ZD!Bht=mr{r9BnVdZJ=z7d|a`3A=*bwzS>|e#E1Mg)SAI7im3;2yFt%jf8l>pKG?ivHooCTaP#7d3Qz{o;fULEs<}YA7(RjTT02c`ZG;r?Us76gn64$s>laT_-fk~mZ-sL1#VzxSmFd%32sPIhnZi%8=AwC0Jv^} zJKhqO90C_6mv;?G1~3~D@R}FGk{jS+lwICwcZ-@242Tf-8~MMmkQ96KmT zIq-ggAE!LKkDP5S#D_JtJOkO7U>OgDNh}~{lY*v}d>wdIq8eh9MslQmDKQ4Z5)ND) zxFJacW=(XK-Huro=n#n3Q%f%QoX+kCHvk$;qj7jUogD=?2AW8toS@5tOHgDu<)NIS z^Ht#TL1n|_?#uryb7EQv!vBC5Wc8S|%rV`V9GheMF&RuV*&~?T0Nn)r7}^ZDS&F=q zLQ|nB!Kpz;P~SR685KgS1h)~?0*V5SQ&ial?ilDKl>jBto-_F)V8%dnAtjf3-ULt2 z7=rH4p8^w4E3~8)n14ap<`m>$)FA31mR7KWr^k$XkW_%FAywT&DnDlXKz$&p-nU-J z%s}=T03)E$v_ROLY62V&N~Y2Nw7M$y5~C~uIYISLU^i)jtOh_6h^AZBjY$}E0Yq0D zoHM@(AOTX2qy*8lAj=4#JPoSJ`Ovv64qSa2sTYs{xUMu(E+Bp2!fB+7BH3ra4THu& zQ6JJnUJIVij)9AV#Q(}D`++h7nh&l7WCg{5mQysV5?noq#@$7cBU-Vl9Y7!G45%O5 z9#6+jxW5%=#Q^dkYLQCcEI9eQSRM4!EUByjI8YNP3O}*A{T~7_0805tuQ~=`3MBqF zWDJ_|w6>}YKqaUJR1T0q@gtX?X<%P3Kbmv&RQ`frzQ8i4Kw~ekD2Rz{JXP_3u-K^+ z3m1v215J-L1|Dr|ZEb80aE+Tu`{@mlFHiqb)_L7FWWVZixEU?O;Fl7H(S4|6^fAM? z2D$MoW2s4Ra+p3geQx^36tVW&7dZ|%l8*DP)9xGYr#(zL!#H8GTI1)_DTomkU8bfQRkSm%hm1barL>J?s9j9yV5=DPP!S7*dy~?@C`l{TPl@6_(oc4^CWTAfu_uB*`Tx*1(UmqZCp>Id|L`eFTuzTVJa$TzBu z8e^I9rg733GxEk`rsJlt>7*O=?f8_o4*xkYIiv)r(ZTW(sqtv%L5)??OkTZOIC zmb5W;nSIzkVjr~!9PN%Sht_FyTAfa3xpVW3Gww_{XPrssfa{EF&~?Ez>}qiP-7Rjl zN8>5+lzFtCNl(l(<(cs?gQ-#+*M_zI+LPJ=ZH=x@w^3KGYtSk6Dt*5GhJIW>p}(o0 V)b|(;8Tt&z495+TFT$UR{s)yhnqmL| delta 4685 zcmZu!4^&&%d4KOAAvuU5*|L#?3<6{uJ4*c|J)wV3e{fJo9Fz!#5^DP-N{T(jAsM!X zLsK}GCp;rR$YkHFhbD9fH(o}A*N}=D{3osK!?B6uW^#jj+(pUM9JW1IoK9<%MO!tq z?>@;%cQ(%X?!CX?_uYHH@4Mf&@9wK^KVtqyuJ~d&&AMaOwfExLGz8x z(A+XWqi%ra1a3aV)5dDhK~Z({k{ZT;-U!VDbUhPUtq=YM8C+G$cX1LKvxv% zxTbuFvc3SGBMt32% zbl(PS@sKAQ_2f8j&hAwm)*b^-&?TwEQdH$nj+}rcN4)pA^#bG1bDnIO2Y9^R$Vsf_ z{Mj;p{-o#L2sn-CHTz81lmG`0QJHOmJ14!;5n)DgnaEW#Dy%0cOG$wEHpJ6wUKUZ| z8|a%~i-D8z%-7zhD)4IeZR)o_gOZ{{D7N-Ug|3H`AOA&&i8yGaSht;|5xZ`;2(x&p zazD2coQk6J>*^`!ezopt=;BtTi-PszuWZ;#l5G43)r}<9UROOVpJO?KOsO_9 zqz-vE?jUvXp^XD1&43<`i1WyOoLAPt`K6t!>oFON49Uv+H^5xMqLTB-e5>new7I6S zsyJzF#DNE72=zYjDAJUdD~bdW65o9tPW-x-)X#GsJ|oJUK^?L>I1&YN*L?$y;6&XPvI_mE?jcfw z{;_T^If~4hr;lnPLrNh4<^2F;9sKjlcqdWRvl1CvA^Ii8#N8PjoL}AvLHYQDf?gW+ zWFte_qCN(CVJRu+RYJ5;1>AsQ`9{4whn>om?PQ~#WzM@CxuS}C(-)-#v4^K&$CJgHHVp)K-ID``$gF`=!I#RP z6SO&do9b`?IL@;Ng3g!8Vo`63^QR!OG9UlFU*p6};fU=}1cDFRsQ(V+j`QBx&na8> z3rQ$$qmFu)s^)M~mhP{VJLDHOMUzqfreB4YOQj-MvDwAYY?q%A_vhowe6Jb zN%WSs)`2TZD5I~|KTDkHh>S-FXCw11^Dn8HTl6xz8BX|pA5s(`hgly7Wo;oj;hyk@!1pbT&J_{Zo! zxBU(Id3=2P2c*RCE4;M~Kd30IGfLX9$y;~OMcreP*qx%TemfI)Kl~^u31j8lFH!94 zk%~zebAAYT={Bm}(Mm;cqn;i06;qhTHTc|Z6x-2GRozCP?x=lW7Sr&k@)=Z4Td8wP zsD(Zw2`=Fc@M~UuTEB_%EulL7%MB+!!YtIsGL8=JiSPb%9L)VCIPg~=p?Ur98?+~2 z{MWz0wyL{tLoVS2BHvcRCHg*qs`Kkv^mD^lxeuHD3kn$Dq$+M9F|%Daff>auVUyq# z0HIhvNeaY>XEivBId8s$Ka)gznB9^Dp1>v1WyWr370g6c=NFH^AKC`B(iu!*^%KSE z2guS$bb#PJ0(aWxgXgn49y6UHHS!PfF8Fu9mV+y|Qv|U|IYnpiGEQyXhp5H;A{F^L znlVSndx)`^$!q8xGlM2A4oME14BkY`mOrg_!>^6qBkh;WkarV8?9ynZyC?p*)k*5R zM!<0Ph7b?FBwjhEJl4r41P0!>TxKpZlq32T!Cq|n<_+|ot=1%W!T7D>EXYFDdCw}i zSyOf1tAtRif-!76SX?7hyc(XIaFu-aO6u!3&@=Yxqgps1{J!%C-xs!r6|_MH$efHk<#F5I6;el^h%3<~SYef;X;>Z+>v z>S==mcxD)@aM6X|N0n^tjuBxcX(#_%Fa^u1^9k@zjkm==_Q7$`^EzP{*)=hXcC(Yz zsYO&^)siqi<7XC8ouiR@bTQuQ$dy;O310&n{`dDnTMv4o^{MLi|4-N6gWhX>gIf9- z+U;@I_ym&&Igb)*0DB;VT9?Aj_w~eo;#t2IefU%}@^vrQ!N>2P!4VVi$w~x3e1}2y zzySV07jNv=m&t$g!K(VV)|Qqx<}WGhbsv8b@7XgZBANK_o|z}h4BH6w_s{O44BJpk z_Z({f)_7dn6A($=vxK}02RL#@wGh=%(UcqCo`Zb=xWVU)!qMFB>#c|xuN`N}IDAPb1Q z#1_5s0SbVGKxTFk^0cu3D4+?H;9?h2l>16UANy z7}q$|z@%CWfG!!tN(OGgxX=ZIb^w8r0pTmIFaQ{rIW~|E19%Mtz^q~l2A4sSAUL`i z)N*oKu>z<7BDz>)i_s|oHG!}tHX+z{0}6r+f`q*g3udLS0XhdFY_b4@6i5yPZ<53& z$TuviWG;bYAec>KwlV}LTw>ffQONzgSO&yoi40@%6fG*B1tM_?efsi`0aYderAj7~ zB@@L85P1;kWypLxoEAD3omOZ7(IBlL31Bq>yBAOpWB`PKI0Bfh90fFq8Tgw7<{ia6 zpd`o&NCND#LKbB2!8#yKAlSB;F$`g(tqgCzL!G2eb2?y)4cTPcdTtTvt!yp(D1)K4#T+4 zs53smJj!%3dzjCed(2wXN9G?|jkdqFsqMGe4;(9wSDa6{_PY99w_RZGCI}X~?euQL ze;c1-dYN;kUz+}4s%idi^K|n}^FK5%H{WfRnm3sn%#WF0Fn`-@v2?p$bX{|O?1EZ7 zN@!s6MfxLJr#I*=dZ)fszf14aKdIlVe@>78&vk=-%6iVaXzj5DZNoN=U2AvSQ}(pI zU>|2E*m<_g(d`I1I~OB}3FunsHoAu<^dh}Re_5ZL@&$Ed^NWSwqjtFz6SbLO1|C*cyg zW?ZwbdDmrE0y{TJ5c5Z&@1^_b0Xj?%(@lDvp3$>$Cd2zM!8poHgt<28=z% zUZaXpGa9CeSz_)mDQ208nO-xEn5tdC45M3|mGmtkrF8 zv*xV@tH?HMo3|xwefE%jz&>aX+jVS!W*OGPvMkT8uvs?8=Gn83DaVW>;Oub*oxRRJ zr`n})X Date: Mon, 28 Oct 2024 02:06:58 +0000 Subject: [PATCH 111/305] fix build error on linux --- src/arena-abandon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arena-abandon.c b/src/arena-abandon.c index 9c3356fc..48e37794 100644 --- a/src/arena-abandon.c +++ b/src/arena-abandon.c @@ -148,7 +148,7 @@ static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { void _mi_arena_segment_mark_abandoned(mi_segment_t* segment) { mi_assert_internal(segment->used == segment->abandoned); - mi_atomic_store_release(&segment->thread_id, 0); // mark as abandoned for multi-thread free's + mi_atomic_store_release(&segment->thread_id, (uintptr_t)0); // mark as abandoned for multi-thread free's if mi_unlikely(segment->memid.memkind != MI_MEM_ARENA) { mi_arena_segment_os_mark_abandoned(segment); return; From f126b503822addadbdfcc82f940c5a086d3f75dc Mon Sep 17 00:00:00 2001 From: Daan Date: Sun, 27 Oct 2024 21:10:46 -0700 Subject: [PATCH 112/305] update comments, set constructor priority to 101 on macOS --- src/prim/osx/alloc-override-zone.c | 4 ++-- src/prim/prim.c | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/prim/osx/alloc-override-zone.c b/src/prim/osx/alloc-override-zone.c index 1515b886..d3af170d 100644 --- a/src/prim/osx/alloc-override-zone.c +++ b/src/prim/osx/alloc-override-zone.c @@ -418,9 +418,9 @@ static inline malloc_zone_t* mi_get_default_zone(void) } #if defined(__clang__) -__attribute__((constructor(0))) +__attribute__((constructor(101))) // highest priority #else -__attribute__((constructor)) // seems not supported by g++-11 on the M1 +__attribute__((constructor)) // priority level is not supported by gcc #endif __attribute__((used)) static void _mi_macos_override_malloc(void) { diff --git a/src/prim/prim.c b/src/prim/prim.c index a4d3814f..2002853f 100644 --- a/src/prim/prim.c +++ b/src/prim/prim.c @@ -46,6 +46,7 @@ terms of the MIT license. A copy of the license can be found in the file } #elif defined(__cplusplus) // C++: use static initialization to detect process start/end + // This is not guaranteed to be first/last but the best we can generally do? struct mi_init_done_t { mi_init_done_t() { _mi_process_load(); @@ -55,15 +56,6 @@ terms of the MIT license. A copy of the license can be found in the file } }; static mi_init_done_t mi_init_done; - /* - extern mi_heap_t _mi_heap_main; - static bool mi_process_attach(void) { - _mi_process_load(); - atexit(&_mi_process_done); - return (_mi_heap_main.thread_id != 0); - } - static bool mi_initialized = mi_process_attach(); - */ #else #pragma message("define a way to call _mi_process_load/done on your platform") #endif From 5f3593333107066434e77177e0e79d56aba5189d Mon Sep 17 00:00:00 2001 From: Daan Date: Sun, 27 Oct 2024 21:39:07 -0700 Subject: [PATCH 113/305] add 0 byte to canary to prevent spurious read overflow to read the canary (issue #951, pr #953) --- include/mimalloc/internal.h | 10 ++++++++++ src/alloc.c | 2 +- src/free.c | 2 +- test/main-override-static.c | 13 ++++++++++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 63a1e6f0..82e8c766 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -667,6 +667,16 @@ static inline mi_encoded_t mi_ptr_encode(const void* null, const void* p, const return mi_rotl(x ^ keys[1], keys[0]) + keys[0]; } +static inline uint32_t mi_ptr_encode_canary(const void* null, const void* p, const uintptr_t* keys) { + const uint32_t x = (uint32_t)(mi_ptr_encode(null,p,keys)); + // make the lowest byte 0 to prevent spurious read overflows which could be a security issue (issue #951) + #ifdef MI_BIG_ENDIAN + return (x & 0x00FFFFFF); + #else + return (x & 0xFFFFFF00); + #endif +} + static inline mi_block_t* mi_block_nextx( const void* null, const mi_block_t* block, const uintptr_t* keys ) { mi_track_mem_defined(block,sizeof(mi_block_t)); mi_block_t* next; diff --git a/src/alloc.c b/src/alloc.c index ca60c11a..119dfe75 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -99,7 +99,7 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_ mi_assert_internal(delta >= 0 && mi_page_usable_block_size(page) >= (size - MI_PADDING_SIZE + delta)); #endif mi_track_mem_defined(padding,sizeof(mi_padding_t)); // note: re-enable since mi_page_usable_block_size may set noaccess - padding->canary = (uint32_t)(mi_ptr_encode(page,block,page->keys)); + padding->canary = mi_ptr_encode_canary(page,block,page->keys); padding->delta = (uint32_t)(delta); #if MI_PADDING_CHECK if (!mi_page_is_huge(page)) { diff --git a/src/free.c b/src/free.c index a85baa55..046a34e2 100644 --- a/src/free.c +++ b/src/free.c @@ -414,7 +414,7 @@ static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* bloc uintptr_t keys[2]; keys[0] = page->keys[0]; keys[1] = page->keys[1]; - bool ok = ((uint32_t)mi_ptr_encode(page,block,keys) == canary && *delta <= *bsize); + bool ok = (mi_ptr_encode_canary(page,block,keys) == canary && *delta <= *bsize); mi_track_mem_noaccess(padding,sizeof(mi_padding_t)); return ok; } diff --git a/test/main-override-static.c b/test/main-override-static.c index 1ac9bf87..4ad76d6a 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -19,6 +19,7 @@ static void test_reserved(void); static void negative_stat(void); static void alloc_huge(void); static void test_heap_walk(void); +static void test_canary_leak(void); // static void test_large_pages(void); @@ -31,7 +32,8 @@ int main() { // double_free2(); // corrupt_free(); // block_overflow1(); - block_overflow2(); + // block_overflow2(); + test_canary_leak(); // test_aslr(); // invalid_free(); // test_reserved(); @@ -226,6 +228,15 @@ static void test_heap_walk(void) { mi_heap_visit_blocks(heap, true, &test_visit, NULL); } +static void test_canary_leak(void) { + char* p = mi_mallocn_tp(char,23); + for(int i = 0; i < 23; i++) { + p[i] = '0'+i; + } + puts(p); + free(p); +} + // Experiment with huge OS pages #if 0 From b3828bba9e983e4a61cc82b1acc9965f7bb15add Mon Sep 17 00:00:00 2001 From: Daan Date: Sun, 27 Oct 2024 21:58:20 -0700 Subject: [PATCH 114/305] disable aligned hinting or SV39 mmu's, issue #939, and pr #949 --- CMakeLists.txt | 11 +++++++++++ src/os.c | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0aa59b0..4729e5b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -319,6 +319,17 @@ if(MI_WIN_USE_FLS) list(APPEND mi_defines MI_WIN_USE_FLS=1) endif() + + # Check /proc/cpuinfo for an SV39 MMU and define a constant if one is + # found. We will want to skip the aligned hinting in that case. Issue #939, #949 + if (EXISTS /proc/cpuinfo) + file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$") + if (mi_sv39_mmu) + MESSAGE( STATUS "Disable aligned hints (SV39 MMU detected)" ) + list(APPEND mi_defines MI_NO_ALIGNED_HINT=1) + endif() + endif() + # On Haiku use `-DCMAKE_INSTALL_PREFIX` instead, issue #788 # if(CMAKE_SYSTEM_NAME MATCHES "Haiku") # SET(CMAKE_INSTALL_LIBDIR ~/config/non-packaged/lib) diff --git a/src/os.c b/src/os.c index 4babd8da..4b9d6125 100644 --- a/src/os.c +++ b/src/os.c @@ -92,8 +92,9 @@ static void* mi_align_down_ptr(void* p, size_t alignment) { -------------------------------------------------------------- */ // On 64-bit systems, we can do efficient aligned allocation by using -// the 2TiB to 30TiB area to allocate those. -#if (MI_INTPTR_SIZE >= 8) +// the 2TiB to 30TiB area to allocate those. We assume we have +// at least 48 bits of virtual address space on 64-bit systems (but see issue #939) +#if (MI_INTPTR_SIZE >= 8) && !defined(MI_NO_ALIGNED_HINT) static mi_decl_cache_align _Atomic(uintptr_t)aligned_base; // Return a MI_SEGMENT_SIZE aligned address that is probably available. @@ -239,7 +240,7 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit if (!(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0))) return NULL; size = _mi_align_up(size, _mi_os_page_size()); - // try first with a hint (this will be aligned directly on Win 10+ or BSD) + // try first with a requested alignment hint (this will usually be aligned directly on Win 10+ or BSD) void* p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero, stats); if (p == NULL) return NULL; From eda16d7c918b3f172de95bf0453edde6d249a321 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 29 Oct 2024 20:07:35 -0700 Subject: [PATCH 115/305] remove wrong assertion --- src/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.c b/src/options.c index c55e63b1..ed1cf921 100644 --- a/src/options.c +++ b/src/options.c @@ -63,6 +63,7 @@ typedef struct mi_option_desc_s { #define MI_DEFAULT_ARENA_EAGER_COMMIT 2 #endif +// in KiB #ifndef MI_DEFAULT_ARENA_RESERVE #if (MI_INTPTR_SIZE>4) #define MI_DEFAULT_ARENA_RESERVE 1024L*1024L @@ -197,7 +198,6 @@ mi_decl_nodiscard long mi_option_get_clamp(mi_option_t option, long min, long ma } mi_decl_nodiscard size_t mi_option_get_size(mi_option_t option) { - mi_assert_internal(mi_option_has_size_in_kib(option)); const long x = mi_option_get(option); size_t size = (x < 0 ? 0 : (size_t)x); if (mi_option_has_size_in_kib(option)) { From b5ae6fc555749e141d066987307d261f4d31a03a Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 29 Oct 2024 20:08:36 -0700 Subject: [PATCH 116/305] remove wrong assertion --- src/options.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/options.c b/src/options.c index 76d2cf82..cc39dd6d 100644 --- a/src/options.c +++ b/src/options.c @@ -196,7 +196,6 @@ mi_decl_nodiscard long mi_option_get_clamp(mi_option_t option, long min, long ma } mi_decl_nodiscard size_t mi_option_get_size(mi_option_t option) { - mi_assert_internal(mi_option_has_size_in_kib(option)); const long x = mi_option_get(option); size_t size = (x < 0 ? 0 : (size_t)x); if (mi_option_has_size_in_kib(option)) { From e2f4fe647e8aff4603a7d5119b8639fd1a47c8a6 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 29 Oct 2024 22:23:21 -0700 Subject: [PATCH 117/305] update test file --- test/main-override.cpp | 91 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index 50eb0267..9c47d3a1 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -11,7 +11,7 @@ #include #include -#include +//#include #include #ifdef _WIN32 @@ -38,15 +38,17 @@ static void strdup_test(); // issue #445 static void heap_thread_free_huge(); static void test_std_string(); // issue #697 static void test_thread_local(); // issue #944 - +// static void test_mixed0(); // issue #942 +static void test_mixed1(); // issue #942 static void test_stl_allocators(); int main() { // mi_stats_reset(); // ignore earlier allocations + test_mixed1(); //test_std_string(); - test_thread_local(); + //test_thread_local(); // heap_thread_free_huge(); /* heap_thread_free_large(); @@ -179,6 +181,89 @@ static void test_stl_allocators() { #endif } +#if 0 +#include +#include +#include +#include +#include +#include + +static void test_mixed0() { + std::vector> numbers(1024 * 1024 * 100); + std::vector threads(1); + + std::atomic index{}; + + auto start = std::chrono::system_clock::now(); + + for (auto& thread : threads) { + thread = std::thread{[&index, &numbers]() { + while (true) { + auto i = index.fetch_add(1, std::memory_order_relaxed); + if (i >= numbers.size()) return; + + numbers[i] = std::make_unique(i); + } + }}; + } + + for (auto& thread : threads) thread.join(); + + auto end = std::chrono::system_clock::now(); + + auto duration = + std::chrono::duration_cast(end - start); + std::cout << "Running on " << threads.size() << " threads took " << duration + << std::endl; +} +#endif + +void asd() { + void* p = malloc(128); + free(p); +} +static void test_mixed1() { + std::thread thread(asd); + thread.join(); +} + +#if 0 +// issue #691 +static char* cptr; + +static void* thread1_allocate() +{ + cptr = mi_calloc_tp(char,22085632); + return NULL; +} + +static void* thread2_free() +{ + assert(cptr); + mi_free(cptr); + cptr = NULL; + return NULL; +} + +static void test_large_migrate(void) { + auto t1 = std::thread(thread1_allocate); + t1.join(); + auto t2 = std::thread(thread2_free); + t2.join(); + /* + pthread_t thread1, thread2; + + pthread_create(&thread1, NULL, &thread1_allocate, NULL); + pthread_join(thread1, NULL); + + pthread_create(&thread2, NULL, &thread2_free, NULL); + pthread_join(thread2, NULL); + */ + return; +} +#endif + // issue 445 static void strdup_test() { #ifdef _MSC_VER From 4f46cf7d5a0f7cbd30d0048babd3e67a4226ee53 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 29 Oct 2024 22:40:58 -0700 Subject: [PATCH 118/305] ensure we dont reclaim a segment on a free if that would go above the target segment count --- src/segment.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/segment.c b/src/segment.c index 3d411f9c..66ac4bf7 100644 --- a/src/segment.c +++ b/src/segment.c @@ -1261,6 +1261,8 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { if (mi_atomic_load_relaxed(&segment->thread_id) != 0) return false; // it is not abandoned if (segment->subproc != heap->tld->segments.subproc) return false; // only reclaim within the same subprocess if (!_mi_heap_memid_is_suitable(heap,segment->memid)) return false; // don't reclaim between exclusive and non-exclusive arena's + const long target = _mi_option_get_fast(mi_option_target_segments_per_thread); + if (target > 0 && (size_t)target <= heap->tld->segments.count) return false; // don't reclaim if going above the target count // don't reclaim more from a `free` call than half the current segments // this is to prevent a pure free-ing thread to start owning too many segments // (but not for out-of-arena segments as that is the main way to be reclaimed for those) From 826425d5ab84f93dc8970ecea9f942d0e32689a0 Mon Sep 17 00:00:00 2001 From: Daan Date: Sat, 2 Nov 2024 06:24:28 -0700 Subject: [PATCH 119/305] fix merge error, issue #955 --- test/main-override-static.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/main-override-static.c b/test/main-override-static.c index 07af1090..b2b6ee20 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -20,12 +20,9 @@ static void test_reserved(void); static void negative_stat(void); static void alloc_huge(void); static void test_heap_walk(void); -<<<<<<< HEAD static void test_heap_arena(void); static void test_align(void); -======= static void test_canary_leak(void); ->>>>>>> dev // static void test_large_pages(void); int main() { From 54940a6a65d28c0d6499490899f6d420b3bb7e24 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 5 Nov 2024 02:07:45 -0800 Subject: [PATCH 120/305] update mimalloc-redirect to potentially fix issue #957 --- bin/mimalloc-redirect.dll | Bin 70656 -> 70656 bytes bin/mimalloc-redirect32.dll | Bin 47616 -> 48128 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index ed001d64f7f70516577b3f3724b9a1279b73d51c..4702fec0175e66168151f1d995a6148a0e69a1eb 100644 GIT binary patch delta 5842 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 F{}q3uKPUqdCqg5 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 Y3ykCX66}xV2zINK<^5RoS|APm7ZjQ+JOBUy diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index ec4ff1d521292a6fd1403d35c825e1cd1b060b3b..17c0555027cd73317e893549e9831235c35d4d83 100644 GIT binary patch delta 3611 zcmY)x3s6&6_T6VNk;d{+zA6wtf+%W!k35J9vZj?Tu}Ma(R$J+4HAS>kq1sUj8d1VC z7ChQzMt6r*XUYt=rOj6AryZYwZwqaB6hQic(r`=tyxM$$sJEkp{3 zYZ3I3Y2;;yV$(|MbIz_K{B=c zH)?rF*c^lkg5Xvhf<7w9Q`5PWCQ@3|vk2x=`vtKGUW!L>hn~3>Mc|XzZ=fn9CdP

    xmre(Uhf(;I)85s}9yaEqM|7)j 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 Date: Sat, 16 Nov 2024 09:38:26 +0000 Subject: [PATCH 121/305] _mi_memcpy/_mi_memzero: tighten criteria for intrinsics for windows. FSRM is better used for buffer <= 128 bytes and ERMS, if supported for larger chunks. --- include/mimalloc/internal.h | 5 +++-- src/init.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 82e8c766..71de25ad 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -911,8 +911,9 @@ static inline size_t mi_bsr(uintptr_t x) { #if !MI_TRACK_ENABLED && defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) #include extern bool _mi_cpu_has_fsrm; +extern bool _mi_cpu_has_erms; static inline void _mi_memcpy(void* dst, const void* src, size_t n) { - if (_mi_cpu_has_fsrm) { + if ((_mi_cpu_has_fsrm && n <= 128) || (_mi_cpu_has_erms && n > 128)) { __movsb((unsigned char*)dst, (const unsigned char*)src, n); } else { @@ -920,7 +921,7 @@ static inline void _mi_memcpy(void* dst, const void* src, size_t n) { } } static inline void _mi_memzero(void* dst, size_t n) { - if (_mi_cpu_has_fsrm) { + if ((_mi_cpu_has_fsrm && n <= 128) || (_mi_cpu_has_erms && n > 128)) { __stosb((unsigned char*)dst, 0, n); } else { diff --git a/src/init.c b/src/init.c index 75458a1f..e25abd98 100644 --- a/src/init.c +++ b/src/init.c @@ -543,12 +543,15 @@ void _mi_process_load(void) { #if defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64)) #include mi_decl_cache_align bool _mi_cpu_has_fsrm = false; +mi_decl_cache_align bool _mi_cpu_has_erms = false; static void mi_detect_cpu_features(void) { - // FSRM for fast rep movsb support (AMD Zen3+ (~2020) or Intel Ice Lake+ (~2017)) + // FSRM for fast short rep movsb/stosb support (AMD Zen3+ (~2020) or Intel Ice Lake+ (~2017)) + // EMRS for fast enhanced rep movsb/stosb support int32_t cpu_info[4]; __cpuid(cpu_info, 7); _mi_cpu_has_fsrm = ((cpu_info[3] & (1 << 4)) != 0); // bit 4 of EDX : see + _mi_cpu_has_erms = ((cpu_info[2] & (1 << 9)) != 0); // bit 9 of ECX : see } #else static void mi_detect_cpu_features(void) { From b27d154ffda8e411a29d7267826ccf623f18cc41 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 16 Nov 2024 15:37:08 -0800 Subject: [PATCH 122/305] add virtual address bits and physical memory to the mem config --- CMakeLists.txt | 8 ++++---- include/mimalloc/prim.h | 2 ++ src/options.c | 25 ++++++++++++++++--------- src/os.c | 40 +++++++++++++++++++++++++++++----------- src/prim/unix/prim.c | 6 ++++++ src/prim/windows/prim.c | 12 ++++++++++++ 6 files changed, 69 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4729e5b5..87837026 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -320,13 +320,13 @@ if(MI_WIN_USE_FLS) endif() - # Check /proc/cpuinfo for an SV39 MMU and define a constant if one is - # found. We will want to skip the aligned hinting in that case. Issue #939, #949 + # Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits. + # (this will skip the aligned hinting in that case. Issue #939, #949) if (EXISTS /proc/cpuinfo) file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$") if (mi_sv39_mmu) - MESSAGE( STATUS "Disable aligned hints (SV39 MMU detected)" ) - list(APPEND mi_defines MI_NO_ALIGNED_HINT=1) + MESSAGE( STATUS "Set virtual address bits to 39 (SV39 MMU detected)" ) + list(APPEND mi_defines MI_DEFAULT_VIRTUAL_ADDRESS_BITS=39) endif() endif() diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index 640c966f..fb2a9434 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -25,6 +25,8 @@ typedef struct mi_os_mem_config_s { size_t page_size; // default to 4KiB size_t large_page_size; // 0 if not supported, usually 2MiB (4MiB on Windows) size_t alloc_granularity; // smallest allocation size (usually 4KiB, on Windows 64KiB) + size_t physical_memory; // physical memory size + size_t virtual_address_bits; // usually 48 or 56 bits on 64-bit systems. (used to determine secure randomization) bool has_overcommit; // can we reserve more memory than can be actually committed? bool has_partial_free; // can allocated blocks be freed partially? (true for mmap, false for VirtualAlloc) bool has_virtual_reserve; // supports virtual address space reservation? (if true we can reserve virtual address space without using commit or physical memory) diff --git a/src/options.c b/src/options.c index cc39dd6d..9ddf86ba 100644 --- a/src/options.c +++ b/src/options.c @@ -47,7 +47,9 @@ typedef struct mi_option_desc_s { #define MI_OPTION(opt) mi_option_##opt, #opt, NULL #define MI_OPTION_LEGACY(opt,legacy) mi_option_##opt, #opt, #legacy -// Some options can be set at build time for statically linked libraries (use `-DMI_EXTRA_CPPDEFS="opt1=val1;opt2=val2"`) +// Some options can be set at build time for statically linked libraries +// (use `-DMI_EXTRA_CPPDEFS="opt1=val1;opt2=val2"`) +// // This is useful if we cannot pass them as environment variables // (and setting them programmatically would be too late) @@ -99,14 +101,19 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(show_stats) }, { MI_DEFAULT_VERBOSE, UNINIT, MI_OPTION(verbose) }, - // the following options are experimental and not all combinations make sense. - { MI_DEFAULT_EAGER_COMMIT, UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`) - { MI_DEFAULT_ARENA_EAGER_COMMIT, UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux) + // some of the following options are experimental and not all combinations are allowed. + { MI_DEFAULT_EAGER_COMMIT, + UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`) + { MI_DEFAULT_ARENA_EAGER_COMMIT, + UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux) { 1, UNINIT, MI_OPTION_LEGACY(purge_decommits,reset_decommits) }, // purge decommits memory (instead of reset) (note: on linux this uses MADV_DONTNEED for decommit) - { MI_DEFAULT_ALLOW_LARGE_OS_PAGES, UNINIT, MI_OPTION_LEGACY(allow_large_os_pages,large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's - { MI_DEFAULT_RESERVE_HUGE_OS_PAGES, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages + { MI_DEFAULT_ALLOW_LARGE_OS_PAGES, + UNINIT, MI_OPTION_LEGACY(allow_large_os_pages,large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's + { MI_DEFAULT_RESERVE_HUGE_OS_PAGES, + UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages {-1, UNINIT, MI_OPTION(reserve_huge_os_pages_at) }, // reserve huge pages at node N - { MI_DEFAULT_RESERVE_OS_MEMORY, UNINIT, MI_OPTION(reserve_os_memory) }, // reserve N KiB OS memory in advance (use `option_get_size`) + { MI_DEFAULT_RESERVE_OS_MEMORY, + UNINIT, MI_OPTION(reserve_os_memory) }, // reserve N KiB OS memory in advance (use `option_get_size`) { 0, UNINIT, MI_OPTION(deprecated_segment_cache) }, // cache N segments per thread { 0, UNINIT, MI_OPTION(deprecated_page_reset) }, // reset page memory on free { 0, UNINIT, MI_OPTION(abandoned_page_purge) }, // purge free page memory when a thread terminates @@ -124,11 +131,11 @@ static mi_option_desc_t options[_mi_option_last] = { 32, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output { 10, UNINIT, MI_OPTION(max_segment_reclaim)}, // max. percentage of the abandoned segments to be reclaimed per try. { 0, UNINIT, MI_OPTION(destroy_on_exit)}, // release all OS memory on process exit; careful with dangling pointer or after-exit frees! - { MI_DEFAULT_ARENA_RESERVE, UNINIT, MI_OPTION(arena_reserve) }, // reserve memory N KiB at a time (=1GiB) (use `option_get_size`) + { MI_DEFAULT_ARENA_RESERVE, UNINIT, MI_OPTION(arena_reserve) }, // reserve memory N KiB at a time (=1GiB) (use `option_get_size`) { 10, UNINIT, MI_OPTION(arena_purge_mult) }, // purge delay multiplier for arena's { 1, UNINIT, MI_OPTION_LEGACY(purge_extend_delay, decommit_extend_delay) }, { 1, UNINIT, MI_OPTION(abandoned_reclaim_on_free) },// reclaim an abandoned segment on a free - { MI_DEFAULT_DISALLOW_ARENA_ALLOC, UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) + { MI_DEFAULT_DISALLOW_ARENA_ALLOC, UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) { 400, UNINIT, MI_OPTION(retry_on_oom) }, // windows only: retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. #if defined(MI_VISIT_ABANDONED) { 1, INITIALIZED, MI_OPTION(visit_abandoned) }, // allow visiting heap blocks in abandonded segments; requires taking locks during reclaim. diff --git a/src/os.c b/src/os.c index 4b9d6125..827fc6cf 100644 --- a/src/os.c +++ b/src/os.c @@ -11,16 +11,33 @@ terms of the MIT license. A copy of the license can be found in the file /* ----------------------------------------------------------- - Initialization. + Initialization. ----------------------------------------------------------- */ +#ifndef MI_DEFAULT_VIRTUAL_ADDRESS_BITS +#if MI_INTPTR_SIZE < 8 +#define MI_DEFAULT_VIRTUAL_ADDRESS_BITS 32 +#else +#define MI_DEFAULT_VIRTUAL_ADDRESS_BITS 48 +#endif +#endif + +#ifndef MI_DEFAULT_PHYSICAL_MEMORY +#if MI_INTPTR_SIZE < 8 +#define MI_DEFAULT_PHYSICAL_MEMORY 4*MI_GiB +#else +#define MI_DEFAULT_PHYSICAL_MEMORY 32*MI_GiB +#endif +#endif static mi_os_mem_config_t mi_os_mem_config = { - 4096, // page size - 0, // large page size (usually 2MiB) - 4096, // allocation granularity - true, // has overcommit? (if true we use MAP_NORESERVE on mmap systems) - false, // can we partially free allocated blocks? (on mmap systems we can free anywhere in a mapped range, but on Windows we must free the entire span) - true // has virtual reserve? (if true we can reserve virtual address space without using commit or physical memory) + 4096, // page size + 0, // large page size (usually 2MiB) + 4096, // allocation granularity + MI_DEFAULT_PHYSICAL_MEMORY, + MI_DEFAULT_VIRTUAL_ADDRESS_BITS, + true, // has overcommit? (if true we use MAP_NORESERVE on mmap systems) + false, // can we partially free allocated blocks? (on mmap systems we can free anywhere in a mapped range, but on Windows we must free the entire span) + true // has virtual reserve? (if true we can reserve virtual address space without using commit or physical memory) }; bool _mi_os_has_overcommit(void) { @@ -91,9 +108,9 @@ static void* mi_align_down_ptr(void* p, size_t alignment) { aligned hinting -------------------------------------------------------------- */ -// On 64-bit systems, we can do efficient aligned allocation by using -// the 2TiB to 30TiB area to allocate those. We assume we have -// at least 48 bits of virtual address space on 64-bit systems (but see issue #939) +// On systems with enough virtual address bits, we can do efficient aligned allocation by using +// the 2TiB to 30TiB area to allocate those. If we have at least 46 bits of virtual address +// space (64TiB) we use this technique. (but see issue #939) #if (MI_INTPTR_SIZE >= 8) && !defined(MI_NO_ALIGNED_HINT) static mi_decl_cache_align _Atomic(uintptr_t)aligned_base; @@ -111,6 +128,7 @@ static mi_decl_cache_align _Atomic(uintptr_t)aligned_base; void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size) { if (try_alignment <= 1 || try_alignment > MI_SEGMENT_SIZE) return NULL; + if (mi_os_mem_config.virtual_address_bits < 46) return NULL; // < 64TiB virtual address space size = _mi_align_up(size, MI_SEGMENT_SIZE); if (size > 1*MI_GiB) return NULL; // guarantee the chance of fixed valid address is at most 1/(MI_HINT_AREA / 1<<30) = 1/4096. #if (MI_SECURE>0) @@ -276,7 +294,7 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit p = mi_os_prim_alloc(over_size, 1, commit, false, is_large, is_zero, stats); if (p == NULL) return NULL; - // and selectively unmap parts around the over-allocated area. + // and selectively unmap parts around the over-allocated area. void* aligned_p = mi_align_up_ptr(p, alignment); size_t pre_size = (uint8_t*)aligned_p - (uint8_t*)p; size_t mid_size = _mi_align_up(size, _mi_os_page_size()); diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 0ea8189c..9075f9bd 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -139,6 +139,12 @@ void _mi_prim_mem_init( mi_os_mem_config_t* config ) if (psize > 0) { config->page_size = (size_t)psize; config->alloc_granularity = (size_t)psize; + #if defined(_SC_PHYS_PAGES) + long pphys = sysconf(_SC_PHYS_PAGES); + if (pphys > 0 && (size_t)pphys < (SIZE_MAX/(size_t)psize)) { + config->physical_memory = (size_t)pphys * (size_t)psize; + } + #endif } config->large_page_size = 2*MI_MiB; // TODO: can we query the OS for this? config->has_overcommit = unix_detect_overcommit(); diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 385354fc..494fac78 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -118,6 +118,18 @@ void _mi_prim_mem_init( mi_os_mem_config_t* config ) GetSystemInfo(&si); if (si.dwPageSize > 0) { config->page_size = si.dwPageSize; } if (si.dwAllocationGranularity > 0) { config->alloc_granularity = si.dwAllocationGranularity; } + // get virtual address bits + if ((uintptr_t)si.lpMaximumApplicationAddress > 0) { + const size_t vbits = MI_INTPTR_BITS - mi_clz((uintptr_t)si.lpMaximumApplicationAddress); + config->virtual_address_bits = vbits; + } + // get physical memory + ULONGLONG memInKiB = 0; + if (GetPhysicallyInstalledSystemMemory(&memInKiB)) { + if (memInKiB > 0 && memInKiB < (SIZE_MAX / MI_KiB)) { + config->physical_memory = memInKiB * MI_KiB; + } + } // get the VirtualAlloc2 function HINSTANCE hDll; hDll = LoadLibrary(TEXT("kernelbase.dll")); From 0e76fe3798ee975db1db4289f054a34175859c37 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 16 Nov 2024 16:57:37 -0800 Subject: [PATCH 123/305] add address hint to primitive allocation API --- ide/vs2022/mimalloc.vcxproj | 2 +- include/mimalloc/prim.h | 3 ++- src/arena.c | 2 +- src/os.c | 11 ++++++++--- src/prim/emscripten/prim.c | 4 ++-- src/prim/unix/prim.c | 4 ++-- src/prim/wasi/prim.c | 4 ++-- src/prim/windows/prim.c | 22 +++++++++++----------- 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index 5efc8fd0..fd7d99d5 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -116,7 +116,7 @@ true Default ../../include - MI_DEBUG=4;%(PreprocessorDefinitions); + MI_DEBUG=1;%(PreprocessorDefinitions); CompileAsCpp false stdcpp20 diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index fb2a9434..f8bf948e 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -43,9 +43,10 @@ int _mi_prim_free(void* addr, size_t size ); // If `commit` is false, the virtual memory range only needs to be reserved (with no access) // which will later be committed explicitly using `_mi_prim_commit`. // `is_zero` is set to true if the memory was zero initialized (as on most OS's) +// The `hint_addr` address is either `NULL` or a preferred allocation address but can be ignored. // pre: !commit => !allow_large // try_alignment >= _mi_os_page_size() and a power of 2 -int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr); +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr); // Commit memory. Returns error code or 0 on success. // For example, on Linux this would make the memory PROT_READ|PROT_WRITE. diff --git a/src/arena.c b/src/arena.c index 3bb8f502..8ca5aaf3 100644 --- a/src/arena.c +++ b/src/arena.c @@ -289,7 +289,7 @@ static void* mi_arena_try_alloc_at_id(mi_arena_id_t arena_id, bool match_numa_no bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld ) { MI_UNUSED_RELEASE(alignment); - mi_assert_internal(alignment <= MI_SEGMENT_ALIGN); + mi_assert(alignment <= MI_SEGMENT_ALIGN); const size_t bcount = mi_block_count_of_size(size); const size_t arena_index = mi_arena_id_index(arena_id); mi_assert_internal(arena_index < mi_atomic_load_relaxed(&mi_arena_count)); diff --git a/src/os.c b/src/os.c index 827fc6cf..62c8c934 100644 --- a/src/os.c +++ b/src/os.c @@ -214,7 +214,8 @@ void _mi_os_free(void* p, size_t size, mi_memid_t memid, mi_stats_t* stats) { -------------------------------------------------------------- */ // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. -static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, mi_stats_t* tld_stats) { +// Also `hint_addr` is a hint and may be ignored. +static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, mi_stats_t* tld_stats) { mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); mi_assert_internal(is_zero != NULL); mi_assert_internal(is_large != NULL); @@ -223,9 +224,9 @@ static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bo if (try_alignment == 0) { try_alignment = 1; } // avoid 0 to ensure there will be no divide by zero when aligning *is_zero = false; void* p = NULL; - int err = _mi_prim_alloc(size, try_alignment, commit, allow_large, is_large, is_zero, &p); + int err = _mi_prim_alloc(hint_addr, size, try_alignment, commit, allow_large, is_large, is_zero, &p); if (err != 0) { - _mi_warning_message("unable to allocate OS memory (error: %d (0x%x), size: 0x%zx bytes, align: 0x%zx, commit: %d, allow large: %d)\n", err, err, size, try_alignment, commit, allow_large); + _mi_warning_message("unable to allocate OS memory (error: %d (0x%x), addr: %p, size: 0x%zx bytes, align: 0x%zx, commit: %d, allow large: %d)\n", err, err, hint_addr, size, try_alignment, commit, allow_large); } MI_UNUSED(tld_stats); @@ -245,6 +246,10 @@ static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bo return p; } +static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, mi_stats_t* tld_stats) { + return mi_os_prim_alloc_at(NULL, size, try_alignment, commit, allow_large, is_large, is_zero, tld_stats); +} + // Primitive aligned allocation from the OS. // This function guarantees the allocated memory is aligned. diff --git a/src/prim/emscripten/prim.c b/src/prim/emscripten/prim.c index 944c0cb4..82147de7 100644 --- a/src/prim/emscripten/prim.c +++ b/src/prim/emscripten/prim.c @@ -71,8 +71,8 @@ int _mi_prim_free(void* addr, size_t size) { extern void* emmalloc_memalign(size_t alignment, size_t size); // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. -int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { - MI_UNUSED(try_alignment); MI_UNUSED(allow_large); MI_UNUSED(commit); +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { + MI_UNUSED(try_alignment); MI_UNUSED(allow_large); MI_UNUSED(commit); MI_UNUSED(hint_addr); *is_large = false; // TODO: Track the highest address ever seen; first uses of it are zeroes. // That assumes no one else uses sbrk but us (they could go up, diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 9075f9bd..59421e52 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -357,14 +357,14 @@ static void* unix_mmap(void* addr, size_t size, size_t try_alignment, int protec } // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. -int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); mi_assert_internal(commit || !allow_large); mi_assert_internal(try_alignment > 0); *is_zero = true; int protect_flags = (commit ? (PROT_WRITE | PROT_READ) : PROT_NONE); - *addr = unix_mmap(NULL, size, try_alignment, protect_flags, false, allow_large, is_large); + *addr = unix_mmap(hint_addr, size, try_alignment, protect_flags, false, allow_large, is_large); return (*addr != NULL ? 0 : errno); } diff --git a/src/prim/wasi/prim.c b/src/prim/wasi/prim.c index 5d7a8132..e1e7de5e 100644 --- a/src/prim/wasi/prim.c +++ b/src/prim/wasi/prim.c @@ -119,8 +119,8 @@ static void* mi_prim_mem_grow(size_t size, size_t try_alignment) { } // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. -int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { - MI_UNUSED(allow_large); MI_UNUSED(commit); +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { + MI_UNUSED(allow_large); MI_UNUSED(commit); MI_UNUSED(hint_addr); *is_large = false; *is_zero = false; *addr = mi_prim_mem_grow(size, try_alignment); diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 494fac78..1d3d6f41 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -123,7 +123,7 @@ void _mi_prim_mem_init( mi_os_mem_config_t* config ) const size_t vbits = MI_INTPTR_BITS - mi_clz((uintptr_t)si.lpMaximumApplicationAddress); config->virtual_address_bits = vbits; } - // get physical memory + // get physical memory ULONGLONG memInKiB = 0; if (GetPhysicallyInstalledSystemMemory(&memInKiB)) { if (memInKiB > 0 && memInKiB < (SIZE_MAX / MI_KiB)) { @@ -203,7 +203,7 @@ static void* win_virtual_alloc_prim_once(void* addr, size_t size, size_t try_ali } #endif // on modern Windows try use VirtualAlloc2 for aligned allocation - if (try_alignment > 1 && (try_alignment % _mi_os_page_size()) == 0 && pVirtualAlloc2 != NULL) { + if (addr == NULL && try_alignment > 1 && (try_alignment % _mi_os_page_size()) == 0 && pVirtualAlloc2 != NULL) { MI_MEM_ADDRESS_REQUIREMENTS reqs = { 0, 0, 0 }; reqs.Alignment = try_alignment; MI_MEM_EXTENDED_PARAMETER param = { {0, 0}, {0} }; @@ -291,14 +291,14 @@ static void* win_virtual_alloc(void* addr, size_t size, size_t try_alignment, DW return p; } -int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { +int _mi_prim_alloc(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** addr) { mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); mi_assert_internal(commit || !allow_large); mi_assert_internal(try_alignment > 0); *is_zero = true; int flags = MEM_RESERVE; if (commit) { flags |= MEM_COMMIT; } - *addr = win_virtual_alloc(NULL, size, try_alignment, flags, false, allow_large, is_large); + *addr = win_virtual_alloc(hint_addr, size, try_alignment, flags, false, allow_large, is_large); return (*addr != NULL ? 0 : (int)GetLastError()); } @@ -629,8 +629,8 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { _mi_process_done(); } else if (reason==DLL_THREAD_DETACH && !_mi_is_redirected()) { - _mi_thread_done(NULL); - } + _mi_thread_done(NULL); + } } @@ -693,7 +693,7 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { #pragma data_seg() #pragma data_seg(".CRT$XLY") PIMAGE_TLS_CALLBACK _mi_tls_callback_post[] = { &mi_win_main_detach }; - #pragma data_seg() + #pragma data_seg() #endif #if defined(__cplusplus) @@ -707,13 +707,13 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { MI_UNUSED(heap); } -#else // deprecated: statically linked, use fiber api +#else // deprecated: statically linked, use fiber api #if defined(_MSC_VER) // on clang/gcc use the constructor attribute (in `src/prim/prim.c`) // MSVC: use data section magic for static libraries // See #define MI_PRIM_HAS_PROCESS_ATTACH 1 - + static int mi_process_attach(void) { mi_win_main(NULL,DLL_PROCESS_ATTACH,NULL); atexit(&_mi_process_done); @@ -766,9 +766,9 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { } #endif -// ---------------------------------------------------- +// ---------------------------------------------------- // Communicate with the redirection module on Windows -// ---------------------------------------------------- +// ---------------------------------------------------- #if defined(MI_SHARED_LIB) && !defined(MI_WIN_NOREDIRECT) #define MI_PRIM_HAS_ALLOCATOR_INIT 1 From c57e9b855cc97ea53112ad755ce1d0290cef23af Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Sat, 16 Nov 2024 19:43:13 -0800 Subject: [PATCH 124/305] fix std malloc compile of the stress test --- test/test-stress.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/test-stress.c b/test/test-stress.c index 30ad0e77..9d40a6d9 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -47,10 +47,6 @@ static int ITER = 50; // N full iterations destructing and re-creating a #define STRESS // undefine for leak test -#ifndef NDEBUG -#define HEAP_WALK // walk the heap objects? -#endif - static bool allow_large_objects = true; // allow very large objects? (set to `true` if SCALE>100) static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`? @@ -66,6 +62,9 @@ static bool main_participates = false; // main thread participates as a #define custom_calloc(n,s) mi_calloc(n,s) #define custom_realloc(p,s) mi_realloc(p,s) #define custom_free(p) mi_free(p) +#ifndef NDEBUG +#define HEAP_WALK // walk the heap objects? +#endif #endif // transfer pointer between threads @@ -220,7 +219,7 @@ static void test_stress(void) { uintptr_t r = rand(); for (int n = 0; n < ITER; n++) { run_os_threads(THREADS, &stress); - #ifndef NDEBUG + #if !defined(NDEBUG) && !defined(USE_STD_MALLOC) // switch between arena and OS allocation for testing mi_option_set_enabled(mi_option_disallow_arena_alloc, (n%2)==1); #endif @@ -270,7 +269,7 @@ int main(int argc, char** argv) { #ifdef HEAP_WALK mi_option_enable(mi_option_visit_abandoned); #endif - #ifndef NDEBUG + #if !defined(NDEBUG) && !defined(USE_STD_MALLOC) mi_option_set(mi_option_arena_reserve, 32 * 1024 /* in kib = 32MiB */); #endif #ifndef USE_STD_MALLOC From 498c92e34894977b0e599fb276b1fcf9faebacb4 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 16 Nov 2024 21:15:50 -0800 Subject: [PATCH 125/305] update guarded implementation to use block tags --- ide/vs2022/mimalloc.vcxproj | 2 +- include/mimalloc.h | 2 + include/mimalloc/internal.h | 17 ++++-- include/mimalloc/types.h | 7 +++ src/alloc-aligned.c | 44 ++++++++++---- src/alloc.c | 116 +++++++++++++++++++----------------- src/free.c | 63 +++++++++++--------- src/heap.c | 2 +- src/options.c | 8 ++- src/page.c | 6 -- test/test-stress.c | 2 + 11 files changed, 161 insertions(+), 108 deletions(-) diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index fd7d99d5..5a614289 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -116,7 +116,7 @@ true Default ../../include - MI_DEBUG=1;%(PreprocessorDefinitions); + MI_DEBUG=4;MI_DEBUG_GUARDED=1;%(PreprocessorDefinitions); CompileAsCpp false stdcpp20 diff --git a/include/mimalloc.h b/include/mimalloc.h index e5133c96..940284b6 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -368,6 +368,8 @@ typedef enum mi_option_e { mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) mi_option_debug_guarded_min, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) mi_option_debug_guarded_max, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) + mi_option_debug_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) + mi_option_debug_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 82e8c766..d73532e0 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -600,16 +600,25 @@ static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { page->flags.x.has_aligned = has_aligned; } +/* ------------------------------------------------------------------- + Guarded objects +------------------------------------------------------------------- */ #if MI_DEBUG_GUARDED -static inline bool mi_page_has_guarded(const mi_page_t* page) { - return page->flags.x.has_guarded; +static inline bool mi_block_ptr_is_guarded(const mi_block_t* block, const void* p) { + const ptrdiff_t offset = (uint8_t*)p - (uint8_t*)block; + return (offset >= (ptrdiff_t)(sizeof(mi_block_t)) && block->next == MI_BLOCK_TAG_GUARDED); } -static inline void mi_page_set_has_guarded(mi_page_t* page, bool has_guarded) { - page->flags.x.has_guarded = has_guarded; +static inline bool mi_heap_malloc_use_guarded(mi_heap_t* heap, size_t size) { + MI_UNUSED(heap); + return (size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max) + && size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min)); } + +mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; #endif + /* ------------------------------------------------------------------- Encoding/Decoding the free list next pointers diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index d1e6e5d8..e01754e2 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -232,6 +232,13 @@ typedef struct mi_block_s { mi_encoded_t next; } mi_block_t; +#if MI_DEBUG_GUARDED +// we always align guarded pointers in a block at an offset +// the block `next` field is then used as a tag to distinguish regular offset aligned blocks from guarded ones +#define MI_BLOCK_TAG_ALIGNED ((mi_encoded_t)(0)) +#define MI_BLOCK_TAG_GUARDED (~MI_BLOCK_TAG_ALIGNED) +#endif + // The delayed flags are used for efficient multi-threaded free-ing typedef enum mi_delayed_e { diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 248c932d..12815689 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -20,14 +20,24 @@ static bool mi_malloc_is_naturally_aligned( size_t size, size_t alignment ) { mi_assert_internal(_mi_is_power_of_two(alignment) && (alignment > 0)); if (alignment > size) return false; if (alignment <= MI_MAX_ALIGN_SIZE) return true; - #if MI_DEBUG_GUARDED - return false; - #else const size_t bsize = mi_good_size(size); - return (bsize <= MI_MAX_ALIGN_GUARANTEE && (bsize & (alignment-1)) == 0); - #endif + return (bsize <= MI_MAX_ALIGN_GUARANTEE && (bsize & (alignment-1)) == 0); } +#if MI_DEBUG_GUARDED +static mi_decl_restrict void* mi_heap_malloc_guarded_aligned(mi_heap_t* heap, size_t size, size_t alignment, bool zero) mi_attr_noexcept { + // use over allocation for guarded blocksl + mi_assert_internal(alignment > 0 && alignment < MI_BLOCK_ALIGNMENT_MAX); + const size_t oversize = size + alignment - 1; + void* base = _mi_heap_malloc_guarded(heap, oversize, zero); + void* p = mi_align_up_ptr(base, alignment); + mi_track_align(base, p, (uint8_t*)p - (uint8_t*)base, size); + mi_assert_internal(mi_usable_size(p) >= size); + mi_assert_internal(_mi_is_aligned(p, alignment)); + return p; +} +#endif + // Fallback aligned allocation that over-allocates -- split out for better codegen static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept { @@ -68,6 +78,13 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t void* aligned_p = (void*)((uintptr_t)p + adjust); if (aligned_p != p) { mi_page_set_has_aligned(page, true); + #if MI_DEBUG_GUARDED + // set tag to aligned so mi_usable_size works with guard pages + if (adjust > sizeof(mi_block_t)) { + mi_block_t* const block = (mi_block_t*)p; + block->next = MI_BLOCK_TAG_ALIGNED; + } + #endif _mi_padding_shrink(page, (mi_block_t*)p, adjust + size); } // todo: expand padding if overallocated ? @@ -76,10 +93,8 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t mi_assert_internal(((uintptr_t)aligned_p + offset) % alignment == 0); mi_assert_internal(mi_usable_size(aligned_p)>=size); mi_assert_internal(mi_usable_size(p) == mi_usable_size(aligned_p)+adjust); - #if !MI_DEBUG_GUARDED mi_assert_internal(p == _mi_page_ptr_unalign(_mi_ptr_page(aligned_p), aligned_p)); - #endif - + // now zero the block if needed if (alignment > MI_BLOCK_ALIGNMENT_MAX) { // for the tracker, on huge aligned allocations only from the start of the large block is defined @@ -128,6 +143,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_generic(mi_heap_t* return mi_heap_malloc_zero_aligned_at_overalloc(heap,size,alignment,offset,zero); } + // Primitive aligned allocation static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept { @@ -138,8 +154,13 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t #endif return NULL; } + + #if MI_DEBUG_GUARDED + if (offset==0 && alignment < MI_BLOCK_ALIGNMENT_MAX && mi_heap_malloc_use_guarded(heap,size)) { + return mi_heap_malloc_guarded_aligned(heap, size, alignment, zero); + } + #endif - #if !MI_DEBUG_GUARDED // try first if there happens to be a small block available with just the right alignment if mi_likely(size <= MI_SMALL_SIZE_MAX && alignment <= size) { const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` @@ -160,8 +181,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t } } } - #endif - + // fallback to generic aligned allocation return mi_heap_malloc_zero_aligned_at_generic(heap, size, alignment, offset, zero); } @@ -313,3 +333,5 @@ mi_decl_nodiscard void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t mi_decl_nodiscard void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_recalloc_aligned(mi_prim_get_default_heap(), p, newcount, size, alignment); } + + diff --git a/src/alloc.c b/src/alloc.c index 119dfe75..b4713ff1 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -31,22 +31,22 @@ terms of the MIT license. A copy of the license can be found in the file extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept { mi_assert_internal(page->block_size == 0 /* empty heap */ || mi_page_block_size(page) >= size); - + // check the free list mi_block_t* const block = page->free; if mi_unlikely(block == NULL) { return _mi_malloc_generic(heap, size, zero, 0); } mi_assert_internal(block != NULL && _mi_ptr_page(block) == page); - + // pop from the free list page->free = mi_block_next(page, block); page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); mi_assert_internal(page->block_size < MI_MAX_ALIGN_SIZE || _mi_is_aligned(block, MI_MAX_ALIGN_SIZE)); - + #if MI_DEBUG>3 - if (page->free_is_zero && size > sizeof(*block)) { + if (page->free_is_zero && size > sizeof(*block)) { mi_assert_expensive(mi_mem_is_zero(block+1,size - sizeof(*block))); } #endif @@ -122,9 +122,7 @@ extern void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t siz } #if MI_DEBUG_GUARDED -static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; -static inline bool mi_heap_malloc_use_guarded(size_t size, bool has_huge_alignment); -static inline bool mi_heap_malloc_small_use_guarded(size_t size); +mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; #endif static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { @@ -138,7 +136,9 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, if (size == 0) { size = sizeof(void*); } #endif #if MI_DEBUG_GUARDED - if (mi_heap_malloc_small_use_guarded(size)) { return mi_heap_malloc_guarded(heap, size, zero); } + if (mi_heap_malloc_use_guarded(heap,size)) { + return _mi_heap_malloc_guarded(heap, size, zero); + } #endif // get page in constant time, and allocate from it @@ -171,13 +171,15 @@ mi_decl_nodiscard extern inline mi_decl_restrict void* mi_malloc_small(size_t si // The main allocation function extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept { - // fast path for small objects + // fast path for small objects if mi_likely(size <= MI_SMALL_SIZE_MAX) { mi_assert_internal(huge_alignment == 0); return mi_heap_malloc_small_zero(heap, size, zero); } #if MI_DEBUG_GUARDED - else if (mi_heap_malloc_use_guarded(size,huge_alignment>0)) { return mi_heap_malloc_guarded(heap, size, zero); } + else if (huge_alignment==0 && mi_heap_malloc_use_guarded(heap,size)) { + return _mi_heap_malloc_guarded(heap, size, zero); + } #endif else { // regular allocation @@ -185,7 +187,7 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local void* const p = _mi_malloc_generic(heap, size + MI_PADDING_SIZE, zero, huge_alignment); // note: size can overflow but it is detected in malloc_generic mi_track_malloc(p,size,zero); - + #if MI_STAT>1 if (p != NULL) { if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); } @@ -602,61 +604,65 @@ mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) { } #if MI_DEBUG_GUARDED -static inline bool mi_heap_malloc_small_use_guarded(size_t size) { - return (size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max) - && size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min)); +// We always allocate a guarded allocation at an offset (`mi_page_has_aligned` will be true). +// We then set the first word of the block to `0` for regular offset aligned allocations (in `alloc-aligned.c`) +// and the first word to `~0` for guarded allocations to have a correct `mi_usable_size` + +static void* mi_block_ptr_set_guarded(mi_block_t* block, size_t obj_size) { + // TODO: we can still make padding work by moving it out of the guard page area + mi_page_t* const page = _mi_ptr_page(block); + mi_page_set_has_aligned(page, true); + block->next = MI_BLOCK_TAG_GUARDED; + + // set guard page at the end of the block + mi_segment_t* const segment = _mi_page_segment(page); + const size_t block_size = mi_page_block_size(page); // must use `block_size` to match `mi_free_local` + const size_t os_page_size = _mi_os_page_size(); + mi_assert_internal(block_size >= obj_size + os_page_size + sizeof(mi_block_t)); + if (block_size < obj_size + os_page_size + sizeof(mi_block_t)) { + // should never happen + mi_free(block); + return NULL; + } + uint8_t* guard_page = (uint8_t*)block + block_size - os_page_size; + mi_assert_internal(_mi_is_aligned(guard_page, os_page_size)); + if (segment->allow_decommit && _mi_is_aligned(guard_page, os_page_size)) { + _mi_os_protect(guard_page, os_page_size); + } + else { + _mi_warning_message("unable to set a guard page behind an object due to pinned memory (large OS pages?) (object %p of size %zu)\n", block, block_size); + } + + // align pointer just in front of the guard page + size_t offset = block_size - os_page_size - obj_size; + mi_assert_internal(offset > sizeof(mi_block_t)); + if (offset > MI_BLOCK_ALIGNMENT_MAX) { + // give up to place it right in front of the guard page if the offset is too large for unalignment + offset = MI_BLOCK_ALIGNMENT_MAX; + } + void* p = (uint8_t*)block + offset; + mi_track_align(block, p, offset, obj_size); + return p; } -static inline bool mi_heap_malloc_use_guarded(size_t size, bool has_huge_alignment) { - return (!has_huge_alignment // guarded pages do not work with huge aligments at the moment - && _mi_option_get_fast(mi_option_debug_guarded_max) > 0 // guarded must be enabled - && (mi_heap_malloc_small_use_guarded(size) - || ((mi_good_size(size) & (_mi_os_page_size() - 1)) == 0)) // page-size multiple are always guarded so we can have a correct `mi_usable_size`. - ); -} - -static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept +mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept { #if defined(MI_PADDING_SIZE) mi_assert(MI_PADDING_SIZE==0); #endif // allocate multiple of page size ending in a guard page - const size_t obj_size = _mi_align_up(size, MI_MAX_ALIGN_SIZE); // ensure minimal alignment requirement + // ensure minimal alignment requirement? const size_t os_page_size = _mi_os_page_size(); - const size_t req_size = _mi_align_up(obj_size + os_page_size, os_page_size); - void* const block = _mi_malloc_generic(heap, req_size, zero, 0 /* huge_alignment */); + const size_t obj_size = (mi_option_is_enabled(mi_option_debug_guarded_precise) ? size : _mi_align_up(size, MI_MAX_ALIGN_SIZE)); + const size_t bsize = _mi_align_up(_mi_align_up(obj_size, MI_MAX_ALIGN_SIZE) + sizeof(mi_block_t), MI_MAX_ALIGN_SIZE); + const size_t req_size = _mi_align_up(bsize + os_page_size, os_page_size); + mi_block_t* const block = (mi_block_t*)_mi_malloc_generic(heap, req_size, zero, 0 /* huge_alignment */); if (block==NULL) return NULL; - mi_page_t* page = _mi_ptr_page(block); - mi_segment_t* segment = _mi_page_segment(page); - - const size_t block_size = mi_page_block_size(page); // must use `block_size` to match `mi_free_local` - void* const guard_page = (uint8_t*)block + (block_size - os_page_size); - mi_assert_internal(_mi_is_aligned(guard_page, os_page_size)); - - // place block in front of the guard page - size_t offset = block_size - os_page_size - obj_size; - if (offset > MI_BLOCK_ALIGNMENT_MAX) { - // give up to place it right in front of the guard page if the offset is too large for unalignment - offset = MI_BLOCK_ALIGNMENT_MAX; - } - void* const p = (uint8_t*)block + offset; - mi_assert_internal(p>=block); - - // set page flags - if (offset > 0) { - mi_page_set_has_aligned(page, true); - } - - // set guard page - if (segment->allow_decommit) { - mi_page_set_has_guarded(page, true); - _mi_os_protect(guard_page, os_page_size); - } - else { - _mi_warning_message("unable to set a guard page behind an object due to pinned memory (large OS pages?) (object %p of size %zu)\n", p, size); - } + void* const p = mi_block_ptr_set_guarded(block, obj_size); // stats + const size_t usize = mi_usable_size(p); + mi_assert_internal(usize >= size); mi_track_malloc(p, size, zero); #if MI_STAT>1 if (p != NULL) { diff --git a/src/free.c b/src/free.c index 046a34e2..73c05c87 100644 --- a/src/free.c +++ b/src/free.c @@ -70,20 +70,29 @@ mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p) { } // forward declaration for a MI_DEBUG_GUARDED build -static void mi_block_unguard(mi_page_t* page, mi_block_t* block); +#if MI_DEBUG_GUARDED +static void mi_block_unguard_prim(mi_page_t* page, mi_block_t* block, void* p); // forward declaration +static inline void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) { + if (mi_block_ptr_is_guarded(block, p)) { mi_block_unguard_prim(page, block, p); } +} +#else +static inline void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) { + MI_UNUSED(page); MI_UNUSED(block); MI_UNUSED(p); +} +#endif // free a local pointer (page parameter comes first for better codegen) static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept { MI_UNUSED(segment); mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(page, p) : (mi_block_t*)p); - mi_block_unguard(page,block); + mi_block_unguard(page, block, p); mi_free_block_local(page, block, true /* track stats */, true /* check for a full page */); } // free a pointer owned by another thread (page parameter comes first for better codegen) static void mi_decl_noinline mi_free_generic_mt(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept { mi_block_t* const block = _mi_page_ptr_unalign(page, p); // don't check `has_aligned` flag to avoid a race (issue #865) - mi_block_unguard(page, block); + mi_block_unguard(page, block, p); mi_free_block_mt(page, segment, block); } @@ -297,20 +306,19 @@ static size_t mi_decl_noinline mi_page_usable_aligned_size_of(const mi_page_t* p const size_t size = mi_page_usable_size_of(page, block); const ptrdiff_t adjust = (uint8_t*)p - (uint8_t*)block; mi_assert_internal(adjust >= 0 && (size_t)adjust <= size); - return (size - adjust); + const size_t aligned_size = (size - adjust); + #if MI_DEBUG_GUARDED + if (mi_block_ptr_is_guarded(block, p)) { + return aligned_size - _mi_os_page_size(); + } + #endif + return aligned_size; } static inline size_t _mi_usable_size(const void* p, const char* msg) mi_attr_noexcept { const mi_segment_t* const segment = mi_checked_ptr_segment(p, msg); if mi_unlikely(segment==NULL) return 0; - const mi_page_t* const page = _mi_segment_page_of(segment, p); - #if MI_DEBUG_GUARDED - if (mi_page_has_guarded(page)) { - const size_t bsize = mi_page_usable_aligned_size_of(page, p); - mi_assert_internal(bsize > _mi_os_page_size()); - return (bsize > _mi_os_page_size() ? bsize - _mi_os_page_size() : bsize); - } else - #endif + const mi_page_t* const page = _mi_segment_page_of(segment, p); if mi_likely(!mi_page_has_aligned(page)) { const mi_block_t* block = (const mi_block_t*)p; return mi_page_usable_size_of(page, block); @@ -534,22 +542,19 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { // Remove guard page when building with MI_DEBUG_GUARDED -#if !MI_DEBUG_GUARDED -static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { - MI_UNUSED(page); - MI_UNUSED(block); - // do nothing -} -#else -static void mi_block_unguard(mi_page_t* page, mi_block_t* block) { - if (mi_page_has_guarded(page)) { - const size_t bsize = mi_page_block_size(page); - const size_t psize = _mi_os_page_size(); - mi_assert_internal(bsize > psize); - mi_assert_internal(_mi_page_segment(page)->allow_decommit); - void* gpage = (uint8_t*)block + (bsize - psize); - mi_assert_internal(_mi_is_aligned(gpage, psize)); - _mi_os_unprotect(gpage, psize); - } +#if MI_DEBUG_GUARDED +static void mi_block_unguard_prim(mi_page_t* page, mi_block_t* block, void* p) { + mi_assert_internal(mi_block_ptr_is_guarded(block, p)); + mi_assert_internal(mi_page_has_aligned(page)); + mi_assert_internal((uint8_t*)p - (uint8_t*)block >= sizeof(mi_block_t)); + mi_assert_internal(block->next == MI_BLOCK_TAG_GUARDED); + + const size_t bsize = mi_page_block_size(page); + const size_t psize = _mi_os_page_size(); + mi_assert_internal(bsize > psize); + mi_assert_internal(_mi_page_segment(page)->allow_decommit); + void* gpage = (uint8_t*)block + bsize - psize; + mi_assert_internal(_mi_is_aligned(gpage, psize)); + _mi_os_unprotect(gpage, psize); } #endif diff --git a/src/heap.c b/src/heap.c index 206d3a36..eb0ab991 100644 --- a/src/heap.c +++ b/src/heap.c @@ -370,7 +370,7 @@ void mi_heap_destroy(mi_heap_t* heap) { mi_assert_expensive(mi_heap_is_valid(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return; #if MI_DEBUG_GUARDED - _mi_warning_message("'mi_heap_destroy' called but ignored as MI_DEBUG_GUARDED is enabled (heap at %p)\n", heap); + // _mi_warning_message("'mi_heap_destroy' called but MI_DEBUG_GUARDED is enabled -- using `mi_heap_delete` instead (heap at %p)\n", heap); mi_heap_delete(heap); return; #else diff --git a/src/options.c b/src/options.c index 9ddf86ba..3d9017f1 100644 --- a/src/options.c +++ b/src/options.c @@ -143,7 +143,13 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(visit_abandoned) }, #endif { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects - { 0, UNINIT, MI_OPTION(debug_guarded_max) }, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects + { MI_GiB, UNINIT, MI_OPTION(debug_guarded_max) }, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects + { 0, UNINIT, MI_OPTION(debug_guarded_precise) }, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) +#if MI_DEBUG_GUARDED + { 1000,UNINIT, MI_OPTION(debug_guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded(= 1000) +#else + { 0, UNINIT, MI_OPTION(debug_guarded_sample_rate)}, +#endif }; static void mi_option_init(mi_option_desc_t* desc); diff --git a/src/page.c b/src/page.c index 49f9ed52..d6dcfb15 100644 --- a/src/page.c +++ b/src/page.c @@ -414,9 +414,6 @@ void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force) { // no more aligned blocks in here mi_page_set_has_aligned(page, false); - #if MI_DEBUG_GUARDED - mi_page_set_has_guarded(page, false); - #endif // remove from the page list // (no need to do _mi_heap_delayed_free first as all blocks are already free) @@ -443,9 +440,6 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept { mi_assert_internal(mi_page_all_free(page)); mi_page_set_has_aligned(page, false); - #if MI_DEBUG_GUARDED - mi_page_set_has_guarded(page, false); - #endif // don't retire too often.. // (or we end up retiring and re-allocating most of the time) diff --git a/test/test-stress.c b/test/test-stress.c index 30ad0e77..b062f2ce 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -22,6 +22,8 @@ terms of the MIT license. #include #include +#define MI_DEBUG_GUARDED + // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // // argument defaults From 8b6017d976ed98b0ec71bf34f0c8089b00b52e67 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 16 Nov 2024 22:42:32 -0800 Subject: [PATCH 126/305] rename mi_debug_guarded_ to mi_guarded_ --- CMakeLists.txt | 8 +++--- azure-pipelines.yml | 6 ++--- ide/vs2022/mimalloc.vcxproj | 2 +- include/mimalloc.h | 18 ++++++------- include/mimalloc/internal.h | 6 ++--- include/mimalloc/types.h | 8 +++--- src/alloc-aligned.c | 26 +++++++++---------- src/alloc.c | 20 +++++++------- src/free.c | 48 +++++++++++++++++----------------- src/heap.c | 4 +-- src/options.c | 52 ++++++++++++++++++------------------- src/segment.c | 2 +- test/test-api-fill.c | 2 +- test/test-stress.c | 12 ++++----- 14 files changed, 106 insertions(+), 108 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 87837026..5fc1808e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ option(MI_BUILD_OBJECT "Build object library" ON) option(MI_BUILD_TESTS "Build test executables" ON) option(MI_DEBUG_TSAN "Build with thread sanitizer (needs clang)" OFF) option(MI_DEBUG_UBSAN "Build with undefined-behavior sanitizer (needs clang++)" OFF) -option(MI_DEBUG_GUARDED "Build with guard pages behind certain object allocations (implies MI_NO_PADDING=ON)" OFF) +option(MI_GUARDED "Build with guard pages behind certain object allocations (implies MI_NO_PADDING=ON)" OFF) option(MI_SKIP_COLLECT_ON_EXIT "Skip collecting memory on program exit" OFF) option(MI_NO_PADDING "Force no use of padding even in DEBUG mode etc." OFF) option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) @@ -207,9 +207,9 @@ if(MI_TRACK_ETW) endif() endif() -if(MI_DEBUG_GUARDED) - message(STATUS "Compile guard pages behind certain object allocations (MI_DEBUG_GUARDED=ON)") - list(APPEND mi_defines MI_DEBUG_GUARDED=1) +if(MI_GUARDED) + message(STATUS "Compile guard pages behind certain object allocations (MI_GUARDED=ON)") + list(APPEND mi_defines MI_GUARDED=1) if(NOT MI_NO_PADDING) message(STATUS " Disabling padding due to guard pages (MI_NO_PADDING=ON)") set(MI_NO_PADDING ON) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4455dfeb..e4361f98 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -117,8 +117,8 @@ jobs: CC: clang CXX: clang BuildType: debug-guarded-clang - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMI_DEBUG_FULL=ON -DMI_DEBUG_GUARDED=ON - + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMI_DEBUG_FULL=ON -DMI_GUARDED=ON + steps: - task: CMake@1 inputs: @@ -129,7 +129,7 @@ jobs: - script: ctest --verbose --timeout 180 workingDirectory: $(BuildType) displayName: CTest - env: + env: MIMALLOC_DEBUG_GUARDED_MAX: 1024 # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-ubuntu-$(BuildType) diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index 5a614289..160f1436 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -116,7 +116,7 @@ true Default ../../include - MI_DEBUG=4;MI_DEBUG_GUARDED=1;%(PreprocessorDefinitions); + MI_DEBUG=4;MI_GUARDED=1;%(PreprocessorDefinitions); CompileAsCpp false stdcpp20 diff --git a/include/mimalloc.h b/include/mimalloc.h index 940284b6..4ecb8be0 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -290,7 +290,7 @@ mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t a #endif -// Experimental: allow sub-processes whose memory segments stay separated (and no reclamation between them) +// Experimental: allow sub-processes whose memory segments stay separated (and no reclamation between them) // Used for example for separate interpreter's in one process. typedef void* mi_subproc_id_t; mi_decl_export mi_subproc_id_t mi_subproc_main(void); @@ -349,7 +349,7 @@ typedef enum mi_option_e { mi_option_deprecated_segment_cache, mi_option_deprecated_page_reset, mi_option_abandoned_page_purge, // immediately purge delayed purges on thread termination - mi_option_deprecated_segment_reset, + mi_option_deprecated_segment_reset, mi_option_eager_commit_delay, // the first N segments per thread are not eagerly committed (but per page in the segment on demand) mi_option_purge_delay, // memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10) mi_option_use_numa_nodes, // 0 = use all available numa nodes, otherwise use at most N nodes. @@ -366,10 +366,10 @@ typedef enum mi_option_e { mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's) mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows) mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0) - mi_option_debug_guarded_min, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects (=0) - mi_option_debug_guarded_max, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects (=0) - mi_option_debug_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) - mi_option_debug_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000) + mi_option_guarded_min, // only used when building with MI_GUARDED: minimal rounded object size for guarded objects (=0) + mi_option_guarded_max, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects (=0) + mi_option_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) + mi_option_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, @@ -539,7 +539,7 @@ template struct _mi_heap_stl_allocator_common : publi protected: std::shared_ptr heap; template friend struct _mi_heap_stl_allocator_common; - + _mi_heap_stl_allocator_common() { mi_heap_t* hp = mi_heap_new(); this->heap.reset(hp, (_mi_destroy ? &heap_destroy : &heap_delete)); /* calls heap_delete/destroy when the refcount drops to zero */ @@ -556,7 +556,7 @@ private: template struct mi_heap_stl_allocator : public _mi_heap_stl_allocator_common { using typename _mi_heap_stl_allocator_common::size_type; mi_heap_stl_allocator() : _mi_heap_stl_allocator_common() { } // creates fresh heap that is deleted when the destructor is called - mi_heap_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common(hp) { } // no delete nor destroy on the passed in heap + mi_heap_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common(hp) { } // no delete nor destroy on the passed in heap template mi_heap_stl_allocator(const mi_heap_stl_allocator& x) mi_attr_noexcept : _mi_heap_stl_allocator_common(x) { } mi_heap_stl_allocator select_on_container_copy_construction() const { return *this; } @@ -573,7 +573,7 @@ template bool operator!=(const mi_heap_stl_allocator& x, template struct mi_heap_destroy_stl_allocator : public _mi_heap_stl_allocator_common { using typename _mi_heap_stl_allocator_common::size_type; mi_heap_destroy_stl_allocator() : _mi_heap_stl_allocator_common() { } // creates fresh heap that is destroyed when the destructor is called - mi_heap_destroy_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common(hp) { } // no delete nor destroy on the passed in heap + mi_heap_destroy_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common(hp) { } // no delete nor destroy on the passed in heap template mi_heap_destroy_stl_allocator(const mi_heap_destroy_stl_allocator& x) mi_attr_noexcept : _mi_heap_stl_allocator_common(x) { } mi_heap_destroy_stl_allocator select_on_container_copy_construction() const { return *this; } diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index d73532e0..ae3a3358 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -603,7 +603,7 @@ static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { /* ------------------------------------------------------------------- Guarded objects ------------------------------------------------------------------- */ -#if MI_DEBUG_GUARDED +#if MI_GUARDED static inline bool mi_block_ptr_is_guarded(const mi_block_t* block, const void* p) { const ptrdiff_t offset = (uint8_t*)p - (uint8_t*)block; return (offset >= (ptrdiff_t)(sizeof(mi_block_t)) && block->next == MI_BLOCK_TAG_GUARDED); @@ -611,8 +611,8 @@ static inline bool mi_block_ptr_is_guarded(const mi_block_t* block, const void* static inline bool mi_heap_malloc_use_guarded(mi_heap_t* heap, size_t size) { MI_UNUSED(heap); - return (size <= (size_t)_mi_option_get_fast(mi_option_debug_guarded_max) - && size >= (size_t)_mi_option_get_fast(mi_option_debug_guarded_min)); + return (size <= (size_t)_mi_option_get_fast(mi_option_guarded_max) + && size >= (size_t)_mi_option_get_fast(mi_option_guarded_min)); } mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index e01754e2..29ba8564 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -74,8 +74,8 @@ terms of the MIT license. A copy of the license can be found in the file // Use guard pages behind objects of a certain size (set by the MIMALLOC_DEBUG_GUARDED_MIN/MAX options) // Padding should be disabled when using guard pages -// #define MI_DEBUG_GUARDED 1 -#if defined(MI_DEBUG_GUARDED) +// #define MI_GUARDED 1 +#if defined(MI_GUARDED) #define MI_PADDING 0 #endif @@ -232,7 +232,7 @@ typedef struct mi_block_s { mi_encoded_t next; } mi_block_t; -#if MI_DEBUG_GUARDED +#if MI_GUARDED // we always align guarded pointers in a block at an offset // the block `next` field is then used as a tag to distinguish regular offset aligned blocks from guarded ones #define MI_BLOCK_TAG_ALIGNED ((mi_encoded_t)(0)) @@ -257,7 +257,6 @@ typedef union mi_page_flags_s { struct { uint8_t in_full : 1; uint8_t has_aligned : 1; - uint8_t has_guarded : 1; // only used with MI_DEBUG_GUARDED } x; } mi_page_flags_t; #else @@ -267,7 +266,6 @@ typedef union mi_page_flags_s { struct { uint8_t in_full; uint8_t has_aligned; - uint8_t has_guarded; // only used with MI_DEBUG_GUARDED } x; } mi_page_flags_t; #endif diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 12815689..86b13dea 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -21,10 +21,10 @@ static bool mi_malloc_is_naturally_aligned( size_t size, size_t alignment ) { if (alignment > size) return false; if (alignment <= MI_MAX_ALIGN_SIZE) return true; const size_t bsize = mi_good_size(size); - return (bsize <= MI_MAX_ALIGN_GUARANTEE && (bsize & (alignment-1)) == 0); + return (bsize <= MI_MAX_ALIGN_GUARANTEE && (bsize & (alignment-1)) == 0); } -#if MI_DEBUG_GUARDED +#if MI_GUARDED static mi_decl_restrict void* mi_heap_malloc_guarded_aligned(mi_heap_t* heap, size_t size, size_t alignment, bool zero) mi_attr_noexcept { // use over allocation for guarded blocksl mi_assert_internal(alignment > 0 && alignment < MI_BLOCK_ALIGNMENT_MAX); @@ -69,7 +69,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t if (p == NULL) return NULL; } mi_page_t* page = _mi_ptr_page(p); - + // .. and align within the allocation const uintptr_t align_mask = alignment - 1; // for any x, `(x & align_mask) == (x % alignment)` const uintptr_t poffset = ((uintptr_t)p + offset) & align_mask; @@ -78,7 +78,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t void* aligned_p = (void*)((uintptr_t)p + adjust); if (aligned_p != p) { mi_page_set_has_aligned(page, true); - #if MI_DEBUG_GUARDED + #if MI_GUARDED // set tag to aligned so mi_usable_size works with guard pages if (adjust > sizeof(mi_block_t)) { mi_block_t* const block = (mi_block_t*)p; @@ -94,7 +94,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t mi_assert_internal(mi_usable_size(aligned_p)>=size); mi_assert_internal(mi_usable_size(p) == mi_usable_size(aligned_p)+adjust); mi_assert_internal(p == _mi_page_ptr_unalign(_mi_ptr_page(aligned_p), aligned_p)); - + // now zero the block if needed if (alignment > MI_BLOCK_ALIGNMENT_MAX) { // for the tracker, on huge aligned allocations only from the start of the large block is defined @@ -115,27 +115,27 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_generic(mi_heap_t* { mi_assert_internal(alignment != 0 && _mi_is_power_of_two(alignment)); // we don't allocate more than MI_MAX_ALLOC_SIZE (see ) - if mi_unlikely(size > (MI_MAX_ALLOC_SIZE - MI_PADDING_SIZE)) { + if mi_unlikely(size > (MI_MAX_ALLOC_SIZE - MI_PADDING_SIZE)) { #if MI_DEBUG > 0 _mi_error_message(EOVERFLOW, "aligned allocation request is too large (size %zu, alignment %zu)\n", size, alignment); #endif return NULL; } - + // use regular allocation if it is guaranteed to fit the alignment constraints. // this is important to try as the fast path in `mi_heap_malloc_zero_aligned` only works when there exist // a page with the right block size, and if we always use the over-alloc fallback that would never happen. if (offset == 0 && mi_malloc_is_naturally_aligned(size,alignment)) { void* p = _mi_heap_malloc_zero(heap, size, zero); mi_assert_internal(p == NULL || ((uintptr_t)p % alignment) == 0); - const bool is_aligned_or_null = (((uintptr_t)p) & (alignment-1))==0; + const bool is_aligned_or_null = (((uintptr_t)p) & (alignment-1))==0; if mi_likely(is_aligned_or_null) { return p; } else { // this should never happen if the `mi_malloc_is_naturally_aligned` check is correct.. mi_assert(false); - mi_free(p); + mi_free(p); } } @@ -155,16 +155,16 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t return NULL; } - #if MI_DEBUG_GUARDED + #if MI_GUARDED if (offset==0 && alignment < MI_BLOCK_ALIGNMENT_MAX && mi_heap_malloc_use_guarded(heap,size)) { return mi_heap_malloc_guarded_aligned(heap, size, alignment, zero); } #endif - + // try first if there happens to be a small block available with just the right alignment if mi_likely(size <= MI_SMALL_SIZE_MAX && alignment <= size) { const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` - const size_t padsize = size + MI_PADDING_SIZE; + const size_t padsize = size + MI_PADDING_SIZE; mi_page_t* page = _mi_heap_get_free_small_page(heap, padsize); if mi_likely(page->free != NULL) { const bool is_aligned = (((uintptr_t)page->free + offset) & align_mask)==0; @@ -181,7 +181,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t } } } - + // fallback to generic aligned allocation return mi_heap_malloc_zero_aligned_at_generic(heap, size, alignment, offset, zero); } diff --git a/src/alloc.c b/src/alloc.c index b4713ff1..561b0026 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -121,7 +121,7 @@ extern void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t siz return _mi_page_malloc_zero(heap,page,size,true); } -#if MI_DEBUG_GUARDED +#if MI_GUARDED mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; #endif @@ -132,12 +132,12 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, const uintptr_t tid = _mi_thread_id(); mi_assert(heap->thread_id == 0 || heap->thread_id == tid); // heaps are thread local #endif - #if (MI_PADDING || MI_DEBUG_GUARDED) + #if (MI_PADDING || MI_GUARDED) if (size == 0) { size = sizeof(void*); } #endif - #if MI_DEBUG_GUARDED - if (mi_heap_malloc_use_guarded(heap,size)) { - return _mi_heap_malloc_guarded(heap, size, zero); + #if MI_GUARDED + if (mi_heap_malloc_use_guarded(heap,size)) { + return _mi_heap_malloc_guarded(heap, size, zero); } #endif @@ -176,9 +176,9 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z mi_assert_internal(huge_alignment == 0); return mi_heap_malloc_small_zero(heap, size, zero); } - #if MI_DEBUG_GUARDED - else if (huge_alignment==0 && mi_heap_malloc_use_guarded(heap,size)) { - return _mi_heap_malloc_guarded(heap, size, zero); + #if MI_GUARDED + else if (huge_alignment==0 && mi_heap_malloc_use_guarded(heap,size)) { + return _mi_heap_malloc_guarded(heap, size, zero); } #endif else { @@ -603,7 +603,7 @@ mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) { } } -#if MI_DEBUG_GUARDED +#if MI_GUARDED // We always allocate a guarded allocation at an offset (`mi_page_has_aligned` will be true). // We then set the first word of the block to `0` for regular offset aligned allocations (in `alloc-aligned.c`) // and the first word to `~0` for guarded allocations to have a correct `mi_usable_size` @@ -653,7 +653,7 @@ mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, boo // allocate multiple of page size ending in a guard page // ensure minimal alignment requirement? const size_t os_page_size = _mi_os_page_size(); - const size_t obj_size = (mi_option_is_enabled(mi_option_debug_guarded_precise) ? size : _mi_align_up(size, MI_MAX_ALIGN_SIZE)); + const size_t obj_size = (mi_option_is_enabled(mi_option_guarded_precise) ? size : _mi_align_up(size, MI_MAX_ALIGN_SIZE)); const size_t bsize = _mi_align_up(_mi_align_up(obj_size, MI_MAX_ALIGN_SIZE) + sizeof(mi_block_t), MI_MAX_ALIGN_SIZE); const size_t req_size = _mi_align_up(bsize + os_page_size, os_page_size); mi_block_t* const block = (mi_block_t*)_mi_malloc_generic(heap, req_size, zero, 0 /* huge_alignment */); diff --git a/src/free.c b/src/free.c index 73c05c87..afbafae6 100644 --- a/src/free.c +++ b/src/free.c @@ -33,8 +33,8 @@ static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool // checks if mi_unlikely(mi_check_is_double_free(page, block)) return; mi_check_padding(page, block); - if (track_stats) { mi_stat_free(page, block); } - #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN && !MI_DEBUG_GUARDED + if (track_stats) { mi_stat_free(page, block); } + #if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN && !MI_GUARDED memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); #endif if (track_stats) { mi_track_free_size(block, mi_page_usable_size_of(page, block)); } // faster then mi_usable_size as we already know the page and that p is unaligned @@ -69,14 +69,14 @@ mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p) { return (mi_block_t*)((uintptr_t)p - adjust); } -// forward declaration for a MI_DEBUG_GUARDED build -#if MI_DEBUG_GUARDED -static void mi_block_unguard_prim(mi_page_t* page, mi_block_t* block, void* p); // forward declaration -static inline void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) { - if (mi_block_ptr_is_guarded(block, p)) { mi_block_unguard_prim(page, block, p); } +// forward declaration for a MI_GUARDED build +#if MI_GUARDED +static void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p); // forward declaration +static inline void mi_block_check_unguard(mi_page_t* page, mi_block_t* block, void* p) { + if (mi_block_ptr_is_guarded(block, p)) { mi_block_unguard(page, block, p); } } #else -static inline void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) { +static inline void mi_block_check_unguard(mi_page_t* page, mi_block_t* block, void* p) { MI_UNUSED(page); MI_UNUSED(block); MI_UNUSED(p); } #endif @@ -85,14 +85,14 @@ static inline void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept { MI_UNUSED(segment); mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(page, p) : (mi_block_t*)p); - mi_block_unguard(page, block, p); + mi_block_check_unguard(page, block, p); mi_free_block_local(page, block, true /* track stats */, true /* check for a full page */); } // free a pointer owned by another thread (page parameter comes first for better codegen) static void mi_decl_noinline mi_free_generic_mt(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept { mi_block_t* const block = _mi_page_ptr_unalign(page, p); // don't check `has_aligned` flag to avoid a race (issue #865) - mi_block_unguard(page, block, p); + mi_block_check_unguard(page, block, p); mi_free_block_mt(page, segment, block); } @@ -109,17 +109,17 @@ static inline mi_segment_t* mi_checked_ptr_segment(const void* p, const char* ms { MI_UNUSED(msg); -#if (MI_DEBUG>0) - if mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0) { + #if (MI_DEBUG>0) + if mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0 && !mi_option_is_enabled(mi_option_guarded_precise)) { _mi_error_message(EINVAL, "%s: invalid (unaligned) pointer: %p\n", msg, p); return NULL; } -#endif + #endif mi_segment_t* const segment = _mi_ptr_segment(p); if mi_unlikely(segment==NULL) return segment; -#if (MI_DEBUG>0) + #if (MI_DEBUG>0) if mi_unlikely(!mi_is_in_heap_region(p)) { _mi_warning_message("%s: pointer might not point to a valid heap region: %p\n" "(this may still be a valid very large allocation (over 64MiB))\n", msg, p); @@ -127,13 +127,13 @@ static inline mi_segment_t* mi_checked_ptr_segment(const void* p, const char* ms _mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p); } } -#endif -#if (MI_DEBUG>0 || MI_SECURE>=4) + #endif + #if (MI_DEBUG>0 || MI_SECURE>=4) if mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie) { _mi_error_message(EINVAL, "%s: pointer does not point to a valid heap space: %p\n", msg, p); return NULL; } -#endif + #endif return segment; } @@ -307,7 +307,7 @@ static size_t mi_decl_noinline mi_page_usable_aligned_size_of(const mi_page_t* p const ptrdiff_t adjust = (uint8_t*)p - (uint8_t*)block; mi_assert_internal(adjust >= 0 && (size_t)adjust <= size); const size_t aligned_size = (size - adjust); - #if MI_DEBUG_GUARDED + #if MI_GUARDED if (mi_block_ptr_is_guarded(block, p)) { return aligned_size - _mi_os_page_size(); } @@ -318,7 +318,7 @@ static size_t mi_decl_noinline mi_page_usable_aligned_size_of(const mi_page_t* p static inline size_t _mi_usable_size(const void* p, const char* msg) mi_attr_noexcept { const mi_segment_t* const segment = mi_checked_ptr_segment(p, msg); if mi_unlikely(segment==NULL) return 0; - const mi_page_t* const page = _mi_segment_page_of(segment, p); + const mi_page_t* const page = _mi_segment_page_of(segment, p); if mi_likely(!mi_page_has_aligned(page)) { const mi_block_t* block = (const mi_block_t*)p; return mi_page_usable_size_of(page, block); @@ -541,12 +541,12 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { #endif -// Remove guard page when building with MI_DEBUG_GUARDED -#if MI_DEBUG_GUARDED -static void mi_block_unguard_prim(mi_page_t* page, mi_block_t* block, void* p) { +// Remove guard page when building with MI_GUARDED +#if MI_GUARDED +static void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) { mi_assert_internal(mi_block_ptr_is_guarded(block, p)); mi_assert_internal(mi_page_has_aligned(page)); - mi_assert_internal((uint8_t*)p - (uint8_t*)block >= sizeof(mi_block_t)); + mi_assert_internal((uint8_t*)p - (uint8_t*)block >= (ptrdiff_t)sizeof(mi_block_t)); mi_assert_internal(block->next == MI_BLOCK_TAG_GUARDED); const size_t bsize = mi_page_block_size(page); @@ -555,6 +555,6 @@ static void mi_block_unguard_prim(mi_page_t* page, mi_block_t* block, void* p) { mi_assert_internal(_mi_page_segment(page)->allow_decommit); void* gpage = (uint8_t*)block + bsize - psize; mi_assert_internal(_mi_is_aligned(gpage, psize)); - _mi_os_unprotect(gpage, psize); + _mi_os_unprotect(gpage, psize); } #endif diff --git a/src/heap.c b/src/heap.c index eb0ab991..78ebcd1e 100644 --- a/src/heap.c +++ b/src/heap.c @@ -369,8 +369,8 @@ void mi_heap_destroy(mi_heap_t* heap) { mi_assert(heap->no_reclaim); mi_assert_expensive(mi_heap_is_valid(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return; - #if MI_DEBUG_GUARDED - // _mi_warning_message("'mi_heap_destroy' called but MI_DEBUG_GUARDED is enabled -- using `mi_heap_delete` instead (heap at %p)\n", heap); + #if MI_GUARDED + // _mi_warning_message("'mi_heap_destroy' called but MI_GUARDED is enabled -- using `mi_heap_delete` instead (heap at %p)\n", heap); mi_heap_delete(heap); return; #else diff --git a/src/options.c b/src/options.c index 3d9017f1..c5f1e2a1 100644 --- a/src/options.c +++ b/src/options.c @@ -47,9 +47,9 @@ typedef struct mi_option_desc_s { #define MI_OPTION(opt) mi_option_##opt, #opt, NULL #define MI_OPTION_LEGACY(opt,legacy) mi_option_##opt, #opt, #legacy -// Some options can be set at build time for statically linked libraries +// Some options can be set at build time for statically linked libraries // (use `-DMI_EXTRA_CPPDEFS="opt1=val1;opt2=val2"`) -// +// // This is useful if we cannot pass them as environment variables // (and setting them programmatically would be too late) @@ -102,17 +102,17 @@ static mi_option_desc_t options[_mi_option_last] = { MI_DEFAULT_VERBOSE, UNINIT, MI_OPTION(verbose) }, // some of the following options are experimental and not all combinations are allowed. - { MI_DEFAULT_EAGER_COMMIT, + { MI_DEFAULT_EAGER_COMMIT, UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`) - { MI_DEFAULT_ARENA_EAGER_COMMIT, + { MI_DEFAULT_ARENA_EAGER_COMMIT, UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux) { 1, UNINIT, MI_OPTION_LEGACY(purge_decommits,reset_decommits) }, // purge decommits memory (instead of reset) (note: on linux this uses MADV_DONTNEED for decommit) - { MI_DEFAULT_ALLOW_LARGE_OS_PAGES, + { MI_DEFAULT_ALLOW_LARGE_OS_PAGES, UNINIT, MI_OPTION_LEGACY(allow_large_os_pages,large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's - { MI_DEFAULT_RESERVE_HUGE_OS_PAGES, + { MI_DEFAULT_RESERVE_HUGE_OS_PAGES, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages {-1, UNINIT, MI_OPTION(reserve_huge_os_pages_at) }, // reserve huge pages at node N - { MI_DEFAULT_RESERVE_OS_MEMORY, + { MI_DEFAULT_RESERVE_OS_MEMORY, UNINIT, MI_OPTION(reserve_os_memory) }, // reserve N KiB OS memory in advance (use `option_get_size`) { 0, UNINIT, MI_OPTION(deprecated_segment_cache) }, // cache N segments per thread { 0, UNINIT, MI_OPTION(deprecated_page_reset) }, // reset page memory on free @@ -137,18 +137,18 @@ static mi_option_desc_t options[_mi_option_last] = { 1, UNINIT, MI_OPTION(abandoned_reclaim_on_free) },// reclaim an abandoned segment on a free { MI_DEFAULT_DISALLOW_ARENA_ALLOC, UNINIT, MI_OPTION(disallow_arena_alloc) }, // 1 = do not use arena's for allocation (except if using specific arena id's) { 400, UNINIT, MI_OPTION(retry_on_oom) }, // windows only: retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. -#if defined(MI_VISIT_ABANDONED) +#if defined(MI_VISIT_ABANDONED) { 1, INITIALIZED, MI_OPTION(visit_abandoned) }, // allow visiting heap blocks in abandonded segments; requires taking locks during reclaim. #else - { 0, UNINIT, MI_OPTION(visit_abandoned) }, + { 0, UNINIT, MI_OPTION(visit_abandoned) }, #endif - { 0, UNINIT, MI_OPTION(debug_guarded_min) }, // only used when building with MI_DEBUG_GUARDED: minimal rounded object size for guarded objects - { MI_GiB, UNINIT, MI_OPTION(debug_guarded_max) }, // only used when building with MI_DEBUG_GUARDED: maximal rounded object size for guarded objects - { 0, UNINIT, MI_OPTION(debug_guarded_precise) }, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) -#if MI_DEBUG_GUARDED - { 1000,UNINIT, MI_OPTION(debug_guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded(= 1000) + { 0, UNINIT, MI_OPTION(guarded_min) }, // only used when building with MI_GUARDED: minimal rounded object size for guarded objects + { MI_GiB, UNINIT, MI_OPTION(guarded_max) }, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects + { 0, UNINIT, MI_OPTION(guarded_precise) }, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) +#if MI_GUARDED + { 1000,UNINIT, MI_OPTION(guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded(= 1000) #else - { 0, UNINIT, MI_OPTION(debug_guarded_sample_rate)}, + { 0, UNINIT, MI_OPTION(guarded_sample_rate)}, #endif }; @@ -172,25 +172,25 @@ void _mi_options_init(void) { } mi_max_error_count = mi_option_get(mi_option_max_errors); mi_max_warning_count = mi_option_get(mi_option_max_warnings); - #if MI_DEBUG_GUARDED - if (mi_option_get(mi_option_debug_guarded_max) > 0) { + #if MI_GUARDED + if (mi_option_get(mi_option_guarded_max) > 0) { if (mi_option_is_enabled(mi_option_allow_large_os_pages)) { mi_option_disable(mi_option_allow_large_os_pages); _mi_warning_message("option 'allow_large_os_pages' is disabled to allow for guarded objects\n"); } } - _mi_verbose_message("guarded build: %s\n", mi_option_get(mi_option_debug_guarded_max) > 0 ? "enabled" : "disabled"); + _mi_verbose_message("guarded build: %s\n", mi_option_get(mi_option_guarded_max) > 0 ? "enabled" : "disabled"); #endif } long _mi_option_get_fast(mi_option_t option) { mi_assert(option >= 0 && option < _mi_option_last); - mi_option_desc_t* desc = &options[option]; + mi_option_desc_t* desc = &options[option]; mi_assert(desc->option == option); // index should match the option //mi_assert(desc->init != UNINIT); return desc->value; } - + mi_decl_nodiscard long mi_option_get(mi_option_t option) { mi_assert(option >= 0 && option < _mi_option_last); @@ -225,11 +225,11 @@ void mi_option_set(mi_option_t option, long value) { desc->value = value; desc->init = INITIALIZED; // ensure min/max range; be careful to not recurse. - if (desc->option == mi_option_debug_guarded_min && _mi_option_get_fast(mi_option_debug_guarded_max) < value) { - mi_option_set(mi_option_debug_guarded_max, value); + if (desc->option == mi_option_guarded_min && _mi_option_get_fast(mi_option_guarded_max) < value) { + mi_option_set(mi_option_guarded_max, value); } - else if (desc->option == mi_option_debug_guarded_max && _mi_option_get_fast(mi_option_debug_guarded_min) > value) { - mi_option_set(mi_option_debug_guarded_min, value); + else if (desc->option == mi_option_guarded_max && _mi_option_get_fast(mi_option_guarded_min) > value) { + mi_option_set(mi_option_guarded_min, value); } } @@ -565,7 +565,7 @@ static void mi_option_init(mi_option_desc_t* desc) { char* end = buf; long value = strtol(buf, &end, 10); if (mi_option_has_size_in_kib(desc->option)) { - // this option is interpreted in KiB to prevent overflow of `long` for large allocations + // this option is interpreted in KiB to prevent overflow of `long` for large allocations // (long is 32-bit on 64-bit windows, which allows for 4TiB max.) size_t size = (value < 0 ? 0 : (size_t)value); bool overflow = false; @@ -580,7 +580,7 @@ static void mi_option_init(mi_option_desc_t* desc) { value = (size > LONG_MAX ? LONG_MAX : (long)size); } if (*end == 0) { - mi_option_set(desc->option, value); + mi_option_set(desc->option, value); } else { // set `init` first to avoid recursion through _mi_warning_message on mimalloc_verbose. diff --git a/src/segment.c b/src/segment.c index 837a65e9..18736818 100644 --- a/src/segment.c +++ b/src/segment.c @@ -455,7 +455,7 @@ static size_t mi_segment_calculate_sizes(size_t capacity, size_t required, size_ if (MI_SECURE == 0) { // normally no guard pages - #if MI_DEBUG_GUARDED + #if MI_GUARDED isize = _mi_align_up(minsize, _mi_os_page_size()); #else isize = _mi_align_up(minsize, 16 * MI_MAX_ALIGN_SIZE); diff --git a/test/test-api-fill.c b/test/test-api-fill.c index 3baee83d..eebbd394 100644 --- a/test/test-api-fill.c +++ b/test/test-api-fill.c @@ -271,7 +271,7 @@ int main(void) { mi_free(p); }; - #if !(MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_DEBUG_GUARDED) + #if !(MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_GUARDED) CHECK_BODY("fill-freed-small") { size_t malloc_size = MI_SMALL_SIZE_MAX / 2; uint8_t* p = (uint8_t*)mi_malloc(malloc_size); diff --git a/test/test-stress.c b/test/test-stress.c index b062f2ce..cb769dbf 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -22,21 +22,22 @@ terms of the MIT license. #include #include -#define MI_DEBUG_GUARDED +// #define MI_GUARDED +// #define USE_STD_MALLOC // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // // argument defaults #if defined(MI_TSAN) // with thread-sanitizer reduce the threads to test within the azure pipeline limits -static int THREADS = 8; +static int THREADS = 8; static int SCALE = 25; static int ITER = 400; #elif defined(MI_UBSAN) // with undefined behavious sanitizer reduce parameters to stay within the azure pipeline limits -static int THREADS = 8; +static int THREADS = 8; static int SCALE = 25; static int ITER = 20; -#elif defined(MI_DEBUG_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits -static int THREADS = 8; +#elif defined(MI_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits +static int THREADS = 8; static int SCALE = 10; static int ITER = 10; #else @@ -58,7 +59,6 @@ static size_t use_one_size = 0; // use single object size of `N * static bool main_participates = false; // main thread participates as a worker too -// #define USE_STD_MALLOC #ifdef USE_STD_MALLOC #define custom_calloc(n,s) calloc(n,s) #define custom_realloc(p,s) realloc(p,s) From 8ba1879073785ebbc0a27e2aeace3a0d3e6ff076 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 17 Nov 2024 00:06:16 -0800 Subject: [PATCH 127/305] add sampling for guarded objects --- include/mimalloc.h | 1 + include/mimalloc/internal.h | 16 +++++++++++++--- include/mimalloc/types.h | 8 ++++++++ src/alloc-aligned.c | 25 +++++++++++++++++++++---- src/alloc.c | 1 + src/heap.c | 1 + src/init.c | 26 +++++++++++++++++++++++++- src/options.c | 3 ++- src/stats.c | 2 ++ test/test-stress.c | 3 +-- 10 files changed, 75 insertions(+), 11 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 4ecb8be0..8cbe265f 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -370,6 +370,7 @@ typedef enum mi_option_e { mi_option_guarded_max, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects (=0) mi_option_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) mi_option_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000) + mi_option_guarded_sample_seed, // can be set to allow for a (more) deterministic re-execution when a guard page is triggered (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index ae3a3358..7809503b 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -91,6 +91,7 @@ void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap); mi_threadid_t _mi_thread_id(void) mi_attr_noexcept; mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id); +void _mi_heap_guarded_init(mi_heap_t* heap); // os.c void _mi_os_init(void); // called from process init @@ -610,12 +611,21 @@ static inline bool mi_block_ptr_is_guarded(const mi_block_t* block, const void* } static inline bool mi_heap_malloc_use_guarded(mi_heap_t* heap, size_t size) { - MI_UNUSED(heap); - return (size <= (size_t)_mi_option_get_fast(mi_option_guarded_max) - && size >= (size_t)_mi_option_get_fast(mi_option_guarded_min)); + MI_UNUSED(heap); + if (heap->guarded_sample_rate==0 || + size > heap->guarded_size_max || + size < heap->guarded_size_min) { + return false; + } + if (++heap->guarded_sample_count < heap->guarded_sample_rate) { + return false; + } + heap->guarded_sample_count = 0; // reset + return true; } mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; + #endif diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 29ba8564..ec181e61 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -502,6 +502,13 @@ struct mi_heap_s { mi_heap_t* next; // list of heaps per thread bool no_reclaim; // `true` if this heap should not reclaim abandoned pages uint8_t tag; // custom tag, can be used for separating heaps based on the object types + #if MI_GUARDED + size_t guarded_size_min; // minimal size for guarded objects + size_t guarded_size_max; // maximal size for guarded objects + size_t guarded_sample_rate; // sample rate (set to 0 to disable guarded pages) + size_t guarded_sample_seed; // starting sample count + size_t guarded_sample_count; // current sample count (wraps at `sample_rate`) + #endif mi_page_t* pages_free_direct[MI_PAGES_DIRECT]; // optimize: array where every entry points a page with possibly free blocks in the corresponding queue for that size. mi_page_queue_t pages[MI_BIN_FULL + 1]; // queue of pages for each size class (or "bin") }; @@ -594,6 +601,7 @@ typedef struct mi_stats_s { mi_stat_counter_t arena_count; mi_stat_counter_t arena_crossover_count; mi_stat_counter_t arena_rollback_count; + mi_stat_counter_t guarded_alloc_count; #if MI_STAT>1 mi_stat_count_t normal_bins[MI_BIN_HUGE+1]; #endif diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 86b13dea..6aee38c3 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -36,6 +36,18 @@ static mi_decl_restrict void* mi_heap_malloc_guarded_aligned(mi_heap_t* heap, si mi_assert_internal(_mi_is_aligned(p, alignment)); return p; } + +static void* mi_heap_malloc_zero_no_guarded(mi_heap_t* heap, size_t size, bool zero) { + const size_t rate = heap->guarded_sample_rate; + heap->guarded_sample_rate = 0; + void* p = _mi_heap_malloc_zero(heap, size, zero); + heap->guarded_sample_rate = rate; + return p; +} +#else +static void* mi_heap_malloc_zero_no_guarded(mi_heap_t* heap, size_t size, bool zero) { + return _mi_heap_malloc_zero(heap, size, zero); +} #endif // Fallback aligned allocation that over-allocates -- split out for better codegen @@ -58,6 +70,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t return NULL; } oversize = (size <= MI_SMALL_SIZE_MAX ? MI_SMALL_SIZE_MAX + 1 /* ensure we use generic malloc path */ : size); + // note: no guarded as alignment > 0 p = _mi_heap_malloc_zero_ex(heap, oversize, false, alignment); // the page block size should be large enough to align in the single huge page block // zero afterwards as only the area from the aligned_p may be committed! if (p == NULL) return NULL; @@ -65,7 +78,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t else { // otherwise over-allocate oversize = size + alignment - 1; - p = _mi_heap_malloc_zero(heap, oversize, zero); + p = mi_heap_malloc_zero_no_guarded(heap, oversize, zero); if (p == NULL) return NULL; } mi_page_t* page = _mi_ptr_page(p); @@ -80,7 +93,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t mi_page_set_has_aligned(page, true); #if MI_GUARDED // set tag to aligned so mi_usable_size works with guard pages - if (adjust > sizeof(mi_block_t)) { + if (adjust >= sizeof(mi_block_t)) { mi_block_t* const block = (mi_block_t*)p; block->next = MI_BLOCK_TAG_ALIGNED; } @@ -93,7 +106,11 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t mi_assert_internal(((uintptr_t)aligned_p + offset) % alignment == 0); mi_assert_internal(mi_usable_size(aligned_p)>=size); mi_assert_internal(mi_usable_size(p) == mi_usable_size(aligned_p)+adjust); - mi_assert_internal(p == _mi_page_ptr_unalign(_mi_ptr_page(aligned_p), aligned_p)); + #if MI_DEBUG > 1 + mi_page_t* const apage = _mi_ptr_page(aligned_p); + void* unalign_p = _mi_page_ptr_unalign(apage, aligned_p); + mi_assert_internal(p == unalign_p); + #endif // now zero the block if needed if (alignment > MI_BLOCK_ALIGNMENT_MAX) { @@ -126,7 +143,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_generic(mi_heap_t* // this is important to try as the fast path in `mi_heap_malloc_zero_aligned` only works when there exist // a page with the right block size, and if we always use the over-alloc fallback that would never happen. if (offset == 0 && mi_malloc_is_naturally_aligned(size,alignment)) { - void* p = _mi_heap_malloc_zero(heap, size, zero); + void* p = mi_heap_malloc_zero_no_guarded(heap, size, zero); mi_assert_internal(p == NULL || ((uintptr_t)p % alignment) == 0); const bool is_aligned_or_null = (((uintptr_t)p) & (alignment-1))==0; if mi_likely(is_aligned_or_null) { diff --git a/src/alloc.c b/src/alloc.c index 561b0026..25b05526 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -668,6 +668,7 @@ mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, boo if (p != NULL) { if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); } mi_heap_stat_increase(heap, malloc, mi_usable_size(p)); + mi_heap_stat_counter_increase(heap, guarded_alloc_count, 1); } #endif #if MI_DEBUG>3 diff --git a/src/heap.c b/src/heap.c index 78ebcd1e..581b3f71 100644 --- a/src/heap.c +++ b/src/heap.c @@ -221,6 +221,7 @@ void _mi_heap_init(mi_heap_t* heap, mi_tld_t* tld, mi_arena_id_t arena_id, bool heap->cookie = _mi_heap_random_next(heap) | 1; heap->keys[0] = _mi_heap_random_next(heap); heap->keys[1] = _mi_heap_random_next(heap); + _mi_heap_guarded_init(heap); // push on the thread local heaps list heap->next = heap->tld->heaps; heap->tld->heaps = heap; diff --git a/src/init.c b/src/init.c index 75458a1f..822d5a18 100644 --- a/src/init.c +++ b/src/init.c @@ -86,7 +86,8 @@ const mi_page_t _mi_page_empty = { MI_STAT_COUNT_NULL(), \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ - { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 } \ MI_STAT_COUNT_END_NULL() // -------------------------------------------------------- @@ -111,6 +112,9 @@ mi_decl_cache_align const mi_heap_t _mi_heap_empty = { NULL, // next false, // can reclaim 0, // tag + #if MI_GUARDED + 0, 0, 0, 0, 0, + #endif MI_SMALL_PAGES_EMPTY, MI_PAGE_QUEUES_EMPTY }; @@ -151,6 +155,9 @@ mi_decl_cache_align mi_heap_t _mi_heap_main = { NULL, // next heap false, // can reclaim 0, // tag + #if MI_GUARDED + 0, 0, 0, 0, 0, + #endif MI_SMALL_PAGES_EMPTY, MI_PAGE_QUEUES_EMPTY }; @@ -159,6 +166,22 @@ bool _mi_process_is_initialized = false; // set to `true` in `mi_process_init`. mi_stats_t _mi_stats_main = { MI_STATS_NULL }; +#if MI_GUARDED +void _mi_heap_guarded_init(mi_heap_t* heap) { + heap->guarded_sample_rate = mi_option_get_clamp(mi_option_guarded_sample_rate, 0, LONG_MAX); + heap->guarded_size_max = mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX); + heap->guarded_size_min = mi_option_get_clamp(mi_option_guarded_min, 0, (long)heap->guarded_size_max); + heap->guarded_sample_seed = (size_t)mi_option_get(mi_option_guarded_sample_seed); + if (heap->guarded_sample_seed == 0) { heap->guarded_sample_seed = _mi_heap_random_next(heap); } + heap->guarded_sample_seed = heap->guarded_sample_seed % heap->guarded_sample_rate; + heap->guarded_sample_count = heap->guarded_sample_seed; +} +#else +void _mi_heap_guarded_init(mi_heap_t* heap) { + MI_UNUSED(heap); +} +#endif + static void mi_heap_main_init(void) { if (_mi_heap_main.cookie == 0) { @@ -174,6 +197,7 @@ static void mi_heap_main_init(void) { _mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main); mi_lock_init(&mi_subproc_default.abandoned_os_lock); mi_lock_init(&mi_subproc_default.abandoned_os_visit_lock); + _mi_heap_guarded_init(&_mi_heap_main); } } diff --git a/src/options.c b/src/options.c index c5f1e2a1..2c6814c8 100644 --- a/src/options.c +++ b/src/options.c @@ -150,6 +150,7 @@ static mi_option_desc_t options[_mi_option_last] = #else { 0, UNINIT, MI_OPTION(guarded_sample_rate)}, #endif + { 0, UNINIT, MI_OPTION(guarded_sample_seed)}, }; static void mi_option_init(mi_option_desc_t* desc); @@ -173,7 +174,7 @@ void _mi_options_init(void) { mi_max_error_count = mi_option_get(mi_option_max_errors); mi_max_warning_count = mi_option_get(mi_option_max_warnings); #if MI_GUARDED - if (mi_option_get(mi_option_guarded_max) > 0) { + if (mi_option_get(mi_option_guarded_sample_rate) > 0) { if (mi_option_is_enabled(mi_option_allow_large_os_pages)) { mi_option_disable(mi_option_allow_large_os_pages); _mi_warning_message("option 'allow_large_os_pages' is disabled to allow for guarded objects\n"); diff --git a/src/stats.c b/src/stats.c index 99cf89c5..29376ace 100644 --- a/src/stats.c +++ b/src/stats.c @@ -118,6 +118,7 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) { mi_stat_counter_add(&stats->searches, &src->searches, 1); mi_stat_counter_add(&stats->normal_count, &src->normal_count, 1); mi_stat_counter_add(&stats->huge_count, &src->huge_count, 1); + mi_stat_counter_add(&stats->guarded_alloc_count, &src->guarded_alloc_count, 1); #if MI_STAT>1 for (size_t i = 0; i <= MI_BIN_HUGE; i++) { if (src->normal_bins[i].allocated > 0 || src->normal_bins[i].freed > 0) { @@ -342,6 +343,7 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_stat_counter_print(&stats->commit_calls, "commits", out, arg); mi_stat_counter_print(&stats->reset_calls, "resets", out, arg); mi_stat_counter_print(&stats->purge_calls, "purges", out, arg); + mi_stat_counter_print(&stats->guarded_alloc_count, "guarded", out, arg); mi_stat_print(&stats->threads, "threads", -1, out, arg); mi_stat_counter_print_avg(&stats->searches, "searches", out, arg); _mi_fprintf(out, arg, "%10s: %5zu\n", "numa nodes", _mi_os_numa_node_count()); diff --git a/test/test-stress.c b/test/test-stress.c index cb769dbf..88c39f23 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -22,7 +22,6 @@ terms of the MIT license. #include #include -// #define MI_GUARDED // #define USE_STD_MALLOC // > mimalloc-test-stress [THREADS] [SCALE] [ITER] @@ -36,7 +35,7 @@ static int ITER = 400; static int THREADS = 8; static int SCALE = 25; static int ITER = 20; -#elif defined(MI_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits +#elif defined(MI_XGUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits static int THREADS = 8; static int SCALE = 10; static int ITER = 10; From d57cb0765d4673ee10a577d741455ead9396b944 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 17 Nov 2024 22:45:09 -0800 Subject: [PATCH 128/305] add guarded objects that are sampled (and fit a size range). guarded sample rate etc can be set per heap as well as defaulted with options --- include/mimalloc.h | 6 ++++++ include/mimalloc/internal.h | 22 ++++++++++++-------- include/mimalloc/types.h | 2 +- src/alloc.c | 8 +++----- src/free.c | 1 + src/init.c | 41 +++++++++++++++++++++++++++++-------- src/options.c | 2 +- test/main-override.cpp | 2 +- test/test-stress.c | 3 ++- 9 files changed, 61 insertions(+), 26 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 8cbe265f..e3fecdf1 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -309,6 +309,12 @@ mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_ex(int heap_tag, bool al // deprecated mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; +// Experimental: objects followed by a guard page. +// A sample rate of 0 disables guarded objects, while 1 uses a guard page for every object. +// A seed of 0 uses a random start point. Only objects within the size bound are eligable for guard pages. +mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed); +mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max); + // ------------------------------------------------------ // Convenience diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 7809503b..d58bd9ca 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -611,17 +611,23 @@ static inline bool mi_block_ptr_is_guarded(const mi_block_t* block, const void* } static inline bool mi_heap_malloc_use_guarded(mi_heap_t* heap, size_t size) { - MI_UNUSED(heap); - if (heap->guarded_sample_rate==0 || - size > heap->guarded_size_max || - size < heap->guarded_size_min) { + // this code is written to result in fast assembly as it is on the hot path for allocation + const size_t count = heap->guarded_sample_count - 1; // if the rate was 0, this will underflow and count for a long time.. + if mi_likely(count != 0) { + // no sample + heap->guarded_sample_count = count; return false; } - if (++heap->guarded_sample_count < heap->guarded_sample_rate) { - return false; + else if (size >= heap->guarded_size_min && size <= heap->guarded_size_max) { + // use guarded allocation + heap->guarded_sample_count = heap->guarded_sample_rate; // reset + return (heap->guarded_sample_rate != 0); } - heap->guarded_sample_count = 0; // reset - return true; + else { + // failed size criteria, rewind count (but don't write to an empty heap) + if (heap->guarded_sample_rate != 0) { heap->guarded_sample_count = 1; } + return false; + } } mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index ec181e61..f7bca137 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -507,7 +507,7 @@ struct mi_heap_s { size_t guarded_size_max; // maximal size for guarded objects size_t guarded_sample_rate; // sample rate (set to 0 to disable guarded pages) size_t guarded_sample_seed; // starting sample count - size_t guarded_sample_count; // current sample count (wraps at `sample_rate`) + size_t guarded_sample_count; // current sample count (counting down to 0) #endif mi_page_t* pages_free_direct[MI_PAGES_DIRECT]; // optimize: array where every entry points a page with possibly free blocks in the corresponding queue for that size. mi_page_queue_t pages[MI_BIN_FULL + 1]; // queue of pages for each size class (or "bin") diff --git a/src/alloc.c b/src/alloc.c index 25b05526..bc4f2aa5 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -661,16 +661,14 @@ mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, boo void* const p = mi_block_ptr_set_guarded(block, obj_size); // stats - const size_t usize = mi_usable_size(p); - mi_assert_internal(usize >= size); mi_track_malloc(p, size, zero); - #if MI_STAT>1 if (p != NULL) { if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); } + #if MI_STAT>1 mi_heap_stat_increase(heap, malloc, mi_usable_size(p)); - mi_heap_stat_counter_increase(heap, guarded_alloc_count, 1); + #endif + _mi_stat_counter_increase(&heap->tld->stats.guarded_alloc_count, 1); } - #endif #if MI_DEBUG>3 if (p != NULL && zero) { mi_assert_expensive(mi_mem_is_zero(p, size)); diff --git a/src/free.c b/src/free.c index afbafae6..f2e30b65 100644 --- a/src/free.c +++ b/src/free.c @@ -544,6 +544,7 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { // Remove guard page when building with MI_GUARDED #if MI_GUARDED static void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) { + MI_UNUSED(p); mi_assert_internal(mi_block_ptr_is_guarded(block, p)); mi_assert_internal(mi_page_has_aligned(page)); mi_assert_internal((uint8_t*)p - (uint8_t*)block >= (ptrdiff_t)sizeof(mi_block_t)); diff --git a/src/init.c b/src/init.c index 822d5a18..ed161831 100644 --- a/src/init.c +++ b/src/init.c @@ -113,7 +113,7 @@ mi_decl_cache_align const mi_heap_t _mi_heap_empty = { false, // can reclaim 0, // tag #if MI_GUARDED - 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, // count is 1 so we never write to it (see `internal.h:mi_heap_malloc_use_guarded`) #endif MI_SMALL_PAGES_EMPTY, MI_PAGE_QUEUES_EMPTY @@ -167,16 +167,39 @@ bool _mi_process_is_initialized = false; // set to `true` in `mi_process_init`. mi_stats_t _mi_stats_main = { MI_STATS_NULL }; #if MI_GUARDED +mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) { + heap->guarded_sample_seed = seed; + if (heap->guarded_sample_seed == 0) { + heap->guarded_sample_seed = _mi_heap_random_next(heap); + } + heap->guarded_sample_rate = sample_rate; + if (heap->guarded_sample_rate >= 1) { + heap->guarded_sample_seed = heap->guarded_sample_seed % heap->guarded_sample_rate; + } + heap->guarded_sample_count = heap->guarded_sample_seed; // count down samples +} + +mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max) { + heap->guarded_size_min = min; + heap->guarded_size_max = (min > max ? min : max); +} + void _mi_heap_guarded_init(mi_heap_t* heap) { - heap->guarded_sample_rate = mi_option_get_clamp(mi_option_guarded_sample_rate, 0, LONG_MAX); - heap->guarded_size_max = mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX); - heap->guarded_size_min = mi_option_get_clamp(mi_option_guarded_min, 0, (long)heap->guarded_size_max); - heap->guarded_sample_seed = (size_t)mi_option_get(mi_option_guarded_sample_seed); - if (heap->guarded_sample_seed == 0) { heap->guarded_sample_seed = _mi_heap_random_next(heap); } - heap->guarded_sample_seed = heap->guarded_sample_seed % heap->guarded_sample_rate; - heap->guarded_sample_count = heap->guarded_sample_seed; + mi_heap_guarded_set_sample_rate(heap, + (size_t)mi_option_get_clamp(mi_option_guarded_sample_rate, 0, LONG_MAX), + (size_t)mi_option_get(mi_option_guarded_sample_seed)); + mi_heap_guarded_set_size_bound(heap, + (size_t)mi_option_get_clamp(mi_option_guarded_min, 0, LONG_MAX), + (size_t)mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX) ); } #else +mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) { + MI_UNUSED(heap); MI_UNUSED(sample_rate); MI_UNUSED(seed); +} + +mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max) { + MI_UNUSED(heap); MI_UNUSED(min); MI_UNUSED(max); +} void _mi_heap_guarded_init(mi_heap_t* heap) { MI_UNUSED(heap); } @@ -576,7 +599,7 @@ static void mi_detect_cpu_features(void) { } #else static void mi_detect_cpu_features(void) { - // nothing + // nothing } #endif diff --git a/src/options.c b/src/options.c index 2c6814c8..4f95e601 100644 --- a/src/options.c +++ b/src/options.c @@ -146,7 +146,7 @@ static mi_option_desc_t options[_mi_option_last] = { MI_GiB, UNINIT, MI_OPTION(guarded_max) }, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects { 0, UNINIT, MI_OPTION(guarded_precise) }, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) #if MI_GUARDED - { 1000,UNINIT, MI_OPTION(guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded(= 1000) + { 4000,UNINIT, MI_OPTION(guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded(= 1000) #else { 0, UNINIT, MI_OPTION(guarded_sample_rate)}, #endif diff --git a/test/main-override.cpp b/test/main-override.cpp index 9c47d3a1..3f64117a 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -62,7 +62,7 @@ int main() { test_mt_shutdown(); */ //fail_aslr(); - // mi_stats_print(NULL); + mi_stats_print(NULL); return 0; } diff --git a/test/test-stress.c b/test/test-stress.c index 88c39f23..ba9ab459 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -22,6 +22,7 @@ terms of the MIT license. #include #include +// #define MI_GUARDED // #define USE_STD_MALLOC // > mimalloc-test-stress [THREADS] [SCALE] [ITER] @@ -35,7 +36,7 @@ static int ITER = 400; static int THREADS = 8; static int SCALE = 25; static int ITER = 20; -#elif defined(MI_XGUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits +#elif defined(xMI_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits static int THREADS = 8; static int SCALE = 10; static int ITER = 10; From b8dc09e3d2adde248daabe1303b161c714bff298 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 17 Nov 2024 22:56:26 -0800 Subject: [PATCH 129/305] fix asan with MI_GUARDED --- src/alloc-aligned.c | 3 +++ src/alloc.c | 5 +++-- src/os.c | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 6aee38c3..b4da4ded 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -123,6 +123,9 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t if (p != aligned_p) { mi_track_align(p,aligned_p,adjust,mi_usable_size(aligned_p)); + #if MI_GUARDED + mi_track_mem_defined(p, sizeof(mi_block_t)); + #endif } return aligned_p; } diff --git a/src/alloc.c b/src/alloc.c index bc4f2aa5..a093f108 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -640,8 +640,9 @@ static void* mi_block_ptr_set_guarded(mi_block_t* block, size_t obj_size) { // give up to place it right in front of the guard page if the offset is too large for unalignment offset = MI_BLOCK_ALIGNMENT_MAX; } - void* p = (uint8_t*)block + offset; + void* p = (uint8_t*)block + offset; mi_track_align(block, p, offset, obj_size); + mi_track_mem_defined(block, sizeof(mi_block_t)); return p; } @@ -661,7 +662,7 @@ mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, boo void* const p = mi_block_ptr_set_guarded(block, obj_size); // stats - mi_track_malloc(p, size, zero); + mi_track_malloc(p, size, zero); if (p != NULL) { if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); } #if MI_STAT>1 diff --git a/src/os.c b/src/os.c index 62c8c934..a7130b90 100644 --- a/src/os.c +++ b/src/os.c @@ -273,7 +273,9 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit } else { // if not aligned, free it, overallocate, and unmap around it + #if !MI_TRACK_ASAN _mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n", size, p, alignment, commit); + #endif mi_os_prim_free(p, size, commit, stats); if (size >= (SIZE_MAX - alignment)) return NULL; // overflow const size_t over_size = size + alignment; From ff56f6acbc786ddf533d348b27d249256d14dc44 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 17 Nov 2024 23:01:16 -0800 Subject: [PATCH 130/305] update azure pipeline to use sample rate of 1000 for guarded objects --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e4361f98..1fd71663 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -130,7 +130,7 @@ jobs: workingDirectory: $(BuildType) displayName: CTest env: - MIMALLOC_DEBUG_GUARDED_MAX: 1024 + MIMALLOC_GUARDED_SAMPLE_RATE: 1000 # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-ubuntu-$(BuildType) From e7198ce3977f26716c014819df92d48b6058f569 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 17 Nov 2024 23:16:59 -0800 Subject: [PATCH 131/305] Extend azure pipeline with Ubuntu 24 & 20, windows 2019, and macOS 15 --- azure-pipelines.yml | 163 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 127 insertions(+), 36 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1fd71663..6a2544f8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,7 @@ trigger: jobs: - job: - displayName: Windows + displayName: Windows 2022 pool: vmImage: windows-2022 @@ -52,7 +52,7 @@ jobs: # artifact: mimalloc-windows-$(BuildType) - job: - displayName: Linux + displayName: Ubuntu 22.04 pool: vmImage: ubuntu-22.04 @@ -135,10 +135,10 @@ jobs: # artifact: mimalloc-ubuntu-$(BuildType) - job: - displayName: macOS + displayName: macOS 14 (Sonoma) pool: vmImage: - macOS-latest + macOS-14 strategy: matrix: Debug: @@ -163,35 +163,126 @@ jobs: # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-macos-$(BuildType) -# - job: -# displayName: Windows-2017 -# pool: -# vmImage: -# vs2017-win2016 -# strategy: -# matrix: -# Debug: -# BuildType: debug -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -# MSBuildConfiguration: Debug -# Release: -# BuildType: release -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release -# MSBuildConfiguration: Release -# Secure: -# BuildType: secure -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON -# MSBuildConfiguration: Release -# steps: -# - task: CMake@1 -# inputs: -# workingDirectory: $(BuildType) -# cmakeArgs: .. $(cmakeExtraArgs) -# - task: MSBuild@1 -# inputs: -# solution: $(BuildType)/libmimalloc.sln -# configuration: '$(MSBuildConfiguration)' -# - script: | -# cd $(BuildType) -# ctest --verbose --timeout 180 -# displayName: CTest +# ---------------------------------------------------------- +# Other OS versions (just debug mode) +# ---------------------------------------------------------- + +- job: + displayName: Windows 2019 + pool: + vmImage: + windows-2019 + strategy: + matrix: + Debug: + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + MSBuildConfiguration: Debug + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - task: MSBuild@1 + inputs: + solution: $(BuildType)/libmimalloc.sln + configuration: '$(MSBuildConfiguration)' + msbuildArguments: -m + - script: ctest --verbose --timeout 180 -C $(MSBuildConfiguration) + workingDirectory: $(BuildType) + displayName: CTest + +- job: + displayName: Ubuntu 24.04 + pool: + vmImage: + ubuntu-24.04 + strategy: + matrix: + Debug: + CC: gcc + CXX: g++ + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + Debug++: + CC: gcc + CXX: g++ + BuildType: debug-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON + Debug Clang: + CC: clang + CXX: clang++ + BuildType: debug-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - script: make -j$(nproc) -C $(BuildType) + displayName: Make + - script: ctest --verbose --timeout 180 + workingDirectory: $(BuildType) + displayName: CTest + +- job: + displayName: Ubuntu 20.04 + pool: + vmImage: + ubuntu-20.04 + strategy: + matrix: + Debug: + CC: gcc + CXX: g++ + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + Debug++: + CC: gcc + CXX: g++ + BuildType: debug-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON + Debug Clang: + CC: clang + CXX: clang++ + BuildType: debug-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - script: make -j$(nproc) -C $(BuildType) + displayName: Make + - script: ctest --verbose --timeout 180 + workingDirectory: $(BuildType) + displayName: CTest + +- job: + displayName: macOS 15 (Sequia) + pool: + vmImage: + macOS-15 + strategy: + matrix: + Debug: + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + Release: + BuildType: release + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + Secure: + BuildType: secure + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) + displayName: Make + - script: ctest --verbose --timeout 180 + workingDirectory: $(BuildType) + displayName: CTest From 41029d9d49439cb1191fcc984592d0e9e56e73af Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 17 Nov 2024 23:20:18 -0800 Subject: [PATCH 132/305] fix azure pipeline --- azure-pipelines.yml | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6a2544f8..00bfe8e9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -178,6 +178,10 @@ jobs: BuildType: debug cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON MSBuildConfiguration: Debug + Release: + BuildType: release + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + MSBuildConfiguration: Release steps: - task: CMake@1 inputs: @@ -214,7 +218,16 @@ jobs: CXX: clang++ BuildType: debug-clang cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON - + Debug++ Clang: + CC: clang + CXX: clang++ + BuildType: debug-clang-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON + Release Clang: + CC: clang + CXX: clang++ + BuildType: release-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release steps: - task: CMake@1 inputs: @@ -248,7 +261,16 @@ jobs: CXX: clang++ BuildType: debug-clang cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON - + Debug++ Clang: + CC: clang + CXX: clang++ + BuildType: debug-clang-cxx + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON + Release Clang: + CC: clang + CXX: clang++ + BuildType: release-clang + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release steps: - task: CMake@1 inputs: @@ -273,9 +295,6 @@ jobs: Release: BuildType: release cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release - Secure: - BuildType: secure - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON steps: - task: CMake@1 inputs: From 3a7b6f0a8d83052adcb1b0ae27840b2f6d61ab06 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 18 Nov 2024 10:28:00 -0800 Subject: [PATCH 133/305] allow build time setting of sample rate --- src/options.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/options.c b/src/options.c index 4f95e601..6635f661 100644 --- a/src/options.c +++ b/src/options.c @@ -89,6 +89,14 @@ typedef struct mi_option_desc_s { #define MI_DEFAULT_RESERVE_OS_MEMORY 0 #endif +#ifndef MI_DEFAULT_GUARDED_SAMPLE_RATE +#if MI_GUARDED +#define MI_DEFAULT_GUARDED_SAMPLE_RATE 4000 +#else +#define MI_DEFAULT_GUARDED_SAMPLE_RATE 0 +#endif +#endif + static mi_option_desc_t options[_mi_option_last] = { @@ -145,11 +153,8 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(guarded_min) }, // only used when building with MI_GUARDED: minimal rounded object size for guarded objects { MI_GiB, UNINIT, MI_OPTION(guarded_max) }, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects { 0, UNINIT, MI_OPTION(guarded_precise) }, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) -#if MI_GUARDED - { 4000,UNINIT, MI_OPTION(guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded(= 1000) -#else - { 0, UNINIT, MI_OPTION(guarded_sample_rate)}, -#endif + { MI_DEFAULT_GUARDED_SAMPLE_RATE, + UNINIT, MI_OPTION(guarded_sample_rate)}, // 1 out of N allocations in the min/max range will be guarded (=4000) { 0, UNINIT, MI_OPTION(guarded_sample_seed)}, }; @@ -180,7 +185,7 @@ void _mi_options_init(void) { _mi_warning_message("option 'allow_large_os_pages' is disabled to allow for guarded objects\n"); } } - _mi_verbose_message("guarded build: %s\n", mi_option_get(mi_option_guarded_max) > 0 ? "enabled" : "disabled"); + _mi_verbose_message("guarded build: %s\n", mi_option_get(mi_option_guarded_sample_rate) != 0 ? "enabled" : "disabled"); #endif } From 71fec8caf5a6f3219f37ccfe38b71d73d6274c37 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 18 Nov 2024 15:05:22 -0800 Subject: [PATCH 134/305] add target_segments_per_thread option --- include/mimalloc.h | 1 + include/mimalloc/internal.h | 6 ++- src/options.c | 2 + src/page.c | 33 +++++++++++++--- src/segment.c | 79 ++++++++++++++++++++++++++++++++++++- 5 files changed, 112 insertions(+), 9 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index e3fecdf1..83cbda12 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -377,6 +377,7 @@ typedef enum mi_option_e { mi_option_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0) mi_option_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000) mi_option_guarded_sample_seed, // can be set to allow for a (more) deterministic re-execution when a guard page is triggered (=0) + mi_option_target_segments_per_thread, // experimental (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index d58bd9ca..8de37edf 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -178,6 +178,8 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept; / 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_page_force_abandon(mi_page_t* page); + void _mi_heap_delayed_free_all(mi_heap_t* heap); bool _mi_heap_delayed_free_partial(mi_heap_t* heap); void _mi_heap_collect_retired(mi_heap_t* heap, bool force); @@ -625,9 +627,9 @@ static inline bool mi_heap_malloc_use_guarded(mi_heap_t* heap, size_t size) { } else { // failed size criteria, rewind count (but don't write to an empty heap) - if (heap->guarded_sample_rate != 0) { heap->guarded_sample_count = 1; } + if (heap->guarded_sample_rate != 0) { heap->guarded_sample_count = 1; } return false; - } + } } mi_decl_restrict void* _mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept; diff --git a/src/options.c b/src/options.c index 4f95e601..d49d4aa8 100644 --- a/src/options.c +++ b/src/options.c @@ -65,6 +65,7 @@ typedef struct mi_option_desc_s { #define MI_DEFAULT_ARENA_EAGER_COMMIT 2 #endif +// in KiB #ifndef MI_DEFAULT_ARENA_RESERVE #if (MI_INTPTR_SIZE>4) #define MI_DEFAULT_ARENA_RESERVE 1024L*1024L @@ -151,6 +152,7 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(guarded_sample_rate)}, #endif { 0, UNINIT, MI_OPTION(guarded_sample_seed)}, + { 0, UNINIT, MI_OPTION(target_segments_per_thread) }, // abandon segments beyond this point, or 0 to disable. }; static void mi_option_init(mi_option_desc_t* desc); diff --git a/src/page.c b/src/page.c index 9d8a7b0d..3cf91ba8 100644 --- a/src/page.c +++ b/src/page.c @@ -357,7 +357,7 @@ void _mi_page_unfull(mi_page_t* page) { mi_page_set_in_full(page, false); // to get the right queue mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); mi_page_set_in_full(page, true); - mi_page_queue_enqueue_from_full(pq, pqfull, page); + mi_page_queue_enqueue_from_full(pq, pqfull, page); } static void mi_page_to_full(mi_page_t* page, mi_page_queue_t* pq) { @@ -403,6 +403,29 @@ void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) { _mi_segment_page_abandon(page,segments_tld); } +// force abandon a page +void _mi_page_force_abandon(mi_page_t* page) { + mi_heap_t* heap = mi_page_heap(page); + // mark page as not using delayed free + _mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false); + + // ensure this page is no longer in the heap delayed free list + _mi_heap_delayed_free_all(heap); + // TODO: can we still access the page as it may have been + // freed and the memory decommitted? + // A way around this is to explicitly unlink this page from + // the heap delayed free list. + if (page->capacity == 0) return; // it may have been freed now + + // and now unlink it from the page queue and abandon (or free) + mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page); + if (mi_page_all_free(page)) { + _mi_page_free(page, pq, false); + } + else { + _mi_page_abandon(page, pq); + } +} // Free a page with no more free blocks void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force) { @@ -743,7 +766,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p #if defined(MI_MAX_CANDIDATE_SEARCH) // search up to N pages for a best candidate - + // is the local free list non-empty? const bool immediate_available = mi_page_immediate_available(page); @@ -758,9 +781,9 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p // we prefer non-expandable pages with high usage as candidates (to reduce commit, and increase chances of free-ing up pages) if (page_candidate == NULL) { page_candidate = page; - candidate_count = 0; + candidate_count = 0; } - else if (!mi_page_is_expandable(page) && page->capacity < page_candidate->capacity) { + else if (!mi_page_is_expandable(page) && page->used >= page_candidate->used) { page_candidate = page; } // if we find a non-expandable candidate, or searched for N pages, return with the best candidate @@ -805,7 +828,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p } } else { - mi_assert(pq->first == page); + // mi_assert(pq->first == page); page->retire_expire = 0; } mi_assert_internal(page == NULL || mi_page_immediate_available(page)); diff --git a/src/segment.c b/src/segment.c index 18736818..d2604436 100644 --- a/src/segment.c +++ b/src/segment.c @@ -952,6 +952,9 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) { if (mi_atomic_load_relaxed(&segment->thread_id) != 0) return false; // it is not abandoned if (segment->subproc != heap->tld->segments.subproc) return false; // only reclaim within the same subprocess if (!_mi_heap_memid_is_suitable(heap,segment->memid)) return false; // don't reclaim between exclusive and non-exclusive arena's + const long target = _mi_option_get_fast(mi_option_target_segments_per_thread); + if (target > 0 && (size_t)target <= heap->tld->segments.count) return false; // don't reclaim if going above the target count + // don't reclaim more from a `free` call than half the current segments // this is to prevent a pure free-ing thread to start owning too many segments // (but not for out-of-arena segments as that is the main way to be reclaimed for those) @@ -1023,8 +1026,8 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, result = mi_segment_reclaim(segment, heap, block_size, reclaimed, tld); break; } - else if (segment->abandoned_visits >= 3 && is_suitable) { - // always reclaim on 3rd visit to limit the list length. + else if (segment->abandoned_visits > 3 && is_suitable && !mi_option_is_enabled(mi_option_target_segments_per_thread)) { + // always reclaim on 3rd visit to limit the abandoned segment count. mi_segment_reclaim(segment, heap, 0, NULL, tld); } else { @@ -1038,6 +1041,75 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, } +/* ----------------------------------------------------------- + Force abandon a segment that is in use by our thread +----------------------------------------------------------- */ + +// force abandon a segment +static void mi_segment_force_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) +{ + mi_assert_internal(segment->abandoned < segment->used); + + // for all pages + for (size_t i = 0; i < segment->capacity; i++) { + mi_page_t* page = &segment->pages[i]; + if (page->segment_in_use) { + // ensure used count is up to date and collect potential concurrent frees + _mi_page_free_collect(page, false); + { + // abandon the page if it is still in-use (this will free it if possible as well) + mi_assert_internal(segment->used > 0); + if (segment->used == segment->abandoned+1) { + // the last page.. abandon and return as the segment will be abandoned after this + // and we should no longer access it. + _mi_page_force_abandon(page); + return; + } + else { + // abandon and continue + _mi_page_force_abandon(page); + } + } + } + } + mi_assert(segment->used == segment->abandoned); + mi_assert(segment->used == 0); + if (segment->used == 0) { + // all free now + mi_segment_free(segment, false, tld); + } + else { + // perform delayed purges + mi_pages_try_purge(false /* force? */, tld); + } +} + + +// try abandon segments. +// this should be called from `reclaim_or_alloc` so we know all segments are (about) fully in use. +static void mi_segments_try_abandon(mi_heap_t* heap, mi_segments_tld_t* tld) { + const size_t target = (size_t)mi_option_get_clamp(mi_option_target_segments_per_thread,0,1024); + // we call this when we are about to add a fresh segment so we should be under our target segment count. + if (target == 0 || tld->count < target) return; + + const size_t min_target = (target > 4 ? (target*3)/4 : target); // 75% + + // todo: we should maintain a list of segments per thread; for now, only consider segments from the heap full pages + for (int i = 0; i < 16 && tld->count >= min_target; i++) { + mi_page_t* page = heap->pages[MI_BIN_FULL].first; + while (page != NULL && mi_page_is_huge(page)) { + page = page->next; + } + if (page==NULL) { + break; + } + mi_segment_t* segment = _mi_page_segment(page); + mi_segment_force_abandon(segment, tld); + mi_assert_internal(page != heap->pages[MI_BIN_FULL].first); // as it is just abandoned + } +} + + /* ----------------------------------------------------------- Reclaim or allocate ----------------------------------------------------------- */ @@ -1047,6 +1119,9 @@ static mi_segment_t* mi_segment_reclaim_or_alloc(mi_heap_t* heap, size_t block_s mi_assert_internal(page_kind <= MI_PAGE_LARGE); mi_assert_internal(block_size <= MI_LARGE_OBJ_SIZE_MAX); + // try to abandon some segments to increase reuse between threads + mi_segments_try_abandon(heap,tld); + // 1. try to reclaim an abandoned segment bool reclaimed; mi_segment_t* segment = mi_segment_try_reclaim(heap, block_size, page_kind, &reclaimed, tld); From c58990d4eb93ebe05699cc5e6fa1697a050213aa Mon Sep 17 00:00:00 2001 From: Daan Date: Fri, 22 Nov 2024 13:55:10 -0800 Subject: [PATCH 135/305] fix syntax error (issue #963) --- test/main-override-static.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/main-override-static.c b/test/main-override-static.c index b2b6ee20..ccaba543 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -252,6 +252,8 @@ static void test_heap_arena(void) { break; } } +} + static void test_canary_leak(void) { char* p = mi_mallocn_tp(char,23); for(int i = 0; i < 23; i++) { From 3adb19c84cec47c3012e1253d952823e4d45f61b Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Mon, 21 Oct 2024 17:32:45 +0100 Subject: [PATCH 136/305] Fix illegal instruction for older Arm architectures This is a port of the PR https://github.com/python/cpython/issues/125444 --- include/mimalloc/prim.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index f8bf948e..56715df4 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -138,9 +138,9 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap); // but unfortunately we can not detect support reliably (see issue #883) // We also use it on Apple OS as we use a TLS slot for the default heap there. #if defined(__GNUC__) && ( \ - (defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__))) \ + (defined(__GLIBC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \ || (defined(__APPLE__) && (defined(__x86_64__) || defined(__aarch64__) || defined(__POWERPC__))) \ - || (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__))) \ + || (defined(__BIONIC__) && (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__))) \ || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ || (defined(__OpenBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ ) From 9b7ac9a1a67308a26d09f0b87d2e876fbc61c86c Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 25 Nov 2024 16:58:02 -0800 Subject: [PATCH 137/305] clean up candidate search; add mi_collect_reduce --- ide/vs2022/mimalloc.vcxproj | 2 +- include/mimalloc.h | 1 + src/page-queue.c | 10 +++++++++- src/page.c | 23 ++++++++++++++------- src/segment.c | 40 ++++++++++++++++++++++++++++--------- 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index 160f1436..dddab777 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -116,7 +116,7 @@ true Default ../../include - MI_DEBUG=4;MI_GUARDED=1;%(PreprocessorDefinitions); + MI_DEBUG=3;MI_GUARDED=0;%(PreprocessorDefinitions); CompileAsCpp false stdcpp20 diff --git a/include/mimalloc.h b/include/mimalloc.h index 83cbda12..5916228b 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -148,6 +148,7 @@ typedef void (mi_cdecl mi_error_fun)(int err, void* arg); mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg); mi_decl_export void mi_collect(bool force) mi_attr_noexcept; +mi_decl_export void mi_collect_reduce(size_t target_thread_owned) mi_attr_noexcept; mi_decl_export int mi_version(void) mi_attr_noexcept; mi_decl_export void mi_stats_reset(void) mi_attr_noexcept; mi_decl_export void mi_stats_merge(void) mi_attr_noexcept; diff --git a/src/page-queue.c b/src/page-queue.c index 3034e15d..9796f3dc 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -259,6 +259,14 @@ static void mi_page_queue_push(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_ heap->page_count++; } +static void mi_page_queue_move_to_front(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_t* page) { + mi_assert_internal(mi_page_heap(page) == heap); + mi_assert_internal(mi_page_queue_contains(queue, page)); + if (queue->first == page) return; + mi_page_queue_remove(queue, page); + mi_page_queue_push(heap, queue, page); + mi_assert_internal(queue->first == page); +} static void mi_page_queue_enqueue_from_ex(mi_page_queue_t* to, mi_page_queue_t* from, bool enqueue_at_end, mi_page_t* page) { mi_assert_internal(page != NULL); @@ -335,7 +343,7 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro static void mi_page_queue_enqueue_from_full(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { // note: we could insert at the front to increase reuse, but it slows down certain benchmarks (like `alloc-test`) - mi_page_queue_enqueue_from_ex(to, from, true /* enqueue at the end of the `to` queue? */, page); + mi_page_queue_enqueue_from_ex(to, from, false /* enqueue at the end of the `to` queue? */, page); } // Only called from `mi_heap_absorb`. diff --git a/src/page.c b/src/page.c index 3cf91ba8..43ac7c4e 100644 --- a/src/page.c +++ b/src/page.c @@ -471,6 +471,7 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept { // how to check this efficiently though... // for now, we don't retire if it is the only page left of this size class. mi_page_queue_t* pq = mi_page_queue_of(page); + #if MI_RETIRE_CYCLES > 0 const size_t bsize = mi_page_block_size(page); if mi_likely( /* bsize < MI_MAX_RETIRE_SIZE && */ !mi_page_queue_is_special(pq)) { // not full or huge queue? if (pq->last==page && pq->first==page) { // the only page in the queue? @@ -486,7 +487,7 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept { return; // don't free after all } } - + #endif _mi_page_free(page, pq, false); } @@ -753,6 +754,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p size_t candidate_count = 0; // we reset this on the first candidate to limit the search mi_page_t* page_candidate = NULL; // a page with free space mi_page_t* page = pq->first; + while (page != NULL) { mi_page_t* next = page->next; // remember next @@ -764,7 +766,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p // collect freed blocks by us and other threads _mi_page_free_collect(page, false); -#if defined(MI_MAX_CANDIDATE_SEARCH) + #if MI_MAX_CANDIDATE_SEARCH > 1 // search up to N pages for a best candidate // is the local free list non-empty? @@ -783,7 +785,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p page_candidate = page; candidate_count = 0; } - else if (!mi_page_is_expandable(page) && page->used >= page_candidate->used) { + else if (/* !mi_page_is_expandable(page) && */ page->used >= page_candidate->used) { page_candidate = page; } // if we find a non-expandable candidate, or searched for N pages, return with the best candidate @@ -792,7 +794,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p break; } } -#else + #else // first-fit algorithm // If the page contains free blocks, we are done if (mi_page_immediate_available(page) || mi_page_is_expandable(page)) { @@ -803,7 +805,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p // queue so we don't visit long-lived pages too often. mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page)); mi_page_to_full(page, pq); -#endif + #endif page = next; } // for each page @@ -828,10 +830,14 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p } } else { - // mi_assert(pq->first == page); + // move the page to the front of the queue + mi_page_queue_move_to_front(heap, pq, page); page->retire_expire = 0; + // _mi_heap_collect_retired(heap, false); // update retire counts; note: increases rss on MemoryLoad bench so don't do this } mi_assert_internal(page == NULL || mi_page_immediate_available(page)); + + return page; } @@ -839,7 +845,9 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p // Find a page with free blocks of `size`. static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) { - mi_page_queue_t* pq = mi_page_queue(heap,size); + mi_page_queue_t* pq = mi_page_queue(heap, size); + + // check the first page: we even do this with candidate search or otherwise we re-search every time mi_page_t* page = pq->first; if (page != NULL) { #if (MI_SECURE>=3) // in secure mode, we extend half the time to increase randomness @@ -858,6 +866,7 @@ static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) { return page; // fast path } } + return mi_page_queue_find_free_ex(heap, pq, true); } diff --git a/src/segment.c b/src/segment.c index d2604436..16764da8 100644 --- a/src/segment.c +++ b/src/segment.c @@ -979,6 +979,13 @@ void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) { _mi_arena_field_cursor_done(¤t); } + +static bool segment_count_is_within_target(mi_segments_tld_t* tld, size_t* ptarget) { + const size_t target = (size_t)mi_option_get_clamp(mi_option_target_segments_per_thread, 0, 1024); + if (ptarget != NULL) { *ptarget = target; } + return (target == 0 || tld->count < target); +} + static long mi_segment_get_reclaim_tries(mi_segments_tld_t* tld) { // limit the tries to 10% (default) of the abandoned segments with at least 8 and at most 1024 tries. const size_t perc = (size_t)mi_option_get_clamp(mi_option_max_segment_reclaim, 0, 100); @@ -1001,7 +1008,7 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, mi_segment_t* segment = NULL; mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, tld->subproc, false /* non-blocking */, ¤t); - while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL)) + while (segment_count_is_within_target(tld,NULL) && (max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(¤t)) != NULL)) { mi_assert(segment->subproc == heap->tld->segments.subproc); // cursor only visits segments in our sub-process segment->abandoned_visits++; @@ -1026,7 +1033,7 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, result = mi_segment_reclaim(segment, heap, block_size, reclaimed, tld); break; } - else if (segment->abandoned_visits > 3 && is_suitable && !mi_option_is_enabled(mi_option_target_segments_per_thread)) { + else if (segment->abandoned_visits > 3 && is_suitable) { // always reclaim on 3rd visit to limit the abandoned segment count. mi_segment_reclaim(segment, heap, 0, NULL, tld); } @@ -1087,15 +1094,11 @@ static void mi_segment_force_abandon(mi_segment_t* segment, mi_segments_tld_t* t // try abandon segments. // this should be called from `reclaim_or_alloc` so we know all segments are (about) fully in use. -static void mi_segments_try_abandon(mi_heap_t* heap, mi_segments_tld_t* tld) { - const size_t target = (size_t)mi_option_get_clamp(mi_option_target_segments_per_thread,0,1024); - // we call this when we are about to add a fresh segment so we should be under our target segment count. - if (target == 0 || tld->count < target) return; - +static void mi_segments_try_abandon_to_target(mi_heap_t* heap, size_t target, mi_segments_tld_t* tld) { + if (target <= 1) return; const size_t min_target = (target > 4 ? (target*3)/4 : target); // 75% - // todo: we should maintain a list of segments per thread; for now, only consider segments from the heap full pages - for (int i = 0; i < 16 && tld->count >= min_target; i++) { + for (int i = 0; i < 64 && tld->count >= min_target; i++) { mi_page_t* page = heap->pages[MI_BIN_FULL].first; while (page != NULL && mi_page_is_huge(page)) { page = page->next; @@ -1109,6 +1112,25 @@ static void mi_segments_try_abandon(mi_heap_t* heap, mi_segments_tld_t* tld) { } } +// try abandon segments. +// this should be called from `reclaim_or_alloc` so we know all segments are (about) fully in use. +static void mi_segments_try_abandon(mi_heap_t* heap, mi_segments_tld_t* tld) { + // we call this when we are about to add a fresh segment so we should be under our target segment count. + size_t target = 0; + if (segment_count_is_within_target(tld, &target)) return; + mi_segments_try_abandon_to_target(heap, target, tld); +} + +void mi_collect_reduce(size_t target_size) mi_attr_noexcept { + mi_collect(true); + mi_heap_t* heap = mi_heap_get_default(); + mi_segments_tld_t* tld = &heap->tld->segments; + size_t target = target_size / MI_SEGMENT_SIZE; + if (target == 0) { + target = (size_t)mi_option_get_clamp(mi_option_target_segments_per_thread, 1, 1024); + } + mi_segments_try_abandon_to_target(heap, target, tld); +} /* ----------------------------------------------------------- Reclaim or allocate From 7673aa2517fa44080c51df8833aa7e79dad12ea8 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 25 Nov 2024 18:41:57 -0800 Subject: [PATCH 138/305] ensure forced abandoned pages can be accessed after free --- include/mimalloc/types.h | 3 ++- src/page.c | 6 ++---- src/segment.c | 38 ++++++++++++++++++++++---------------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index f7bca137..44074450 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -416,7 +416,8 @@ typedef struct mi_segment_s { // segment fields struct mi_segment_s* next; // must be the first (non-constant) segment field -- see `segment.c:segment_init` struct mi_segment_s* prev; - bool was_reclaimed; // true if it was reclaimed (used to limit on-free reclamation) + bool was_reclaimed; // true if it was reclaimed (used to limit reclaim-on-free reclamation) + bool dont_free; // can be temporarily true to ensure the segment is not freed size_t abandoned; // abandoned pages (i.e. the original owning thread stopped) (`abandoned <= used`) size_t abandoned_visits; // count how often this segment is visited for reclaiming (to force reclaim if it is too long) diff --git a/src/page.c b/src/page.c index 43ac7c4e..c681d6d0 100644 --- a/src/page.c +++ b/src/page.c @@ -411,10 +411,8 @@ void _mi_page_force_abandon(mi_page_t* page) { // ensure this page is no longer in the heap delayed free list _mi_heap_delayed_free_all(heap); - // TODO: can we still access the page as it may have been - // freed and the memory decommitted? - // A way around this is to explicitly unlink this page from - // the heap delayed free list. + // We can still access the page meta-info even if it is freed as we ensure + // in `mi_segment_force_abandon` that the segment is not freed (yet) if (page->capacity == 0) return; // it may have been freed now // and now unlink it from the page queue and abandon (or free) diff --git a/src/segment.c b/src/segment.c index 16764da8..74abcdbc 100644 --- a/src/segment.c +++ b/src/segment.c @@ -652,6 +652,10 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, static void mi_segment_free(mi_segment_t* segment, bool force, mi_segments_tld_t* tld) { MI_UNUSED(force); mi_assert(segment != NULL); + + // in `mi_segment_force_abandon` we set this to true to ensure the segment's memory stays valid + if (segment->dont_free) return; + // don't purge as we are freeing now mi_segment_remove_all_purges(segment, false /* don't force as we are about to free */, tld); mi_segment_remove_from_free_queue(segment, tld); @@ -1056,32 +1060,34 @@ static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, static void mi_segment_force_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) { mi_assert_internal(segment->abandoned < segment->used); + mi_assert_internal(!segment->dont_free); + + // ensure the segment does not get free'd underneath us (so we can check if a page has been freed in `mi_page_force_abandon`) + segment->dont_free = true; // for all pages for (size_t i = 0; i < segment->capacity; i++) { mi_page_t* page = &segment->pages[i]; if (page->segment_in_use) { - // ensure used count is up to date and collect potential concurrent frees - _mi_page_free_collect(page, false); - { - // abandon the page if it is still in-use (this will free it if possible as well) - mi_assert_internal(segment->used > 0); - if (segment->used == segment->abandoned+1) { - // the last page.. abandon and return as the segment will be abandoned after this - // and we should no longer access it. - _mi_page_force_abandon(page); - return; - } - else { - // abandon and continue - _mi_page_force_abandon(page); - } + // abandon the page if it is still in-use (this will free the page if possible as well (but not our segment)) + mi_assert_internal(segment->used > 0); + if (segment->used == segment->abandoned+1) { + // the last page.. abandon and return as the segment will be abandoned after this + // and we should no longer access it. + segment->dont_free = false; + _mi_page_force_abandon(page); + return; + } + else { + // abandon and continue + _mi_page_force_abandon(page); } } } + segment->dont_free = false; mi_assert(segment->used == segment->abandoned); mi_assert(segment->used == 0); - if (segment->used == 0) { + if (segment->used == 0) { // paranoia // all free now mi_segment_free(segment, false, tld); } From bdc87fc91b3654f73a5c0ea78ccb210769c84244 Mon Sep 17 00:00:00 2001 From: Joris van der Geer Date: Mon, 2 Dec 2024 20:50:08 +1000 Subject: [PATCH 139/305] readme - describe how to run under Valgrind with dynamic override --- readme.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index a0296b43..5c85392e 100644 --- a/readme.md +++ b/readme.md @@ -505,9 +505,13 @@ you also need to tell `valgrind` to not intercept those calls itself, and use: By setting the `MIMALLOC_SHOW_STATS` environment variable you can check that mimalloc is indeed used and not the standard allocator. Even though the [Valgrind option][valgrind-soname] -is called `--soname-synonyms`, this also -works when overriding with a static library or object file. Unfortunately, it is not possible to -dynamically override mimalloc using `LD_PRELOAD` together with `valgrind`. +is called `--soname-synonyms`, this also works when overriding with a static library or object file. +To dynamically override mimalloc using `LD_PRELOAD` together with `valgrind`, use: + +``` +> valgrind --trace-children=yes --soname-synonyms=somalloc=*mimalloc* /usr/bin/env LD_PRELOAD=/usr/lib/libmimalloc.so -- +``` + See also the `test/test-wrong.c` file to test with `valgrind`. Valgrind support is in its initial development -- please report any issues. From 469ade882dbff3226be92e71e2d75d04d84029b1 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 7 Dec 2024 14:03:16 -0800 Subject: [PATCH 140/305] Add MI_ARCHOPT option to enable architecture specific optimizations --- CMakeLists.txt | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fc1808e..6b89da08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhea option(MI_TRACK_ASAN "Compile with address sanitizer support (adds a small overhead)" OFF) option(MI_TRACK_ETW "Compile with Windows event tracing (ETW) support (adds a small overhead)" OFF) option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF) +option(MI_ARCHOPT "Only for optimized builds: turn on architecture specific optimizations (for x64: '-march=haswell -mavx2' (2013), for arm64: '-march=armv8.1-a' (2016))" ON) option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON) option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON) @@ -112,6 +113,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel") set(MI_USE_CXX "ON") endif() +if(NOT CMAKE_BUILD_TYPE MATCHES "Release|RelWithDebInfo") + set(MI_ARCHOPT OFF) +endif() + if(MI_OVERRIDE) message(STATUS "Override standard malloc (MI_OVERRIDE=ON)") if(APPLE) @@ -319,16 +324,31 @@ if(MI_WIN_USE_FLS) list(APPEND mi_defines MI_WIN_USE_FLS=1) endif() +# Check architecture +set(MI_ARCH "unknown") +if(APPLE) + list(FIND CMAKE_OSX_ARCHITECTURES "x86_64" x64_index) + list(FIND CMAKE_OSX_ARCHITECTURES "arm64" arm64_index) + if(x64_index GREATER_EQUAL 0) + set(MI_ARCH "x64") + elseif(arm64_index GREATER_EQUAL 0) + set(MI_ARCH "arm64") + endif() +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") + set(MI_ARCH "x64") +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") + set(MI_ARCH "arm64") +endif() - # Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits. - # (this will skip the aligned hinting in that case. Issue #939, #949) - if (EXISTS /proc/cpuinfo) - file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$") - if (mi_sv39_mmu) - MESSAGE( STATUS "Set virtual address bits to 39 (SV39 MMU detected)" ) - list(APPEND mi_defines MI_DEFAULT_VIRTUAL_ADDRESS_BITS=39) - endif() - endif() +# Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits. +# (this will skip the aligned hinting in that case. Issue #939, #949) +if (EXISTS /proc/cpuinfo) + file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$") + if (mi_sv39_mmu) + MESSAGE( STATUS "Set virtual address bits to 39 (SV39 MMU detected)" ) + list(APPEND mi_defines MI_DEFAULT_VIRTUAL_ADDRESS_BITS=39) + endif() +endif() # On Haiku use `-DCMAKE_INSTALL_PREFIX` instead, issue #788 # if(CMAKE_SYSTEM_NAME MATCHES "Haiku") @@ -367,6 +387,18 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM if(MI_OVERRIDE) list(APPEND mi_cflags -fno-builtin-malloc) endif() + if(MI_ARCHOPT) + set(mi_arch_opt "") + if(MI_ARCH STREQUAL "x64") + set(mi_arch_opt "-march=haswell;-mavx2") # fast bit scan, ~ 2013 + elseif(MI_ARCH STREQUAL "arm64") + set(mi_arch_opt "-march=armv8.1-a") # fast atomics, ~ 2016 + endif() + if(mi_arch_opt) + list(APPEND mi_cflags ${mi_arch_opt}) + message(STATUS "Architecture specific optimization is enabled (with ${mi_arch_opt}) (since MI_ARCHOPT=ON)") + endif() + endif() endif() if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) From 60a8da75ff426d0684f5fc065526f22c32b8f744 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 7 Dec 2024 14:16:39 -0800 Subject: [PATCH 141/305] Add MI_ARCHOPT support for msvc --- CMakeLists.txt | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b89da08..16d153aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,11 @@ if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel") set(MI_USE_CXX "ON") endif() -if(NOT CMAKE_BUILD_TYPE MATCHES "Release|RelWithDebInfo") +if(CMAKE_BUILD_TYPE MATCHES "Release|RelWithDebInfo") + if (NOT MI_ARCHOPT) + message(STATUS "Architecture specific optimizations are disabled (MI_ARCHOPT=OFF)") + endif() +else() set(MI_ARCHOPT OFF) endif() @@ -325,6 +329,7 @@ if(MI_WIN_USE_FLS) endif() # Check architecture +set(MI_ARCHOPT_FLAGS "") set(MI_ARCH "unknown") if(APPLE) list(FIND CMAKE_OSX_ARCHITECTURES "x86_64" x64_index) @@ -388,27 +393,34 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM list(APPEND mi_cflags -fno-builtin-malloc) endif() if(MI_ARCHOPT) - set(mi_arch_opt "") if(MI_ARCH STREQUAL "x64") - set(mi_arch_opt "-march=haswell;-mavx2") # fast bit scan, ~ 2013 + set(MI_ARCH_OPT_FLAGS "-march=haswell;-mavx2") # fast bit scan, ~ 2013 elseif(MI_ARCH STREQUAL "arm64") - set(mi_arch_opt "-march=armv8.1-a") # fast atomics, ~ 2016 - endif() - if(mi_arch_opt) - list(APPEND mi_cflags ${mi_arch_opt}) - message(STATUS "Architecture specific optimization is enabled (with ${mi_arch_opt}) (since MI_ARCHOPT=ON)") + set(MI_ARCH_OPT_FLAGS "-march=armv8.1-a") # fast atomics, ~ 2016 endif() endif() endif() if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) list(APPEND mi_cflags /Zc:__cplusplus) + if(MI_ARCHOPT) + if(MI_ARCH STREQUAL "x64") + set(MI_ARCHOPT_FLAGS "/arch:AVX2") # fast bit scan, ~ 2013 + elseif(MI_ARCH STREQUAL "arm64") + set(MI_ARCHOPT_FLAGS "/arch:armv8.1") # fast atomics, ~ 2016 + endif() + endif() endif() if(MINGW) add_definitions(-D_WIN32_WINNT=0x600) endif() +if(MI_ARCH_OPT_FLAGS) + list(APPEND mi_cflags ${MI_ARCH_OPT_FLAGS}) + message(STATUS "Architecture specific optimization is enabled (with ${MI_ARCH_OPT_FLAGS}) (MI_ARCHOPT=ON)") +endif() + # extra needed libraries # we prefer -l test over `find_library` as sometimes core libraries From 7c2b09fc3e9d1eec62dc240610e8193cf1eec3fe Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 8 Dec 2024 09:02:16 -0800 Subject: [PATCH 142/305] only enable architecture specific optimization for armv8.1 --- CMakeLists.txt | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16d153aa..892a51fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhea option(MI_TRACK_ASAN "Compile with address sanitizer support (adds a small overhead)" OFF) option(MI_TRACK_ETW "Compile with Windows event tracing (ETW) support (adds a small overhead)" OFF) option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF) -option(MI_ARCHOPT "Only for optimized builds: turn on architecture specific optimizations (for x64: '-march=haswell -mavx2' (2013), for arm64: '-march=armv8.1-a' (2016))" ON) +option(MI_OPT_ARCH "Only for optimized builds: turn on architecture specific optimizations (for arm64: '-march=armv8.1-a' (2016))" ON) option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON) option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON) @@ -114,11 +114,11 @@ if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel") endif() if(CMAKE_BUILD_TYPE MATCHES "Release|RelWithDebInfo") - if (NOT MI_ARCHOPT) - message(STATUS "Architecture specific optimizations are disabled (MI_ARCHOPT=OFF)") + if (NOT MI_OPT_ARCH) + message(STATUS "Architecture specific optimizations are disabled (MI_OPT_ARCH=OFF)") endif() else() - set(MI_ARCHOPT OFF) + set(MI_OPT_ARCH OFF) endif() if(MI_OVERRIDE) @@ -328,8 +328,8 @@ if(MI_WIN_USE_FLS) list(APPEND mi_defines MI_WIN_USE_FLS=1) endif() -# Check architecture -set(MI_ARCHOPT_FLAGS "") +# Determine architecture +set(MI_OPT_ARCH_FLAGS "") set(MI_ARCH "unknown") if(APPLE) list(FIND CMAKE_OSX_ARCHITECTURES "x86_64" x64_index) @@ -392,22 +392,18 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM if(MI_OVERRIDE) list(APPEND mi_cflags -fno-builtin-malloc) endif() - if(MI_ARCHOPT) - if(MI_ARCH STREQUAL "x64") - set(MI_ARCH_OPT_FLAGS "-march=haswell;-mavx2") # fast bit scan, ~ 2013 - elseif(MI_ARCH STREQUAL "arm64") - set(MI_ARCH_OPT_FLAGS "-march=armv8.1-a") # fast atomics, ~ 2016 + if(MI_OPT_ARCH) + if(MI_ARCH STREQUAL "arm64") + set(MI_ARCH_OPT_FLAGS "-march=armv8.1-a") # fast atomics, since ~ 2016 endif() endif() endif() if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) list(APPEND mi_cflags /Zc:__cplusplus) - if(MI_ARCHOPT) - if(MI_ARCH STREQUAL "x64") - set(MI_ARCHOPT_FLAGS "/arch:AVX2") # fast bit scan, ~ 2013 - elseif(MI_ARCH STREQUAL "arm64") - set(MI_ARCHOPT_FLAGS "/arch:armv8.1") # fast atomics, ~ 2016 + if(MI_OPT_ARCH) + if(MI_ARCH STREQUAL "arm64") + set(MI_OPT_ARCH_FLAGS "/arch:armv8.1") # fast atomics, since ~ 2016 endif() endif() endif() @@ -418,7 +414,7 @@ endif() if(MI_ARCH_OPT_FLAGS) list(APPEND mi_cflags ${MI_ARCH_OPT_FLAGS}) - message(STATUS "Architecture specific optimization is enabled (with ${MI_ARCH_OPT_FLAGS}) (MI_ARCHOPT=ON)") + message(STATUS "Architecture specific optimization is enabled (with ${MI_ARCH_OPT_FLAGS}) (MI_OPT_ARCH=ON)") endif() # extra needed libraries From 68bd8744b7722d918a9a2403eeb4248ee30afb84 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 8 Dec 2024 09:13:48 -0800 Subject: [PATCH 143/305] fix spelling --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 892a51fa..17f2071a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,7 +394,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM endif() if(MI_OPT_ARCH) if(MI_ARCH STREQUAL "arm64") - set(MI_ARCH_OPT_FLAGS "-march=armv8.1-a") # fast atomics, since ~ 2016 + set(MI_OPT_ARCH_FLAGS "-march=armv8.1-a") # fast atomics endif() endif() endif() @@ -403,7 +403,7 @@ if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) list(APPEND mi_cflags /Zc:__cplusplus) if(MI_OPT_ARCH) if(MI_ARCH STREQUAL "arm64") - set(MI_OPT_ARCH_FLAGS "/arch:armv8.1") # fast atomics, since ~ 2016 + set(MI_OPT_ARCH_FLAGS "/arch:armv8.1") # fast atomics endif() endif() endif() @@ -412,9 +412,9 @@ if(MINGW) add_definitions(-D_WIN32_WINNT=0x600) endif() -if(MI_ARCH_OPT_FLAGS) - list(APPEND mi_cflags ${MI_ARCH_OPT_FLAGS}) - message(STATUS "Architecture specific optimization is enabled (with ${MI_ARCH_OPT_FLAGS}) (MI_OPT_ARCH=ON)") +if(MI_OPT_ARCH_FLAGS) + list(APPEND mi_cflags ${MI_OPT_ARCH_FLAGS}) + message(STATUS "Architecture specific optimization is enabled (with ${MI_OPT_ARCH_FLAGS}) (MI_OPT_ARCH=ON)") endif() # extra needed libraries From d9a2f76ff759f04c591d0d7e2595417ccf7f4655 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 8 Dec 2024 17:23:09 -0800 Subject: [PATCH 144/305] fix write to empty heap in mi_guarded build --- src/alloc-aligned.c | 5 +-- test/main-override-static.c | 70 +++++++++++++++++++++++++++---------- test/test-stress.c | 4 +-- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index b4da4ded..6b0a33c1 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -39,9 +39,10 @@ static mi_decl_restrict void* mi_heap_malloc_guarded_aligned(mi_heap_t* heap, si static void* mi_heap_malloc_zero_no_guarded(mi_heap_t* heap, size_t size, bool zero) { const size_t rate = heap->guarded_sample_rate; - heap->guarded_sample_rate = 0; + // only write if `rate!=0` so we don't write to the constant `_mi_heap_empty` + if (rate != 0) { heap->guarded_sample_rate = 0; } void* p = _mi_heap_malloc_zero(heap, size, zero); - heap->guarded_sample_rate = rate; + if (rate != 0) { heap->guarded_sample_rate = rate; } return p; } #else diff --git a/test/main-override-static.c b/test/main-override-static.c index 4ad76d6a..34860717 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -7,6 +7,8 @@ #include #include // redefines malloc etc. +static void mi_bins(void); + static void double_free1(); static void double_free2(); static void corrupt_free(); @@ -41,6 +43,9 @@ int main() { // test_heap_walk(); // alloc_huge(); + // mi_bins(); + + void* p1 = malloc(78); void* p2 = malloc(24); free(p1); @@ -290,11 +295,11 @@ static void test_large_pages(void) { static inline uint8_t mi_bsr32(uint32_t x); #if defined(_MSC_VER) -#include +//#include #include static inline uint8_t mi_bsr32(uint32_t x) { uint32_t idx; - _BitScanReverse((DWORD*)&idx, x); + _BitScanReverse(&idx, x); return idx; } #elif defined(__GNUC__) || defined(__clang__) @@ -318,7 +323,7 @@ static inline uint8_t mi_bsr32(uint32_t x) { } #endif -/* + // Bit scan reverse: return the index of the highest bit. uint8_t _mi_bsr(uintptr_t x) { if (x == 0) return 0; @@ -331,7 +336,7 @@ uint8_t _mi_bsr(uintptr_t x) { # error "define bsr for non-32 or 64-bit platforms" #endif } -*/ + static inline size_t _mi_wsize_from_size(size_t size) { @@ -408,11 +413,20 @@ static inline uint8_t _mi_bin4(size_t size) { return bin; } -static size_t _mi_binx4(size_t bsize) { - if (bsize==0) return 0; - uint8_t b = mi_bsr32((uint32_t)bsize); - if (b <= 1) return bsize; - size_t bin = ((b << 1) | (bsize >> (b - 1))&0x01); +static size_t _mi_binx4(size_t wsize) { + size_t bin; + if (wsize <= 1) { + bin = 1; + } + else if (wsize <= 8) { + // bin = (wsize+1)&~1; // round to double word sizes + bin = (uint8_t)wsize; + } + else { + uint8_t b = mi_bsr32((uint32_t)wsize); + if (b <= 1) return wsize; + bin = ((b << 1) | (wsize >> (b - 1))&0x01) + 3; + } return bin; } @@ -424,22 +438,40 @@ static size_t _mi_binx8(size_t bsize) { return bin; } + +static inline size_t mi_bin(size_t wsize) { + uint8_t bin; + if (wsize <= 1) { + bin = 1; + } + else if (wsize <= 8) { + // bin = (wsize+1)&~1; // round to double word sizes + bin = (uint8_t)wsize; + } + else { + wsize--; + // find the highest bit + uint8_t b = (uint8_t)mi_bsr32((uint32_t)wsize); // note: wsize != 0 + // and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation). + // - adjust with 3 because we use do not round the first 8 sizes + // which each get an exact bin + bin = ((b << 2) + (uint8_t)((wsize >> (b - 2)) & 0x03)) - 3; + } + return bin; +} + + static void mi_bins(void) { //printf(" QNULL(1), /* 0 */ \\\n "); size_t last_bin = 0; - size_t min_bsize = 0; - size_t last_bsize = 0; - for (size_t bsize = 1; bsize < 2*1024; bsize++) { - size_t size = bsize * 64 * 1024; - size_t bin = _mi_binx8(bsize); + for (size_t wsize = 1; wsize <= (4*1024*1024) / 8 + 1024; wsize++) { + size_t bin = mi_bin(wsize); if (bin != last_bin) { - printf("min bsize: %6zd, max bsize: %6zd, bin: %6zd\n", min_bsize, last_bsize, last_bin); - //printf("QNULL(%6zd), ", wsize); - //if (last_bin%8 == 0) printf("/* %i */ \\\n ", last_bin); + //printf("min bsize: %6zd, max bsize: %6zd, bin: %6zd\n", min_wsize, last_wsize, last_bin); + printf("QNULL(%6zd), ", wsize-1); + if (last_bin%8 == 0) printf("/* %zu */ \\\n ", last_bin); last_bin = bin; - min_bsize = bsize; } - last_bsize = bsize; } } #endif diff --git a/test/test-stress.c b/test/test-stress.c index 1e70e699..8ede5db2 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -42,7 +42,7 @@ static int SCALE = 10; static int ITER = 10; #else static int THREADS = 32; // more repeatable if THREADS <= #processors -static int SCALE = 25; // scaling factor +static int SCALE = 50; // scaling factor static int ITER = 50; // N full iterations destructing and re-creating all threads #endif @@ -50,7 +50,7 @@ static int ITER = 50; // N full iterations destructing and re-creating a #define STRESS // undefine for leak test -static bool allow_large_objects = true; // allow very large objects? (set to `true` if SCALE>100) +static bool allow_large_objects = false; // allow very large objects? (set to `true` if SCALE>100) static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`? static bool main_participates = false; // main thread participates as a worker too From c8607a8d012665782b9e2dc7cc6a35449ac803f5 Mon Sep 17 00:00:00 2001 From: daanx Date: Sun, 8 Dec 2024 17:56:13 -0800 Subject: [PATCH 145/305] remove os_tld and stats parameters to os interface --- include/mimalloc/internal.h | 223 ++++++++++++++++++------------------ include/mimalloc/types.h | 8 -- src/arena.c | 92 +++++++-------- src/bitmap.c | 12 +- src/bitmap.h | 2 +- src/heap.c | 2 +- src/init.c | 17 ++- src/os.c | 130 ++++++++++----------- src/page.c | 2 +- src/segment-map.c | 4 +- src/segment.c | 70 +++++------ test/test-stress.c | 2 +- 12 files changed, 270 insertions(+), 294 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 716386d2..703c44b9 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -53,89 +53,100 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_decl_externc #endif +// "libc.c" +#include +void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args); +void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...); +char _mi_toupper(char c); +int _mi_strnicmp(const char* s, const char* t, size_t n); +void _mi_strlcpy(char* dest, const char* src, size_t dest_size); +void _mi_strlcat(char* dest, const char* src, size_t dest_size); +size_t _mi_strlen(const char* s); +size_t _mi_strnlen(const char* s, size_t max_len); +bool _mi_getenv(const char* name, char* result, size_t result_size); // "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); -long _mi_option_get_fast(mi_option_t option); -void _mi_error_message(int err, const char* fmt, ...); +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); +long _mi_option_get_fast(mi_option_t option); +void _mi_error_message(int err, const char* fmt, ...); // random.c -void _mi_random_init(mi_random_ctx_t* ctx); -void _mi_random_init_weak(mi_random_ctx_t* ctx); -void _mi_random_reinit_if_weak(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 _mi_os_random_weak(uintptr_t extra_seed); +void _mi_random_init(mi_random_ctx_t* ctx); +void _mi_random_init_weak(mi_random_ctx_t* ctx); +void _mi_random_reinit_if_weak(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 _mi_os_random_weak(uintptr_t extra_seed); static inline uintptr_t _mi_random_shuffle(uintptr_t x); // init.c extern mi_decl_cache_align mi_stats_t _mi_stats_main; extern mi_decl_cache_align const mi_page_t _mi_page_empty; -void _mi_process_load(void); +void _mi_process_load(void); void mi_cdecl _mi_process_done(void); -bool _mi_is_redirected(void); -bool _mi_allocator_init(const char** message); -void _mi_allocator_done(void); -bool _mi_is_main_thread(void); -size_t _mi_current_thread_count(void); -bool _mi_preloading(void); // true while the C runtime is not initialized yet -void _mi_thread_done(mi_heap_t* heap); -void _mi_thread_data_collect(void); -void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap); +bool _mi_is_redirected(void); +bool _mi_allocator_init(const char** message); +void _mi_allocator_done(void); +bool _mi_is_main_thread(void); +size_t _mi_current_thread_count(void); +bool _mi_preloading(void); // true while the C runtime is not initialized yet +void _mi_thread_done(mi_heap_t* heap); +void _mi_thread_data_collect(void); +void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap); mi_threadid_t _mi_thread_id(void) mi_attr_noexcept; mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id); -void _mi_heap_guarded_init(mi_heap_t* heap); +void _mi_heap_guarded_init(mi_heap_t* heap); // os.c -void _mi_os_init(void); // called from process init -void* _mi_os_alloc(size_t size, mi_memid_t* memid, mi_stats_t* stats); -void _mi_os_free(void* p, size_t size, mi_memid_t memid, mi_stats_t* stats); -void _mi_os_free_ex(void* p, size_t size, bool still_committed, mi_memid_t memid, mi_stats_t* stats); +void _mi_os_init(void); // called from process init +void* _mi_os_alloc(size_t size, mi_memid_t* memid); +void _mi_os_free(void* p, size_t size, mi_memid_t memid); +void _mi_os_free_ex(void* p, size_t size, bool still_committed, mi_memid_t memid); -size_t _mi_os_page_size(void); -size_t _mi_os_good_alloc_size(size_t size); -bool _mi_os_has_overcommit(void); -bool _mi_os_has_virtual_reserve(void); +size_t _mi_os_page_size(void); +size_t _mi_os_good_alloc_size(size_t size); +bool _mi_os_has_overcommit(void); +bool _mi_os_has_virtual_reserve(void); -bool _mi_os_reset(void* addr, size_t size, mi_stats_t* tld_stats); -bool _mi_os_commit(void* p, size_t size, bool* is_zero, mi_stats_t* stats); -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); -bool _mi_os_protect(void* addr, size_t size); -bool _mi_os_unprotect(void* addr, size_t size); -bool _mi_os_purge(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, mi_stats_t* stats); +bool _mi_os_reset(void* addr, size_t size); +bool _mi_os_commit(void* p, size_t size, bool* is_zero); +bool _mi_os_decommit(void* addr, size_t size); +bool _mi_os_protect(void* addr, size_t size); +bool _mi_os_unprotect(void* addr, size_t size); +bool _mi_os_purge(void* p, size_t size); +bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset); -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* stats); -void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* tld_stats); +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid); +void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_large, mi_memid_t* memid); -void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size); -bool _mi_os_use_large_page(size_t size, size_t alignment); -size_t _mi_os_large_page_size(void); +void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size); +bool _mi_os_use_large_page(size_t size, size_t alignment); +size_t _mi_os_large_page_size(void); -void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_secs, size_t* pages_reserved, size_t* psize, mi_memid_t* memid); +void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_secs, size_t* pages_reserved, size_t* psize, mi_memid_t* memid); // arena.c mi_arena_id_t _mi_arena_id_none(void); -void _mi_arena_free(void* p, size_t size, size_t still_committed_size, mi_memid_t memid, mi_stats_t* stats); -void* _mi_arena_alloc(size_t size, bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld); -void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld); -bool _mi_arena_memid_is_suitable(mi_memid_t memid, mi_arena_id_t request_arena_id); -bool _mi_arena_contains(const void* p); -void _mi_arenas_collect(bool force_purge, mi_stats_t* stats); -void _mi_arena_unsafe_destroy_all(mi_stats_t* stats); +void _mi_arena_free(void* p, size_t size, size_t still_committed_size, mi_memid_t memid); +void* _mi_arena_alloc(size_t size, bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid); +void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid); +bool _mi_arena_memid_is_suitable(mi_memid_t memid, mi_arena_id_t request_arena_id); +bool _mi_arena_contains(const void* p); +void _mi_arenas_collect(bool force_purge); +void _mi_arena_unsafe_destroy_all(void); -bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment); -void _mi_arena_segment_mark_abandoned(mi_segment_t* segment); +bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment); +void _mi_arena_segment_mark_abandoned(mi_segment_t* segment); -void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid); -void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size); +void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid); +void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size); typedef struct mi_arena_field_cursor_s { // abstract struct size_t os_list_count; // max entries to visit in the OS abandoned list @@ -151,63 +162,63 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr void _mi_arena_field_cursor_done(mi_arena_field_cursor_t* current); // "segment-map.c" -void _mi_segment_map_allocated_at(const mi_segment_t* segment); -void _mi_segment_map_freed_at(const mi_segment_t* segment); +void _mi_segment_map_allocated_at(const mi_segment_t* segment); +void _mi_segment_map_freed_at(const mi_segment_t* segment); // "segment.c" -mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment, 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* page_size); +mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment, mi_segments_tld_t* 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* page_size); #if MI_HUGE_PAGE_ABANDON -void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block_t* block); +void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block_t* block); #else -void _mi_segment_huge_page_reset(mi_segment_t* segment, mi_page_t* page, mi_block_t* block); +void _mi_segment_huge_page_reset(mi_segment_t* segment, mi_page_t* page, mi_block_t* block); #endif -void _mi_segments_collect(bool force, mi_segments_tld_t* tld); -void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld); -bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment); -bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); +void _mi_segments_collect(bool force, mi_segments_tld_t* tld); +void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld); +bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment); +bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); // "page.c" -void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept mi_attr_malloc; +void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept mi_attr_malloc; -void _mi_page_retire(mi_page_t* page) mi_attr_noexcept; // 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_page_force_abandon(mi_page_t* page); +void _mi_page_retire(mi_page_t* page) mi_attr_noexcept; // 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_page_force_abandon(mi_page_t* page); -void _mi_heap_delayed_free_all(mi_heap_t* heap); -bool _mi_heap_delayed_free_partial(mi_heap_t* heap); -void _mi_heap_collect_retired(mi_heap_t* heap, bool force); +void _mi_heap_delayed_free_all(mi_heap_t* heap); +bool _mi_heap_delayed_free_partial(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); -bool _mi_page_try_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_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never); +bool _mi_page_try_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 +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 +size_t _mi_bin_size(uint8_t bin); // for stats +uint8_t _mi_bin(size_t size); // for stats // "heap.c" -void _mi_heap_init(mi_heap_t* heap, mi_tld_t* tld, mi_arena_id_t arena_id, bool noreclaim, uint8_t tag); -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); -bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid); -void _mi_heap_unsafe_destroy_all(void); -mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag); -void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page); -bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg); +void _mi_heap_init(mi_heap_t* heap, mi_tld_t* tld, mi_arena_id_t arena_id, bool noreclaim, uint8_t tag); +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); +bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid); +void _mi_heap_unsafe_destroy_all(void); +mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag); +void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page); +bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg); // "stats.c" -void _mi_stats_done(mi_stats_t* stats); +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); @@ -224,18 +235,6 @@ bool _mi_free_delayed_block(mi_block_t* block); void _mi_free_generic(mi_segment_t* segment, mi_page_t* page, bool is_local, void* p) mi_attr_noexcept; // for runtime integration void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size); -// "libc.c" -#include -void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args); -void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...); -char _mi_toupper(char c); -int _mi_strnicmp(const char* s, const char* t, size_t n); -void _mi_strlcpy(char* dest, const char* src, size_t dest_size); -void _mi_strlcat(char* dest, const char* src, size_t dest_size); -size_t _mi_strlen(const char* s); -size_t _mi_strnlen(const char* s, size_t max_len); -bool _mi_getenv(const char* name, char* result, size_t result_size); - #if MI_DEBUG>1 bool _mi_page_is_valid(mi_page_t* page); #endif @@ -806,13 +805,13 @@ static inline uintptr_t _mi_random_shuffle(uintptr_t x) { // Optimize numa node access for the common case (= one node) // ------------------------------------------------------------------- -int _mi_os_numa_node_get(mi_os_tld_t* tld); +int _mi_os_numa_node_get(void); size_t _mi_os_numa_node_count_get(void); extern _Atomic(size_t) _mi_numa_node_count; -static inline int _mi_os_numa_node(mi_os_tld_t* tld) { +static inline int _mi_os_numa_node(void) { if mi_likely(mi_atomic_load_relaxed(&_mi_numa_node_count) == 1) { return 0; } - else return _mi_os_numa_node_get(tld); + else return _mi_os_numa_node_get(); } static inline size_t _mi_os_numa_node_count(void) { const size_t count = mi_atomic_load_relaxed(&_mi_numa_node_count); diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 44074450..3d8014c3 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -656,12 +656,6 @@ typedef struct mi_segment_queue_s { mi_segment_t* last; } mi_segment_queue_t; -// OS thread local data -typedef struct mi_os_tld_s { - size_t region_idx; // start point for next allocation - mi_stats_t* stats; // points to tld stats -} mi_os_tld_t; - // Segments thread local data typedef struct mi_segments_tld_s { mi_segment_queue_t small_free; // queue of segments with free small pages @@ -674,7 +668,6 @@ typedef struct mi_segments_tld_s { size_t reclaim_count;// number of reclaimed (abandoned) segments mi_subproc_t* subproc; // sub-process this thread belongs to. mi_stats_t* stats; // points to tld stats - mi_os_tld_t* os; // points to os tld } mi_segments_tld_t; // Thread local data @@ -684,7 +677,6 @@ struct mi_tld_s { mi_heap_t* heap_backing; // backing heap of this thread (cannot be deleted) mi_heap_t* heaps; // list of heaps in this thread (so we can abandon all when the thread terminates) mi_segments_tld_t segments; // segment tld - mi_os_tld_t os; // os tld mi_stats_t stats; // statistics }; diff --git a/src/arena.c b/src/arena.c index 8ca5aaf3..164f3116 100644 --- a/src/arena.c +++ b/src/arena.c @@ -186,7 +186,7 @@ void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid) { if (p != NULL) return p; // or fall back to the OS - p = _mi_os_alloc(size, memid, &_mi_stats_main); + p = _mi_os_alloc(size, memid); if (p == NULL) return NULL; // zero the OS memory if needed @@ -199,7 +199,7 @@ void* _mi_arena_meta_zalloc(size_t size, mi_memid_t* memid) { void _mi_arena_meta_free(void* p, mi_memid_t memid, size_t size) { if (mi_memkind_is_os(memid.memkind)) { - _mi_os_free(p, size, memid, &_mi_stats_main); + _mi_os_free(p, size, memid); } else { mi_assert(memid.memkind == MI_MEM_STATIC); @@ -216,10 +216,10 @@ void* mi_arena_block_start(mi_arena_t* arena, mi_bitmap_index_t bindex) { ----------------------------------------------------------- */ // claim the `blocks_inuse` bits -static bool mi_arena_try_claim(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats) +static bool mi_arena_try_claim(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx) { size_t idx = 0; // mi_atomic_load_relaxed(&arena->search_idx); // start from last search; ok to be relaxed as the exact start does not matter - if (_mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx, stats)) { + if (_mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) { mi_atomic_store_relaxed(&arena->search_idx, mi_bitmap_index_field(*bitmap_idx)); // start search from found location next time around return true; }; @@ -232,13 +232,13 @@ static bool mi_arena_try_claim(mi_arena_t* arena, size_t blocks, mi_bitmap_index ----------------------------------------------------------- */ static mi_decl_noinline void* mi_arena_try_alloc_at(mi_arena_t* arena, size_t arena_index, size_t needed_bcount, - bool commit, mi_memid_t* memid, mi_os_tld_t* tld) + bool commit, mi_memid_t* memid) { MI_UNUSED(arena_index); mi_assert_internal(mi_arena_id_index(arena->id) == arena_index); mi_bitmap_index_t bitmap_index; - if (!mi_arena_try_claim(arena, needed_bcount, &bitmap_index, tld->stats)) return NULL; + if (!mi_arena_try_claim(arena, needed_bcount, &bitmap_index)) return NULL; // claimed it! void* p = mi_arena_block_start(arena, bitmap_index); @@ -268,7 +268,7 @@ static mi_decl_noinline void* mi_arena_try_alloc_at(mi_arena_t* arena, size_t ar _mi_bitmap_claim_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted); if (any_uncommitted) { bool commit_zero = false; - if (!_mi_os_commit(p, mi_arena_block_size(needed_bcount), &commit_zero, tld->stats)) { + if (!_mi_os_commit(p, mi_arena_block_size(needed_bcount), &commit_zero)) { memid->initially_committed = false; } else { @@ -286,7 +286,7 @@ static mi_decl_noinline void* mi_arena_try_alloc_at(mi_arena_t* arena, size_t ar // allocate in a speficic arena static void* mi_arena_try_alloc_at_id(mi_arena_id_t arena_id, bool match_numa_node, int numa_node, size_t size, size_t alignment, - bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld ) + bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid ) { MI_UNUSED_RELEASE(alignment); mi_assert(alignment <= MI_SEGMENT_ALIGN); @@ -307,7 +307,7 @@ static void* mi_arena_try_alloc_at_id(mi_arena_id_t arena_id, bool match_numa_no } // try to allocate - void* p = mi_arena_try_alloc_at(arena, arena_index, bcount, commit, memid, tld); + void* p = mi_arena_try_alloc_at(arena, arena_index, bcount, commit, memid); mi_assert_internal(p == NULL || _mi_is_aligned(p, alignment)); return p; } @@ -316,7 +316,7 @@ static void* mi_arena_try_alloc_at_id(mi_arena_id_t arena_id, bool match_numa_no // allocate from an arena with fallback to the OS static mi_decl_noinline void* mi_arena_try_alloc(int numa_node, size_t size, size_t alignment, bool commit, bool allow_large, - mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld ) + mi_arena_id_t req_arena_id, mi_memid_t* memid ) { MI_UNUSED(alignment); mi_assert_internal(alignment <= MI_SEGMENT_ALIGN); @@ -326,21 +326,21 @@ static mi_decl_noinline void* mi_arena_try_alloc(int numa_node, size_t size, siz if (req_arena_id != _mi_arena_id_none()) { // try a specific arena if requested if (mi_arena_id_index(req_arena_id) < max_arena) { - void* p = mi_arena_try_alloc_at_id(req_arena_id, true, numa_node, size, alignment, commit, allow_large, req_arena_id, memid, tld); + void* p = mi_arena_try_alloc_at_id(req_arena_id, true, numa_node, size, alignment, commit, allow_large, req_arena_id, memid); if (p != NULL) return p; } } else { // try numa affine allocation for (size_t i = 0; i < max_arena; i++) { - void* p = mi_arena_try_alloc_at_id(mi_arena_id_create(i), true, numa_node, size, alignment, commit, allow_large, req_arena_id, memid, tld); + void* p = mi_arena_try_alloc_at_id(mi_arena_id_create(i), true, numa_node, size, alignment, commit, allow_large, req_arena_id, memid); if (p != NULL) return p; } // try from another numa node instead.. if (numa_node >= 0) { // if numa_node was < 0 (no specific affinity requested), all arena's have been tried already for (size_t i = 0; i < max_arena; i++) { - void* p = mi_arena_try_alloc_at_id(mi_arena_id_create(i), false /* only proceed if not numa local */, numa_node, size, alignment, commit, allow_large, req_arena_id, memid, tld); + void* p = mi_arena_try_alloc_at_id(mi_arena_id_create(i), false /* only proceed if not numa local */, numa_node, size, alignment, commit, allow_large, req_arena_id, memid); if (p != NULL) return p; } } @@ -385,18 +385,18 @@ static bool mi_arena_reserve(size_t req_size, bool allow_large, mi_arena_id_t re void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_large, - mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld) + mi_arena_id_t req_arena_id, mi_memid_t* memid) { - mi_assert_internal(memid != NULL && tld != NULL); + mi_assert_internal(memid != NULL); mi_assert_internal(size > 0); *memid = _mi_memid_none(); - const int numa_node = _mi_os_numa_node(tld); // current numa node + const int numa_node = _mi_os_numa_node(); // current numa node // try to allocate in an arena if the alignment is small enough and the object is not too small (as for heap meta data) if (!mi_option_is_enabled(mi_option_disallow_arena_alloc) || req_arena_id != _mi_arena_id_none()) { // is arena allocation allowed? if (size >= MI_ARENA_MIN_OBJ_SIZE && alignment <= MI_SEGMENT_ALIGN && align_offset == 0) { - void* p = mi_arena_try_alloc(numa_node, size, alignment, commit, allow_large, req_arena_id, memid, tld); + void* p = mi_arena_try_alloc(numa_node, size, alignment, commit, allow_large, req_arena_id, memid); if (p != NULL) return p; // otherwise, try to first eagerly reserve a new arena @@ -405,7 +405,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset if (mi_arena_reserve(size, allow_large, req_arena_id, &arena_id)) { // and try allocate in there mi_assert_internal(req_arena_id == _mi_arena_id_none()); - p = mi_arena_try_alloc_at_id(arena_id, true, numa_node, size, alignment, commit, allow_large, req_arena_id, memid, tld); + p = mi_arena_try_alloc_at_id(arena_id, true, numa_node, size, alignment, commit, allow_large, req_arena_id, memid); if (p != NULL) return p; } } @@ -420,16 +420,16 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset // finally, fall back to the OS if (align_offset > 0) { - return _mi_os_alloc_aligned_at_offset(size, alignment, align_offset, commit, allow_large, memid, tld->stats); + return _mi_os_alloc_aligned_at_offset(size, alignment, align_offset, commit, allow_large, memid); } else { - return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid, tld->stats); + return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid); } } -void* _mi_arena_alloc(size_t size, bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid, mi_os_tld_t* tld) +void* _mi_arena_alloc(size_t size, bool commit, bool allow_large, mi_arena_id_t req_arena_id, mi_memid_t* memid) { - return _mi_arena_alloc_aligned(size, MI_ARENA_BLOCK_SIZE, 0, commit, allow_large, req_arena_id, memid, tld); + return _mi_arena_alloc_aligned(size, MI_ARENA_BLOCK_SIZE, 0, commit, allow_large, req_arena_id, memid); } @@ -455,7 +455,7 @@ static long mi_arena_purge_delay(void) { // reset or decommit in an arena and update the committed/decommit bitmaps // assumes we own the area (i.e. blocks_in_use is claimed by us) -static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks, mi_stats_t* stats) { +static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks) { mi_assert_internal(arena->blocks_committed != NULL); mi_assert_internal(arena->blocks_purge != NULL); mi_assert_internal(!arena->memid.is_pinned); @@ -464,7 +464,7 @@ static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks, bool needs_recommit; if (_mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx)) { // all blocks are committed, we can purge freely - needs_recommit = _mi_os_purge(p, size, stats); + needs_recommit = _mi_os_purge(p, size); } else { // some blocks are not committed -- this can happen when a partially committed block is freed @@ -472,7 +472,7 @@ static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks, // we need to ensure we do not try to reset (as that may be invalid for uncommitted memory), // and also undo the decommit stats (as it was already adjusted) mi_assert_internal(mi_option_is_enabled(mi_option_purge_decommits)); - needs_recommit = _mi_os_purge_ex(p, size, false /* allow reset? */, stats); + needs_recommit = _mi_os_purge_ex(p, size, false /* allow reset? */); if (needs_recommit) { _mi_stat_increase(&_mi_stats_main.committed, size); } } @@ -486,14 +486,14 @@ static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks, // Schedule a purge. This is usually delayed to avoid repeated decommit/commit calls. // Note: assumes we (still) own the area as we may purge immediately -static void mi_arena_schedule_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks, mi_stats_t* stats) { +static void mi_arena_schedule_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks) { mi_assert_internal(arena->blocks_purge != NULL); const long delay = mi_arena_purge_delay(); if (delay < 0) return; // is purging allowed at all? if (_mi_preloading() || delay == 0) { // decommit directly - mi_arena_purge(arena, bitmap_idx, blocks, stats); + mi_arena_purge(arena, bitmap_idx, blocks); } else { // schedule decommit @@ -511,7 +511,7 @@ static void mi_arena_schedule_purge(mi_arena_t* arena, size_t bitmap_idx, size_t // purge a range of blocks // return true if the full range was purged. // assumes we own the area (i.e. blocks_in_use is claimed by us) -static bool mi_arena_purge_range(mi_arena_t* arena, size_t idx, size_t startidx, size_t bitlen, size_t purge, mi_stats_t* stats) { +static bool mi_arena_purge_range(mi_arena_t* arena, size_t idx, size_t startidx, size_t bitlen, size_t purge) { const size_t endidx = startidx + bitlen; size_t bitidx = startidx; bool all_purged = false; @@ -524,7 +524,7 @@ static bool mi_arena_purge_range(mi_arena_t* arena, size_t idx, size_t startidx, if (count > 0) { // found range to be purged const mi_bitmap_index_t range_idx = mi_bitmap_index_create(idx, bitidx); - mi_arena_purge(arena, range_idx, count, stats); + mi_arena_purge(arena, range_idx, count); if (count == bitlen) { all_purged = true; } @@ -535,7 +535,7 @@ static bool mi_arena_purge_range(mi_arena_t* arena, size_t idx, size_t startidx, } // returns true if anything was purged -static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force, mi_stats_t* stats) +static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force) { if (arena->memid.is_pinned || arena->blocks_purge == NULL) return false; mi_msecs_t expire = mi_atomic_loadi64_relaxed(&arena->purge_expire); @@ -571,7 +571,7 @@ static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force, mi if (bitlen > 0) { // read purge again now that we have the in_use bits purge = mi_atomic_load_acquire(&arena->blocks_purge[i]); - if (!mi_arena_purge_range(arena, i, bitidx, bitlen, purge, stats)) { + if (!mi_arena_purge_range(arena, i, bitidx, bitlen, purge)) { full_purge = false; } any_purged = true; @@ -591,7 +591,7 @@ static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force, mi return any_purged; } -static void mi_arenas_try_purge( bool force, bool visit_all, mi_stats_t* stats ) { +static void mi_arenas_try_purge( bool force, bool visit_all ) { if (_mi_preloading() || mi_arena_purge_delay() <= 0) return; // nothing will be scheduled const size_t max_arena = mi_atomic_load_acquire(&mi_arena_count); @@ -606,7 +606,7 @@ static void mi_arenas_try_purge( bool force, bool visit_all, mi_stats_t* stats ) for (size_t i = 0; i < max_arena; i++) { mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[i]); if (arena != NULL) { - if (mi_arena_try_purge(arena, now, force, stats)) { + if (mi_arena_try_purge(arena, now, force)) { if (max_purge_count <= 1) break; max_purge_count--; } @@ -620,8 +620,8 @@ static void mi_arenas_try_purge( bool force, bool visit_all, mi_stats_t* stats ) Arena free ----------------------------------------------------------- */ -void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memid, mi_stats_t* stats) { - mi_assert_internal(size > 0 && stats != NULL); +void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memid) { + mi_assert_internal(size > 0); mi_assert_internal(committed_size <= size); if (p==NULL) return; if (size==0) return; @@ -636,7 +636,7 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi // if partially committed, adjust the committed stats (as `_mi_os_free` will increase decommit by the full size) _mi_stat_decrease(&_mi_stats_main.committed, committed_size); } - _mi_os_free(p, size, memid, stats); + _mi_os_free(p, size, memid); } else if (memid.memkind == MI_MEM_ARENA) { // allocated in an arena @@ -681,7 +681,7 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi // works (as we should never reset decommitted parts). } // (delay) purge the entire range - mi_arena_schedule_purge(arena, bitmap_idx, blocks, stats); + mi_arena_schedule_purge(arena, bitmap_idx, blocks); } // and make it available to others again @@ -697,7 +697,7 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi } // purge expired decommits - mi_arenas_try_purge(false, false, stats); + mi_arenas_try_purge(false, false); } // destroy owned arenas; this is unsafe and should only be done using `mi_option_destroy_on_exit` @@ -711,7 +711,7 @@ static void mi_arenas_unsafe_destroy(void) { mi_lock_done(&arena->abandoned_visit_lock); if (arena->start != NULL && mi_memkind_is_os(arena->memid.memkind)) { mi_atomic_store_ptr_release(mi_arena_t, &mi_arenas[i], NULL); - _mi_os_free(arena->start, mi_arena_size(arena), arena->memid, &_mi_stats_main); + _mi_os_free(arena->start, mi_arena_size(arena), arena->memid); } else { new_max_arena = i; @@ -726,15 +726,15 @@ static void mi_arenas_unsafe_destroy(void) { } // Purge the arenas; if `force_purge` is true, amenable parts are purged even if not yet expired -void _mi_arenas_collect(bool force_purge, mi_stats_t* stats) { - mi_arenas_try_purge(force_purge, force_purge /* visit all? */, stats); +void _mi_arenas_collect(bool force_purge) { + mi_arenas_try_purge(force_purge, force_purge /* visit all? */); } // destroy owned arenas; this is unsafe and should only be done using `mi_option_destroy_on_exit` // for dynamic libraries that are unloaded and need to release all their allocated memory. -void _mi_arena_unsafe_destroy_all(mi_stats_t* stats) { +void _mi_arena_unsafe_destroy_all(void) { mi_arenas_unsafe_destroy(); - _mi_arenas_collect(true /* force purge */, stats); // purge non-owned arenas + _mi_arenas_collect(true /* force purge */); // purge non-owned arenas } // Is a pointer inside any of our arenas? @@ -838,11 +838,11 @@ int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exc if (arena_id != NULL) *arena_id = _mi_arena_id_none(); size = _mi_align_up(size, MI_ARENA_BLOCK_SIZE); // at least one block mi_memid_t memid; - void* start = _mi_os_alloc_aligned(size, MI_SEGMENT_ALIGN, commit, allow_large, &memid, &_mi_stats_main); + void* start = _mi_os_alloc_aligned(size, MI_SEGMENT_ALIGN, commit, allow_large, &memid); if (start == NULL) return ENOMEM; const bool is_large = memid.is_pinned; // todo: use separate is_large field? if (!mi_manage_os_memory_ex2(start, size, is_large, -1 /* numa node */, exclusive, memid, arena_id)) { - _mi_os_free_ex(start, size, commit, memid, &_mi_stats_main); + _mi_os_free_ex(start, size, commit, memid); _mi_verbose_message("failed to reserve %zu KiB memory\n", _mi_divide_up(size, 1024)); return ENOMEM; } @@ -938,7 +938,7 @@ int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_m _mi_verbose_message("numa node %i: reserved %zu GiB huge pages (of the %zu GiB requested)\n", numa_node, pages_reserved, pages); if (!mi_manage_os_memory_ex2(p, hsize, true, numa_node, exclusive, memid, arena_id)) { - _mi_os_free(p, hsize, memid, &_mi_stats_main); + _mi_os_free(p, hsize, memid); return ENOMEM; } return 0; diff --git a/src/bitmap.c b/src/bitmap.c index 976ba72c..98f6ab7b 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -182,7 +182,7 @@ bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t // Try to atomically claim a sequence of `count` bits starting from the field // at `idx` in `bitmap` and crossing into subsequent fields. Returns `true` on success. // Only needs to consider crossing into the next fields (see `mi_bitmap_try_find_from_claim_across`) -static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t idx, const size_t count, const size_t retries, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats) +static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t idx, const size_t count, const size_t retries, mi_bitmap_index_t* bitmap_idx) { mi_assert_internal(bitmap_idx != NULL); @@ -242,7 +242,7 @@ static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bit } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); // claimed! - mi_stat_counter_increase(stats->arena_crossover_count,1); + mi_stat_counter_increase(_mi_stats_main.arena_crossover_count,1); *bitmap_idx = mi_bitmap_index_create(idx, initial_idx); return true; @@ -262,10 +262,10 @@ rollback: newmap = (map & ~initial_mask); } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); } - mi_stat_counter_increase(stats->arena_rollback_count,1); + mi_stat_counter_increase(_mi_stats_main.arena_rollback_count,1); // retry? (we make a recursive call instead of goto to be able to use const declarations) if (retries <= 2) { - return mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, retries+1, bitmap_idx, stats); + return mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, retries+1, bitmap_idx); } else { return false; @@ -275,7 +275,7 @@ rollback: // Find `count` bits of zeros and set them to 1 atomically; returns `true` on success. // Starts at idx, and wraps around to search in all `bitmap_fields` fields. -bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats) { +bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) { mi_assert_internal(count > 0); if (count <= 2) { // we don't bother with crossover fields for small counts @@ -295,7 +295,7 @@ bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitm } */ // if that fails, then try to claim across fields - if (mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, 0, bitmap_idx, stats)) { + if (mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, 0, bitmap_idx)) { return true; } } diff --git a/src/bitmap.h b/src/bitmap.h index f8898935..d60668cb 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -94,7 +94,7 @@ bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t // Find `count` bits of zeros and set them to 1 atomically; returns `true` on success. // Starts at idx, and wraps around to search in all `bitmap_fields` fields. -bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats); +bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx); // Set `count` bits at `bitmap_idx` to 0 atomically // Returns `true` if all `count` bits were 1 previously. diff --git a/src/heap.c b/src/heap.c index 581b3f71..4459ff77 100644 --- a/src/heap.c +++ b/src/heap.c @@ -166,7 +166,7 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) } // collect arenas (this is program wide so don't force purges on abandonment of threads) - _mi_arenas_collect(collect == MI_FORCE /* force purge? */, &heap->tld->stats); + _mi_arenas_collect(collect == MI_FORCE /* force purge? */); } void _mi_heap_collect_abandon(mi_heap_t* heap) { diff --git a/src/init.c b/src/init.c index a90818a4..3e4da831 100644 --- a/src/init.c +++ b/src/init.c @@ -136,9 +136,8 @@ static mi_decl_cache_align mi_tld_t tld_main = { &_mi_heap_main, &_mi_heap_main, { { NULL, NULL }, {NULL ,NULL}, {NULL ,NULL, 0}, 0, 0, 0, 0, 0, &mi_subproc_default, - &tld_main.stats, &tld_main.os + &tld_main.stats }, // segments - { 0, &tld_main.stats }, // os { MI_STATS_NULL } // stats }; @@ -320,10 +319,10 @@ static mi_thread_data_t* mi_thread_data_zalloc(void) { // if that fails, allocate as meta data if (td == NULL) { mi_memid_t memid; - td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &memid, &_mi_stats_main); + td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &memid); if (td == NULL) { // if this fails, try once more. (issue #257) - td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &memid, &_mi_stats_main); + td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &memid); if (td == NULL) { // really out of memory _mi_error_message(ENOMEM, "unable to allocate thread local heap metadata (%zu bytes)\n", sizeof(mi_thread_data_t)); @@ -353,7 +352,7 @@ static void mi_thread_data_free( mi_thread_data_t* tdfree ) { } } // if that fails, just free it directly - _mi_os_free(tdfree, sizeof(mi_thread_data_t), tdfree->memid, &_mi_stats_main); + _mi_os_free(tdfree, sizeof(mi_thread_data_t), tdfree->memid); } void _mi_thread_data_collect(void) { @@ -363,7 +362,7 @@ void _mi_thread_data_collect(void) { if (td != NULL) { td = mi_atomic_exchange_ptr_acq_rel(mi_thread_data_t, &td_cache[i], NULL); if (td != NULL) { - _mi_os_free(td, sizeof(mi_thread_data_t), td->memid, &_mi_stats_main); + _mi_os_free(td, sizeof(mi_thread_data_t), td->memid); } } } @@ -399,9 +398,7 @@ void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap) { tld->heap_backing = bheap; tld->heaps = NULL; tld->segments.subproc = &mi_subproc_default; - tld->segments.stats = &tld->stats; - tld->segments.os = &tld->os; - tld->os.stats = &tld->stats; + tld->segments.stats = &tld->stats; } // Free the thread local default heap (called from `mi_thread_done`) @@ -685,7 +682,7 @@ void mi_cdecl _mi_process_done(void) { if (mi_option_is_enabled(mi_option_destroy_on_exit)) { mi_collect(true /* force */); _mi_heap_unsafe_destroy_all(); // forcefully release all memory held by all heaps (of this thread only!) - _mi_arena_unsafe_destroy_all(& _mi_heap_main_get()->tld->stats); + _mi_arena_unsafe_destroy_all(); } if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) { diff --git a/src/os.c b/src/os.c index a7130b90..81dda8a1 100644 --- a/src/os.c +++ b/src/os.c @@ -9,6 +9,7 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc/atomic.h" #include "mimalloc/prim.h" +#define os_stats (&_mi_stats_main) /* ----------------------------------------------------------- Initialization. @@ -85,8 +86,8 @@ void _mi_os_init(void) { /* ----------------------------------------------------------- Util -------------------------------------------------------------- */ -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); -bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats); +bool _mi_os_decommit(void* addr, size_t size); +bool _mi_os_commit(void* addr, size_t size, bool* is_zero); static inline uintptr_t _mi_align_down(uintptr_t sz, size_t alignment) { mi_assert_internal(alignment != 0); @@ -161,23 +162,20 @@ void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size) { Free memory -------------------------------------------------------------- */ -static void mi_os_free_huge_os_pages(void* p, size_t size, mi_stats_t* stats); +static void mi_os_free_huge_os_pages(void* p, size_t size); -static void mi_os_prim_free(void* addr, size_t size, bool still_committed, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; +static void mi_os_prim_free(void* addr, size_t size, bool still_committed) { mi_assert_internal((size % _mi_os_page_size()) == 0); if (addr == NULL || size == 0) return; // || _mi_os_is_huge_reserved(addr) int err = _mi_prim_free(addr, size); if (err != 0) { _mi_warning_message("unable to free OS memory (error: %d (0x%x), size: 0x%zx bytes, address: %p)\n", err, err, size, addr); } - if (still_committed) { _mi_stat_decrease(&stats->committed, size); } - _mi_stat_decrease(&stats->reserved, size); + if (still_committed) { _mi_stat_decrease(&os_stats->committed, size); } + _mi_stat_decrease(&os_stats->reserved, size); } -void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t memid, mi_stats_t* stats) { - if (stats == NULL) stats = &_mi_stats_main; +void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t memid) { if (mi_memkind_is_os(memid.memkind)) { size_t csize = _mi_os_good_alloc_size(size); void* base = addr; @@ -191,10 +189,10 @@ void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t me // free it if (memid.memkind == MI_MEM_OS_HUGE) { mi_assert(memid.is_pinned); - mi_os_free_huge_os_pages(base, csize, stats); + mi_os_free_huge_os_pages(base, csize); } else { - mi_os_prim_free(base, csize, still_committed, stats); + mi_os_prim_free(base, csize, still_committed); } } else { @@ -203,9 +201,8 @@ void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t me } } -void _mi_os_free(void* p, size_t size, mi_memid_t memid, mi_stats_t* stats) { - if (stats == NULL) stats = &_mi_stats_main; - _mi_os_free_ex(p, size, true, memid, stats); +void _mi_os_free(void* p, size_t size, mi_memid_t memid) { + _mi_os_free_ex(p, size, true, memid); } @@ -215,7 +212,7 @@ void _mi_os_free(void* p, size_t size, mi_memid_t memid, mi_stats_t* stats) { // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. // Also `hint_addr` is a hint and may be ignored. -static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, mi_stats_t* tld_stats) { +static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero) { mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); mi_assert_internal(is_zero != NULL); mi_assert_internal(is_large != NULL); @@ -229,13 +226,13 @@ static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignm _mi_warning_message("unable to allocate OS memory (error: %d (0x%x), addr: %p, size: 0x%zx bytes, align: 0x%zx, commit: %d, allow large: %d)\n", err, err, hint_addr, size, try_alignment, commit, allow_large); } - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; - mi_stat_counter_increase(stats->mmap_calls, 1); + + + mi_stat_counter_increase(os_stats->mmap_calls, 1); if (p != NULL) { - _mi_stat_increase(&stats->reserved, size); + _mi_stat_increase(&os_stats->reserved, size); if (commit) { - _mi_stat_increase(&stats->committed, size); + _mi_stat_increase(&os_stats->committed, size); // seems needed for asan (or `mimalloc-test-api` fails) #ifdef MI_TRACK_ASAN if (*is_zero) { mi_track_mem_defined(p,size); } @@ -246,14 +243,14 @@ static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignm return p; } -static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, mi_stats_t* tld_stats) { - return mi_os_prim_alloc_at(NULL, size, try_alignment, commit, allow_large, is_large, is_zero, tld_stats); +static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero) { + return mi_os_prim_alloc_at(NULL, size, try_alignment, commit, allow_large, is_large, is_zero); } // Primitive aligned allocation from the OS. // This function guarantees the allocated memory is aligned. -static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** base, mi_stats_t* stats) { +static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** base) { mi_assert_internal(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0)); mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); mi_assert_internal(is_large != NULL); @@ -264,7 +261,7 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit size = _mi_align_up(size, _mi_os_page_size()); // try first with a requested alignment hint (this will usually be aligned directly on Win 10+ or BSD) - void* p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero, stats); + void* p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero); if (p == NULL) return NULL; // aligned already? @@ -276,13 +273,13 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit #if !MI_TRACK_ASAN _mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n", size, p, alignment, commit); #endif - mi_os_prim_free(p, size, commit, stats); + mi_os_prim_free(p, size, commit); if (size >= (SIZE_MAX - alignment)) return NULL; // overflow const size_t over_size = size + alignment; if (!mi_os_mem_config.has_partial_free) { // win32 virtualAlloc cannot free parts of an allocated block // over-allocate uncommitted (virtual) memory - p = mi_os_prim_alloc(over_size, 1 /*alignment*/, false /* commit? */, false /* allow_large */, is_large, is_zero, stats); + p = mi_os_prim_alloc(over_size, 1 /*alignment*/, false /* commit? */, false /* allow_large */, is_large, is_zero); if (p == NULL) return NULL; // set p to the aligned part in the full region @@ -293,12 +290,12 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit // explicitly commit only the aligned part if (commit) { - _mi_os_commit(p, size, NULL, stats); + _mi_os_commit(p, size, NULL); } } else { // mmap can free inside an allocation // overallocate... - p = mi_os_prim_alloc(over_size, 1, commit, false, is_large, is_zero, stats); + p = mi_os_prim_alloc(over_size, 1, commit, false, is_large, is_zero); if (p == NULL) return NULL; // and selectively unmap parts around the over-allocated area. @@ -307,8 +304,8 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit size_t mid_size = _mi_align_up(size, _mi_os_page_size()); size_t post_size = over_size - pre_size - mid_size; mi_assert_internal(pre_size < over_size&& post_size < over_size&& mid_size >= size); - if (pre_size > 0) { mi_os_prim_free(p, pre_size, commit, stats); } - if (post_size > 0) { mi_os_prim_free((uint8_t*)aligned_p + mid_size, post_size, commit, stats); } + if (pre_size > 0) { mi_os_prim_free(p, pre_size, commit); } + if (post_size > 0) { mi_os_prim_free((uint8_t*)aligned_p + mid_size, post_size, commit); } // we can return the aligned pointer on `mmap` systems p = aligned_p; *base = aligned_p; // since we freed the pre part, `*base == p`. @@ -324,33 +321,31 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit OS API: alloc and alloc_aligned ----------------------------------------------------------- */ -void* _mi_os_alloc(size_t size, mi_memid_t* memid, mi_stats_t* stats) { +void* _mi_os_alloc(size_t size, mi_memid_t* memid) { *memid = _mi_memid_none(); if (size == 0) return NULL; - if (stats == NULL) stats = &_mi_stats_main; size = _mi_os_good_alloc_size(size); bool os_is_large = false; bool os_is_zero = false; - void* p = mi_os_prim_alloc(size, 0, true, false, &os_is_large, &os_is_zero, stats); + void* p = mi_os_prim_alloc(size, 0, true, false, &os_is_large, &os_is_zero); if (p != NULL) { *memid = _mi_memid_create_os(true, os_is_zero, os_is_large); } return p; } -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* stats) +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid) { MI_UNUSED(&_mi_os_get_aligned_hint); // suppress unused warnings *memid = _mi_memid_none(); if (size == 0) return NULL; - if (stats == NULL) stats = &_mi_stats_main; size = _mi_os_good_alloc_size(size); alignment = _mi_align_up(alignment, _mi_os_page_size()); bool os_is_large = false; bool os_is_zero = false; void* os_base = NULL; - void* p = mi_os_prim_alloc_aligned(size, alignment, commit, allow_large, &os_is_large, &os_is_zero, &os_base, stats ); + void* p = mi_os_prim_alloc_aligned(size, alignment, commit, allow_large, &os_is_large, &os_is_zero, &os_base ); if (p != NULL) { *memid = _mi_memid_create_os(commit, os_is_zero, os_is_large); memid->mem.os.base = os_base; @@ -367,29 +362,28 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allo to use the actual start of the memory region. ----------------------------------------------------------- */ -void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offset, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* stats) { +void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offset, bool commit, bool allow_large, mi_memid_t* memid) { mi_assert(offset <= MI_SEGMENT_SIZE); mi_assert(offset <= size); mi_assert((alignment % _mi_os_page_size()) == 0); *memid = _mi_memid_none(); - if (stats == NULL) stats = &_mi_stats_main; if (offset > MI_SEGMENT_SIZE) return NULL; if (offset == 0) { // regular aligned allocation - return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid, stats); + return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid); } else { // overallocate to align at an offset const size_t extra = _mi_align_up(offset, alignment) - offset; const size_t oversize = size + extra; - void* const start = _mi_os_alloc_aligned(oversize, alignment, commit, allow_large, memid, stats); + void* const start = _mi_os_alloc_aligned(oversize, alignment, commit, allow_large, memid); if (start == NULL) return NULL; void* const p = (uint8_t*)start + extra; mi_assert(_mi_is_aligned((uint8_t*)p + offset, alignment)); // decommit the overallocation at the start if (commit && extra > _mi_os_page_size()) { - _mi_os_decommit(start, extra, stats); + _mi_os_decommit(start, extra); } return p; } @@ -423,12 +417,10 @@ static void* mi_os_page_align_area_conservative(void* addr, size_t size, size_t* return mi_os_page_align_areax(true, addr, size, newsize); } -bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; +bool _mi_os_commit(void* addr, size_t size, bool* is_zero) { if (is_zero != NULL) { *is_zero = false; } - _mi_stat_increase(&stats->committed, size); // use size for precise commit vs. decommit - _mi_stat_counter_increase(&stats->commit_calls, 1); + _mi_stat_increase(&os_stats->committed, size); // use size for precise commit vs. decommit + _mi_stat_counter_increase(&os_stats->commit_calls, 1); // page align range size_t csize; @@ -454,11 +446,8 @@ bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats return true; } -static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit, mi_stats_t* tld_stats) { - MI_UNUSED(tld_stats); - mi_stats_t* stats = &_mi_stats_main; - mi_assert_internal(needs_recommit!=NULL); - _mi_stat_decrease(&stats->committed, size); +static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit) { mi_assert_internal(needs_recommit!=NULL); + _mi_stat_decrease(&os_stats->committed, size); // page align size_t csize; @@ -475,9 +464,9 @@ static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit, mi_ return (err == 0); } -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* tld_stats) { +bool _mi_os_decommit(void* addr, size_t size) { bool needs_recommit; - return mi_os_decommit_ex(addr, size, &needs_recommit, tld_stats); + return mi_os_decommit_ex(addr, size, &needs_recommit); } @@ -485,13 +474,13 @@ bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* tld_stats) { // but may be used later again. This will release physical memory // pages and reduce swapping while keeping the memory committed. // We page align to a conservative area inside the range to reset. -bool _mi_os_reset(void* addr, size_t size, mi_stats_t* stats) { +bool _mi_os_reset(void* addr, size_t size) { // page align conservatively within the range size_t csize; void* start = mi_os_page_align_area_conservative(addr, size, &csize); if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr) - _mi_stat_increase(&stats->reset, csize); - _mi_stat_counter_increase(&stats->reset_calls, 1); + _mi_stat_increase(&os_stats->reset, csize); + _mi_stat_counter_increase(&os_stats->reset_calls, 1); #if (MI_DEBUG>1) && !MI_SECURE && !MI_TRACK_ENABLED // && !MI_TSAN memset(start, 0, csize); // pretend it is eagerly reset @@ -507,22 +496,22 @@ bool _mi_os_reset(void* addr, size_t size, mi_stats_t* stats) { // either resets or decommits memory, returns true if the memory needs // to be recommitted if it is to be re-used later on. -bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, mi_stats_t* stats) +bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset) { if (mi_option_get(mi_option_purge_delay) < 0) return false; // is purging allowed? - _mi_stat_counter_increase(&stats->purge_calls, 1); - _mi_stat_increase(&stats->purged, size); + _mi_stat_counter_increase(&os_stats->purge_calls, 1); + _mi_stat_increase(&os_stats->purged, size); if (mi_option_is_enabled(mi_option_purge_decommits) && // should decommit? !_mi_preloading()) // don't decommit during preloading (unsafe) { bool needs_recommit = true; - mi_os_decommit_ex(p, size, &needs_recommit, stats); + mi_os_decommit_ex(p, size, &needs_recommit); return needs_recommit; } else { if (allow_reset) { // this can sometimes be not allowed if the range is not fully committed - _mi_os_reset(p, size, stats); + _mi_os_reset(p, size); } return false; // needs no recommit } @@ -530,8 +519,8 @@ bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, mi_stats_t* stats) // either resets or decommits memory, returns true if the memory needs // to be recommitted if it is to be re-used later on. -bool _mi_os_purge(void* p, size_t size, mi_stats_t * stats) { - return _mi_os_purge_ex(p, size, true, stats); +bool _mi_os_purge(void* p, size_t size) { + return _mi_os_purge_ex(p, size, true); } @@ -639,15 +628,15 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse // no success, issue a warning and break if (p != NULL) { _mi_warning_message("could not allocate contiguous huge OS page %zu at %p\n", page, addr); - mi_os_prim_free(p, MI_HUGE_OS_PAGE_SIZE, true, &_mi_stats_main); + mi_os_prim_free(p, MI_HUGE_OS_PAGE_SIZE, true); } break; } // success, record it page++; // increase before timeout check (see issue #711) - _mi_stat_increase(&_mi_stats_main.committed, MI_HUGE_OS_PAGE_SIZE); - _mi_stat_increase(&_mi_stats_main.reserved, MI_HUGE_OS_PAGE_SIZE); + _mi_stat_increase(&os_stats->committed, MI_HUGE_OS_PAGE_SIZE); + _mi_stat_increase(&os_stats->reserved, MI_HUGE_OS_PAGE_SIZE); // check for timeout if (max_msecs > 0) { @@ -681,11 +670,11 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse // free every huge page in a range individually (as we allocated per page) // note: needed with VirtualAlloc but could potentially be done in one go on mmap'd systems. -static void mi_os_free_huge_os_pages(void* p, size_t size, mi_stats_t* stats) { +static void mi_os_free_huge_os_pages(void* p, size_t size) { if (p==NULL || size==0) return; uint8_t* base = (uint8_t*)p; while (size >= MI_HUGE_OS_PAGE_SIZE) { - mi_os_prim_free(base, MI_HUGE_OS_PAGE_SIZE, true, stats); + mi_os_prim_free(base, MI_HUGE_OS_PAGE_SIZE, true); size -= MI_HUGE_OS_PAGE_SIZE; base += MI_HUGE_OS_PAGE_SIZE; } @@ -714,8 +703,7 @@ size_t _mi_os_numa_node_count_get(void) { return count; } -int _mi_os_numa_node_get(mi_os_tld_t* tld) { - MI_UNUSED(tld); +int _mi_os_numa_node_get() { size_t numa_count = _mi_os_numa_node_count(); if (numa_count<=1) return 0; // optimize on single numa node systems: always node 0 // never more than the node count and >= 0 diff --git a/src/page.c b/src/page.c index c681d6d0..85e831d2 100644 --- a/src/page.c +++ b/src/page.c @@ -276,7 +276,7 @@ static mi_page_t* mi_page_fresh_alloc(mi_heap_t* heap, mi_page_queue_t* pq, size mi_assert_internal(mi_heap_contains_queue(heap, pq)); mi_assert_internal(page_alignment > 0 || block_size > MI_LARGE_OBJ_SIZE_MAX || block_size == pq->block_size); #endif - mi_page_t* page = _mi_segment_page_alloc(heap, block_size, page_alignment, &heap->tld->segments, &heap->tld->os); + mi_page_t* page = _mi_segment_page_alloc(heap, block_size, page_alignment, &heap->tld->segments); if (page == NULL) { // this may be out-of-memory, or an abandoned page was reclaimed (and in our queue) return NULL; diff --git a/src/segment-map.c b/src/segment-map.c index 2c3964fe..399f221c 100644 --- a/src/segment-map.c +++ b/src/segment-map.c @@ -55,11 +55,11 @@ static mi_segmap_part_t* mi_segment_map_index_of(const mi_segment_t* segment, bo if (part == NULL) { if (!create_on_demand) return NULL; mi_memid_t memid; - part = (mi_segmap_part_t*)_mi_os_alloc(sizeof(mi_segmap_part_t), &memid, NULL); + part = (mi_segmap_part_t*)_mi_os_alloc(sizeof(mi_segmap_part_t), &memid); if (part == NULL) return NULL; mi_segmap_part_t* expected = NULL; if (!mi_atomic_cas_ptr_strong_release(mi_segmap_part_t, &mi_segment_map[segindex], &expected, part)) { - _mi_os_free(part, sizeof(mi_segmap_part_t), memid, NULL); + _mi_os_free(part, sizeof(mi_segmap_part_t), memid); part = expected; if (part == NULL) return NULL; } diff --git a/src/segment.c b/src/segment.c index 74abcdbc..660351a7 100644 --- a/src/segment.c +++ b/src/segment.c @@ -189,7 +189,7 @@ static void mi_segment_protect_range(void* p, size_t size, bool protect) { } } -static void mi_segment_protect(mi_segment_t* segment, bool protect, mi_os_tld_t* tld) { +static void mi_segment_protect(mi_segment_t* segment, bool protect) { // add/remove guard pages if (MI_SECURE != 0) { // in secure mode, we set up a protected page in between the segment info and the page data @@ -207,7 +207,7 @@ static void mi_segment_protect(mi_segment_t* segment, bool protect, mi_os_tld_t* if (protect && !segment->memid.initially_committed) { if (protect) { // ensure secure page is committed - if (_mi_os_commit(start, os_psize, NULL, tld->stats)) { // if this fails that is ok (as it is an unaccessible page) + if (_mi_os_commit(start, os_psize, NULL)) { // if this fails that is ok (as it is an unaccessible page) mi_segment_protect_range(start, os_psize, protect); } } @@ -241,23 +241,23 @@ static void mi_page_purge(mi_segment_t* segment, mi_page_t* page, mi_segments_tl if (!segment->allow_purge) return; mi_assert_internal(page->used == 0); mi_assert_internal(page->free == NULL); - mi_assert_expensive(!mi_pages_purge_contains(page, tld)); + mi_assert_expensive(!mi_pages_purge_contains(page, tld)); MI_UNUSED(tld); size_t psize; void* start = mi_segment_raw_page_start(segment, page, &psize); - const bool needs_recommit = _mi_os_purge(start, psize, tld->stats); + const bool needs_recommit = _mi_os_purge(start, psize); if (needs_recommit) { page->is_committed = false; } } static bool mi_page_ensure_committed(mi_segment_t* segment, mi_page_t* page, mi_segments_tld_t* tld) { if (page->is_committed) return true; mi_assert_internal(segment->allow_decommit); - mi_assert_expensive(!mi_pages_purge_contains(page, tld)); + mi_assert_expensive(!mi_pages_purge_contains(page, tld)); MI_UNUSED(tld); size_t psize; uint8_t* start = mi_segment_raw_page_start(segment, page, &psize); bool is_zero = false; const size_t gsize = (MI_SECURE >= 2 ? _mi_os_page_size() : 0); - bool ok = _mi_os_commit(start, psize + gsize, &is_zero, tld->stats); + bool ok = _mi_os_commit(start, psize + gsize, &is_zero); if (!ok) return false; // failed to commit! page->is_committed = true; page->used = 0; @@ -502,7 +502,7 @@ static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_se if (MI_SECURE != 0) { mi_assert_internal(!segment->memid.is_pinned); - mi_segment_protect(segment, false, tld->os); // ensure no more guard pages are set + mi_segment_protect(segment, false); // ensure no more guard pages are set } bool fully_committed = true; @@ -516,7 +516,7 @@ static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_se MI_UNUSED(fully_committed); mi_assert_internal((fully_committed && committed_size == segment_size) || (!fully_committed && committed_size < segment_size)); - _mi_arena_free(segment, segment_size, committed_size, segment->memid, tld->stats); + _mi_arena_free(segment, segment_size, committed_size, segment->memid); } // called from `heap_collect`. @@ -537,7 +537,7 @@ void _mi_segments_collect(bool force, mi_segments_tld_t* tld) { static mi_segment_t* mi_segment_os_alloc(bool eager_delayed, size_t page_alignment, mi_arena_id_t req_arena_id, size_t pre_size, size_t info_size, bool commit, size_t segment_size, - mi_segments_tld_t* tld, mi_os_tld_t* tld_os) + mi_segments_tld_t* tld) { mi_memid_t memid; bool allow_large = (!eager_delayed && (MI_SECURE == 0)); // only allow large OS pages once we are no longer lazy @@ -549,7 +549,7 @@ static mi_segment_t* mi_segment_os_alloc(bool eager_delayed, size_t page_alignme segment_size = segment_size + (align_offset - pre_size); // adjust the segment size } - mi_segment_t* segment = (mi_segment_t*)_mi_arena_alloc_aligned(segment_size, alignment, align_offset, commit, allow_large, req_arena_id, &memid, tld_os); + mi_segment_t* segment = (mi_segment_t*)_mi_arena_alloc_aligned(segment_size, alignment, align_offset, commit, allow_large, req_arena_id, &memid); if (segment == NULL) { return NULL; // failed to allocate } @@ -557,10 +557,10 @@ static mi_segment_t* mi_segment_os_alloc(bool eager_delayed, size_t page_alignme if (!memid.initially_committed) { // ensure the initial info is committed mi_assert_internal(!memid.is_pinned); - bool ok = _mi_os_commit(segment, pre_size, NULL, tld_os->stats); + bool ok = _mi_os_commit(segment, pre_size, NULL); if (!ok) { // commit failed; we cannot touch the memory: free the segment directly and return `NULL` - _mi_arena_free(segment, segment_size, 0, memid, tld_os->stats); + _mi_arena_free(segment, segment_size, 0, memid); return NULL; } } @@ -578,7 +578,7 @@ static mi_segment_t* mi_segment_os_alloc(bool eager_delayed, size_t page_alignme // Allocate a segment from the OS aligned to `MI_SEGMENT_SIZE` . static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, size_t page_shift, size_t page_alignment, - mi_arena_id_t req_arena_id, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) + mi_arena_id_t req_arena_id, mi_segments_tld_t* tld) { // required is only > 0 for huge page allocations mi_assert_internal((required > 0 && page_kind > MI_PAGE_LARGE)|| (required==0 && page_kind <= MI_PAGE_LARGE)); @@ -610,7 +610,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, const bool init_commit = eager; // || (page_kind >= MI_PAGE_LARGE); // Allocate the segment from the OS (segment_size can change due to alignment) - mi_segment_t* segment = mi_segment_os_alloc(eager_delayed, page_alignment, req_arena_id, pre_size, info_size, init_commit, init_segment_size, tld, os_tld); + mi_segment_t* segment = mi_segment_os_alloc(eager_delayed, page_alignment, req_arena_id, pre_size, info_size, init_commit, init_segment_size, tld); if (segment == NULL) return NULL; mi_assert_internal(segment != NULL && (uintptr_t)segment % MI_SEGMENT_SIZE == 0); mi_assert_internal(segment->memid.is_pinned ? segment->memid.initially_committed : true); @@ -638,7 +638,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, segment->cookie = _mi_ptr_cookie(segment); // set protection - mi_segment_protect(segment, true, tld->os); + mi_segment_protect(segment, true); // insert in free lists for small and medium pages if (page_kind <= MI_PAGE_MEDIUM) { @@ -1142,7 +1142,7 @@ void mi_collect_reduce(size_t target_size) mi_attr_noexcept { Reclaim or allocate ----------------------------------------------------------- */ -static mi_segment_t* mi_segment_reclaim_or_alloc(mi_heap_t* heap, size_t block_size, mi_page_kind_t page_kind, size_t page_shift, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) +static mi_segment_t* mi_segment_reclaim_or_alloc(mi_heap_t* heap, size_t block_size, mi_page_kind_t page_kind, size_t page_shift, mi_segments_tld_t* tld) { mi_assert_internal(page_kind <= MI_PAGE_LARGE); mi_assert_internal(block_size <= MI_LARGE_OBJ_SIZE_MAX); @@ -1164,7 +1164,7 @@ static mi_segment_t* mi_segment_reclaim_or_alloc(mi_heap_t* heap, size_t block_s return segment; } // 2. otherwise allocate a fresh segment - return mi_segment_alloc(0, page_kind, page_shift, 0, heap->arena_id, tld, os_tld); + return mi_segment_alloc(0, page_kind, page_shift, 0, heap->arena_id, tld); } @@ -1203,11 +1203,11 @@ static mi_page_t* mi_segment_page_try_alloc_in_queue(mi_heap_t* heap, mi_page_ki return NULL; } -static mi_page_t* mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, mi_page_kind_t kind, size_t page_shift, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) { +static mi_page_t* mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, mi_page_kind_t kind, size_t page_shift, mi_segments_tld_t* tld) { mi_page_t* page = mi_segment_page_try_alloc_in_queue(heap, kind, tld); if (page == NULL) { // possibly allocate or reclaim a fresh segment - mi_segment_t* const segment = mi_segment_reclaim_or_alloc(heap, block_size, kind, page_shift, tld, os_tld); + mi_segment_t* const segment = mi_segment_reclaim_or_alloc(heap, block_size, kind, page_shift, tld); if (segment == NULL) return NULL; // return NULL if out-of-memory (or reclaimed) mi_assert_internal(segment->page_kind==kind); mi_assert_internal(segment->used < segment->capacity); @@ -1222,20 +1222,20 @@ static mi_page_t* mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, mi_p return page; } -static mi_page_t* mi_segment_small_page_alloc(mi_heap_t* heap, size_t block_size, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) { - return mi_segment_page_alloc(heap, block_size, MI_PAGE_SMALL,MI_SMALL_PAGE_SHIFT,tld,os_tld); +static mi_page_t* mi_segment_small_page_alloc(mi_heap_t* heap, size_t block_size, mi_segments_tld_t* tld) { + return mi_segment_page_alloc(heap, block_size, MI_PAGE_SMALL,MI_SMALL_PAGE_SHIFT,tld); } -static mi_page_t* mi_segment_medium_page_alloc(mi_heap_t* heap, size_t block_size, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) { - return mi_segment_page_alloc(heap, block_size, MI_PAGE_MEDIUM, MI_MEDIUM_PAGE_SHIFT, tld, os_tld); +static mi_page_t* mi_segment_medium_page_alloc(mi_heap_t* heap, size_t block_size, mi_segments_tld_t* tld) { + return mi_segment_page_alloc(heap, block_size, MI_PAGE_MEDIUM, MI_MEDIUM_PAGE_SHIFT, tld); } /* ----------------------------------------------------------- large page allocation ----------------------------------------------------------- */ -static mi_page_t* mi_segment_large_page_alloc(mi_heap_t* heap, size_t block_size, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) { - mi_segment_t* segment = mi_segment_reclaim_or_alloc(heap,block_size,MI_PAGE_LARGE,MI_LARGE_PAGE_SHIFT,tld,os_tld); +static mi_page_t* mi_segment_large_page_alloc(mi_heap_t* heap, size_t block_size, mi_segments_tld_t* tld) { + mi_segment_t* segment = mi_segment_reclaim_or_alloc(heap,block_size,MI_PAGE_LARGE,MI_LARGE_PAGE_SHIFT,tld); if (segment == NULL) return NULL; mi_page_t* page = mi_segment_find_free(segment, tld); mi_assert_internal(page != NULL); @@ -1245,9 +1245,9 @@ static mi_page_t* mi_segment_large_page_alloc(mi_heap_t* heap, size_t block_size return page; } -static mi_page_t* mi_segment_huge_page_alloc(size_t size, size_t page_alignment, mi_arena_id_t req_arena_id, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) +static mi_page_t* mi_segment_huge_page_alloc(size_t size, size_t page_alignment, mi_arena_id_t req_arena_id, mi_segments_tld_t* tld) { - mi_segment_t* segment = mi_segment_alloc(size, MI_PAGE_HUGE, MI_SEGMENT_SHIFT + 1, page_alignment, req_arena_id, tld, os_tld); + mi_segment_t* segment = mi_segment_alloc(size, MI_PAGE_HUGE, MI_SEGMENT_SHIFT + 1, page_alignment, req_arena_id, tld); if (segment == NULL) return NULL; mi_assert_internal(mi_segment_page_size(segment) - segment->segment_info_size - (2*(MI_SECURE == 0 ? 0 : _mi_os_page_size())) >= size); #if MI_HUGE_PAGE_ABANDON @@ -1271,7 +1271,7 @@ static mi_page_t* mi_segment_huge_page_alloc(size_t size, size_t page_alignment, mi_assert_internal(psize - (aligned_p - start) >= size); uint8_t* decommit_start = start + sizeof(mi_block_t); // for the free list ptrdiff_t decommit_size = aligned_p - decommit_start; - _mi_os_reset(decommit_start, decommit_size, os_tld->stats); // do not decommit as it may be in a region + _mi_os_reset(decommit_start, decommit_size); // do not decommit as it may be in a region } return page; @@ -1318,7 +1318,7 @@ void _mi_segment_huge_page_reset(mi_segment_t* segment, mi_page_t* page, mi_bloc if (usize > sizeof(mi_block_t)) { usize = usize - sizeof(mi_block_t); uint8_t* p = (uint8_t*)block + sizeof(mi_block_t); - _mi_os_reset(p, usize, &_mi_stats_main); + _mi_os_reset(p, usize); } } } @@ -1328,26 +1328,26 @@ void _mi_segment_huge_page_reset(mi_segment_t* segment, mi_page_t* page, mi_bloc Page allocation ----------------------------------------------------------- */ -mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment, mi_segments_tld_t* tld, mi_os_tld_t* os_tld) { +mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment, mi_segments_tld_t* tld) { mi_page_t* page; if mi_unlikely(page_alignment > MI_BLOCK_ALIGNMENT_MAX) { mi_assert_internal(_mi_is_power_of_two(page_alignment)); mi_assert_internal(page_alignment >= MI_SEGMENT_SIZE); //mi_assert_internal((MI_SEGMENT_SIZE % page_alignment) == 0); if (page_alignment < MI_SEGMENT_SIZE) { page_alignment = MI_SEGMENT_SIZE; } - page = mi_segment_huge_page_alloc(block_size, page_alignment, heap->arena_id, tld, os_tld); + page = mi_segment_huge_page_alloc(block_size, page_alignment, heap->arena_id, tld); } else if (block_size <= MI_SMALL_OBJ_SIZE_MAX) { - page = mi_segment_small_page_alloc(heap, block_size, tld, os_tld); + page = mi_segment_small_page_alloc(heap, block_size, tld); } else if (block_size <= MI_MEDIUM_OBJ_SIZE_MAX) { - page = mi_segment_medium_page_alloc(heap, block_size, tld, os_tld); + page = mi_segment_medium_page_alloc(heap, block_size, tld); } else if (block_size <= MI_LARGE_OBJ_SIZE_MAX /* || mi_is_good_fit(block_size, MI_LARGE_PAGE_SIZE - sizeof(mi_segment_t)) */ ) { - page = mi_segment_large_page_alloc(heap, block_size, tld, os_tld); + page = mi_segment_large_page_alloc(heap, block_size, tld); } else { - page = mi_segment_huge_page_alloc(block_size, page_alignment, heap->arena_id, tld, os_tld); + page = mi_segment_huge_page_alloc(block_size, page_alignment, heap->arena_id, tld); } mi_assert_expensive(page == NULL || mi_segment_is_valid(_mi_page_segment(page),tld)); mi_assert_internal(page == NULL || (mi_segment_page_size(_mi_page_segment(page)) - (MI_SECURE == 0 ? 0 : _mi_os_page_size())) >= block_size); diff --git a/test/test-stress.c b/test/test-stress.c index 8ede5db2..261c5dfe 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -36,7 +36,7 @@ static int ITER = 400; static int THREADS = 8; static int SCALE = 25; static int ITER = 20; -#elif defined(xMI_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits +#elif defined(MI_GUARDED) // with debug guard pages reduce parameters to stay within the azure pipeline limits static int THREADS = 8; static int SCALE = 10; static int ITER = 10; From ed318471126918fce7caf0001cf1e0c78f95173e Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 9 Dec 2024 20:45:22 -0800 Subject: [PATCH 146/305] fix generic ctz/clz --- include/mimalloc/internal.h | 57 ++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 703c44b9..012ce4f0 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -873,16 +873,18 @@ static inline size_t mi_ctz(uintptr_t x) { } #else -static inline size_t mi_ctz32(uint32_t x) { + +static inline size_t mi_ctz_generic32(uint32_t x) { // de Bruijn multiplication, see - static const unsigned char debruijn[32] = { + static const uint8_t debruijn[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; if (x==0) return 32; - return debruijn[((x & -(int32_t)x) * 0x077CB531UL) >> 27]; + return debruijn[(uint32_t)((x & -(int32_t)x) * (uint32_t)(0x077CB531U)) >> 27]; } -static inline size_t mi_clz32(uint32_t x) { + +static inline size_t mi_clz_generic32(uint32_t x) { // de Bruijn multiplication, see static const uint8_t debruijn[32] = { 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, @@ -894,28 +896,37 @@ static inline size_t mi_clz32(uint32_t x) { x |= x >> 4; x |= x >> 8; x |= x >> 16; - return debruijn[(uint32_t)(x * 0x07C4ACDDUL) >> 27]; + return debruijn[(uint32_t)(x * (uint32_t)(0x07C4ACDDU)) >> 27]; } -static inline size_t mi_clz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; -#if (MI_INTPTR_BITS <= 32) - return mi_clz32((uint32_t)x); -#else - size_t count = mi_clz32((uint32_t)(x >> 32)); - if (count < 32) return count; - return (32 + mi_clz32((uint32_t)x)); -#endif +static inline size_t mi_ctz(size_t x) { + if (x==0) return MI_SIZE_BITS; + #if (MI_SIZE_BITS <= 32) + return mi_ctz_generic32((uint32_t)x); + #else + const uint32_t lo = (uint32_t)x; + if (lo != 0) { + return mi_ctz_generic32(lo); + } + else { + return (32 + mi_ctz_generic32((uint32_t)(x>>32))); + } + #endif } -static inline size_t mi_ctz(uintptr_t x) { - if (x==0) return MI_INTPTR_BITS; -#if (MI_INTPTR_BITS <= 32) - return mi_ctz32((uint32_t)x); -#else - size_t count = mi_ctz32((uint32_t)x); - if (count < 32) return count; - return (32 + mi_ctz32((uint32_t)(x>>32))); -#endif + +static inline size_t mi_clz(size_t x) { + if (x==0) return MI_SIZE_BITS; + #if (MI_SIZE_BITS <= 32) + return mi_clz_generic32((uint32_t)x); + #else + const uint32_t hi = (uint32_t)(x>>32); + if (hi != 0) { + return mi_clz_generic32(hi); + } + else { + return 32 + mi_clz_generic32((uint32_t)x); + } + #endif } #endif From 2556a2022d78d7ab37e284fbea53255d3bdf766f Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 9 Dec 2024 20:50:00 -0800 Subject: [PATCH 147/305] fix missing void --- src/os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index 81dda8a1..32cb11c3 100644 --- a/src/os.c +++ b/src/os.c @@ -703,7 +703,7 @@ size_t _mi_os_numa_node_count_get(void) { return count; } -int _mi_os_numa_node_get() { +int _mi_os_numa_node_get(void) { size_t numa_count = _mi_os_numa_node_count(); if (numa_count<=1) return 0; // optimize on single numa node systems: always node 0 // never more than the node count and >= 0 From 988637934996fcde3322f55215705abd03ba85d5 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 9 Dec 2024 21:22:30 -0800 Subject: [PATCH 148/305] fix macos 15 OS name --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 00bfe8e9..eb520aa0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -283,7 +283,7 @@ jobs: displayName: CTest - job: - displayName: macOS 15 (Sequia) + displayName: macOS 15 (Sequoia) pool: vmImage: macOS-15 From 7bb4767607cecda55059e59f1597a26697af1bc1 Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 10 Dec 2024 20:45:59 -0800 Subject: [PATCH 149/305] add asan/ubsan/tsan and valgrind to default debug build --- CMakeLists.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17f2071a..adf16a7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,16 +74,16 @@ else() endif() # ----------------------------------------------------------------------------- -# Convenience: set default build type depending on the build directory +# Convenience: set default build type and compiler depending on the build directory # ----------------------------------------------------------------------------- message(STATUS "") if (NOT CMAKE_BUILD_TYPE) - if ("${CMAKE_BINARY_DIR}" MATCHES ".*(D|d)ebug$" OR MI_DEBUG_FULL) - message(STATUS "No build type selected, default to: Debug") + if ("${CMAKE_BINARY_DIR}" MATCHES ".*((D|d)ebug|asan|tsan|ubsan|valgrind)$" OR MI_DEBUG_FULL) + message(STATUS "No build type selected, default to 'Debug'") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "No build type selected, default to: Release") + message(STATUS "No build type selected, default to 'Release'") set(CMAKE_BUILD_TYPE "Release") endif() endif() @@ -93,7 +93,6 @@ if("${CMAKE_BINARY_DIR}" MATCHES ".*(S|s)ecure$") set(MI_SECURE "ON") endif() - # ----------------------------------------------------------------------------- # Process options # ----------------------------------------------------------------------------- From 91215a5512ed4fa916ec26349f69d44235313308 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 11 Dec 2024 09:20:34 -0800 Subject: [PATCH 150/305] ensure incompatible heaps are not absorbed --- src/heap.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/heap.c b/src/heap.c index 4459ff77..c2b5ae42 100644 --- a/src/heap.c +++ b/src/heap.c @@ -446,6 +446,12 @@ static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) { mi_heap_reset_pages(from); } +// are two heaps compatible with respect to heap-tag, exclusive arena etc. +static bool mi_heaps_are_compatible(mi_heap_t* heap1, mi_heap_t* heap2) { + return (heap1->tag == heap2->tag && // store same kind of objects + heap1->arena_id == heap2->arena_id); // same arena preference +} + // Safe delete a heap without freeing any still allocated blocks in that heap. void mi_heap_delete(mi_heap_t* heap) { @@ -454,9 +460,10 @@ void mi_heap_delete(mi_heap_t* heap) mi_assert_expensive(mi_heap_is_valid(heap)); if (heap==NULL || !mi_heap_is_initialized(heap)) return; - if (!mi_heap_is_backing(heap)) { + mi_heap_t* bheap = heap->tld->heap_backing; + if (bheap != heap && mi_heaps_are_compatible(bheap,heap)) { // transfer still used pages to the backing heap - mi_heap_absorb(heap->tld->heap_backing, heap); + mi_heap_absorb(bheap, heap); } else { // the backing heap abandons its pages From d5e1a62a7cebd4585a7f9de07f5acba15394fcf9 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 16 Dec 2024 22:51:30 -0800 Subject: [PATCH 151/305] add windows arm64 target to vs2022 --- bin/readme.md | 6 +- ide/vs2022/mimalloc-override-test.vcxproj | 82 ++++++++++ ide/vs2022/mimalloc-override.vcxproj | 107 ++++++++++++ ide/vs2022/mimalloc-test-api.vcxproj | 65 ++++++++ ide/vs2022/mimalloc-test-stress.vcxproj | 65 ++++++++ ide/vs2022/mimalloc-test.vcxproj | 64 ++++++++ ide/vs2022/mimalloc.sln | 188 ++++++++++++---------- ide/vs2022/mimalloc.vcxproj | 113 +++++++++++++ test/main-override.cpp | 8 +- test/test-stress.c | 2 +- 10 files changed, 613 insertions(+), 87 deletions(-) diff --git a/bin/readme.md b/bin/readme.md index 9b121bda..a699a2cd 100644 --- a/bin/readme.md +++ b/bin/readme.md @@ -15,7 +15,7 @@ There are four requirements to make the overriding work robustly: (or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project for an example on how to use this. -3. The `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) must be put +3. The `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`, or `mimalloc-redirect-arm64.dll`) must be put in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc functions (which reside in `mimalloc-override.dll`). @@ -40,7 +40,9 @@ if they are linked with the dynamic C runtime (`ucrtbase.dll`) -- just put the ` 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). -The `minject` program can also do this from the command line, use `minject --help` for options: +The `minject` program can also do this from the command line +(or `minject32` for 32-bit PE files, or `minject-arm64` on arm64 Windows). +Use `minject --help` for options: ``` > minject --help diff --git a/ide/vs2022/mimalloc-override-test.vcxproj b/ide/vs2022/mimalloc-override-test.vcxproj index a3c56f7b..ff5d53d0 100644 --- a/ide/vs2022/mimalloc-override-test.vcxproj +++ b/ide/vs2022/mimalloc-override-test.vcxproj @@ -1,10 +1,18 @@ + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -42,12 +50,23 @@ true v143 + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + @@ -62,9 +81,15 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +103,18 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -128,6 +161,30 @@ + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + + + kernel32.lib;%(AdditionalDependencies) + + + + + + + Level3 @@ -176,6 +233,31 @@ + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index 4383d886..16a48740 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -1,10 +1,18 @@  + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -41,11 +49,21 @@ true v143 + + DynamicLibrary + true + v143 + DynamicLibrary false v143 + + DynamicLibrary + false + v143 + @@ -60,9 +78,15 @@ + + + + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -82,12 +106,24 @@ .dll mimalloc-override + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc-override + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll mimalloc-override + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc-override + Level3 @@ -144,6 +180,34 @@ copy mimalloc-redirect.dll to the output directory + + + Level3 + Disabled + true + true + ../../include + MI_DEBUG=4;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); + MultiThreadedDebugDLL + false + CompileAsCpp + + + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64.lib;%(AdditionalDependencies) + + + + + Default + false + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64.dll to the output directory + + Level3 @@ -208,6 +272,39 @@ copy mimalloc-redirect.dll to the output directory + + + Level3 + MaxSpeed + true + true + true + ../../include + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + MultiThreadedDLL + CompileAsCpp + false + CPUExtensionRequirementsARMv81 + + + true + true + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64.lib;%(AdditionalDependencies) + + + Default + false + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64.dll to the output directory + + @@ -226,13 +323,17 @@ false false false + false false + false true true true + true true + true @@ -240,7 +341,9 @@ true true true + true true + true @@ -252,7 +355,9 @@ true true true + true true + true @@ -260,7 +365,9 @@ true true true + true true + true diff --git a/ide/vs2022/mimalloc-test-api.vcxproj b/ide/vs2022/mimalloc-test-api.vcxproj index d9b9cae4..babe7f96 100644 --- a/ide/vs2022/mimalloc-test-api.vcxproj +++ b/ide/vs2022/mimalloc-test-api.vcxproj @@ -1,10 +1,18 @@ + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -42,12 +50,23 @@ true v143 + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + @@ -62,9 +81,15 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +103,18 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -106,6 +139,18 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + Level3 @@ -140,15 +185,35 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + + + true + true + Console + + true true true + true true + true false + false diff --git a/ide/vs2022/mimalloc-test-stress.vcxproj b/ide/vs2022/mimalloc-test-stress.vcxproj index c7e820df..c033aaeb 100644 --- a/ide/vs2022/mimalloc-test-stress.vcxproj +++ b/ide/vs2022/mimalloc-test-stress.vcxproj @@ -1,10 +1,18 @@ + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -42,12 +50,23 @@ true v143 + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + @@ -62,9 +81,15 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +103,18 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -106,6 +139,18 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + Level3 @@ -140,12 +185,32 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + CPUExtensionRequirementsARMv81 + + + true + true + Console + + false false + false false false + false diff --git a/ide/vs2022/mimalloc-test.vcxproj b/ide/vs2022/mimalloc-test.vcxproj index 506dd7d4..bfd72287 100644 --- a/ide/vs2022/mimalloc-test.vcxproj +++ b/ide/vs2022/mimalloc-test.vcxproj @@ -1,10 +1,18 @@ + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -42,12 +50,23 @@ true v143 + + Application + true + v143 + Application false v143 true + + Application + false + v143 + true + @@ -62,9 +81,15 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -78,10 +103,18 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -108,6 +141,19 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + stdcpp17 + + + Console + + Level3 @@ -144,6 +190,24 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + stdcpp17 + + + true + true + Console + + {abb5eae7-b3e6-432e-b636-333449892ea6} diff --git a/ide/vs2022/mimalloc.sln b/ide/vs2022/mimalloc.sln index 6ff01d3b..e4a6538b 100644 --- a/ide/vs2022/mimalloc.sln +++ b/ide/vs2022/mimalloc.sln @@ -1,81 +1,107 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-api", "mimalloc-test-api.vcxproj", "{FFF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {4297F93D-486A-4243-995F-7D32F59AE82A} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-api", "mimalloc-test-api.vcxproj", "{FFF7958F-750E-4C21-A04D-22707CC66878}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64.Build.0 = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64.ActiveCfg = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64.Build.0 = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64.Build.0 = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64.ActiveCfg = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64.Build.0 = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64.ActiveCfg = Release|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4297F93D-486A-4243-995F-7D32F59AE82A} + EndGlobalSection +EndGlobal diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index dddab777..fb13cd1f 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -1,10 +1,18 @@  + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -42,12 +50,23 @@ true v143 + + StaticLibrary + true + v143 + StaticLibrary false v143 true + + StaticLibrary + false + v143 + true + @@ -62,9 +81,15 @@ + + + + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -84,12 +109,24 @@ .lib mimalloc-static + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc-static + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .lib mimalloc-static + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc-static + Level4 @@ -136,6 +173,33 @@ + + + Level4 + Disabled + true + Default + ../../include + MI_DEBUG=3;MI_GUARDED=0;%(PreprocessorDefinitions); + CompileAsCpp + false + stdcpp20 + + + + + + + + + + + + + + + + Level4 @@ -198,18 +262,58 @@ + + + Level4 + MaxSpeed + true + Default + ../../include + %(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + false + Default + CompileAsCpp + true + stdcpp20 + CPUExtensionRequirementsARMv81 + Sync + + + true + true + + + + + + + + + + + + + + false false + false false false + false true true true + true true + true @@ -217,17 +321,22 @@ true true true + true true + true false + false true + true true true true + true @@ -237,14 +346,18 @@ true true true + true true + true true true true + true true + true diff --git a/test/main-override.cpp b/test/main-override.cpp index 3f64117a..3d56ae42 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -44,8 +44,8 @@ static void test_stl_allocators(); int main() { - // mi_stats_reset(); // ignore earlier allocations - + mi_stats_reset(); // ignore earlier allocations + various_tests(); test_mixed1(); //test_std_string(); //test_thread_local(); @@ -55,8 +55,10 @@ int main() { heap_no_delete(); heap_late_free(); padding_shrink(); - various_tests(); + tsan_numa_test(); + */ + /* strdup_test(); test_stl_allocators(); test_mt_shutdown(); diff --git a/test/test-stress.c b/test/test-stress.c index 261c5dfe..1848e9f5 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -23,7 +23,7 @@ terms of the MIT license. #include // #define MI_GUARDED -// #define USE_STD_MALLOC +#define USE_STD_MALLOC // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // From b47c68fefd505f1b78284299309253fb9471bbd9 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 16 Dec 2024 22:53:23 -0800 Subject: [PATCH 152/305] add redirection dll for windows on arm64 --- bin/mimalloc-redirect-arm64.dll | Bin 0 -> 80896 bytes bin/mimalloc-redirect-arm64.lib | Bin 0 -> 2976 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 bin/mimalloc-redirect-arm64.dll create mode 100644 bin/mimalloc-redirect-arm64.lib diff --git a/bin/mimalloc-redirect-arm64.dll b/bin/mimalloc-redirect-arm64.dll new file mode 100644 index 0000000000000000000000000000000000000000..0cae1d5170e37a11e6e767b24f102a8811e322e5 GIT binary patch literal 80896 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 Q50(~TPy6Bz(SH+v04r#&VE_OC literal 0 HcmV?d00001 From de8d73d2086da80e8df902d1c1b262bc54c2894e Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 16 Dec 2024 22:53:52 -0800 Subject: [PATCH 153/305] add minject for windows arm64 --- bin/minject-arm64.exe | Bin 0 -> 20992 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 bin/minject-arm64.exe diff --git a/bin/minject-arm64.exe b/bin/minject-arm64.exe new file mode 100644 index 0000000000000000000000000000000000000000..63987afcacc42511aca435e78a70d56a64163ff2 GIT binary patch literal 20992 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 jM=FnOKhkof Date: Mon, 16 Dec 2024 23:09:50 -0800 Subject: [PATCH 154/305] add Windows arm64 support in cmame; name the mimalloc dll 'mimalloc-override.dll' on Windows with cmake (to match the IDE and minject --- CMakeLists.txt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index adf16a7f..490cb483 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,13 +146,7 @@ if(MI_OVERRIDE) endif() endif() -if(WIN32) - if (MI_WIN_REDIRECT) - if (MSVC_C_ARCHITECTURE_ID MATCHES "ARM") - message(STATUS "Cannot use redirection on Windows ARM (MI_WIN_REDIRECT=OFF)") - set(MI_WIN_REDIRECT OFF) - endif() - endif() +if(WIN32) if (NOT MI_WIN_REDIRECT) # use a negative define for backward compatibility list(APPEND mi_defines MI_WIN_NOREDIRECT=1) @@ -340,7 +334,7 @@ if(APPLE) endif() elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") set(MI_ARCH "x64") -elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") set(MI_ARCH "arm64") endif() @@ -534,7 +528,9 @@ if(MI_BUILD_SHARED) ) if(WIN32 AND MI_WIN_REDIRECT) # On windows, link and copy the mimalloc redirection dll too. - if(CMAKE_SIZEOF_VOID_P EQUAL 4) + if(MI_ARCH STREQUAL "arm64") + set(MIMALLOC_REDIRECT_SUFFIX "-arm64") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) set(MIMALLOC_REDIRECT_SUFFIX "32") else() set(MIMALLOC_REDIRECT_SUFFIX "") @@ -656,6 +652,11 @@ endif() if (MI_OVERRIDE) if (MI_BUILD_SHARED) target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) + if (WIN32) + # on windows we should generate mimalloc-override.dll. + string(REPLACE "mimalloc" "mimalloc-override" mi_override_output_name ${mi_basename}) + set_target_properties(mimalloc PROPERTIES OUTPUT_NAME ${mi_override_output_name}) + endif() endif() if(NOT WIN32) # It is only possible to override malloc on Windows when building as a DLL. From 6ac636e2e2e0726d4360e5119cfbf7ad6a8725a7 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 16 Dec 2024 23:22:52 -0800 Subject: [PATCH 155/305] update readme --- bin/readme.md | 9 +++++---- test/test-stress.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bin/readme.md b/bin/readme.md index a699a2cd..d133eea2 100644 --- a/bin/readme.md +++ b/bin/readme.md @@ -11,11 +11,12 @@ There are four requirements to make the overriding work robustly: 2. Link your program explicitly with `mimalloc-override.dll` library. To ensure the `mimalloc-override.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. + call to the mimalloc API in the `main` function, like `mi_version()` + (or use the `/INCLUDE:mi_version` switch on the linker, or + use `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-override-test` project for an example on how to use this. -3. The `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`, or `mimalloc-redirect-arm64.dll`) must be put +3. The `mimalloc-redirect.dll` (x64) (or `mimalloc-redirect32.dll` (x86), or `mimalloc-redirect-arm64.dll` (arm64)) must be put in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc functions (which reside in `mimalloc-override.dll`). diff --git a/test/test-stress.c b/test/test-stress.c index 1848e9f5..261c5dfe 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -23,7 +23,7 @@ terms of the MIT license. #include // #define MI_GUARDED -#define USE_STD_MALLOC +// #define USE_STD_MALLOC // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // From ac52b6967d06bac6515e8325c9dd34121154a6b5 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Tue, 17 Dec 2024 00:06:03 -0800 Subject: [PATCH 156/305] update arm64 redirection --- bin/mimalloc-redirect-arm64.dll | Bin 80896 -> 53760 bytes test/test-stress.c | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/mimalloc-redirect-arm64.dll b/bin/mimalloc-redirect-arm64.dll index 0cae1d5170e37a11e6e767b24f102a8811e322e5..2b1d3e355ccd3bb8aa3442f90f3490a3a4a167f0 100644 GIT binary patch delta 10318 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 u`8z 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 Date: Tue, 17 Dec 2024 00:35:28 -0800 Subject: [PATCH 157/305] make timeout for tests in the pipeline up to 4 min --- azure-pipelines.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index eb520aa0..bccf7a3f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,7 +43,7 @@ jobs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' msbuildArguments: -m - - script: ctest --verbose --timeout 180 -C $(MSBuildConfiguration) + - script: ctest --verbose --timeout 240 -C $(MSBuildConfiguration) workingDirectory: $(BuildType) displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress @@ -126,7 +126,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(nproc) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 180 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest env: @@ -157,7 +157,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 180 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest # - upload: $(Build.SourcesDirectory)/$(BuildType) @@ -192,7 +192,7 @@ jobs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' msbuildArguments: -m - - script: ctest --verbose --timeout 180 -C $(MSBuildConfiguration) + - script: ctest --verbose --timeout 240 -C $(MSBuildConfiguration) workingDirectory: $(BuildType) displayName: CTest @@ -235,7 +235,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(nproc) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 180 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest @@ -278,7 +278,7 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(nproc) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 180 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest @@ -302,6 +302,6 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) displayName: Make - - script: ctest --verbose --timeout 180 + - script: ctest --verbose --timeout 240 workingDirectory: $(BuildType) displayName: CTest From c2e0aa49c46894d4fe41037067a9048c1094ab3f Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 17 Dec 2024 16:07:18 -0800 Subject: [PATCH 158/305] update minject to v1.1 --- bin/minject-arm64.exe | Bin 20992 -> 20992 bytes bin/minject.exe | Bin 22016 -> 22016 bytes bin/minject32.exe | Bin 18944 -> 18944 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/minject-arm64.exe b/bin/minject-arm64.exe index 63987afcacc42511aca435e78a70d56a64163ff2..97188c4f14e644b66d938ce44a940f3058153a13 100644 GIT binary patch delta 1887 zcmeIyPe_wt90%~<`}&79E38b#L?)P+$x;&&v3jKuDkjUO){>YtY(WQ!AtJ(dD3DI+ z>%mL0LSj^e_;v{CVB*1p$PN;o!u}j2q9i(ui0J$5{jO%W?!GWS`+c9^^JinvqBB}_ zMw@kLS^BQ4W}bFOU-OxhTD4X>QGUo=*8=)dsnx7Mt#m%jn{bFE3SQ@#U#qS--?7wo zqinZgM*@0e>$0St#(vvDdYgKwle(zgEwbKczkAHQg)XwObVhTxgyRn{<}? z>3qLc?Ow~xaShkG>#Sc5_j9aR^ORPIpW$`2&K|r%x=7TESBt4-HCiJlTeL_51MXYF zf$)Gmrh4qUVsvygn3}xVErQ=F^6<5a_SROl-qyCvpZXe-nVHY-lM5MheRiJ%*@}ks zMuKNj8?X69UZ@RjsDo70s}06`M2i1r$5j?X)}#(-_cf?&z0Vpx-K$47FqVFr@TC|A zK2UEu5y{47+CWytAG;cRv6w zQrNUlq!z}Z0TZwjy7r3%VJ!?p1CBw@0g)-_g)ta_FJTle!M20AYOtV4cc$_XjGYfzd9a$D}F4BD3J6l-uok~HTpH1 zAB9=zpEzNW-D?U3hrUH)EAuAP$ds9>Of4G8o3zza))TL2_7>}3nD3ds?fc#In>YMq z-e-miw6bk%)|9(fLmrK;oi@jXqI7JVm@2b4NH@`WF7TWk^USZz4JL7+Pt0UyCi4ul zn0bM@&K%}EFWFuYME$=bj{~xqQ5^V)+0BhsF_SrNi0$u82Xllu%bZ|_3NFLe3nPXT zO>@91)5kP1r(68l`nP-i5&2Id{f~m*DSK6QsL z7Pe92uGhgZ|1T3uE|ptn_YpxK!N0|RQCc<9x7BAhPhE?Z`0S((VS zwoPjezSs3|twD?1+@@)9)IhW(Az!~*9xS|MCYlii+C?LoXG8%{BT?!C2Z=_&I&d7c zfK#9coCS@CkONFgA^HFsQmCHRu?RpQG~zpnW978CT_;KdyEo;txc@FqQxS diff --git a/bin/minject.exe b/bin/minject.exe index dba8f80fd2a0ef8b0137d50a8e67996c5b84a9c9..53c42f5d6dc7f643c03e832ff9e0aff42b2fc265 100644 GIT binary patch delta 10296 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 XSWvGy4SYjULvce%LwN&~I@tdPn9V1t delta 9946 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%0DVy0e+#w&*e+l+?3>Rs^t`bhntS{I_mhnMZ%?w` z7feMm<}Tq+)|uW}l9dj3nWv+}(eAG9*uKTl*}1BPWZit8`U+tGjh`TkCE|O=WARy8=_lW71WfD;)QF?z_*?QQhI_#4E@f z^4fOi=Ju90M~i*e7DwI=ckA|c*l{~L2-zvGak&3Yeyf-hj@V|UJxrab+TP-6b5um_ zpsq56_iQQ5LE&TD!%vo~71$SK%_p{#y}r@|j1ZJKdy`gNXS{S9FzjM>BkN_KW#49h z#r~fCD?3e_uGMRsv_I5-q*dxNbjx*3x?Q?H{crV(d{cgZezxI$!%K!Ytxq|S#f&tv&AnJzgc{~ z_@m-*vCN$0HP1B9H!n38nqM&g#{5U~Kh4>er51yw*|Nj(kcG26Yx$|=q-D_Z2g_B9 z)S6+{ShZHGwbI&X-D-W%y5IV;^=)g=dcpds^=m64$;L^8KxJ$)JD1I4JK1jb6#FH+ zP`gq4q_$uCtyZVos(W5{Q76-9>&x_<-utBf2l^NFefkmoH~O^v1^I>f4f*@?f0F-U z{&;@6!D?7<_@3dA;W@+0hBpjf88Qp}1+N!`3eFV#uHbJ4UlowTqQcF~1IvTUKUx0u za-}iZm~Nb7)EJi-S)<*!!MNFYpYb81-#BUv8?%daMLUapMO@L-MXwcoQuOyCscD+m zRA6c{IZXGP9x<&hb``se4;Q~*e7U&5Y&EYi*PHJ*?=bt#N6e?p#3HxMw9L2US$=Q% z(DI38o;A;Euv)A&)+Q@&J#77<^;PRz)=SnuS+7~ITM6pF8wr_)Ow49AY$0oB?_}4q z^=vb{g>|tz*H+@N>G~%{tpi@_0a$T From 617190880daf359249844aa447b28aabe9d28434 Mon Sep 17 00:00:00 2001 From: daanx Date: Tue, 17 Dec 2024 17:53:34 -0800 Subject: [PATCH 159/305] add ajust stats to compensate for double counting --- include/mimalloc/types.h | 15 ++++++++++++--- src/stats.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index 3d8014c3..ad948d36 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -609,18 +609,27 @@ typedef struct mi_stats_s { } mi_stats_t; +// add to stat keeping track of the peak void _mi_stat_increase(mi_stat_count_t* stat, size_t amount); void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount); +// adjust stat in special cases to compensate for double counting +void _mi_stat_adjust_increase(mi_stat_count_t* stat, size_t amount); +void _mi_stat_adjust_decrease(mi_stat_count_t* stat, size_t amount); +// counters can just be increased void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); #if (MI_STAT) #define mi_stat_increase(stat,amount) _mi_stat_increase( &(stat), amount) #define mi_stat_decrease(stat,amount) _mi_stat_decrease( &(stat), amount) #define mi_stat_counter_increase(stat,amount) _mi_stat_counter_increase( &(stat), amount) +#define mi_stat_adjust_increase(stat,amount) _mi_stat_adjust_increase( &(stat), amount) +#define mi_stat_adjust_decrease(stat,amount) _mi_stat_adjust_decrease( &(stat), amount) #else -#define mi_stat_increase(stat,amount) (void)0 -#define mi_stat_decrease(stat,amount) (void)0 -#define mi_stat_counter_increase(stat,amount) (void)0 +#define mi_stat_increase(stat,amount) ((void)0) +#define mi_stat_decrease(stat,amount) ((void)0) +#define mi_stat_counter_increase(stat,amount) ((void)0) +#define mi_stat_adjuct_increase(stat,amount) ((void)0) +#define mi_stat_adjust_decrease(stat,amount) ((void)0) #endif #define mi_heap_stat_counter_increase(heap,stat,amount) mi_stat_counter_increase( (heap)->tld->stats.stat, amount) diff --git a/src/stats.c b/src/stats.c index 29376ace..8566e8f2 100644 --- a/src/stats.c +++ b/src/stats.c @@ -26,7 +26,7 @@ static bool mi_is_in_main(void* stat) { static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) { if (amount == 0) return; - if (mi_is_in_main(stat)) + if mi_unlikely(mi_is_in_main(stat)) { // add atomically (for abandoned pages) int64_t current = mi_atomic_addi64_relaxed(&stat->current, amount); @@ -51,6 +51,27 @@ static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) { } } +// Adjust stats to compensate; for example before committing a range, +// first adjust downwards with parts that were already committed so +// we avoid double counting. +static void mi_stat_adjust(mi_stat_count_t* stat, int64_t amount) { + if (amount == 0) return; + if mi_unlikely(mi_is_in_main(stat)) + { + // adjust atomically + mi_atomic_addi64_relaxed(&stat->current, amount); + mi_atomic_addi64_relaxed(&stat->allocated, amount); + mi_atomic_addi64_relaxed(&stat->freed, amount); + } + else { + // don't affect the peak + stat->current += amount; + // add to both + stat->allocated += amount; + stat->freed += amount; + } +} + void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount) { if (mi_is_in_main(stat)) { mi_atomic_addi64_relaxed( &stat->count, 1 ); @@ -70,6 +91,14 @@ void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount) { mi_stat_update(stat, -((int64_t)amount)); } +void _mi_stat_adjust_increase(mi_stat_count_t* stat, size_t amount) { + mi_stat_adjust(stat, (int64_t)amount); +} + +void _mi_stat_adjust_decrease(mi_stat_count_t* stat, size_t amount) { + mi_stat_adjust(stat, -((int64_t)amount)); +} + // must be thread safe as it is called from stats_merge static void mi_stat_add(mi_stat_count_t* stat, const mi_stat_count_t* src, int64_t unit) { if (stat==src) return; From 636d646b9ca9a20fe23239150da823844804dd44 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 18 Dec 2024 14:20:49 -0800 Subject: [PATCH 160/305] update arch detection in cmake --- CMakeLists.txt | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 490cb483..c329d385 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,7 +146,7 @@ if(MI_OVERRIDE) endif() endif() -if(WIN32) +if(WIN32) if (NOT MI_WIN_REDIRECT) # use a negative define for backward compatibility list(APPEND mi_defines MI_WIN_NOREDIRECT=1) @@ -324,19 +324,24 @@ endif() # Determine architecture set(MI_OPT_ARCH_FLAGS "") set(MI_ARCH "unknown") -if(APPLE) - list(FIND CMAKE_OSX_ARCHITECTURES "x86_64" x64_index) - list(FIND CMAKE_OSX_ARCHITECTURES "arm64" arm64_index) - if(x64_index GREATER_EQUAL 0) - set(MI_ARCH "x64") - elseif(arm64_index GREATER_EQUAL 0) - set(MI_ARCH "arm64") - endif() -elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86|i[3456]86" OR CMAKE_GENERATOR_PLATFORM MATCHES "x86|Win32") + set(MI_ARCH "x86") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|x64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") set(MI_ARCH "x64") -elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|armv8.?" OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM64") set(MI_ARCH "arm64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + set(MI_ARCH "arm32") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv") + if(CMAKE_SIZEOF_VOID_P==4) + set(MI_ARCH "riscv32") + else + set(MI_ARCH "riscv64") + endif() +else() + set(MI_ARCH ${CMAKE_SYSTEM_PROCESSOR}) endif() +message(STATUS "Architecture: ${MI_ARCH}") # Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits. # (this will skip the aligned hinting in that case. Issue #939, #949) @@ -528,12 +533,12 @@ if(MI_BUILD_SHARED) ) if(WIN32 AND MI_WIN_REDIRECT) # On windows, link and copy the mimalloc redirection dll too. - if(MI_ARCH STREQUAL "arm64") - set(MIMALLOC_REDIRECT_SUFFIX "-arm64") - elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + if(MI_ARCH STREQUAL "x64") + set(MIMALLOC_REDIRECT_SUFFIX "") + elseif(MI_ARCH STREQUAL "x86") set(MIMALLOC_REDIRECT_SUFFIX "32") else() - set(MIMALLOC_REDIRECT_SUFFIX "") + set(MIMALLOC_REDIRECT_SUFFIX "-${MI_ARCH}") # -arm64 etc. endif() target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.lib) From 515ae84174fb1d91e2523a8b2ef3162b5c0aa7c0 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 18 Dec 2024 14:35:10 -0800 Subject: [PATCH 161/305] syntax error --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c329d385..859c0e23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD 17) option(MI_SECURE "Use full security mitigations (like guard pages, allocation randomization, double-free mitigation, and free-list corruption detection)" OFF) option(MI_DEBUG_FULL "Use full internal heap invariant checking in DEBUG mode (expensive)" OFF) option(MI_PADDING "Enable padding to detect heap block overflow (always on in DEBUG or SECURE mode, or with Valgrind/ASAN)" OFF) -option(MI_OVERRIDE "Override the standard malloc interface (e.g. define entry points for malloc() etc)" ON) +option(MI_OVERRIDE "Override the standard malloc interface (i.e. define entry points for 'malloc', 'free', etc)" ON) option(MI_XMALLOC "Enable abort() call on memory allocation failure by default" OFF) option(MI_SHOW_ERRORS "Show error and warning messages by default (only enabled by default in DEBUG mode)" OFF) option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhead)" OFF) @@ -326,7 +326,7 @@ set(MI_OPT_ARCH_FLAGS "") set(MI_ARCH "unknown") if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86|i[3456]86" OR CMAKE_GENERATOR_PLATFORM MATCHES "x86|Win32") set(MI_ARCH "x86") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|x64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|x64|amd64|AMD64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") set(MI_ARCH "x64") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|armv8.?" OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM64") set(MI_ARCH "arm64") @@ -335,7 +335,7 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv") if(CMAKE_SIZEOF_VOID_P==4) set(MI_ARCH "riscv32") - else + else() set(MI_ARCH "riscv64") endif() else() From 69d2b4e991a15b2564ac21b0b555147825f24fa9 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 18 Dec 2024 14:41:20 -0800 Subject: [PATCH 162/305] add comments/doc --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 859c0e23..e216a4a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON) option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON) option(MI_WIN_REDIRECT "Use redirection module ('mimalloc-redirect') on Windows if compiling mimalloc as a DLL" ON) -option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) +option(MI_LOCAL_DYNAMIC_TLS "Use local-dynamic-tls, a slightly slower but dlopen-compatible thread local storage mechanism (Unix)" OFF) option(MI_LIBC_MUSL "Set this when linking with musl libc" OFF) option(MI_BUILD_SHARED "Build shared library" ON) option(MI_BUILD_STATIC "Build static library" ON) @@ -162,8 +162,8 @@ if(MI_TRACK_VALGRIND) CHECK_INCLUDE_FILES("valgrind/valgrind.h;valgrind/memcheck.h" MI_HAS_VALGRINDH) if (NOT MI_HAS_VALGRINDH) set(MI_TRACK_VALGRIND OFF) - message(WARNING "Cannot find the 'valgrind/valgrind.h' and 'valgrind/memcheck.h' -- install valgrind first") - message(STATUS "Compile **without** Valgrind support (MI_TRACK_VALGRIND=OFF)") + message(WARNING "Cannot find the 'valgrind/valgrind.h' and 'valgrind/memcheck.h' -- install valgrind first?") + message(STATUS "Disabling Valgrind support (MI_TRACK_VALGRIND=OFF)") else() message(STATUS "Compile with Valgrind support (MI_TRACK_VALGRIND=ON)") list(APPEND mi_defines MI_TRACK_VALGRIND=1) @@ -317,7 +317,7 @@ if(MI_LIBC_MUSL) endif() if(MI_WIN_USE_FLS) - message(STATUS "Use the Fiber API to detect thread termination") + message(STATUS "Use the Fiber API to detect thread termination (MI_WIN_USE_FLS=ON)") list(APPEND mi_defines MI_WIN_USE_FLS=1) endif() From 61a112cde5c083c6fa0ba71374adccabdf0b8b4a Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 18 Dec 2024 14:45:44 -0800 Subject: [PATCH 163/305] fix MI_ARCH test --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e216a4a3..8896dfd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,15 +324,15 @@ endif() # Determine architecture set(MI_OPT_ARCH_FLAGS "") set(MI_ARCH "unknown") -if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86|i[3456]86" OR CMAKE_GENERATOR_PLATFORM MATCHES "x86|Win32") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|i[3456]86)$" OR CMAKE_GENERATOR_PLATFORM MATCHES "^(x86|Win32)$") set(MI_ARCH "x86") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|x64|amd64|AMD64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") set(MI_ARCH "x64") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|armv8.?" OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv8.?)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") set(MI_ARCH "arm64") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|armv[34567])$") set(MI_ARCH "arm32") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv|riscv32|riscv64)$") if(CMAKE_SIZEOF_VOID_P==4) set(MI_ARCH "riscv32") else() From 27d929f338a7da875a734920f473e04562c5bfc3 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Wed, 18 Dec 2024 23:55:37 -0800 Subject: [PATCH 164/305] add support for arm64ec --- bin/mimalloc-redirect-arm64.dll | Bin 53760 -> 55296 bytes bin/mimalloc-redirect-arm64ec.dll | Bin 0 -> 100864 bytes bin/mimalloc-redirect-arm64ec.lib | Bin 0 -> 3308 bytes bin/mimalloc-redirect.dll | Bin 70656 -> 54272 bytes bin/mimalloc-redirect.lib | Bin 2874 -> 2874 bytes bin/mimalloc-redirect32.dll | Bin 48128 -> 35840 bytes bin/mimalloc-redirect32.lib | Bin 2928 -> 2928 bytes ide/vs2022/mimalloc-override-test.vcxproj | 82 ++++++++++++++++ ide/vs2022/mimalloc-override.vcxproj | 107 ++++++++++++++++++++ ide/vs2022/mimalloc-test-api.vcxproj | 65 +++++++++++++ ide/vs2022/mimalloc-test-stress.vcxproj | 65 +++++++++++++ ide/vs2022/mimalloc-test.vcxproj | 64 ++++++++++++ ide/vs2022/mimalloc.sln | 28 +++++- ide/vs2022/mimalloc.vcxproj | 113 ++++++++++++++++++++++ test/main-override.cpp | 3 + 15 files changed, 526 insertions(+), 1 deletion(-) create mode 100644 bin/mimalloc-redirect-arm64ec.dll create mode 100644 bin/mimalloc-redirect-arm64ec.lib diff --git a/bin/mimalloc-redirect-arm64.dll b/bin/mimalloc-redirect-arm64.dll index 2b1d3e355ccd3bb8aa3442f90f3490a3a4a167f0..98268796c03f790362d628c25ab684a96a6b4fd4 100644 GIT binary patch delta 8358 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 literal 0 HcmV?d00001 diff --git a/bin/mimalloc-redirect-arm64ec.lib b/bin/mimalloc-redirect-arm64ec.lib new file mode 100644 index 0000000000000000000000000000000000000000..1c7c368fc6ae255df671dd2ca96ae9e66ef76659 GIT binary patch literal 3308 zcmc&$&1(}u6n{xtTVs*<0iIeS7OX;>G)-a)rEI@wOVg$#DcI9=n_cZf(v)qg0S{7I zdJyrS5Ij`yA}C%;LA=zf$BHNM*n=nq1${F+v)N5{lP*XdNM`0YZ+3p~&HI?^!?K=V z9SKIl_SV~PpNm#6uB&S$HdZA9DKpwcMf1W1PP)CTrSCB z=)%DzJWt3`T!Qd{ANy{=M1!rfVbI=$D0UY9lera6 z&CJj8bz6rSjb>_0WVB(s00D5vjAaN>#0GKj~DnfD7wm3HUT2=DH1H{ih8GH7)SaQ(JnaZ9Y9*$IwKAI{4 zIC-3c>(*xRxB-Dvk9#X7yr&*_MxJyUZ|Fo?uEpJJsimsy{i7^`-JXI4WF XtR87whiT+A?aWHNLcCEkb_M?eX{j9D literal 0 HcmV?d00001 diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 4702fec0175e66168151f1d995a6148a0e69a1eb..5dee3713751104a965b40d13f21bbaac571b99f5 100644 GIT binary patch delta 13047 zcmbt*e_YgMw*T`PK!%?)Dkz}Hpo5I^YXsC$LkGqBq-3L_Vx^5g!|RVGfnr;2#?%(S zMBzSrciFpkcTfaGMT%0^@4ek&^|shni|%gA*0xc(^&#pml^V6xeBbBud1l6}{r+=# zb>^Jsob#M>p7WgN$LI4gPg}UBEv(@-ssC`%BKd*UX;-Jre&}2PmY;QAjrn8!{KY(BOFk=>ydn7g>0lOqt8$k^5*C4Sz@a-g8If`2JZn&pTD2_2>ftOnflXGhoE%^RvVfR{9c9}i#$U_D=^OEIW^ z;h&8H>t)7&sY{-%#)R0I4!l0VO@DSWw|mQu2RA_k6^2+kl%f^hPoEY_zg3oH6+~C1w*DlJ{SJtRfDK(eZ& zZn7+I_c6IXt_(_s7sI84zUuG--%up_6@ztw+edl$z$hR0MLM`uKS6ic&+pQ&S#w)C zI(rzaoCVFSe)14&mg~yQCOPb~T=%kEmzW9_!`Z0XSfgAQVMIgr`{Y9rqd*NEL9gq7 zQscU@CJ@)fqzgPNs$_gUOgB7hRSps!+>KutXjsFah$@w)^WR5h6or#St}8LyFfaoQ z$XUH|U5|XI#B3$DOP&L&a;m(q=;PJUr9hJnXG_f$$|c5UM&Ds*1Y2~fkK6w`uZy1K z-t;mu%lyfo|Ach>cl)<-OXz;HHPDy}Ut`pLdUt}BJ_Fx6>&+;ml5W=^k7 zkOtTL{eEO$rtGVKwWVe~0*MlV?A8sP5n- z%J|aQl3U0g|UK5%6u!Wk&qO70m=aKRgnJ* zaUiKsL8Z(~6p{#%V1}9U+dNIeJ;~`&$DH8&G!~rpWLwnZ)LKQYp=3F7Ikie|@VP1F zQ97cJ$3XInl!D0j??>yzb^gbcl2j|Urme-@;gVec6Ep2~*l~VF@@UeYH6b%=RyRdN zn~~wg1L35yf25#l-1l$``R)mYsm|W-T8t%&4@AS_g$Z)xo9oe9eT|QqxHRhLL|?=< z$+u3FBc0Uh`i#FYaZak^4(U6QO(c05X~(3>k?*ZTEB-TnPim1qu7etPUgs^T8R1vr zpz*s@)7r;~`2{KoW%Fau@}UFfMs<)8Tr|B}^N47+Y0cxJ*{LLk;yIWVXEWCZp9Qp7~`mxeM?msPszv6!hnBzy$ImrBf2*ial; zzarLV(nlG7RH7ER0sJ1~ANhtkE&rSyvzDFGrUZ3c6se$rt$5DaE>I8_zV~ZnhMwSuWO!I5PL8T-2pRQ3aEU%q=Gi3i`rB$FC8#bpK%8p&z3U3sE<~D|Q&I)kcY$!^l zO=wVu3L0{Q+6Z7AY@stAwL(Y#{u(PY92gdzsO>;|0PXYPl(+gP%|0}gC77K8-&WZ4 zpov`wTL&7CqaoKHF#Fs@fI(|XSoYy8?IQyo@RTo&H|1@ms#0gK$e^2`y1?oq^!Jhp zTs+k5MF(1%HSkTPm=sqjW|W*Dr&i?jvwL7W_wRl;YDXPVogEvyws({wFfUZ)x}Ru! zNnox263m7nQ*au`(E_pwi|5JWTmM7F2(DeOQ-iXDw)*KfvQjbFS(TB*HFQa`8xHQ0 zQQwBMT6JNGQY{8AFX|0OK6KMf!m_yF(qf$Ep?c2w8ta1&8s4}pbqy6Hjaaw}ZQ)dx zc5%nl4Na#IkQO^`J%Ou>%JLhvQ!q+xy<|7iTEQ(NHY0mV)r(D;oG+pJdW{gj^LAMUU<0^59D9}~- zRi2w^*Uio6uFUDuL;M$+i?I!sAtUJER4&Hy;mldwW62Mn3w3_hk`~@d#GfsBiGRR0 zsV65}%+Zj)vp2i*1Q%1jqBU*T;^&a*v|Kar1 z$>hyW-Ym)`><^`&Y^C)`NWqnYOa8>;3&=o1lnwJ-f!*K&|9rY7O@=8tC1}Yh*3Y## ztOZvn3aet^^Ru#azrVqIvc~eqvL>e=!3K#OqIztG{TJ0DRf`R->SAk^y`(vL{E7Gc z{)0Zl!F@u(QYV|~ra)HWvW*FOu(DMx6q>I(d7=_`gU`sGtQ)+p>QrPWMbf=Q`QSSL zAUjoR;}JPo+@3Q_SDC|Wa%A3@GgtR(#$$6Q>z=yCt+}T3`<5gA*1yndAF42%!)B(A zpzg^YT6M}@*Z4!ZQ*@SV{HM8DQMfx%Wns&X&YKx|mjenTZ}QvoW<}YF{=aYf{XA#- z1n$er(-nQjKgnB|I{2yIkBBV@xE!OmJTjRI$XX}smDfJy4y%cKt*N>^KmRYQRa(b~ zt&^nr+%O}3bnq6g&Fj}+@C`HW=L0hm3;lB#qa-@Jf)1+iRG;^jqq=DR*V}r(pgE3$WVH&Q}aL%s7=18PWL;v%iDd99S z=T>b=RbVUDvnn+^me|*6DZ_?( z84Bo`eR)9jKpp*;=Jgor^Qh-0=n&tg?JI@@$=~MUp{*9#?OuT3so2bvF4O)Iw;PXx zpi~~rTh#5*GU$FD`Bx=HJ?P>#+$8&XQ1mv5?$ktLI8pO@_RiLf52W=Bj6zHne~-NB zlDbbC&c;UXe`i5VPtf0fpN=YNkS;2kzrT}F_ZG4W;Z0^&2(yNsf!Oag+w;z-m>!bs z@6rALJcg+re-A&J$6=zLybx?(qodgHbQc&}6k(w#4E0CA4&_@s`@*7KgcsQ}Fh;%a z$lEVrW5qTkM&0vHY)nr;f`Q#ELEr%ioRyi~fle_!Fm2sOx3vCvwmXR^|J(8Gk$8k= z&0#EFn@=s!a2go}mrW5n<+?ldhI3_R^VUNN#n8xBXE%GWg$^oJOH>op>;8-7q0^2> zXC%09s(LF1t=8vvtN!)>Mb#htcGV+^L(w!YHBPscNG(Dv6jYYB3WAHz-;1S@ZKy90 zwQi+B+YRT!i?QDxNc|31-DLwy7ee2^@JMW`Ee$tQ zM{wDogG!Y&i~KlQ+>1y6UmCAxWE76=I3L=931zh}$yoEC6g0>B z8QZ%{n0_1nAKOT_!$P)W$@ai^Y*R3r`LDc29TM-A`k4O0y_r4n2$q(<>i6gShAcdO>3BXoFD9-BPu88ZPU(dvZ!AlX9!qAyz>Rat zZF{7*xc9ahx_iIoch8^7UzwlHpDxn#oT59VZeCqEH9T1!=nZUvT?^Y{|!ew;-86u|SsAgIZv?9jAu!^DEkjDlYJ6$|i=BYkC6Z zPIDa3DNY@G6xSHKw&56}ABvLiEY6L({66?o=^*c4xTcI26B)r1TaASo4o;>8f@^sjT+&5q4BA+(C7Mzx?)G(|XM+YP zDMLsz#e(y951y{QDW1*@fF`*^33=*Z-f47s)E54 zRA>7x)`oumcQLS5*vzPpSI-qe;|80SaY2GYYLP6qvC+1RnHc@XmM)-brHcVFckdeX1F(x&| z)o~PpMM?dXU%vAWUBYKPWr;cFDLiln+?-fatXrt?kCv3geDy)Fkomn!CrVp*&C;~Q z#cCSqy&t`6X`KZxIv+o^w9um7#l-ttipVi1;)N6mkMf<;;1}pctV0n;Q@Evcg>KAO zd{60vx~6~dk4y0&bJwP|hbiEzzo9ItgFu{kN#Coa{}n7uvvsJ2>IAPrXm~#)?Qt)v zcjsl4M(ysba8#YvtdCoR3#l^sb)LO!LgXsaH@(7_Et|}}%O<(wg;n*r&%~-C2CpMT z%vZ}lQjWAHxT6bf>GUCYrwhR^QfR zd)>1D@l zPr-eG-mq$+B}NIJCrS-vrD!e%4u-OFa_l6*9|w%Cq@Wa@C_kYcwUYp4K%BDmmQ)boOJ9gECaW9~y?L;w@ZmUuP zhWa9sJ65epo*5M5H5iGn;WY)mdFZ%(MY3LFo%X9PD*YiB+IJ!(dB^H>UD`kR)2j=k zl4(;@{oYn?$q6**3GQ33U^JVDAP+v`mGJbn7U@fvAIAq)PnkAIUrNZ*Kj}OzV4Rn( z$<{T~(6x?-0z>~N9e)sz^Hb%ix=Qkx$Op= zAEV<}(0CR2A&i^sV(M>@lwT0Nex zS~ErWe2Do=mAUwy{HTA`I^*!{EKiY;jJ1hfzI&3TV!VyeQm^LLu5d7hrVg3$miJGw z*qf@7ZheE?12$zpPz%%V%P!d(G=mjHuU4+(*zS~sp$EU;&{|9ZlslNvGceMID*4VZD;g2Qv^ABTt z!QV>)4+#9F!10f0@@#>TqNa`LJU^PBvqaEf6^JrQ~HuzXL>R0h0 zyrRILTW!#%a`m&hdFL*b4MjVM+->wx+&q(b>W6mX?bbe&-v=F2ux)<$!5vjQ@nu4F zPC;mT=0_iWbo0gs!0&trfQN$I8m+(fp&$Npw`dId;-5eUHK%xkhm8R|8in9tD`(6J zo;}3FPRbZ%r8C5vMLgzV%=a(otC?rM4;d>5FLz^QC5hF4QILmch+LP@z)L_U__@0) zcW*LVXONB)Jp32n<#+Y&PL*cqC8l49clq%Wi{A*0chcd6sU6@S6>Y+roR6)Vo;X%w zV@Y*_j!lr}i7tF@RTjTqW$fBgH6$&;&f+KE=c}Oyj1X0*Mf(V#6JSbX%nEPE2@mscYMvNF`3n5qPF3VOoSyQ)|F-T9hOemFap$gWRmHn1x2>$&y=~V6 ztcI0t-hIcGs*)W$RAz4(t zd-s-IRgNvljpJvV^wK9k-s9@>>}ilvH&$=kv3aiP;TgFF*`|^$n@lrorhIFDVYaDe zR$*7pV?HVApGo<3_X=IXw63UqNs>%PGAgrG*tnr`3tA{)mO=c=?b}=~48gQzr>p7* zrkxLNuHLaF+jNr}+f}uB$BtY;*AE__tut6Q?A|%6aLcA?CN;PG%z^QV8I@HJns#p6 zxnT$X=|_5o%Vf#eHjTe|U}ju^sp-ZYG)D_9FuLX)TqVUB-&X64SqS6bvlK*_R)NAM zQ6R&9R6QY8hY&dhcHN@t45=Ovq6UGzx2QG*RpUB^$VXTk ze7|5Rg0(}6eNPO8u%=`ZENhUJVHYfiz)pb!!@em)H9}M?aKkOCH)Y5xM4bZn2HG@% zFg+X`OU8f@4GXNls;LYJRnuB6d`yu^h^zwJ1#S?keL<@;%Y~>y;J|Q(*J;)R?V5mm zyQC&*kuVC`?(aJOT)M8dgE zV28kg*oW`aRFN5%5P1Zyy+t)NHR+8))G2W9t*Tv3KblSdO3sv_2+@eZ#`m>=O!sQo z7YrcIB1Cq=YO$r43zkdZT7d)MTZ4`gJB6rE;9q6&e7$q*{{O6eXUY81FzV2_wLS1|J#{X#S>@QA$bcYaC2wW?$PpCEo14wNXqF#Xmj+v+}3`Y?n{fAlr7J==g z0{u?SnzKILBqT0@8wK_V%|2DL%lUAl)Yb5pPh#Ch#_j?bcjI{+I1-=#6kL^!z!v}v z{665cG1#)eHvumOjDU6k4*@K@Ap`El_1OyAlgQYIfPUx<18*9~STAT7@PzTW6_Xv{ zX8`U2G`t`N0dz+n2EL9vcOPh$%-C8$H)tpDzX42e;068?pa;!T5YQxS5uhEw&j6B0 z2Y3Q*r5@09Q@saJ4w`PPH2^zk++5x4H8f;2=n6Z@1S6nL!0A(=2-*t#IKT;hk+llGFD4E!2THs3^dDU><&ObXb14G0eztRfL|^^R?xQ( zcqKiufOY~K-7}F!G>pJM0T@Ahfum<(p3vC{ym&UI0JH=6Q9v(fFL1bxu{P2H#LD@Y$W?ha%Tv=KNT-~w$2-V100?E!us&=1-NoFQZWhtaUgaI_TZ z2kittUy8XTCE$O*3mCK)IQed50<;PEB)|c>6L^{fjzC+1mn}zzKs$hoSD?0t2Hw9C z=?C2a{CF8MM0A;(vFFfWRd53Q0YDELw`4Yc6-ELY7jae!NCJ&JFna`G0*%WuYXVq6 z;Zrb8dq0#1mJL^fvYOJ3@8VUn<KqqLNYV2V^H)xzq>=eKU8b=xX3!oP?4kY$9pbs>T6E*|T4;rTs z+W{B=jkAM22~a@es9`;TVbFcRUjas{=miA+xz$7ft40vO3juo24&XfiBWN5O>{&n( zXzbwZ2EYUwTQr*iuz<#1%pL|y02t361{y zF$L9l_Nx6^e6%!ol+z=zz0$e$F;bW0_Aq9Kzkw6V2~&IdN$1JNlYOW9PZ>|k9gdFL z4&RyHGpqp_gbwrCn(R$AO`S)(j}9NTG+Uc1n!U%{jt?A9YBjZ%w>Gpjw)M5?+l}pV zyXR!>N#DtlQ|z?uw5y}0qq9RfGkk_@Foq9v%-K}Y)PHo~s9QNYa@5gW-t264HTNFx zJKld>Ic{&2TOF;=*6uc6TW?!`o3-86-gdI{r0KNfbYq9NgI`N04Xur>18qv%NSpqI z@kF`1-P!JH_q5lx_nquNDW7(nEW zUz6pS^_aK0t+}(=*PPU1YO%D~TF7);E15N&Ad8LdBPZD@<0;qan$w=swWk|SD;>if zBOUCFo-)ygS)u=3#ObZ@y1X@BkGH>RplP_tajg89^H{|(*RkH_zUKaBrPVnL uTbwQ3t-jXY*1p#MR_h7d3Hd}@duMxhyRW^s-E_)w%6iIn%66yn5cNo{uzS~|VR zGS3b&GI?@@=4rk#c^<+fG8UFFwsAHP4sjad!6G3Og@MGGY?@3mQ<`=rVnVf zOW9W@e`iL&qvAU=Dubb@7LGJ+iTE3|T7P3>Q%tJ~XpwlM7HZVW*KN=mn(6}c3ks&V zr0Adh^z*}?`^Lyobq$_)?Q45@{I#Qh4LZ2w^{;)N(~++|%xU3KLI0D-*N19@RCX*) zeJdHO`_v?M|F3S?qIgEwOl|6fOK)KHNV&zqlkYA9p^LFroD8T$jc`x6f4row{`wv6N)aWHQ_CCJZ^gS|ouv@%wz($0lKuIjs7 z?DJ!RmKZXAeh+S>GPPZ{10nv=7^|Kisq@GDj2)VSq*h$haD{PMK3$b@_;FqSCqxK!Xp09GWZgGhMQfC4VR(IhhLh9+iV#AaLshw3Sc6` zhKAcE6#XgP9*6x7Prn|w8znk*GJLT4)phw@G=b}I<>FlJCmqJA%G&(>L zuim!ZRm5T_LCk1);Zu{_!Hn2wLP>D)FoYzZp~4=t%$=o1j+Tm~Z2d~8R*l60>vor$ z#isx=?g*1k3XS4}YVwj%nLmlclB}bshc(|#N@#^ov3AiwO{#}3DR;Rkz1-#CVVNQE z5KZLg!E}577{GtTfR&wrbqZab^wZmK#{3ZH{Jd9?>l2bE) z^yoL|xuPWsY)!vpK<{{tlySE^lP{lJ-RWITwphC8W$HVRG5_t+(XPziNvS1J&mV3j zBg?I$umYvnG4?hGyk!S@jtHh;c2D+4QU$ABzHAD5&dp_6s^SgeR>6^l7J zEoz=oc&yx2jdn~WoU0950(5=RWBiura0GYg>m_|L9!iCf=1M}e+~w2XjJc}xj^|OE zMsl>a)06MJRD=>96mTV{$=FR4qbgj+!w{M#09n3dPlh5fQh;hH1uWmV7YfWFYalf| zlpNM?Mksnc;Qu@1a`>;J3WCPXTx;T^K?<7u2XZ@b>M**3G}9M)c%FebXZoA3kxX~= zKEcvapr@+sELikAIGm@-9iwRN49QUe?YNP`Azgud>T`ERM}8p+R?K;Rb;n>uXa4Wr zqJnvjvi9<#(HsT;iRV|kX0%Ut41XM>8z!os-yl<+e*q}W#|cbVZxfhCCM0i$d43Q& zq91NTYT;9rE@%66c)@%(qQZ{fN1@LALcvyq7+GDSQY6B>cPX6) zEz%}0eJ*}2<(qz%Gt0g$O7`8+D>i8D1mt z=IAIUm?^Lx4R|o_fi(n}a2Avyd>OfB7qP%ZTrTur&dE(FVWC#nSW5P*8&~Bqa?;QN zQxF^B;M@VWU`@fy_VNCIL-s#cfh<82ej;t|gdT9-XoyiD`S}d3vDl1syU~pH z-*UU*{i0#!{PMXVFBHw3k7#joqneKNjyw)Y+6)AbhE%a0N&bXK&M-@7uQ#|?_pDMg zx>$Yq_-sLDJp=Z>n1+L9(B=uoj$Uz7!VCjWh7!;f?xh1UG2ieqSfyxO0?f6T0y7Yp zCMK=I|KmqX&b=Qp%x27}b^Ky!12+ZjI1Eq)YLb%A#ivm7HL@%x4@9meU-(r1 zg5NN#aN-k^o-r2p!3Y-jbI@EY?vKBPF@)x8y!m4f&usf^(c7MNwNkOzrFzGMJZJytV%!)-F=cy!aBTfUoY)3xU5$$?$L)3nf`~!N&E*G5->1_$@ zYh_rab$Cyc)>Y*9tBk?lkWtj8iicx-9Kvu~gdajEUiiRcBuYE$OS%0N3Hw>-k-ROj>8ez03JgrAb1=Rx(TP>BMG|T2qk*lJlQl2Iomm38eO42FGHz6LQ1=DBO@RiuEVNLn9{~(TnXB*9(QOlXucVjy0 zKa-5H{P`Fz{Fn7Gy5R3dN8!R9ub+bp=l+|f3$;)wC8v)eK?b2a;+IiJdyT)RLGlz$ z+8Sn(-cLDbulxZVxMz^{t)%+kahb8@BG<>y`*xl(&^V0s>l~ZQ`tuxm=R>YR z8oHeY8*pH66sD9A+iWMS!cBOP7jVN1zzlE$Fr}FS7LtH}_;(XE9Ir}`HdhIlYY`AD zHID%ckL}7MEnr$#Su}ERfy3x!WRQ>akR0wKJtUhO0^igvrYO%?tg2d!s%DU`SUVOz z@K?ys)b~q&34Py}(wDDDxR6pMq|~bKbr#h=OJx^XR9j}Mwv2RvYRkk5+)Gg|)vKg> z(^Q**1yQDIx0Cobh?fRfZVD+^Lg;8n^+im}g0k)OB94r1>ZOwm8lgh33R7f-5?Rrn zKXEu)nU_OQ<_*JC#%GrFsggdcGH31Ayfor~W($B@aWU z>{LXhWdv2p;CU(eI2ZV@DIDufB{3WD&aM|qhRv$Ns;V%m!fK^B1|b;zJ4jX^$vUyi z)k^I6(88sK2RbWVEqbS1)AtaYTwztf0k>3Ojnqo~9S?~mSZBdr5WwcvFKPsbrB3dV-M?^F(qx~ZKNf}L06q*iz(uc2)W>$2nN{WAlCez+w1no66 zsc<_u&AmwBu3n0E7OxFye297aaha3^QSj0K9pMtop)Co!Tx#FmW$B38<9 z+QWmi?o9rOWNIvi=S+y|ZKW(uqu?({{6|Q9asiI#uYoEUk-Po~MF5><{N|rWN5v}i zaykmuP~=7`axE1>OW)bqeCGMb&Qs*YY12h67A@irQALXipT@|=0mbJe3Z;ZXMJM`~ zA2=?0dC`lb#lPutFlsJu>-H!~Y9UDk>QU+<9R+;G%R_YfwHc{itluzOBea4x1=uKJ z%eWFJV`wavy8PUG38@4D6&+q2SV@b+z7k2JI3Yn{B^>27wn&mc|F)3-N`UM%^V8 zq6`;Bc?KU@d~$$7RjQ@A$7g10hQ1IVlvW?qPf!i$INIdDLiSARQ?%6h`^f?!HO}a~ zHo=*xUHMLFF>YZZTJjo#T-!X#Er!73qs>hc-8>5ceiZE~e0udn<1W-z_%t2Kx|R;? z2y*_i{(P#Sv-nrFq||_M;-`EKvywUqN?*yjI&`PuMCpzMDGJ2->6N=fpJu%F2bHXz zvY}EhmGUMh4S!S}=bk5knSf@*^%Ds?@iseUb2%!tK1z!y5q!3RPIUcmhM{TM$Zb$t}9v%tovEnB{-FckgH@hdJ_bz;tzu=PTwA)Tq zkrB7Zk=J4wc|l|6kJQNHC~~9t2|9!@4vW$FHfL;lOo_bo7cmtRhE}h)m4=6gsV;Vp2(?UO;?bSfp%)pS$4QSEX@<^q+0z-aOH zpSDbXJIE^YWn;1&y%Z?qVb-OAgAp0#1Bl@K#v*e((S*78hiW*w%?a~=nG>c*+O3!D z)@|%YSurtVo^Xqa`R?60bt|Rm5|y5#30wUA&QtB&j2@CZB6`Df8mWUzc38ESiO&B>!gmwey~!aF+@l1 zGzEYV<;xOU-neLBX~Lerhbe@dkry70917{-rMVetI*VO_G}kP89b0q})~pV)qcf|* z(b;T0JJzwb()fh$)7yp|bY6D_^#jHJNGoP%qkR{G#xXoO zAfTwjtCk`Vxt0gZNxP0gEak8LDA?}!K8@{Ukmpg`JRJ`{NBwQ=5CU9iCmzR=L%EF> zY8obYu9>GpuQaN_1cP@)ISy3bCx%S&J;~`*6;?(xrIBFcN2GS!JKQy-3@haiQ4hL= zcMfjYD=c4gH`XIp6CM=h&Hc_t(5RYMd2?6r9KF_y*KMdfFBy<8RKbh@&(2bM7hNsO zihxyu3eOUS&*oQC8m5QRx|{0p6+Z2qE->pXcVJ~j3s8}+Pc#bf41z|qYwU$6`ai)J zqF8$JmeQj0xgEEX5OmKp;~6|lA|pV&ieBj2%3q8@mecq=ve0(-C3uGfSyj(rS)Jc-6oXMwv4_Biupp|MT{uwmm5ir$w|;QP`q@XakZ?t-|Q^h^#z%P65Qc(!$bs|V3hU}MtFq8446t08f%M=OAhDgOys$x<}tOnbT2QTKVB;Nl!)h7_Ypr<^~GcSUh1ge?&$Z0Ay(+~z?F2QWDeu?Z?h0|o1+0tZ!62SJu% z{2T{Bmb-Lu*h8aU<8cB96OP_iFftiuXm(DhWGoHzl27`Xd1~&e)|X( zjANb*3*)h_4@%Tq_fCj~ndiCCbyAFAy;Km53I#wWz~(49OM`!&`zFJA8m9yrd3}j>|A<4T{7L-D9l! zmN-9mpV3yc@#oVHV4p50S`I(v;ua@OMf_|W6;nbfYtA43wCbp$X05Ehh+@DM=Su|( zFdG16f-e<3243D|UCHap_%XOT5coXJ z5WJiC!9HeiI$&xW^X->(T_~2O4}bS34;9hb2hjE+c+`m-S%BC0)Br#5Emjk~u@)Wh zDiYxxFr`T>0kxBtr=62#DSkURxd%BP1k>~jlF5W+mxh(eJV)n~s4J}c6u ze019B`}OGPefJgeAPlCpu=6t*WcWt0YT|Mn%VF$#Xc>2D;e+&2oea(p9Gp#TXS|g&_I5>@ftx z`tCArR@Bot?fP(8|3t_X)<^lq7tmYj4aEik7eY`e#e(nt?;x0Wu+t1MRyLP%wmNC%u}GC*l;W$*i4HPrU_i% zO5Q3T0dbXi2fT008rqEftV+yQ!=;H-j!GJ>#Jb|2|~qqC%deqpoVM7PP50kE0JgCvf7U zrP>^RVR~DM&a3qf^KGS{t%f-s0Dl)>QjjdM{=*kq5>(Qshj44*uJ1utHON39V}B8p3`4KL2?rV?8YH*6o~g)$)_mFwLd(w*cUsja${nRh%t$4p z2*MH_-gItChgYt2__EW1Y^9@$nt&R)O~STtnvIx713yT3cPVxC4myzh0wxJ#2_DdP z4ZmUL@P_XCSH$tQ(?{_56=$`0N5O3Ku5T;WiVml2JKSn!<1fLyOqF9NPv4L&-1U$u z1}L%c#hE2He=l4x9wg`;lWFOc1rG4f0ZtVMM>ZA$ge2Zr-gM;iW{ZwUbr9$CVWbqi zayy!S>o=(BpCe7*t>+UL+v{ZxO?tEncwjYX`*(l2g#DbRd8`^+etdoF5?!Ky|{yYwSlM@mdm{JX9vXn_SBuEuBE`V71S<1o!9w zB)A~~@9fMV3GS4HI#WVEf990@2h}|!Q9yV;`;f5!Er$vvR*cE;lIm7A<* zw_b#z|Aqzw9*wqdf{nI>ZAK9vd3*xWkY(A~k)>gP(Kluf9_1s2Z~5`9X%s|7)xt^N zUj{?`H5ky8`yoN7f@2YSP<{v-s;=bil;(&R$x_1Wd&F)VQoNcR!8DA~YB}ubuv5N@ z<~DwT@8v0xJ*8dhHQ_}AI%}5fE)sW@##ip1U%pZZE)s{!B#Ay1aWmwFUk$A}f)?a8LARjOm z!rO`_(x9X_QIm&&i!HV!bW9(B zwaoCsT4GPpTqYld!gi+(7&;|kxO**#|2jj6JqGt0jD6<+WCvh2fVSwe1wXbHYI+gTiz zMZCsQ6cJ&1TkHOSMElgjuVs#KQNU6klgSIU(^c;OtTyMf``Q zI3Be4;lFXB=^efzA@vg$soL-@I6}K1xS8kq;_D}0pGGD)V0;ynKS|0wolnElEef^E zLajLp<>IfB{Pg>4nU!RZA6dzDvd}d-3R%n`SA7QUW6`J~(9HTW+b>za3fcvLGn#hL5><7CnDH$XF6E*f#>^2cQP zr^YOA_79CpkMXNN@Nt+jlXUwdzX$(MoVA&pN}u%C$zfUKF};?O!}P`X9Hz(xr1ara zWDIVDYI^{+aR*G_cAi_|H|}#W28(uHp5agT7adQFJVQ-#XLy%wd1RcD_tMkdr;C$7-L& z(kGt@AKtzkm1g$m>$$7P_*eFxX%E=vXA1fC7(zHw;x@LtbSL+VF+`1BK8HR(8$-z1 z^?{S7y$3C)>9DzqTFO_gI`tNQzd}gPKJm!`wdmh}$=ypC{8|1rS9`5YfBN|u=Uv>D zdW~1!P!pDTXl;B33CZj67D?OkFRZ``R;+|upE;q97Vk##S*H|^ce<0oM2Ta^iANmC z+mqOyQup3v)-G4uzx*v7o5=cS=dS-US%1!ToW%!A+7>&iT#M!P?8yg&k4Teg5yJy!%fBbi-FPWcyJE( z?T}GLo(1ov(GQd2n_r7wHr~^#b|uNWryP|wh0^9E zZ$QVr;iZmyFTLC+Miio=5dxaZYh zJ=O6U_sWNdy)W>jU)xe>9NIhQH3M;o#DDPVCRw5pYa)u*owSbKnil0-~2X*rkAw$BACyU{?@T z>55YN3Z!4|V3*I7`4p#gikCQ8NlgywbTB97t9ps=ep&A4p!iZ*-U>-;ER^^uo$6Eh zGiCn$pwlL>X^!P0zedH^Fvn#R*kz8(g#M2ro$6DR%3V2uUFnDleV#|0>Zt*pI)P1f zd?3|s(u>lm{f~mG__c-RI$`OwDBcE^}O8i8XT*|LO+}du6E1Xq3t^F}m%29mx z%lPx4#Ba@~`c@#FaC#I})o0bK2I*8k@m({4U8C@!bZXcAprp^Eph_PlS5eBR@+z+Q z#-fT(l~eU+##OqKlUYusXVOeQ{E*a@q@R+fDB&=k^s)3*a&yrdi6hmg>{e0I5Bc`T zM&R8*0PmO3Pdl(FyJ3r$F&XR0}l5BB4N3@LLizeYjcTXo~5hGDmJWKx^~^tb*u1IGE+Xpu2{E0 ziA|;Z)~{Z-es$&QyH{?iSXWlQY2EtrmFpQBvtD0Wm#g1K+B3>umx^a7sYIX4ltXAV@MS+@lOaoUm!0j)zrLhT)U31sP17x*kKc?fle8CO#c`a%Z z09M*&f2bZsw}xUth>yfVm|3=I{&2WHgk)Y}Agaxqr}=A|kc+y3l~&*6uR~afV^(>l zib622FBC(V zBU1Q{n;g7+VGkNPxW`H410GcA(hzsWcTGM7N;&0r7QcC=+`Zzbbrbbu?MN}C$MPBXv zSfC{)fo+VzMx?Qmr6{~2UqBR%H_kJQQqn9w z_~)YFT&)Jj6iYN}J!95-m8|hl3`jC8jHIZ)IiS@9wl&c-5DWnRmQX{yLHo;iLs*N3 z?nTw`Gukb5xBCBF{$1PL6w&;3b&)_csztGM3utbCOvB8ebQCiJcL?XlJ@ z1oI{yMj1(oWmBLf3=bitnQ@iQ;g40Q%&VVjZ`By2`Zc_Q|oVp`-7ts)j$ohuUS#4E|cR3Ak5^5 zE4(E9EE){d*DqSArXQ&;+Ams77(iU^`BET865rW`set?+Lc2y-EA3JHBt73|4Sh_MKi_hH?)?1{ z?}2gR?z3?pmkFJecpKxyz17BjT)3Z>cspMkpT9U_<329jOC;XzapLa#`1ty3T+03r zD&&!Pd&h~pX5&6CYw$_DgX6@#)y92XxVK2WyT*z8kd6DeaPO9QC&r2U5gYe$;eJx$ zJu*(*i#FNw>Ue;6{-?lAlk|LLcx~Lz7c$OYD)FuwC+@8_?&HEeEb;CdC+-Ow_i^Fg zC-EK_C+@7;_V42Xen{c{oAKf2wQ(O0?Ce^Jw|ktpkE>F<5L+zq_S(3=tJdI?cvndp z%)sC0AD{nuR~zvsSlM=obGxKn8MqhOxL=fB?Up$AN!p)*d#jE6MZtYg;yfhjNCxiJ zHtrV%_q^AI|1OeLlT=mKW#g`(xS-S{arS25eL*X+g=Ha7CGig0xMyK=F%w!P-d#5C z7Zc_z+1(QFBR1|?*j&tngv5JL(xD9e?S0e5LI1SG+4)>Haeqg6tHLc3&-M)5RlZFx4g%d0?|w-KGw@GrPWLw#M~go{sUr&KHwC^{*ZjrQ0(j#@k{=014FADB`66b`Z7o`$gXcht| zCEg>FI!|ZJqZ#|BECF`HxDfD2oPCmpGjP{z+{cCM*$VBEIQM1X9k$QI&Ia8(%I}wW z4`kpzWaIvha6Mb$A&K`$2JYQ9?q`GUo#nqJ=FuWal`yR~V}4Z`HoYJSXcBLaq+Ut8 zB<^0hj=vz4*+NVNswB=qNn0iLDSNkZH?g{qfjtuEK1ur}9hA7Y+PGgxxJ_Au5@$nF zl`&-Ft)RF#^mk(ZERnQSQY|3Tz4pH8qTpU7aSlt`BB`p(J_lAvTv*yJaqgD1UsC%# z^1|YrDQ!^VY)I<-z3?y9($7@eekK#L3leuroOMZ+&?6Fe6}RbyMIb2gZkM!A(h-S! zt8MQW7H}zTP~j|T$=h-rBcC&M+qhp8+-;%%H3*2`YnMNHjNh79TJWE77s)({_{2|~ zZ{l2LR2HCos}wV8$&UoYFDsJ( zqzcKG_~2K-w=@RoM4_x?i{1(kYXR_QB#QzhU-6kgQLP#amK@oz&yg3?(L5#&PEP7^SqYd0VM0>$!MlEJY?X*Vmd(Wa!N*__) zs=xZz7qTyrn{Hp+?j(~mHmWDf&Xgf4c_hnhofORVuxLnnm^||TXRN;uj_fQu75Rc$ z^|^uu{FzC-=FHSF`DAa4UpMDCm^kzH$iA}VTUx{0D+aM-Ks~ApgdVAcw13+XgIh^G zEB>k9ONTs#d#bdsGi$o4EQPh;PRBnbAv;}2kl34yoGs8)g8SX$7;P_;eF+l-~DNhbQ)XPIujsl9;I1fvbc-cs)GMtvH8Rao^0)ZY z_+=VZk)1B>K-DU}lo}*ixWOxOIT`#4KJaJYCJLn0YkER4v{J3G;Aiq!KtRP7d~$N+ zt|tpF;2`R*tJy-$5x7{=%vMMSE?2co6{2!dv`XT9mNe1nDp%IS4MC)-F|9awdHEj- zl$H@!=9BWno1`27lkx>hnygRR81YI8a!i|yydE*md0KkhtTtue7OYJClucOjOuNj$ zj>}j48F^XqEcr?kQ?3O|DhC+OJl-sA%&O;n#)%bE2+C-W#R907GvurOP*|jmKiRpN z<#X_uc$lLihka+%VSzPW|7;lw_Ei6yJn2nM!(j}bEIe}XnH3VV{jm|S5wH=k5wH=k z5wH=k5wH=k5wH=k5wH=k5wH=k5wH=k5wH=k5%_P1K-XoA{RG$CHpaY{GxjvDJcNfp zKXV0R*CLz%Eu7BSG=x2%cjB6ka5d=fag|egF=MCS!&n8vz7occ;(Gml$N}AO6=T0Z zI1GBt)r|cZVISysaJ`N229W2X@A27L?HD+m|8m$ARVwT$WoJ&MbP z@E~aMOvWlnhwB*Ifon0sU7%B4j6H&|7xXW2#Sm@<-Ggf*!rh?%fvXPTqFIc699KQ@ zfJWvp_7K7&a~WGPkFo6tSA!nFwF}_{=tKBJMy zx4~1i0QxRu>?;Vjf?l~8?WHj2!4EL@EW+%Aj4j2r7-fB+|AecD(r;qyzEbcZJOn!X zW?+l37xYWGP9Z!9`mH7CN0cpEioU}&9pMCMcp3T;;cigZa$F=I^eC<$lT6U!TY)pe zVbIbt^cTWMK&P)@>^Q<6Q1@+UFUp2NkK?LGcnEY&IWVMj(A6t}6~e8cui)B<@CfMf zRp=vx+3k!4aXo@?7wAMC{erLu^t~0p7GZ4-V;{ry5W->59$d!}PJqr@3!M@6g1-L_ zV2JP#=!Z5yXM~S{{#7NgLU<5#^<5}W>7YwL4Esd58uW*_mLbfl7<=DG&@TvwLH&2b zo)PW_J^4}e3&Ng_!1QBi55o9gU>3o33SsPw>RQ3a0ZzGKVY-ZCw4jXs? zZ2`R<*EEFjU!Uv~xTYhF|3PGr;<^@L{6`#n8J7!T{7)a7unGN$F#f}g-Gpl~!uVe; zR*!2L!uYQz_C;Lf2;={U*eP5U2(xO&7T~HRe$Y?g+DQDMdvMhu+zt9Xu6l$ALEpv| zLm2PpvlY0uBisdg0@p5t@q2XaG_D5`W;Kk>#Ptxu_VSKNVEywjN!uZY?+llKq!uZ}DdluJA2;)0R>=dq75N35~3$7m{ z>;q9BfBwNTwIJVDVVa%AB_eYYU;OX5YQN1K06+1ToSDf1{(a) zc@3f3NK>?Fb8KF1Q^OK}v|)bpg4tSwzcI8q5LF{s)CN(Swk#HjM`NoSH#bRXGtVMz z(M(8ej z_D5GYHaFc9h|JdFp|aXqjQ!=aH~Z_Of!W%PrkrIrj$O;L8`E@JcB9!i6km3u!VM9# z7wmwIfQFe%0*;jO+cEjF`k!zg@*L_u+;5O0A7lHS`-}FM><{<0^tSf4_jdIfeItGB@uJ5|9#pwZ-<#Mwu=nI%&%V-q-hKK$-@d+{ zBR$%F_kPcQ@BTf#-MxLi{kJ=Aq*`CX7MNhIJp?k19 z+}+aM+TGqgwAa`>viI~}_Gs0<>V4sTgFPpEhI)*iksf`&Z-3SP;QmDKK<{Ah$=;#f z(#O4z>yP^$uX_B*f&K#n2iyle2TKon59$ZI5A_{7a;X1M;t=q$KQ;pAh`|2`F9nxD diff --git a/bin/mimalloc-redirect.lib b/bin/mimalloc-redirect.lib index 7d5f19cee2052225b3f95447945c4b937371c055..851455a50a661f904b6a977f203e77a6e04d9958 100644 GIT binary patch delta 100 zcmdlbwo7b-1Pe>dy|ZU0%dqTV(PC(Bo1Dd=Joz_^15?saGKI(E2rZK&ktjU1g!01|H^egFUf delta 100 zcmdlbwo7b-1Pe<;VeF5|GAuh-G#R{GCueaePyWr~z~tS!*_Kt8k!2#E^XtiZY!eW& kog6$s*~zx7Qj>kzV_7x@#9p7gjvcOD8!EYZBS$9_0B67-?*IS* diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index 17c0555027cd73317e893549e9831235c35d4d83..1bb909e199e55ff9212e913471866c86e0a9bf59 100644 GIT binary patch delta 11168 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 b&O-=^=4o>X8V?k|RypZ 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 diff --git a/bin/mimalloc-redirect32.lib b/bin/mimalloc-redirect32.lib index a7100afcbe011e36358bedf663a5e77a7bdae736..45d7297d8ebd45aee3b18c8a0bc71a691ec862d7 100644 GIT binary patch delta 118 zcmew$_Caie84C-q{=@^5typ%kXfZUmP1a&ppDfR6$JE@mIiA&!kuzxNw&zC~7#Nr) z+p|bd-ojP{Q>G78GC7`AYH}%iENAa+`AZL>s>~(}a@50ANl#wS!2wmd`7*~`CIFm& BByj)$ delta 118 zcmew$_Caie84JryC+YK(typ%kXfk-WPS#>qpDfR6$K>6*IiA&!k<&tj_194b1_q|d z_AJtqx3Cq#l<5PNOpa%jnq0~r%Xuc!`Nc!1DznLg9Q80&(v#P7a6naVzRWR~2>=MW BA`Som diff --git a/ide/vs2022/mimalloc-override-test.vcxproj b/ide/vs2022/mimalloc-override-test.vcxproj index ff5d53d0..97803b9c 100644 --- a/ide/vs2022/mimalloc-override-test.vcxproj +++ b/ide/vs2022/mimalloc-override-test.vcxproj @@ -5,6 +5,10 @@ Debug ARM64 + + Debug + ARM64EC + Debug Win32 @@ -13,6 +17,10 @@ Release ARM64 + + Release + ARM64EC + Release Win32 @@ -55,6 +63,11 @@ true v143 + + Application + true + v143 + Application false @@ -67,6 +80,12 @@ v143 true + + Application + false + v143 + true + @@ -84,12 +103,18 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -107,6 +132,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -115,6 +144,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -185,6 +218,30 @@ + + + Level3 + Disabled + true + true + ..\..\include + MultiThreadedDebugDLL + Sync + Default + false + + + Console + + + kernel32.lib;%(AdditionalDependencies) + + + + + + + Level3 @@ -258,6 +315,31 @@ + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + MultiThreadedDLL + + + true + true + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index 16a48740..9de18895 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -5,6 +5,10 @@ Debug ARM64 + + Debug + ARM64EC + Debug Win32 @@ -13,6 +17,10 @@ Release ARM64 + + Release + ARM64EC + Release Win32 @@ -54,6 +62,11 @@ true v143 + + DynamicLibrary + true + v143 + DynamicLibrary false @@ -64,6 +77,11 @@ false v143 + + DynamicLibrary + false + v143 + @@ -81,12 +99,18 @@ + + + + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -112,6 +136,12 @@ .dll mimalloc-override + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc-override + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -124,6 +154,12 @@ .dll mimalloc-override + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .dll + mimalloc-override + Level3 @@ -208,6 +244,34 @@ copy mimalloc-redirect-arm64.dll to the output directory + + + Level3 + Disabled + true + true + ../../include + MI_DEBUG=4;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); + MultiThreadedDebugDLL + false + CompileAsCpp + + + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64ec.lib;%(AdditionalDependencies) + + + + + Default + false + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64ec.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64ec.dll to the output directory + + Level3 @@ -305,6 +369,39 @@ copy mimalloc-redirect-arm64.dll to the output directory + + + Level3 + MaxSpeed + true + true + true + ../../include + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + MultiThreadedDLL + CompileAsCpp + false + CPUExtensionRequirementsARMv81 + + + true + true + $(ProjectDir)\..\..\bin\mimalloc-redirect-arm64ec.lib;%(AdditionalDependencies) + + + Default + false + + + COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64ec.dll" "$(OutputPath)" + + + copy mimalloc-redirect-arm64ec.dll to the output directory + + @@ -324,16 +421,20 @@ false false false + false false false + false true true true true + true true true + true @@ -342,8 +443,10 @@ true true true + true true true + true @@ -356,8 +459,10 @@ true true true + true true true + true @@ -366,8 +471,10 @@ true true true + true true true + true diff --git a/ide/vs2022/mimalloc-test-api.vcxproj b/ide/vs2022/mimalloc-test-api.vcxproj index babe7f96..27247569 100644 --- a/ide/vs2022/mimalloc-test-api.vcxproj +++ b/ide/vs2022/mimalloc-test-api.vcxproj @@ -5,6 +5,10 @@ Debug ARM64 + + Debug + ARM64EC + Debug Win32 @@ -13,6 +17,10 @@ Release ARM64 + + Release + ARM64EC + Release Win32 @@ -55,6 +63,11 @@ true v143 + + Application + true + v143 + Application false @@ -67,6 +80,12 @@ v143 true + + Application + false + v143 + true + @@ -84,12 +103,18 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -107,6 +132,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -115,6 +144,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -151,6 +184,18 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + Level3 @@ -202,18 +247,38 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + + + true + true + Console + + true true true true + true true true + true false false + false diff --git a/ide/vs2022/mimalloc-test-stress.vcxproj b/ide/vs2022/mimalloc-test-stress.vcxproj index c033aaeb..fd88cd8e 100644 --- a/ide/vs2022/mimalloc-test-stress.vcxproj +++ b/ide/vs2022/mimalloc-test-stress.vcxproj @@ -5,6 +5,10 @@ Debug ARM64 + + Debug + ARM64EC + Debug Win32 @@ -13,6 +17,10 @@ Release ARM64 + + Release + ARM64EC + Release Win32 @@ -55,6 +63,11 @@ true v143 + + Application + true + v143 + Application false @@ -67,6 +80,12 @@ v143 true + + Application + false + v143 + true + @@ -84,12 +103,18 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -107,6 +132,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -115,6 +144,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -151,6 +184,18 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + + + Console + + Level3 @@ -203,14 +248,34 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + %(PreprocessorDefinitions);NDEBUG + CPUExtensionRequirementsARMv81 + + + true + true + Console + + false false false + false false false false + false diff --git a/ide/vs2022/mimalloc-test.vcxproj b/ide/vs2022/mimalloc-test.vcxproj index bfd72287..fc9e9102 100644 --- a/ide/vs2022/mimalloc-test.vcxproj +++ b/ide/vs2022/mimalloc-test.vcxproj @@ -5,6 +5,10 @@ Debug ARM64 + + Debug + ARM64EC + Debug Win32 @@ -13,6 +17,10 @@ Release ARM64 + + Release + ARM64EC + Release Win32 @@ -55,6 +63,11 @@ true v143 + + Application + true + v143 + Application false @@ -67,6 +80,12 @@ v143 true + + Application + false + v143 + true + @@ -84,12 +103,18 @@ + + + + + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -107,6 +132,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -115,6 +144,10 @@ $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + Level3 @@ -154,6 +187,19 @@ Console + + + Level3 + Disabled + true + true + ..\..\include + stdcpp17 + + + Console + + Level3 @@ -208,6 +254,24 @@ Console + + + Level3 + MaxSpeed + true + true + true + true + ..\..\include + _MBCS;%(PreprocessorDefinitions);NDEBUG + stdcpp17 + + + true + true + Console + + {abb5eae7-b3e6-432e-b636-333449892ea6} diff --git a/ide/vs2022/mimalloc.sln b/ide/vs2022/mimalloc.sln index e4a6538b..5a55c98b 100644 --- a/ide/vs2022/mimalloc.sln +++ b/ide/vs2022/mimalloc.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.12.35527.113 d17.12 +VisualStudioVersion = 17.12.35527.113 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" EndProject @@ -18,81 +18,107 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 + Debug|ARM64EC = Debug|ARM64EC Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|ARM64 = Release|ARM64 + Release|ARM64EC = Release|ARM64EC Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64.ActiveCfg = Debug|ARM64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64.Build.0 = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64.ActiveCfg = Release|ARM64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64.Build.0 = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|ARM64EC.Build.0 = Release|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.Build.0 = Release|ARM64EC {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64.ActiveCfg = Debug|ARM64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64.Build.0 = Debug|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64.ActiveCfg = Release|ARM64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64.Build.0 = Release|ARM64 + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|ARM64EC.Build.0 = Release|ARM64EC {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64.ActiveCfg = Release|ARM64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|ARM64EC.Build.0 = Release|ARM64EC {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.Build.0 = Release|ARM64EC {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64.Build.0 = Debug|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.ActiveCfg = Release|ARM64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64.Build.0 = Release|ARM64 + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|ARM64EC.Build.0 = Release|ARM64EC {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index fb13cd1f..34a9317a 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -5,6 +5,10 @@ Debug ARM64 + + Debug + ARM64EC + Debug Win32 @@ -13,6 +17,10 @@ Release ARM64 + + Release + ARM64EC + Release Win32 @@ -55,6 +63,11 @@ true v143 + + StaticLibrary + true + v143 + StaticLibrary false @@ -67,6 +80,12 @@ v143 true + + StaticLibrary + false + v143 + true + @@ -84,12 +103,18 @@ + + + + + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ @@ -115,6 +140,12 @@ .lib mimalloc-static + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc-static + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -127,6 +158,12 @@ .lib mimalloc-static + + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ + $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + .lib + mimalloc-static + Level4 @@ -200,6 +237,33 @@ + + + Level4 + Disabled + true + Default + ../../include + MI_DEBUG=3;MI_GUARDED=0;%(PreprocessorDefinitions); + CompileAsCpp + false + stdcpp20 + + + + + + + + + + + + + + + + Level4 @@ -298,22 +362,62 @@ + + + Level4 + MaxSpeed + true + Default + ../../include + %(PreprocessorDefinitions);NDEBUG + AssemblyAndSourceCode + $(IntDir) + false + false + Default + CompileAsCpp + true + stdcpp20 + CPUExtensionRequirementsARMv81 + Sync + + + true + true + + + + + + + + + + + + + + false false false + false false false false + false true true true true + true true true + true @@ -322,21 +426,26 @@ true true true + true true true + true false false + false true true + true true true true true + true @@ -347,8 +456,10 @@ true true true + true true true + true @@ -356,8 +467,10 @@ true true true + true true true + true diff --git a/test/main-override.cpp b/test/main-override.cpp index 3d56ae42..e7499f2a 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -47,6 +47,9 @@ int main() { mi_stats_reset(); // ignore earlier allocations various_tests(); test_mixed1(); + const char* ptr = ::_Getdays(); + free((void*)ptr); + //test_std_string(); //test_thread_local(); // heap_thread_free_huge(); From 130227e39909d9ba078b84406fff3ea48caa887f Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 19 Dec 2024 11:10:17 -0800 Subject: [PATCH 165/305] update redirection modules to v1.3 --- bin/mimalloc-redirect-arm64.dll | Bin 55296 -> 55296 bytes bin/mimalloc-redirect-arm64ec.dll | Bin 100864 -> 96768 bytes bin/mimalloc-redirect-arm64ec.lib | Bin 3308 -> 3308 bytes bin/mimalloc-redirect.dll | Bin 54272 -> 53760 bytes bin/mimalloc-redirect32.dll | Bin 35840 -> 35328 bytes bin/readme.md | 55 ++++++++++++++++++++++-------- 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/bin/mimalloc-redirect-arm64.dll b/bin/mimalloc-redirect-arm64.dll index 98268796c03f790362d628c25ab684a96a6b4fd4..455f8394df8e935ddda80feb9acac3fbe2c9615e 100644 GIT binary patch delta 3442 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 delta 13100 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 diff --git a/bin/mimalloc-redirect-arm64ec.lib b/bin/mimalloc-redirect-arm64ec.lib index 1c7c368fc6ae255df671dd2ca96ae9e66ef76659..eb724d7405ec7783206578377aab5158d39c11b8 100644 GIT binary patch delta 64 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 U!}>1mpgxv%c{BC1=F5-$A16z~0ssI2 delta 7230 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 LP+-89B%k~*LBs2s delta 5732 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 diff --git a/bin/readme.md b/bin/readme.md index d133eea2..259d74d6 100644 --- a/bin/readme.md +++ b/bin/readme.md @@ -5,24 +5,26 @@ is robust and has the particular advantage to be able to redirect all malloc/fre the (dynamic) C runtime allocator, including those from other DLL's or libraries. As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. -There are four requirements to make the overriding work robustly: +There are four requirements to make the overriding work well: 1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -2. Link your program explicitly with `mimalloc-override.dll` library. - To ensure the `mimalloc-override.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, or - use `#pragma comment(linker, "/include:mi_version")` in some source file). - See the `mimalloc-override-test` project for an example on how to use this. +2. Link your program explicitly with the `mimalloc-override.lib` export library for + the `mimalloc-override.dll` -- which contains all mimalloc functionality. + To ensure the `mimalloc-override.dll` is actually 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, or + use `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-override-test` project for an example on how to use this. -3. The `mimalloc-redirect.dll` (x64) (or `mimalloc-redirect32.dll` (x86), or `mimalloc-redirect-arm64.dll` (arm64)) must be put - in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). - The redirection DLL ensures that all calls to the C runtime malloc API get redirected to - mimalloc functions (which reside in `mimalloc-override.dll`). +3. The `mimalloc-redirect.dll` must be put in the same folder as the main + `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). + The redirection DLL ensures that all calls to the C runtime malloc API get + redirected to mimalloc functions (which reside in `mimalloc-override.dll`). 4. Ensure the `mimalloc-override.dll` comes as early as possible in the import list of the final executable (so it can intercept all potential allocations). + You can use `minject -l ` to check this if needed. For best performance on Windows with C++, it is also recommended to also override the `new`/`delete` operations (by including @@ -32,17 +34,39 @@ 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. -## Minject +### Other Platforms + +You always link with `mimalloc-override.dll` but for different platforms you may +need a specific `mimalloc-redirect.dll`: + +- __x64__: `mimalloc-redirect.dll`. +- __x86__: `mimalloc-redirect32.dll`. Use for older 32-bit Windows programs. +- __arm64__: `mimalloc-redirect-arm64.dll`. Use for native Windows arm64 programs. +- __arm64ec__: `mimalloc-redirect-arm64ec.dll`. The [arm64ec] ABI is "emulation compatible" + mode on Windows arm64. Unfortunately we cannot run x64 code emulated on Windows arm64 with + the x64 mimalloc override directly (since the C runtime always uses `arm64ec`). Instead: + 1. Build the program as normal for x64 and link as normal with the x64 + `mimalloc-override.lib` export library. + 2. Now separately build `mimalloc-override.dll` in `arm64ec` mode and _overwrite_ your + previous (x64) `mimalloc-override.dll` -- the loader can handle the mix of arm64ec + and x64 code. Now use `mimalloc-redirect-arm64ec.dll` in this case to match your + arm64ec `mimalloc-override.dll`. The main program stays as is and can be fully x64 + or contain more arm64ec modules. At runtime, the arm64ec `mimalloc-override.dll` will + run with native arm64 instructions while the rest of the program runs emulated x64. + +[arm64ec]: https://learn.microsoft.com/en-us/windows/arm/arm64ec + + +### Minject We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we cannot always -ensure the the DLL comes first in the import table of the final executable. +ensure that the DLL comes first in the import table of the final executable. In many cases though we can 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). The `minject` program can also do this from the command line -(or `minject32` for 32-bit PE files, or `minject-arm64` on arm64 Windows). Use `minject --help` for options: ``` @@ -72,3 +96,6 @@ examples: > minject --list myprogram.exe > minject --force --inplace myprogram.exe ``` + +For x86 32-bit binaries, use `minject32`, and for arm64 binaries use `minject-arm64`. + From 0c6235e1297844623af4d74b91ea56a917b089c6 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 19 Dec 2024 11:37:42 -0800 Subject: [PATCH 166/305] add _base test for redirection --- test/main-override.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index e7499f2a..c4300420 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -47,9 +47,7 @@ int main() { mi_stats_reset(); // ignore earlier allocations various_tests(); test_mixed1(); - const char* ptr = ::_Getdays(); - free((void*)ptr); - + //test_std_string(); //test_thread_local(); // heap_thread_free_huge(); @@ -110,6 +108,9 @@ static void various_tests() { t = new (tbuf) Test(42); t->~Test(); delete[] tbuf; + + const char* ptr = ::_Getdays(); // test _base overrid + free((void*)ptr); } class Static { From 2876b8c0c54de004fb87ecf7624781d8090acef3 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 19 Dec 2024 11:42:38 -0800 Subject: [PATCH 167/305] update redirection readme --- bin/readme.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/bin/readme.md b/bin/readme.md index 259d74d6..d6c3775f 100644 --- a/bin/readme.md +++ b/bin/readme.md @@ -1,9 +1,9 @@ # Windows Override Dynamically overriding on mimalloc 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. -As it intercepts all allocation calls on a low level, it can be used reliably +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. As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. There are four requirements to make the overriding work well: @@ -11,8 +11,8 @@ There are four requirements to make the overriding work well: 2. Link your program explicitly with the `mimalloc-override.lib` export library for the `mimalloc-override.dll` -- which contains all mimalloc functionality. - To ensure the `mimalloc-override.dll` is actually loaded at run-time it is easiest to insert some - call to the mimalloc API in the `main` function, like `mi_version()` + To ensure the `mimalloc-override.dll` is actually 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, or use `#pragma comment(linker, "/include:mi_version")` in some source file). See the `mimalloc-override-test` project for an example on how to use this. @@ -32,7 +32,8 @@ is also recommended to also override the `new`/`delete` operations (by including 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. +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully +redirected. ### Other Platforms @@ -49,7 +50,7 @@ need a specific `mimalloc-redirect.dll`: `mimalloc-override.lib` export library. 2. Now separately build `mimalloc-override.dll` in `arm64ec` mode and _overwrite_ your previous (x64) `mimalloc-override.dll` -- the loader can handle the mix of arm64ec - and x64 code. Now use `mimalloc-redirect-arm64ec.dll` in this case to match your + and x64 code. Now use `mimalloc-redirect-arm64ec.dll` to match your new arm64ec `mimalloc-override.dll`. The main program stays as is and can be fully x64 or contain more arm64ec modules. At runtime, the arm64ec `mimalloc-override.dll` will run with native arm64 instructions while the rest of the program runs emulated x64. @@ -59,12 +60,12 @@ need a specific `mimalloc-redirect.dll`: ### Minject -We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we cannot always -ensure that the DLL comes first in the import table of the final executable. +We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we +cannot always ensure that the DLL comes first in the import table of the final executable. In many cases though we can 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). +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 +directory) Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388). The `minject` program can also do this from the command line Use `minject --help` for options: From b51c0974d357cda597ab3a242f5723ab516f5503 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 19 Dec 2024 14:00:54 -0800 Subject: [PATCH 168/305] fix cmake for visual studio on arm64 --- CMakeLists.txt | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8896dfd7..e371a33d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,11 @@ if (NOT CMAKE_BUILD_TYPE) endif() endif() +if (CMAKE_GENERATOR MATCHES "^Visual Studio.*$") + message(STATUS "Note: when building with Visual Studio the build type is specified when building.") + message(STATUS "For example: 'cmake --build . --config=Release") +endif() + if("${CMAKE_BINARY_DIR}" MATCHES ".*(S|s)ecure$") message(STATUS "Default to secure build") set(MI_SECURE "ON") @@ -326,11 +331,11 @@ set(MI_OPT_ARCH_FLAGS "") set(MI_ARCH "unknown") if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|i[3456]86)$" OR CMAKE_GENERATOR_PLATFORM MATCHES "^(x86|Win32)$") set(MI_ARCH "x86") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") # must be before arm64 set(MI_ARCH "x64") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv8.?)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv8.?|ARM64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") set(MI_ARCH "arm64") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|armv[34567])$") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|armv[34567]|ARM)$") set(MI_ARCH "arm32") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv|riscv32|riscv64)$") if(CMAKE_SIZEOF_VOID_P==4) @@ -341,7 +346,7 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv|riscv32|riscv64)$") else() set(MI_ARCH ${CMAKE_SYSTEM_PROCESSOR}) endif() -message(STATUS "Architecture: ${MI_ARCH}") +message(STATUS "Architecture: ${MI_ARCH}") # (${CMAKE_SYSTEM_PROCESSOR}, ${CMAKE_GENERATOR_PLATFORM}, ${CMAKE_GENERATOR})") # Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits. # (this will skip the aligned hinting in that case. Issue #939, #949) @@ -533,8 +538,14 @@ if(MI_BUILD_SHARED) ) if(WIN32 AND MI_WIN_REDIRECT) # On windows, link and copy the mimalloc redirection dll too. - if(MI_ARCH STREQUAL "x64") + if(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64ec") + set(MIMALLOC_REDIRECT_SUFFIX "-arm64ec") + elseif(MI_ARCH STREQUAL "x64") set(MIMALLOC_REDIRECT_SUFFIX "") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64") + message(STATUS "Note: x64 code emulated on Windows for arm64 should use an arm64ec build of 'mimalloc-override.dll'") + message(STATUS " with 'mimalloc-redirect-arm64ec.dll'. See the 'bin\\readme.md' for more information.") + endif() elseif(MI_ARCH STREQUAL "x86") set(MIMALLOC_REDIRECT_SUFFIX "32") else() From 3a9c402e5107984324bfea6424370aac37c97a88 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 19 Dec 2024 14:18:16 -0800 Subject: [PATCH 169/305] update readme for cmake on windows --- readme.md | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index a0296b43..7fa5eb54 100644 --- a/readme.md +++ b/readme.md @@ -164,7 +164,7 @@ The `mimalloc` project builds a static library (in `out/msvc-x64`), while the `mimalloc-override` project builds a DLL for overriding malloc in the entire program. -## macOS, Linux, BSD, etc. +## Linux, macOS, BSD, etc. We use [`cmake`](https://cmake.org)1 as the build system: @@ -200,13 +200,25 @@ free lists, etc., as: > make ``` This will name the shared library as `libmimalloc-secure.so`. -Use `ccmake`2 instead of `cmake` -to see and customize all the available build options. +Use `cmake ../.. -LH` to see all the available build options. -Notes: -1. Install CMake: `sudo apt-get install cmake` -2. Install CCMake: `sudo apt-get install cmake-curses-gui` +The examples use the default compiler. If you like to use another, use: +``` +> CC=clang CXX=clang++ cmake ../.. +``` +## Cmake with Visual Studio + +You can also use cmake on Windows. Open a Visual Studio development prompt +and invoke `cmake` with the right generator and architecture, like: +``` +> cmake ..\.. -G "Visual Studio 17 2022" -A x64 -DMI_OVERRIDE=ON +``` + +The cmake build type is specified when actually building, for example: +``` +> cmake --build . --config=Release +``` ## Single source From 7456d22fe36b21a025b2be33ab043256a9e6a3e3 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 19 Dec 2024 14:22:10 -0800 Subject: [PATCH 170/305] add link for VS generator --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7fa5eb54..564ac6d7 100644 --- a/readme.md +++ b/readme.md @@ -210,7 +210,8 @@ The examples use the default compiler. If you like to use another, use: ## Cmake with Visual Studio You can also use cmake on Windows. Open a Visual Studio development prompt -and invoke `cmake` with the right generator and architecture, like: +and invoke `cmake` with the right [generator](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2017%202022.html) +and architecture, like: ``` > cmake ..\.. -G "Visual Studio 17 2022" -A x64 -DMI_OVERRIDE=ON ``` From f8a253e6e8e0f3a811745d7a9449cd73e49509f2 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 20 Dec 2024 12:51:13 -0800 Subject: [PATCH 171/305] update IDE settings to match cmake output; in particular mimalloc-override.dll -> mimalloc.dll --- ide/vs2022/mimalloc-override-test.vcxproj | 2 +- ide/vs2022/mimalloc-override.vcxproj | 18 +++++++++--------- ide/vs2022/mimalloc-test.vcxproj | 2 +- ide/vs2022/mimalloc.vcxproj | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ide/vs2022/mimalloc-override-test.vcxproj b/ide/vs2022/mimalloc-override-test.vcxproj index 97803b9c..0e87cf36 100644 --- a/ide/vs2022/mimalloc-override-test.vcxproj +++ b/ide/vs2022/mimalloc-override-test.vcxproj @@ -39,7 +39,7 @@ {FEF7868F-750E-4C21-A04D-22707CC66879} mimalloc-override-test 10.0 - mimalloc-override-test + mimalloc-test-override diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index 9de18895..1278cd0f 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -39,7 +39,7 @@ {ABB5EAE7-B3E6-432E-B636-333449892EA7} mimalloc-override 10.0 - mimalloc-override + mimalloc-override-dll @@ -116,49 +116,49 @@ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll - mimalloc-override + mimalloc diff --git a/ide/vs2022/mimalloc-test.vcxproj b/ide/vs2022/mimalloc-test.vcxproj index fc9e9102..a8b36d5e 100644 --- a/ide/vs2022/mimalloc-test.vcxproj +++ b/ide/vs2022/mimalloc-test.vcxproj @@ -39,7 +39,7 @@ {FEF7858F-750E-4C21-A04D-22707CC66878} mimalloctest 10.0 - mimalloc-test + mimalloc-test-static diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index 34a9317a..9964310d 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -39,7 +39,7 @@ {ABB5EAE7-B3E6-432E-B636-333449892EA6} mimalloc 10.0 - mimalloc + mimalloc-lib From 4b7313914ee702f1abe16d9021f5ac4867894cf4 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 20 Dec 2024 12:52:00 -0800 Subject: [PATCH 172/305] add updated minject v1.2 that defaults to mimalloc.dll instead of mimalloc-override.dll --- bin/minject-arm64.exe | Bin 20992 -> 20992 bytes bin/minject.exe | Bin 22016 -> 22016 bytes bin/minject32.exe | Bin 18944 -> 18944 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/minject-arm64.exe b/bin/minject-arm64.exe index 97188c4f14e644b66d938ce44a940f3058153a13..637c95d91576043ff83cf2f0ceb5a5555c544764 100644 GIT binary patch delta 1656 zcmY*ZZERCz6h7zPwrjU_9qqc+t)m}Hwh(CnD57uBdb|nEqU?Uo;B+3v7BuX~HglNpB#2=N7d2T;~-lTax&d2+n z_rAUH(-=RE!&($i-Rz)OCtbQ$x($j=|1{}%e7<_TJeG$70#kCrjZS* zODIIc@(s07ZH$Hk69z~h1ZZ*r3~Rf>@>F36@nc$2Y+AX$0FK%9;L`$3cTwWsUb<%jTY0(yr zoY3SVW7)_?_8{+#XT1pN^_zvz0eV~S-HQ96{hkvfGeB8N7!BCYLvN71^9eZrHxFT8 z-v#lu$1g*mIKyGMvRf0-<$0GTpvm(dO+d`^sD_^C9rJ$`q3r#A@Kx^20(^eH3DKOq z{%mgGfk@txttiovl1gpGe&{F{<85@fw4GFj5A_(jSP1c3hXwF`iS&t~6^ZT}UY93I zi?L+Y?A${&7iRj09Mau9chqoldGc0XC!87meO_aWbR*A0^LSqs$?JKYFiKzN zITlG{c^)c~u29tGpjMkfHTHsZE+>q5n%PnupwDa_0vc(`<`kj@WU_x}_J%In)X-}$ zg!UK@qFkhym;SOZM=!Y@NBL!qIa0!;iVit93F9hy=xh_Nts#GnGlFXA9`c3G{@?l` zs+MlEjwASh+vv0RtY6D{I*1?DErdax4$_%(jTlcp5Aw^HhJ=PXU%VzbO5_^X&mxtI7e*E@6YA_<2%^%VG=~c3$JhLS zovNp)mh!^sx~zRhk#2d|-KIgWEH?dtr1dYN7Qa>Q^oK-sric7_%kk_d&c9+EZCkO- z7^wwt_jT>*ThOyhN$F^olPi8hy@$8p-VyENdBG!}eCZujr&K}v2c!=!ZJXia6*yp7 z%-d>Ein6$ydHg@R7=l_J6%sR#9yY;l?c{-(M@p?Sp0yF+HvbNC?d?YSXz-a%9$g0i%#&T*x@h=wZK~7gGFT#uKbd-2fX|#~9Blnw$4AK4x44 zA@q0v)-mp3e1kE?nCZuO2UZKyO8^?Uewi0wC5*0u3rwonxW|}a>{yyjILLUJ8(Vw; xU9cMCIaE#|#=bJqv35dnR4!@N2xYFJ;LzG39ytQQpGV%U_Jq77@&ig9-M_fB&V6h7zPmfk{3p?rft+wswgAYc)Sy0sVu-DFBoNz5`};!2!O9GJO8ZFNqa zOt~B8Qcu#2(PNU%0DJIQV zC|IkN%UZM6Y^`=pm|*%KK$#t2Sjw$d9z=T(&ryjXVac!#j#-T0lmMpiVU|20CI?Qb znqgMM?2z_3YrdFS%^KGF$j=!*WzU3u*5e6#dRTKuw5G7ut!mP2oIk96KvxY3j)Uy! zjhgiY!=8PtK}5S6)^?N8xL&|Rw8>byA$S1lZ`wdk0!SPaMqSzGpbZW}ea8Vf_a`@D zV%-kDx_e8(WeC|YobJ%M^btE(=ZcEhg*ulQv8_7#!)VP)&_H6@ei)gZnTzM=oDh=& z-#(k^F=(hXb^`|KNNl?4#sO$Z7JYS{0yxj0NQX_UNMqV*Eb&~32H&-i9HjS6wW!c7 z)60e;-st|wiMj$!|8`m&+d#vy^@=^tfU)sUXL_bZ2&mg!e@a#HrMOnhCInL36e3h z2S1_y%=ueR@tRN;k5wLs*w*JbE;(>A!u_@o@BNoo%AZASPdt~J68I>>{bu=i#Kstz zBDN=n+x28Ez|IWKY_{5=<}pJ^?H~Njf-Rd)WqGU3O*(m0eDz1*hle`_9vyv=cTvE2Wpn;*@$9?` zVeZXRaHAR!H;byx&umNjP3<>BV_;rJI3d6@rCN5 zFxvToR`4gn4d9k|7~p?$=a(|rCQa^paz|aO4&nNIfX-q7H?Qq1R=VBK^p1)%JKN5j z{ac9XJb!%a)KHZ(u|9p*Yu^34?+@uNM?KmSx9Y|rUJ9TbT3LgHFCE>(Ljp@Z*T|(< zVHA9fxr_sh#jMwGIjZhu>}5X2xR$wvw?D0N#&*VDE@c^b@E+p|#^MryHH<#SP(H>V zph_4h1t{e8Q;bVs^aa?q03efvE=E6NoHHEYX8f8Hk2AJF6;^QHDyp;bvaa@hte#LD hRbp$Sgv6Sm#v$(z_r`xv1_n#7y;mt&eFf!W{XYp<>%ag2 diff --git a/bin/minject.exe b/bin/minject.exe index 53c42f5d6dc7f643c03e832ff9e0aff42b2fc265..bb445706b65269a336d6e6b3ba2eca4f7399acd4 100644 GIT binary patch delta 6740 zcmeHMdsvj$nLpnLBO?fdgyDV}a6mvr1XL8!8HMm+MwdmR)=MHHMp7?inAvz~%A|mm zewkh17~}Ra25n-k%~P%TSj98}F@VOnC|-k65>qpZuEZ;Cy7~5ZzBvTy{=a{99?$u` z_w%01_nt%I_)u_sDAY|C2T1*lS*!D2JNCfC|MKp^=Dj*+w=ejB?Ux#fiWeFM6}ua~ zRXpD~8u(iMB~|X>e`$9zXhKL$k8S1LtaBAF=hpP(>T<5rcfBG6i8gzM74(Q*Enj<>bw^Goo$l_N zy){D2S5C~9cfQlOocY;zs>6`kTa!hze9q$3gik;=PK(i?=nGN^ajVsYjtBakil+wc zw8}jee$FjYI@8VSZ-@|`KPy)b&j9ZS1Gr)x^(HSWu5ZgHPw>bp8xb~ z`Kr`<$5VIYL~Eaa`c<(dCw+K+=I*{ccY=9HZ~zHn1bZXPO{!6B*}5ZM)5qJQt1DY< z;e&Z;vRIPxIi7Oa_`#G_0h^NCq38=CHf63c8g$i%v0lwt=v0H_SbGBfIPf(HtBcNI z8c9%1lr}{_#jUd6kxD*m)-pdOt5wmz$;51#EONi1?@0zHce>-s1BzZ`YWWI_nU*g< zk>vks_rN$!$@B&9(D_|SgIfDJs1*G#nSaUW`L&*B^X2wFe|4Z^?%X^O%HrH*-2Tt)?$mqr2(F=h`yqb-m-|eUM`gxg7MoayQBGo*x zC8zh)S!B-}Y=Iz`O-OnVJ{)HZeKROf)EVeILD7bI0}F03E>iSuuu#d|^p^DVQi)5^ zYYp^L(3lCoiDKUoj4bk}I6hMC2sN^z{}pq|`czl*B}U?5_D0i$;GG3sk<6zzGqP$1 zA$DzMWTITZrS7jq?zeP-#G*nil)Zxz$f>rc8|sU%0){BDW#? z57e!=?7DXc<@1!He+<)RlN!ciEWo@JeQX4x9mz2kB>!aJ4O^HadoTPkjPD5{X^ zXprQyioQQoU6zq5(*s6bX?&tLKvxYYHXA1S5KfT0nr_qM;W3q4!*E=*ihdE$o$xMf zoQ3VrWmorY905hYlG|kbXtRIF=78JA#BKaln|2H|83Ugq&&KFT?zMWS{w-1W!fHVz_`YttumTga4TE ze;nesFn%{Tp317!wp&fpq9cT{TP9&U|0?LJ$6y_5PTA*lXx2jnh8?+i1=q9A(5@IcgN(CaY~!guuhn5k=zrXz%W)&2^izy7K# z1~(w?v;^GCMnv2Lt?Pg)v-^YJ&-nM;HYsT>ed()o>ovK0j91mEJk(WcUW0*DtJwr# zEJLtWfOgH?bhe)QvWield&mG~x{$AUTaf1y`m8v-|_u^=Z6OWI8HrK-CINA~(O z`tvd4Lgzq%b-il$a=qk*!>_}qicB)n=!r42<_x65?ReUr8{_{Ix0aOEX17UIrT$or zx&Dg&ygy`euD?{9i%a|(I9yN@8QtQhopVFne7QfJXPi3P&cew{jRn%vF66y8mF_S` zkFigLREb*vpEG9;3To_$Ul_w8&fsaK+tz}bq*tTE&hxAN#S%A-(*)5fuj{l3DB zL5b_1spzB*%_*u)n5y?-udAv~A*WVDK=yg%$eO2gK|+>roHitw^S;BX9v?w4YE|zK z9hzHU*_rFm^nwzZyjJr$NL}-{ffeB}y5FH`9a0?vSsQtD91TmHTj0wkrAZ#xr&j1Nv|i- zc}Y=~y=;KDTig#eUi*}|^WJRLPpbV9wcn@qzxHABGitv@?L*Xlj@n14eU#c8)IL`2 zjcWg~+9#-elG-QxkUWG-QJGY=Z&rtSU+vukWUBIMYCm1=XQ;hNwGq|+BOjVJ&Lo_s z72}-L-=n3nVHx%VKkZ9yjNmw#;~b7Jaooi53itbv;|?xA!TARq4|BOYIw8HBFaL=u zsU%%)f*j(wlVdf>7P$v}1f+qocs<7AGjIL_hd9*&SZd@GJ{`BIL*;#kP>?>r#~ z=Lh|@sl>$U3~;ha)J=8^4nBi}4lB5PkeBGWl;Dw$B)3;))47z*BZRc3xs$#XsAWnb z{rQxLrr%7N;?dMQtw0bR1$07I5S6AU$Kh}PS6C2Vv}zQ%t^%~_?y!S8zxtTqhHP!+ z4(L!dNDI&(DB!QqV6@+&lKzlNNGgiIH3KgMw6D;Tabv%MhO~$YAKsD4gy0{^n_XmK z0UYs!q}WO~*o?PL+zXL{#&{vzhlH<8BH=}eBs?R5gbPLz*dNgA zUrzsEnvq=>Nyy14e7Z%5s1=F!g1^dt1KDyW!zfHYod3~>CYqxw>tJ#lZ6CANh(zXp2&~+3Gh>JNNaIOFTk%hg|3+Oy!w?h75gzP$BqsD zzQ9hEo3N{k1|@{-MF|NpBjhkyCuA*#b{x*OipcUTt}iLAsK{SQ zOv9u_tF5KQDE9iqj4Xe?h{ekPz8bJ@$ZFl{?0Qo`48GeD*33_-DXT`iL03{T1hJ9!R zwY4AkK#$m{bRWXJ-n2&k{%I*|CRdWJC;_=ZkKf4mt!h!&PVrpcz)6eFJBP4lZZ7Wh@F8 zZ0dk-;90N~GJnhSJgU@9RK(3qkKxN{;B z0R2AjF&dL=(+DX+^ISm4N?;?W8D8Tw!@ZNRudu;Ok2IhqfW~W2z1vbjvpbI6S4R<( z;oZr^gY>@GWG>n&H2D>d62lf9C_k{_04czy!>V9oNTZ=Kp)s{Fvk^w0;Q!C~{x3eF B3n>5q delta 6993 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 S-3#26?pimT4scroBK`r<)^nr) diff --git a/bin/minject32.exe b/bin/minject32.exe index 926facfda8018cf58df19310837661b76dac67c9..6dcb8da9ccb189f0e31daf31b06aa9449c840f9d 100644 GIT binary patch delta 3508 zcmd^CeN>cH9=;bCKIFs6ForJyVGvE|eP5Yr240E3wzk2Z5e zOqy81>-KTNv-we*=d>F&m1esx9av~vw^N&^W7&sGtG$JrX6Vvp%|3U~6aBe=@8vwd z=Xamq?|#1b-Z}UVP~QRCV+td*ci|$r&hLvL0pHLy46-3WY3=Y)N%VJTs`bT2CjTS5B+ zyTK9XK$O|i4+d#pQFPoEA9#U2bxqsfH$%f>r~;<`;Ix+4w} z6kB(B#2TA&F|ae?M;h<8TM6kZoAAW=%$~rb>OGV`#1dwt(F}Iy3@vSAD`zZ((lcXU z!b3cD`tBa|;WM`d@^Ak#oJwqF((L8Qn05E^=&of~#+LXN=1S0w|$cY+OxmjnDF6wp4NAa+?lG3o~&ytLH zD4VRLyZg#d!JyLcO)%Iol-YUCZDRQv(=^{7xs18>v2INUyQWHI?`U>;yDtTU{$&&X z4{XZSfAba*3kEiBxX*v#{z3V`5-U;Gj|GGBS?;ZZS0h)H!z~ZFIovhzxKasEf_J*6 zfhwQH5uz+mVH=h3c(_?`{a2JZ@Ed5CpnS+zJ`}fM_kf%IH92OjHXp6;jX>sg7@P7u z+OJ*PIpA5TT;{43?K=nDvGR#|NZiGvN+dJ|=YuHcc*@C8!`DKg5%}m@rPx`1O2PD< zTpVmjl!cXOt!51=TB>F}DT!)zot4PdB`_5*%4POyiZ*62mJdFnQnS&NTHStLQ)*!S z6G|&5L3seQrY0yTqZ53?;;=LoCW0Zi?mp*HDXUm>YHsQm(|A9FeuttAPfkek?fjA; zp2Yf7b7T4t4|>ik@37BPSE(;WhnARWKcvCYIhDvt((a7XV1872gtey4r^)QuG)=8z zGA+0Bx@WeWhOm;thrw1&m-BcvcCzZeQyLf(I{p&uisxBf@tGl;6S6$9D}H{+3b4bf zWTs9}jI{Cnv9WpS`!eiNq3KNb?TjX#m<0oGBqHxodjH^R|0SPU!_KD9(eRFgK~Jjm1t*=nPAmbvn(!gEQ4uD;eykgEArE1cs6ZqD-*htfVL_5(bqYS$alZ)D9f$ z!4vJQGUIOg1>2p`Mc1-~%-_&w*zYs%nX?&t+a>thB9sjwPx%gXx`!-&8bYx z`^`+2k(C>n$K5=**|(kkWs#p_Em_M7^k^IOBz8pxJ?fw*u0~di`21E}8>JIpsbeT@ z!~KJ3iFI~pZS3o;6P5-D!4V5!anf$%xxixw}&X*8X}b`L|Q|L@(V$I`&2T>Uq+6s4{^ki zP2ldb=p!y(@BHLOFgT)m0b4=wcL>3Ja>S16h^iJgCV~u%sMd$V1e$!)Ylx`bIzUEz zE|!uzN^OB3bHgbc2#fdbs3qj}HP~NZ6u1G*fR+m^0*(SbKp*r?U|xp7C#wkQ2lfLy zfEGXo-n*G|xSEisfFgjGFz_Xypk}hJnPe}~tezC+gO>m@@EGs}a2*Yz!6$*Yfe(T6 zz}K7+8v-t3(4(j~pu;`D0pKXG9N^_7a?Sz^QGXG6-yr{8)HeZf)u<%GDFu1}0mub- z*$%#r_-=3w&<|7syj+`S4KX)T?$5qgYbEp8%DG9QkMTmFaqexAR0??S`ie52I5*Yq z*zDPo>2A(+Ih(d-wmIE$W}~yQ&gE*Z4}2&Vg|h_RerjchbQ@_Yqxx(uehs(qLGY3i z7hci+<$#_mg#S{8VhQZ!ung~W`GjbohWo;O>yc%G{}h;Ou?2*b1E+xh0NT6o(SbLC zQ@~rme1VWcpbt0-WJ=f$z^f(XA5nzx{`+uazJk_aNRIhWcmFxgyw7yl&;H(r{3HiemtsjSO zFSJC&Zk4}7I}fdLigp#61}o~D(l!w{PDbA2Q?x>8wN_G0UY#PYgXlxzi&M1i(AuH# z<=rYL_|>%bX5I1se(7=A|EEhII8}hFnG`Vdp&GnAf)}?k* zG)1kJTO4(Eh$KE7xm6Fhx*d(x&PGQ`>k_BS!9C&+U)tn!JL_D|?T)HSXREscO~`M< zm$sJj7h;Q}#n$3z#SmmvwYo{JYqGl>_OkYR$NX(>XLA$!aXVTFc~({BaQ`AcHT)7g zWKEsZK`e_TJL|4E;1SYg;@c)@Vo@UG#E z;bX&j!$rd-!&O6+G0m85oNFvLmKlF%JZT&?jvEV$78g|(tu1OUI#%>b(Qwh}qVJ0` zit~yKic5;)O}Qq)w9?dLdcte^&UC{>&57nbbH3SXt}{Pk9x(se{E7LZ`Lg-I!Y>vU zTS_eVSgI`REt@T}Wv8Xfvd{8s%Q?$GE&sAiSP0%Pe))+oO_(Xn5^{u6;U1w{SSQpA zPT@h}A>lD$pD-xAFMK3?E?f}46TTOs#TlYjED(*NRrFSgb>bGWQEU|-7QNygv0FSK zJ|i9$kBR-_32{JtTRbCvDvpYZcvZY1#z|??d`TxQmX=B@q}9@WQk}F#YLr@~hb6Dn zDfy*d=}GCJbVNEPy(GORy(zsVjYxl!K9D|=K9?>?m!-`Mh?Emz0VXq8-t|%lNN{lK%qUh!G9| delta 3670 zcmd^CeOOdg8b5bn_=wL;1O%540Yydcy)rlh3^Sl86cFeLSg8Zd=pE!sm?`8*nF0(J zNc6b&@j&WoE%x+bO&_j(ECym9ZqcgMvsr6pbrYWr3yn2v_IEC_v48I0dwhQH?|pyg zJ?FgV%(?fXb1&!I%k`wI#>noBtmdSnUQgLRl&(&}eB|e=n-Mpb*v2ar-ZCyJTs3Z0 zxO%(^9DBqzz6EUi&~`N%e5u5&>OxVgSBsR)TKAVj-6CW155cerKTHp;2ysb+`M1*!z@C@oUm$-U${ zsM^TU5mm72Siei<>CJJyu3OX(uwT9tz&caZk{|8Ijx~x^PB3x1Scx z$bix_V^`o4EH$XL2Xi>}`&~)5ee1#9Nkc+o3sO*dcY#kw{@CbBXGT&`Ybu16?Gq%Z zEgoLyFcuhH(wRN+BGPJZ8?5P7K@ zXD|QA+!(l>V{&K!A(dPQFMq_2Ysh~?>wuj;7w)?*D+#0T@I>Y{m_m6U2CZAyHsC0d zzh|lu<59DpbZ!9>>shbt1x?27BJ!s!<+w8NNu}!)d`zvDO*DA+;-G3K4pz>T>WVPh zgXYhUkJsXGm%fvkb|R>C362Fz<#q%xQ8H!1zy}Y@WeRt1J&s)+ai* ze@oEsO=(1eZx{OAjtlZ}`c}m1;PXDpj-xFH!|bnKned6- z^C-7|u(;FV({|0SZuymSl*?-;M<%pgbHqw3kR{*3R>ls4q(T<{?5l+Kh2p>{-|~*T zBYp}e)7mz{beeQnOXFt(7}?eKAU%O9c4QNPIohv@Y=r&Go&<#q(S9sb4A90AwFXvX#*#IM;h6p53;PFvy|>1Q#o za`)3e#1_C_jIHGwscCK^?2fscV85Qr!_JCZ0eg3x#M$XkTwk-ZoE`Z6%!V{FJIBtf zrjA*C73`+2kVh2?=u&8oq>$R8P`p{8q+AR1V}7@8-LfQc`H zpN2LJoCPid4+E@SM}HXlcObqDUW_;pd;pwhLd7OHt-uIS2W$dZI}T0(hJby*7|;c< zHe;btVP@`3_|5N)H_t{O{7=A43tNo+1MdOeO9&BxLEvrR zJ>Y#n#}kqX906Vcl0-uEKyN$_8xJ;{|1ms6*Pz{pIae(=<&j`Qw#~(1+pVs@qy%vB zVW@L)y`{`vhR-AxNB+$?uAy;KCav_!ve0n05w@Yp?6{_;CX4dt$2~Mgdz;=|G&R;< z5tn<{U6_Vgrfa6mOr}ZD@P@)H$TLmm)zPh(;TiP2#CmLO**FwUhTGR+Px z8K0J$dC5%crzfPQ0 zxQ*@5*ae(wGw_IAfYvol6QPA+N9U)FH9?b*cY2y;hgNDNX=Hqw_&7u-5-(5FjzepN z#FkI{cV8T{y)79TxDr#o?JEUGlVxMsa9F-%N_Og)*5?ZeQkxcp&{2o zglVcts<)O|AQBG`w>Dr2a!$RrMk=eZR9P+AjTP2Kb#_~A4d$_1>j~MbUSqZYSO4_x zCux~6B4igUEx*>{sIulL^WbJIqPvZ^;ZOD_jS<|QtoC^Av)i^l`{K_kzphvJ)r>u# zl|0ildwYe{wqx{p@Atf}RR`yP+(BGzS!LXzz!e_NTa))B4=0~b{#SCeMx&85^_uOP zcFi8mS4T6WqUX&cfOq%Tj; zPp?UTwmIFE9;^@7|4uLHv-P*@*Xy_HAJ&iP&*{I@|ERyAKbSF=kz*(@lo-qgo1xa= zF#O)I&(Lf5qd_)YFYQjbO}^=TsSE73(pI$2yX}{g}(~t zgfE0k!uP^e!7ccT;bNkw6SKrZu~@uEEEgrQMzo7fqEp-{c8Pn$N5v<^!{XE8QSlY= zb@46nZSj5atoV2Fg7}SiS^Pn~A=WN+u(y>F-$VQl?V+52$X@*ceZQV$gk?Z4#0MGF PDzpoSQHSe=oILK|rd?g| From 4ed44f96210c71f6d1945ae950387bc262a75f20 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 20 Dec 2024 12:52:34 -0800 Subject: [PATCH 173/305] update readme to use mimalloc.dll (instead of mimalloc-override.dll) --- bin/readme.md | 38 ++++++++++++++++++------------------ readme.md | 53 ++++++++++++++++++++++++++++----------------------- 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/bin/readme.md b/bin/readme.md index d6c3775f..bc115ce1 100644 --- a/bin/readme.md +++ b/bin/readme.md @@ -9,20 +9,20 @@ There are four requirements to make the overriding work well: 1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -2. Link your program explicitly with the `mimalloc-override.lib` export library for - the `mimalloc-override.dll` -- which contains all mimalloc functionality. - To ensure the `mimalloc-override.dll` is actually loaded at run-time it is easiest +2. Link your program explicitly with the `mimalloc.lib` export library for + the `mimalloc.dll` -- which contains all mimalloc functionality. + To ensure the `mimalloc.dll` is actually 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, or - use `#pragma comment(linker, "/include:mi_version")` in some source file). - See the `mimalloc-override-test` project for an example on how to use this. + similarly, `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-test-override` project for an example on how to use this. 3. The `mimalloc-redirect.dll` must be put in the same folder as the main - `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). + `mimalloc.dll` at runtime (as it is a dependency of that DLL). The redirection DLL ensures that all calls to the C runtime malloc API get - redirected to mimalloc functions (which reside in `mimalloc-override.dll`). + redirected to mimalloc functions (which reside in `mimalloc.dll`). -4. Ensure the `mimalloc-override.dll` comes as early as possible in the import +4. Ensure the `mimalloc.dll` comes as early as possible in the import list of the final executable (so it can intercept all potential allocations). You can use `minject -l ` to check this if needed. @@ -37,8 +37,8 @@ redirected. ### Other Platforms -You always link with `mimalloc-override.dll` but for different platforms you may -need a specific `mimalloc-redirect.dll`: +You always link with `mimalloc.dll` but for different platforms you may +need a specific redirection DLL: - __x64__: `mimalloc-redirect.dll`. - __x86__: `mimalloc-redirect32.dll`. Use for older 32-bit Windows programs. @@ -47,12 +47,12 @@ need a specific `mimalloc-redirect.dll`: mode on Windows arm64. Unfortunately we cannot run x64 code emulated on Windows arm64 with the x64 mimalloc override directly (since the C runtime always uses `arm64ec`). Instead: 1. Build the program as normal for x64 and link as normal with the x64 - `mimalloc-override.lib` export library. - 2. Now separately build `mimalloc-override.dll` in `arm64ec` mode and _overwrite_ your - previous (x64) `mimalloc-override.dll` -- the loader can handle the mix of arm64ec + `mimalloc.lib` export library. + 2. Now separately build `mimalloc.dll` in `arm64ec` mode and _overwrite_ your + previous (x64) `mimalloc.dll` -- the loader can handle the mix of arm64ec and x64 code. Now use `mimalloc-redirect-arm64ec.dll` to match your new - arm64ec `mimalloc-override.dll`. The main program stays as is and can be fully x64 - or contain more arm64ec modules. At runtime, the arm64ec `mimalloc-override.dll` will + arm64ec `mimalloc.dll`. The main program stays as is and can be fully x64 + or contain more arm64ec modules. At runtime, the arm64ec `mimalloc.dll` will run with native arm64 instructions while the rest of the program runs emulated x64. [arm64ec]: https://learn.microsoft.com/en-us/windows/arm/arm64ec @@ -60,11 +60,11 @@ need a specific `mimalloc-redirect.dll`: ### Minject -We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we +We cannot always re-link an executable with `mimalloc.dll`, and similarly, we cannot always ensure that the DLL comes first in the import table of the final executable. In many cases though we can 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 +`mimalloc.dll` into the import table (and put `mimalloc-redirect.dll` in the same directory) Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388). The `minject` program can also do this from the command line @@ -86,8 +86,8 @@ options: -l --list only list imported modules -i --inplace update the exe in-place (make sure there is a backup!) -f --force always overwrite without prompting - --postfix=

    use

    as a postfix to the mimalloc dll (default is 'override') - e.g. use --postfix=override-debug to link with mimalloc-override-debug.dll + --postfix=

    use

    as a postfix to the mimalloc dll. + e.g. use --postfix=debug to link with mimalloc-debug.dll notes: Without '--inplace' an injected is generated with the same name ending in '-mi'. diff --git a/readme.md b/readme.md index 564ac6d7..11f62da4 100644 --- a/readme.md +++ b/readme.md @@ -428,43 +428,48 @@ 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). -### Dynamic Override on Windows +# Windows Override Dynamically overriding on mimalloc 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. -As it intercepts all allocation calls on a low level, it can be used reliably +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. As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. -There are four requirements to make the overriding work robustly: +There are four requirements to make the overriding work well: 1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -2. Link your program explicitly with `mimalloc-override.dll` library. - To ensure the `mimalloc-override.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. -3. The [`mimalloc-redirect.dll`](bin) (or `mimalloc-redirect32.dll`) must be put - in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). - The redirection DLL ensures that all calls to the C runtime malloc API get redirected to - mimalloc functions (which reside in `mimalloc-override.dll`). -4. Ensure the `mimalloc-override.dll` comes as early as possible in the import + +2. Link your program explicitly with the `mimalloc.lib` export library for the `mimalloc.dll`. + (which must be compiled with `-DMI_OVERRIDE=ON`, which is the default though). + To ensure the `mimalloc.dll` is actually 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 command, or + similarly, `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-test-override` project for an example on how to use this. + +3. The `mimalloc-redirect.dll` must be put in the same folder as the main + `mimalloc.dll` at runtime (as it is a dependency of that DLL). + The redirection DLL ensures that all calls to the C runtime malloc API get + redirected to mimalloc functions (which reside in `mimalloc.dll`). + +4. Ensure the `mimalloc.dll` comes as early as possible in the import list of the final executable (so it can intercept all potential allocations). + You can use `minject -l ` to check this if needed. For best performance on Windows with C++, it is also recommended to also override the `new`/`delete` operations (by including -[`mimalloc-new-delete.h`](include/mimalloc-new-delete.h) +[`mimalloc-new-delete.h`](../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. +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully +redirected. + +For different platforms than x64, you may need a specific [redirection dll](bin). +Furthermore, we cannot always re-link an executable or ensure `mimalloc.dll` comes +first in the import table. In such cases the [`minject`](bin) tool can be used +to patch the executable's import tables. -We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we cannot always -ensure the the DLL comes first in the import table of the final executable. -In many cases though we can 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) or -the [`minject`](bin) program. ## Static override From 26eaa1f4e2804fc7dd3cc3997a481c55d484b4f1 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 20 Dec 2024 12:52:58 -0800 Subject: [PATCH 174/305] fix cmake to generate mimalloc.dll on windows --- CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e371a33d..e84283fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -667,12 +667,7 @@ endif() # ----------------------------------------------------------------------------- if (MI_OVERRIDE) if (MI_BUILD_SHARED) - target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) - if (WIN32) - # on windows we should generate mimalloc-override.dll. - string(REPLACE "mimalloc" "mimalloc-override" mi_override_output_name ${mi_basename}) - set_target_properties(mimalloc PROPERTIES OUTPUT_NAME ${mi_override_output_name}) - endif() + target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) endif() if(NOT WIN32) # It is only possible to override malloc on Windows when building as a DLL. From 9c5c628f990735ffc2f626b1cb6d8f26cf8c4701 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 20 Dec 2024 12:58:46 -0800 Subject: [PATCH 175/305] merge from dev --- ide/vs2022/mimalloc-test.vcxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ide/vs2022/mimalloc-test.vcxproj b/ide/vs2022/mimalloc-test.vcxproj index a8b36d5e..6e4576fd 100644 --- a/ide/vs2022/mimalloc-test.vcxproj +++ b/ide/vs2022/mimalloc-test.vcxproj @@ -272,14 +272,14 @@ Console + + + {abb5eae7-b3e6-432e-b636-333449892ea6} - - - From df82338d8a2f118954d82b8421f8c1b9294a78a2 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 20 Dec 2024 13:04:30 -0800 Subject: [PATCH 176/305] don't override a page candidate with a page that is too full --- src/page.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page.c b/src/page.c index 85e831d2..4b25ed5d 100644 --- a/src/page.c +++ b/src/page.c @@ -783,7 +783,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p page_candidate = page; candidate_count = 0; } - else if (/* !mi_page_is_expandable(page) && */ page->used >= page_candidate->used) { + else if (!mi_page_mostly_used(page) && page->used >= page_candidate->used) { page_candidate = page; } // if we find a non-expandable candidate, or searched for N pages, return with the best candidate From f3d83e5fa62f9d5ec653d13db8eec2d814e72046 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 20 Dec 2024 13:55:31 -0800 Subject: [PATCH 177/305] insert full pages at the end of the queue; only override page candidate if the page is not too full --- ide/vs2022/mimalloc-test.vcxproj | 6 +++--- include/mimalloc/internal.h | 2 +- src/page-queue.c | 2 +- src/page.c | 3 ++- test/test-stress.c | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ide/vs2022/mimalloc-test.vcxproj b/ide/vs2022/mimalloc-test.vcxproj index a8b36d5e..6e4576fd 100644 --- a/ide/vs2022/mimalloc-test.vcxproj +++ b/ide/vs2022/mimalloc-test.vcxproj @@ -272,14 +272,14 @@ Console + + + {abb5eae7-b3e6-432e-b636-333449892ea6} - - - diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 012ce4f0..8b22e1c6 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -571,7 +571,7 @@ static inline bool mi_page_immediate_available(const mi_page_t* page) { } // is more than 7/8th of a page in use? -static inline bool mi_page_mostly_used(const mi_page_t* page) { +static inline bool mi_page_is_mostly_used(const mi_page_t* page) { if (page==NULL) return true; uint16_t frac = page->reserved / 8U; return (page->reserved - page->used <= frac); diff --git a/src/page-queue.c b/src/page-queue.c index 9796f3dc..67b54650 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -343,7 +343,7 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro static void mi_page_queue_enqueue_from_full(mi_page_queue_t* to, mi_page_queue_t* from, mi_page_t* page) { // note: we could insert at the front to increase reuse, but it slows down certain benchmarks (like `alloc-test`) - mi_page_queue_enqueue_from_ex(to, from, false /* enqueue at the end of the `to` queue? */, page); + mi_page_queue_enqueue_from_ex(to, from, true /* enqueue at the end of the `to` queue? */, page); } // Only called from `mi_heap_absorb`. diff --git a/src/page.c b/src/page.c index 4b25ed5d..8808c358 100644 --- a/src/page.c +++ b/src/page.c @@ -783,7 +783,8 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p page_candidate = page; candidate_count = 0; } - else if (!mi_page_mostly_used(page) && page->used >= page_candidate->used) { + // prefer to reuse fuller pages (in the hope the less used page gets freed) + else if (page->used >= page_candidate->used && !mi_page_is_mostly_used(page) && !mi_page_is_expandable(page)) { page_candidate = page; } // if we find a non-expandable candidate, or searched for N pages, return with the best candidate diff --git a/test/test-stress.c b/test/test-stress.c index 574d241b..6284ad39 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -319,7 +319,7 @@ int main(int argc, char** argv) { mi_collect(true); #endif #endif - //mi_stats_print(NULL); + mi_stats_print(NULL); //bench_end_program(); return 0; } From 93e14344c7be10f186a39f7bee998db8adcead9b Mon Sep 17 00:00:00 2001 From: daanx Date: Fri, 20 Dec 2024 17:32:26 -0800 Subject: [PATCH 178/305] use srw lock on windows --- include/mimalloc/atomic.h | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index 3a0d4892..0c967896 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -402,28 +402,34 @@ static inline void mi_atomic_yield(void) { // ---------------------------------------------------------------------- -// Locks are only used for abandoned segment visiting in `arena.c` +// Locks +// These do not have to be recursive and should be light-weight +// in-process only locks. Only used for reserving arena's and to +// maintain the abandoned list. // ---------------------------------------------------------------------- +#if _MSC_VER +#pragma warning(disable:26110) // unlock with holding lock +#endif #if defined(_WIN32) -#define mi_lock_t CRITICAL_SECTION +#define mi_lock_t SRWLOCK // slim reader-writer lock static inline bool mi_lock_try_acquire(mi_lock_t* lock) { - return TryEnterCriticalSection(lock); + return TryAcquireSRWLockExclusive(lock); } static inline bool mi_lock_acquire(mi_lock_t* lock) { - EnterCriticalSection(lock); + AcquireSRWLockExclusive(lock); return true; } static inline void mi_lock_release(mi_lock_t* lock) { - LeaveCriticalSection(lock); + ReleaseSRWLockExclusive(lock); } static inline void mi_lock_init(mi_lock_t* lock) { - InitializeCriticalSection(lock); + InitializeSRWLock(lock); } static inline void mi_lock_done(mi_lock_t* lock) { - DeleteCriticalSection(lock); + // nothing } @@ -447,14 +453,13 @@ static inline void mi_lock_done(mi_lock_t* lock) { pthread_mutex_destroy(lock); } -/* #elif defined(__cplusplus) #include #define mi_lock_t std::mutex static inline bool mi_lock_try_acquire(mi_lock_t* lock) { - return lock->lock_try_acquire(); + return lock->try_lock(); } static inline bool mi_lock_acquire(mi_lock_t* lock) { lock->lock(); @@ -469,7 +474,6 @@ static inline void mi_lock_init(mi_lock_t* lock) { static inline void mi_lock_done(mi_lock_t* lock) { (void)(lock); } -*/ #else From e3ebebb9902c56b6899f70f046cbcc8089674569 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 21 Dec 2024 14:39:17 -0800 Subject: [PATCH 179/305] update lock primitive; fix arena exclusive allocation --- include/mimalloc/atomic.h | 31 ++++++++++++++++++++++++++++--- src/arena-abandon.c | 33 +++++++++++---------------------- src/arena.c | 5 +++-- src/init.c | 15 +++++++-------- 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index 0c967896..733dbf42 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2023 Microsoft Research, Daan Leijen +Copyright (c) 2018-2024 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. @@ -411,8 +411,11 @@ static inline void mi_atomic_yield(void) { #pragma warning(disable:26110) // unlock with holding lock #endif +#define mi_lock(lock) for(bool _go = (mi_lock_acquire(lock),true); _go; (mi_lock_release(lock), _go=false) ) + #if defined(_WIN32) +#if 1 #define mi_lock_t SRWLOCK // slim reader-writer lock static inline bool mi_lock_try_acquire(mi_lock_t* lock) { @@ -432,6 +435,30 @@ static inline void mi_lock_done(mi_lock_t* lock) { // nothing } +#else +#define mi_lock_t CRITICAL_SECTION + +static inline bool mi_lock_try_acquire(mi_lock_t* lock) { + return TryEnterCriticalSection(lock); + +} +static inline void mi_lock_acquire(mi_lock_t* lock) { + EnterCriticalSection(lock); + +} +static inline void mi_lock_release(mi_lock_t* lock) { + LeaveCriticalSection(lock); + +} +static inline void mi_lock_init(mi_lock_t* lock) { + InitializeCriticalSection(lock); + +} +static inline void mi_lock_done(mi_lock_t* lock) { + DeleteCriticalSection(lock); + +} +#endif #elif defined(MI_USE_PTHREADS) @@ -506,6 +533,4 @@ static inline void mi_lock_done(mi_lock_t* lock) { #endif - - #endif // __MIMALLOC_ATOMIC_H diff --git a/src/arena-abandon.c b/src/arena-abandon.c index 48e37794..460c80fc 100644 --- a/src/arena-abandon.c +++ b/src/arena-abandon.c @@ -120,11 +120,7 @@ static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { mi_assert(segment->memid.memkind != MI_MEM_ARENA); // not in an arena; we use a list of abandoned segments mi_subproc_t* const subproc = segment->subproc; - if (!mi_lock_acquire(&subproc->abandoned_os_lock)) { - _mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment"); - // we can continue but cannot visit/reclaim such blocks.. - } - else { + mi_lock(&subproc->abandoned_os_lock) { // push on the tail of the list (important for the visitor) mi_segment_t* prev = subproc->abandoned_os_list_tail; mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL); @@ -138,7 +134,6 @@ static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) { mi_atomic_increment_relaxed(&subproc->abandoned_os_list_count); mi_atomic_increment_relaxed(&subproc->abandoned_count); // and release the lock - mi_lock_release(&subproc->abandoned_os_lock); } return; } @@ -251,7 +246,7 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_ if mi_unlikely(field != 0) { // skip zero fields quickly // we only take the arena lock if there are actually abandoned segments present if (!has_lock && mi_option_is_enabled(mi_option_visit_abandoned)) { - has_lock = (previous->visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); + has_lock = (previous->visit_all ? (mi_lock_acquire(&arena->abandoned_visit_lock),true) : mi_lock_try_acquire(&arena->abandoned_visit_lock)); if (!has_lock) { if (previous->visit_all) { _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the visitor lock"); @@ -289,8 +284,8 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_list(mi_arena_field_c // we only allow one thread per sub-process to do to visit guarded by the `abandoned_os_visit_lock`. // The lock is released when the cursor is released. if (!previous->hold_visit_lock) { - previous->hold_visit_lock = (previous->visit_all ? mi_lock_acquire(&previous->subproc->abandoned_os_visit_lock) - : mi_lock_try_acquire(&previous->subproc->abandoned_os_visit_lock)); + previous->hold_visit_lock = (previous->visit_all ? (mi_lock_acquire(&previous->subproc->abandoned_os_visit_lock),true) + : mi_lock_try_acquire(&previous->subproc->abandoned_os_visit_lock)); if (!previous->hold_visit_lock) { if (previous->visit_all) { _mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the OS visitor lock"); @@ -301,21 +296,15 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_list(mi_arena_field_c // One list entry at a time while (previous->os_list_count > 0) { previous->os_list_count--; - const bool has_lock = mi_lock_acquire(&previous->subproc->abandoned_os_lock); // this could contend with concurrent OS block abandonment and reclaim from `free` - if (has_lock) { - mi_segment_t* segment = previous->subproc->abandoned_os_list; - // pop from head of the list, a subsequent mark will push at the end (and thus we iterate through os_list_count entries) - if (segment == NULL || mi_arena_segment_os_clear_abandoned(segment, false /* we already have the lock */)) { - mi_lock_release(&previous->subproc->abandoned_os_lock); - return segment; - } - // already abandoned, try again + mi_lock_acquire(&previous->subproc->abandoned_os_lock); // this could contend with concurrent OS block abandonment and reclaim from `free` + mi_segment_t* segment = previous->subproc->abandoned_os_list; + // pop from head of the list, a subsequent mark will push at the end (and thus we iterate through os_list_count entries) + if (segment == NULL || mi_arena_segment_os_clear_abandoned(segment, false /* we already have the lock */)) { mi_lock_release(&previous->subproc->abandoned_os_lock); + return segment; } - else { - _mi_error_message(EFAULT, "failed to acquire abandoned OS list lock during abandoned block visit\n"); - return NULL; - } + // already abandoned, try again + mi_lock_release(&previous->subproc->abandoned_os_lock); } // done mi_assert_internal(previous->os_list_count == 0); diff --git a/src/arena.c b/src/arena.c index 164f3116..86ac5955 100644 --- a/src/arena.c +++ b/src/arena.c @@ -394,8 +394,9 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset const int numa_node = _mi_os_numa_node(); // current numa node // try to allocate in an arena if the alignment is small enough and the object is not too small (as for heap meta data) - if (!mi_option_is_enabled(mi_option_disallow_arena_alloc) || req_arena_id != _mi_arena_id_none()) { // is arena allocation allowed? - if (size >= MI_ARENA_MIN_OBJ_SIZE && alignment <= MI_SEGMENT_ALIGN && align_offset == 0) { + if (!mi_option_is_enabled(mi_option_disallow_arena_alloc)) { // is arena allocation allowed? + if (size >= MI_ARENA_MIN_OBJ_SIZE && alignment <= MI_SEGMENT_ALIGN && align_offset == 0) + { void* p = mi_arena_try_alloc(numa_node, size, alignment, commit, allow_large, req_arena_id, memid); if (p != NULL) return p; diff --git a/src/init.c b/src/init.c index 3e4da831..68a1d7e2 100644 --- a/src/init.c +++ b/src/init.c @@ -168,8 +168,8 @@ mi_stats_t _mi_stats_main = { MI_STATS_NULL }; #if MI_GUARDED mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) { heap->guarded_sample_seed = seed; - if (heap->guarded_sample_seed == 0) { - heap->guarded_sample_seed = _mi_heap_random_next(heap); + if (heap->guarded_sample_seed == 0) { + heap->guarded_sample_seed = _mi_heap_random_next(heap); } heap->guarded_sample_rate = sample_rate; if (heap->guarded_sample_rate >= 1) { @@ -187,9 +187,9 @@ void _mi_heap_guarded_init(mi_heap_t* heap) { mi_heap_guarded_set_sample_rate(heap, (size_t)mi_option_get_clamp(mi_option_guarded_sample_rate, 0, LONG_MAX), (size_t)mi_option_get(mi_option_guarded_sample_seed)); - mi_heap_guarded_set_size_bound(heap, + mi_heap_guarded_set_size_bound(heap, (size_t)mi_option_get_clamp(mi_option_guarded_min, 0, LONG_MAX), - (size_t)mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX) ); + (size_t)mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX) ); } #else mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) { @@ -257,11 +257,10 @@ void mi_subproc_delete(mi_subproc_id_t subproc_id) { mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id); // check if there are no abandoned segments still.. bool safe_to_delete = false; - if (mi_lock_acquire(&subproc->abandoned_os_lock)) { + mi_lock(&subproc->abandoned_os_lock) { if (subproc->abandoned_os_list == NULL) { safe_to_delete = true; } - mi_lock_release(&subproc->abandoned_os_lock); } if (!safe_to_delete) return; // safe to release @@ -398,7 +397,7 @@ void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap) { tld->heap_backing = bheap; tld->heaps = NULL; tld->segments.subproc = &mi_subproc_default; - tld->segments.stats = &tld->stats; + tld->segments.stats = &tld->stats; } // Free the thread local default heap (called from `mi_thread_done`) @@ -599,7 +598,7 @@ static void mi_detect_cpu_features(void) { } #else static void mi_detect_cpu_features(void) { - // nothing + // nothing } #endif From 476d4699ff93380009ae35780c2261ae674e4200 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 21 Dec 2024 15:24:46 -0800 Subject: [PATCH 180/305] limit purgeing to one purge cycle per purge delay --- include/mimalloc/atomic.h | 26 +++++++-------- src/arena.c | 69 +++++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index 733dbf42..c6083102 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -421,9 +421,8 @@ static inline void mi_atomic_yield(void) { static inline bool mi_lock_try_acquire(mi_lock_t* lock) { return TryAcquireSRWLockExclusive(lock); } -static inline bool mi_lock_acquire(mi_lock_t* lock) { +static inline void mi_lock_acquire(mi_lock_t* lock) { AcquireSRWLockExclusive(lock); - return true; } static inline void mi_lock_release(mi_lock_t* lock) { ReleaseSRWLockExclusive(lock); @@ -432,7 +431,7 @@ static inline void mi_lock_init(mi_lock_t* lock) { InitializeSRWLock(lock); } static inline void mi_lock_done(mi_lock_t* lock) { - // nothing + (void)(lock); } #else @@ -440,24 +439,20 @@ static inline void mi_lock_done(mi_lock_t* lock) { static inline bool mi_lock_try_acquire(mi_lock_t* lock) { return TryEnterCriticalSection(lock); - } static inline void mi_lock_acquire(mi_lock_t* lock) { EnterCriticalSection(lock); - } static inline void mi_lock_release(mi_lock_t* lock) { LeaveCriticalSection(lock); - } static inline void mi_lock_init(mi_lock_t* lock) { InitializeCriticalSection(lock); - } static inline void mi_lock_done(mi_lock_t* lock) { DeleteCriticalSection(lock); - } + #endif #elif defined(MI_USE_PTHREADS) @@ -467,8 +462,11 @@ static inline void mi_lock_done(mi_lock_t* lock) { static inline bool mi_lock_try_acquire(mi_lock_t* lock) { return (pthread_mutex_trylock(lock) == 0); } -static inline bool mi_lock_acquire(mi_lock_t* lock) { - return (pthread_mutex_lock(lock) == 0); +static inline void mi_lock_acquire(mi_lock_t* lock) { + const int err = pthread_mutex_lock(lock); + if (err != 0) { + mi_error_message(EFAULT, "internal error: lock cannot be acquired\n"); + } } static inline void mi_lock_release(mi_lock_t* lock) { pthread_mutex_unlock(lock); @@ -488,9 +486,8 @@ static inline void mi_lock_done(mi_lock_t* lock) { static inline bool mi_lock_try_acquire(mi_lock_t* lock) { return lock->try_lock(); } -static inline bool mi_lock_acquire(mi_lock_t* lock) { +static inline void mi_lock_acquire(mi_lock_t* lock) { lock->lock(); - return true; } static inline void mi_lock_release(mi_lock_t* lock) { lock->unlock(); @@ -513,12 +510,11 @@ static inline bool mi_lock_try_acquire(mi_lock_t* lock) { uintptr_t expected = 0; return mi_atomic_cas_strong_acq_rel(lock, &expected, (uintptr_t)1); } -static inline bool mi_lock_acquire(mi_lock_t* lock) { +static inline void mi_lock_acquire(mi_lock_t* lock) { for (int i = 0; i < 1000; i++) { // for at most 1000 tries? - if (mi_lock_try_acquire(lock)) return true; + if (mi_lock_try_acquire(lock)) return; mi_atomic_yield(); } - return true; } static inline void mi_lock_release(mi_lock_t* lock) { mi_atomic_store_release(lock, (uintptr_t)0); diff --git a/src/arena.c b/src/arena.c index 86ac5955..0ddb2936 100644 --- a/src/arena.c +++ b/src/arena.c @@ -33,7 +33,7 @@ The arena allocation needs to be thread safe and we use an atomic bitmap to allo typedef struct mi_arena_s { mi_arena_id_t id; // arena id; 0 for non-specific mi_memid_t memid; // memid of the memory area - _Atomic(uint8_t*)start; // the start of the memory area + _Atomic(uint8_t*) start; // the start of the memory area size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`) size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) size_t meta_size; // size of the arena structure itself (including its bitmaps) @@ -42,12 +42,13 @@ typedef struct mi_arena_s { bool exclusive; // only allow allocations if specifically for this arena bool is_large; // memory area consists of large- or huge OS pages (always committed) mi_lock_t abandoned_visit_lock; // lock is only used when abandoned segments are being visited - _Atomic(size_t)search_idx; // optimization to start the search for free blocks - _Atomic(mi_msecs_t)purge_expire; // expiration time when blocks should be decommitted from `blocks_decommit`. - mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? - mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) - mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) - mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) + _Atomic(size_t) search_idx; // optimization to start the search for free blocks + _Atomic(mi_msecs_t) purge_expire; // expiration time when blocks should be purged from `blocks_purge`. + + mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? + mi_bitmap_field_t* blocks_committed; // are the blocks committed? (can be NULL for memory that cannot be decommitted) + mi_bitmap_field_t* blocks_purge; // blocks that can be (reset) decommitted. (can be NULL for memory that cannot be (reset) decommitted) + mi_bitmap_field_t* blocks_abandoned; // blocks that start with an abandoned segment. (This crosses API's but it is convenient to have here) mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) // do not add further fields here as the dirty, committed, purged, and abandoned bitmaps follow the inuse bitmap fields. } mi_arena_t; @@ -60,6 +61,7 @@ typedef struct mi_arena_s { // The available arenas static mi_decl_cache_align _Atomic(mi_arena_t*) mi_arenas[MI_MAX_ARENAS]; static mi_decl_cache_align _Atomic(size_t) mi_arena_count; // = 0 +static mi_decl_cache_align _Atomic(int64_t) mi_arenas_purge_expire; // set if there exist purgeable arenas #define MI_IN_ARENA_C #include "arena-abandon.c" @@ -349,11 +351,10 @@ static mi_decl_noinline void* mi_arena_try_alloc(int numa_node, size_t size, siz } // try to reserve a fresh arena space -static bool mi_arena_reserve(size_t req_size, bool allow_large, mi_arena_id_t req_arena_id, mi_arena_id_t *arena_id) +static bool mi_arena_reserve(size_t req_size, bool allow_large, mi_arena_id_t *arena_id) { if (_mi_preloading()) return false; // use OS only while pre loading - if (req_arena_id != _mi_arena_id_none()) return false; - + const size_t arena_count = mi_atomic_load_acquire(&mi_arena_count); if (arena_count > (MI_MAX_ARENAS - 4)) return false; @@ -403,7 +404,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset // otherwise, try to first eagerly reserve a new arena if (req_arena_id == _mi_arena_id_none()) { mi_arena_id_t arena_id = 0; - if (mi_arena_reserve(size, allow_large, req_arena_id, &arena_id)) { + if (mi_arena_reserve(size, allow_large, &arena_id)) { // and try allocate in there mi_assert_internal(req_arena_id == _mi_arena_id_none()); p = mi_arena_try_alloc_at_id(arena_id, true, numa_node, size, alignment, commit, allow_large, req_arena_id, memid); @@ -497,13 +498,16 @@ static void mi_arena_schedule_purge(mi_arena_t* arena, size_t bitmap_idx, size_t mi_arena_purge(arena, bitmap_idx, blocks); } else { - // schedule decommit - mi_msecs_t expire = mi_atomic_loadi64_relaxed(&arena->purge_expire); - if (expire != 0) { - mi_atomic_addi64_acq_rel(&arena->purge_expire, (mi_msecs_t)(delay/10)); // add smallish extra delay + // schedule purge + const mi_msecs_t expire = _mi_clock_now() + delay; + mi_msecs_t expire0 = 0; + if (mi_atomic_casi64_strong_acq_rel(&arena->purge_expire, &expire0, expire)) { + // expiration was not yet set + // maybe set the global arenas expire as well (if it wasn't set already) + mi_atomic_casi64_strong_acq_rel(&mi_arenas_purge_expire, &expire0, expire); } else { - mi_atomic_storei64_release(&arena->purge_expire, _mi_clock_now() + delay); + // already an expiration was set } _mi_bitmap_claim_across(arena->blocks_purge, arena->field_count, blocks, bitmap_idx, NULL); } @@ -538,14 +542,16 @@ static bool mi_arena_purge_range(mi_arena_t* arena, size_t idx, size_t startidx, // returns true if anything was purged static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force) { - if (arena->memid.is_pinned || arena->blocks_purge == NULL) return false; + // check pre-conditions + if (arena->memid.is_pinned) return false; + + // expired yet? mi_msecs_t expire = mi_atomic_loadi64_relaxed(&arena->purge_expire); - if (expire == 0) return false; - if (!force && expire > now) return false; + if (!force && (expire == 0 || expire > now)) return false; // reset expire (if not already set concurrently) mi_atomic_casi64_strong_acq_rel(&arena->purge_expire, &expire, (mi_msecs_t)0); - + // potential purges scheduled, walk through the bitmap bool any_purged = false; bool full_purge = true; @@ -592,9 +598,15 @@ static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force) return any_purged; } -static void mi_arenas_try_purge( bool force, bool visit_all ) { +static void mi_arenas_try_purge( bool force, bool visit_all ) +{ if (_mi_preloading() || mi_arena_purge_delay() <= 0) return; // nothing will be scheduled + // check if any arena needs purging? + const mi_msecs_t now = _mi_clock_now(); + mi_msecs_t arenas_expire = mi_atomic_load_acquire(&mi_arenas_purge_expire); + if (!force && (arenas_expire == 0 || arenas_expire < now)) return; + const size_t max_arena = mi_atomic_load_acquire(&mi_arena_count); if (max_arena == 0) return; @@ -602,17 +614,26 @@ static void mi_arenas_try_purge( bool force, bool visit_all ) { static mi_atomic_guard_t purge_guard; mi_atomic_guard(&purge_guard) { - mi_msecs_t now = _mi_clock_now(); - size_t max_purge_count = (visit_all ? max_arena : 1); + // increase global expire: at most one purge per delay cycle + mi_atomic_store_release(&mi_arenas_purge_expire, now + mi_arena_purge_delay()); + size_t max_purge_count = (visit_all ? max_arena : 2); + bool all_visited = true; for (size_t i = 0; i < max_arena; i++) { mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[i]); if (arena != NULL) { if (mi_arena_try_purge(arena, now, force)) { - if (max_purge_count <= 1) break; + if (max_purge_count <= 1) { + all_visited = false; + break; + } max_purge_count--; } } } + if (all_visited) { + // all arena's were visited and purged: reset global expire + mi_atomic_store_release(&mi_arenas_purge_expire, 0); + } } } From 825dd41769bc01984f7db515fe7df597a71547ab Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 21 Dec 2024 15:29:39 -0800 Subject: [PATCH 181/305] fix build error --- include/mimalloc/atomic.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index c6083102..c4fac766 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -457,6 +457,8 @@ static inline void mi_lock_done(mi_lock_t* lock) { #elif defined(MI_USE_PTHREADS) +void _mi_error_message(int err, const char* fmt, ...); + #define mi_lock_t pthread_mutex_t static inline bool mi_lock_try_acquire(mi_lock_t* lock) { @@ -465,7 +467,7 @@ static inline bool mi_lock_try_acquire(mi_lock_t* lock) { static inline void mi_lock_acquire(mi_lock_t* lock) { const int err = pthread_mutex_lock(lock); if (err != 0) { - mi_error_message(EFAULT, "internal error: lock cannot be acquired\n"); + _mi_error_message(err, "internal error: lock cannot be acquired\n"); } } static inline void mi_lock_release(mi_lock_t* lock) { From 7085b6cec31641fddaca3d40932cda82e91baf07 Mon Sep 17 00:00:00 2001 From: daanx Date: Sat, 21 Dec 2024 15:38:27 -0800 Subject: [PATCH 182/305] limit candidate search to 4 --- src/page.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page.c b/src/page.c index 8808c358..e1c07a93 100644 --- a/src/page.c +++ b/src/page.c @@ -732,7 +732,7 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi -------------------------------------------------------------*/ // search for a best next page to use for at most N pages (often cut short if immediate blocks are available) -#define MI_MAX_CANDIDATE_SEARCH (8) +#define MI_MAX_CANDIDATE_SEARCH (4) // is the page not yet used up to its reserved space? static bool mi_page_is_expandable(const mi_page_t* page) { From 83dacd190ef208e7e4aa792a8f46b12d75bbb952 Mon Sep 17 00:00:00 2001 From: Javier Blazquez Date: Sun, 22 Dec 2024 22:24:13 -0800 Subject: [PATCH 183/305] free segment map when destroy_on_exit is set --- include/mimalloc/internal.h | 1 + src/init.c | 1 + src/segment-map.c | 10 ++++++++++ 3 files changed, 12 insertions(+) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 8b22e1c6..b0e363cf 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -164,6 +164,7 @@ void _mi_arena_field_cursor_done(mi_arena_field_cursor_t* current); // "segment-map.c" void _mi_segment_map_allocated_at(const mi_segment_t* segment); void _mi_segment_map_freed_at(const mi_segment_t* segment); +void _mi_segment_map_destroy(void); // "segment.c" mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment, mi_segments_tld_t* tld); diff --git a/src/init.c b/src/init.c index 68a1d7e2..ab99a8f8 100644 --- a/src/init.c +++ b/src/init.c @@ -682,6 +682,7 @@ void mi_cdecl _mi_process_done(void) { mi_collect(true /* force */); _mi_heap_unsafe_destroy_all(); // forcefully release all memory held by all heaps (of this thread only!) _mi_arena_unsafe_destroy_all(); + _mi_segment_map_destroy(); } if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) { diff --git a/src/segment-map.c b/src/segment-map.c index 399f221c..f6dff96d 100644 --- a/src/segment-map.c +++ b/src/segment-map.c @@ -57,6 +57,7 @@ static mi_segmap_part_t* mi_segment_map_index_of(const mi_segment_t* segment, bo mi_memid_t memid; part = (mi_segmap_part_t*)_mi_os_alloc(sizeof(mi_segmap_part_t), &memid); if (part == NULL) return NULL; + part->memid = memid; mi_segmap_part_t* expected = NULL; if (!mi_atomic_cas_ptr_strong_release(mi_segmap_part_t, &mi_segment_map[segindex], &expected, part)) { _mi_os_free(part, sizeof(mi_segmap_part_t), memid); @@ -124,3 +125,12 @@ static bool mi_is_valid_pointer(const void* p) { mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { return mi_is_valid_pointer(p); } + +void _mi_segment_map_destroy(void) { + for (size_t i = 0; i < MI_SEGMENT_MAP_MAX_PARTS; i++) { + mi_segmap_part_t* part = mi_segment_map[i]; + if (part != NULL) { + _mi_os_free(part, sizeof(mi_segmap_part_t), part->memid); + } + } +} \ No newline at end of file From 095f848ae85b57fd0d478b2db150cf1821bbde47 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Tue, 24 Dec 2024 17:22:58 -0800 Subject: [PATCH 184/305] fix issue #976 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e84283fa..cde8144f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,7 +412,7 @@ if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) endif() if(MINGW) - add_definitions(-D_WIN32_WINNT=0x600) + add_definitions(-D_WIN32_WINNT=0x601) # issue #976 endif() if(MI_OPT_ARCH_FLAGS) From cfe73e9d48d6b27401f28ada8ac5d1a36b0f2747 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 25 Dec 2024 10:56:43 -0800 Subject: [PATCH 185/305] wip: merging from upstream --- include/mimalloc/types.h | 2 +- src/os.c | 47 +++++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/include/mimalloc/types.h b/include/mimalloc/types.h index ad948d36..f2fea3f7 100644 --- a/include/mimalloc/types.h +++ b/include/mimalloc/types.h @@ -377,7 +377,7 @@ static inline bool mi_memkind_is_os(mi_memkind_t memkind) { typedef struct mi_memid_os_info { void* base; // actual base address of the block (used for offset aligned allocations) - size_t alignment; // alignment at allocation + size_t size; // full allocation size } mi_memid_os_info_t; typedef struct mi_memid_arena_info { diff --git a/src/os.c b/src/os.c index 32cb11c3..7e7dcb2c 100644 --- a/src/os.c +++ b/src/os.c @@ -157,34 +157,42 @@ void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size) { } #endif - /* ----------------------------------------------------------- Free memory -------------------------------------------------------------- */ static void mi_os_free_huge_os_pages(void* p, size_t size); -static void mi_os_prim_free(void* addr, size_t size, bool still_committed) { +static void mi_os_prim_free(void* addr, size_t size, size_t commit_size) { mi_assert_internal((size % _mi_os_page_size()) == 0); if (addr == NULL || size == 0) return; // || _mi_os_is_huge_reserved(addr) int err = _mi_prim_free(addr, size); if (err != 0) { _mi_warning_message("unable to free OS memory (error: %d (0x%x), size: 0x%zx bytes, address: %p)\n", err, err, size, addr); } - if (still_committed) { _mi_stat_decrease(&os_stats->committed, size); } + if (commit_size > 0) { + _mi_stat_decrease(&os_stats->committed, commit_size); + } _mi_stat_decrease(&os_stats->reserved, size); } void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t memid) { if (mi_memkind_is_os(memid.memkind)) { - size_t csize = _mi_os_good_alloc_size(size); + size_t csize = memid.mem.os.size; + if (csize==0) { _mi_os_good_alloc_size(size); } + size_t commit_size = (still_committed ? csize : 0); void* base = addr; // different base? (due to alignment) - if (memid.mem.os.base != NULL) { - mi_assert(memid.mem.os.base <= addr); - mi_assert((uint8_t*)memid.mem.os.base + memid.mem.os.alignment >= (uint8_t*)addr); + if (memid.mem.os.base != base) { + mi_assert(memid.mem.os.base <= addr); base = memid.mem.os.base; - csize += ((uint8_t*)addr - (uint8_t*)memid.mem.os.base); + const size_t diff = (uint8_t*)addr - (uint8_t*)memid.mem.os.base; + if (memid.mem.os.size==0) { + csize += diff; + } + if (still_committed) { + commit_size -= diff; // the (addr-base) part was already un-committed + } } // free it if (memid.memkind == MI_MEM_OS_HUGE) { @@ -192,7 +200,7 @@ void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t me mi_os_free_huge_os_pages(base, csize); } else { - mi_os_prim_free(base, csize, still_committed); + mi_os_prim_free(base, csize, (still_committed ? commit_size : 0)); } } else { @@ -273,7 +281,7 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit #if !MI_TRACK_ASAN _mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n", size, p, alignment, commit); #endif - mi_os_prim_free(p, size, commit); + if (p != NULL) { mi_os_prim_free(p, size, (commit ? size : 0)); } if (size >= (SIZE_MAX - alignment)) return NULL; // overflow const size_t over_size = size + alignment; @@ -304,8 +312,8 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit size_t mid_size = _mi_align_up(size, _mi_os_page_size()); size_t post_size = over_size - pre_size - mid_size; mi_assert_internal(pre_size < over_size&& post_size < over_size&& mid_size >= size); - if (pre_size > 0) { mi_os_prim_free(p, pre_size, commit); } - if (post_size > 0) { mi_os_prim_free((uint8_t*)aligned_p + mid_size, post_size, commit); } + if (pre_size > 0) { mi_os_prim_free(p, pre_size, (commit ? pre_size : 0)); } + if (post_size > 0) { mi_os_prim_free((uint8_t*)aligned_p + mid_size, post_size, (commit ? post_size : 0)); } // we can return the aligned pointer on `mmap` systems p = aligned_p; *base = aligned_p; // since we freed the pre part, `*base == p`. @@ -446,8 +454,13 @@ bool _mi_os_commit(void* addr, size_t size, bool* is_zero) { return true; } -static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit) { mi_assert_internal(needs_recommit!=NULL); - _mi_stat_decrease(&os_stats->committed, size); +bool _mi_os_commit(void* addr, size_t size, bool* is_zero) { + return _mi_os_commit_ex(addr, size, is_zero, size); +} + +static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit, size_t stat_size) { + mi_assert_internal(needs_recommit!=NULL); + mi_os_stat_decrease(committed, stat_size); // page align size_t csize; @@ -466,7 +479,7 @@ static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit) { bool _mi_os_decommit(void* addr, size_t size) { bool needs_recommit; - return mi_os_decommit_ex(addr, size, &needs_recommit); + return mi_os_decommit_ex(addr, size, &needs_recommit, size); } @@ -628,7 +641,7 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse // no success, issue a warning and break if (p != NULL) { _mi_warning_message("could not allocate contiguous huge OS page %zu at %p\n", page, addr); - mi_os_prim_free(p, MI_HUGE_OS_PAGE_SIZE, true); + mi_os_prim_free(p, MI_HUGE_OS_PAGE_SIZE, MI_HUGE_OS_PAGE_SIZE); } break; } @@ -674,7 +687,7 @@ static void mi_os_free_huge_os_pages(void* p, size_t size) { if (p==NULL || size==0) return; uint8_t* base = (uint8_t*)p; while (size >= MI_HUGE_OS_PAGE_SIZE) { - mi_os_prim_free(base, MI_HUGE_OS_PAGE_SIZE, true); + mi_os_prim_free(base, MI_HUGE_OS_PAGE_SIZE, MI_HUGE_OS_PAGE_SIZE); size -= MI_HUGE_OS_PAGE_SIZE; base += MI_HUGE_OS_PAGE_SIZE; } From 587e08ccd44430bb3f5d2975653fffd18008de24 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 25 Dec 2024 11:12:26 -0800 Subject: [PATCH 186/305] improve commit stats --- include/mimalloc/internal.h | 2 +- src/arena.c | 3 +-- src/os.c | 41 ++++++++++++++++++++----------------- test/test-stress.c | 3 ++- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 8b22e1c6..48ec3f1c 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -121,7 +121,7 @@ bool _mi_os_decommit(void* addr, size_t size); bool _mi_os_protect(void* addr, size_t size); bool _mi_os_unprotect(void* addr, size_t size); bool _mi_os_purge(void* p, size_t size); -bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset); +bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, size_t stat_size); void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid); void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t align_offset, bool commit, bool allow_large, mi_memid_t* memid); diff --git a/src/arena.c b/src/arena.c index 0ddb2936..5952c544 100644 --- a/src/arena.c +++ b/src/arena.c @@ -474,8 +474,7 @@ static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks) // we need to ensure we do not try to reset (as that may be invalid for uncommitted memory), // and also undo the decommit stats (as it was already adjusted) mi_assert_internal(mi_option_is_enabled(mi_option_purge_decommits)); - needs_recommit = _mi_os_purge_ex(p, size, false /* allow reset? */); - if (needs_recommit) { _mi_stat_increase(&_mi_stats_main.committed, size); } + needs_recommit = _mi_os_purge_ex(p, size, false /* allow reset? */, 0); } // clear the purged blocks diff --git a/src/os.c b/src/os.c index 7e7dcb2c..77469775 100644 --- a/src/os.c +++ b/src/os.c @@ -9,7 +9,9 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc/atomic.h" #include "mimalloc/prim.h" -#define os_stats (&_mi_stats_main) +#define mi_os_stat_increase(stat,amount) _mi_stat_increase(&_mi_stats_main.stat, amount) +#define mi_os_stat_decrease(stat,amount) _mi_stat_decrease(&_mi_stats_main.stat, amount) +#define mi_os_stat_counter_increase(stat,inc) _mi_stat_counter_increase(&_mi_stats_main.stat, inc) /* ----------------------------------------------------------- Initialization. @@ -171,9 +173,9 @@ static void mi_os_prim_free(void* addr, size_t size, size_t commit_size) { _mi_warning_message("unable to free OS memory (error: %d (0x%x), size: 0x%zx bytes, address: %p)\n", err, err, size, addr); } if (commit_size > 0) { - _mi_stat_decrease(&os_stats->committed, commit_size); + mi_os_stat_decrease(committed, commit_size); } - _mi_stat_decrease(&os_stats->reserved, size); + mi_os_stat_decrease(reserved, size); } void _mi_os_free_ex(void* addr, size_t size, bool still_committed, mi_memid_t memid) { @@ -236,11 +238,11 @@ static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignm - mi_stat_counter_increase(os_stats->mmap_calls, 1); + mi_os_stat_counter_increase(mmap_calls, 1); if (p != NULL) { - _mi_stat_increase(&os_stats->reserved, size); + mi_os_stat_increase(reserved, size); if (commit) { - _mi_stat_increase(&os_stats->committed, size); + mi_os_stat_increase(committed, size); // seems needed for asan (or `mimalloc-test-api` fails) #ifdef MI_TRACK_ASAN if (*is_zero) { mi_track_mem_defined(p,size); } @@ -357,7 +359,8 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allo if (p != NULL) { *memid = _mi_memid_create_os(commit, os_is_zero, os_is_large); memid->mem.os.base = os_base; - memid->mem.os.alignment = alignment; + // memid->mem.os.alignment = alignment; + memid->mem.os.size += ((uint8_t*)p - (uint8_t*)os_base); // todo: return from prim_alloc_aligned } return p; } @@ -425,10 +428,10 @@ static void* mi_os_page_align_area_conservative(void* addr, size_t size, size_t* return mi_os_page_align_areax(true, addr, size, newsize); } -bool _mi_os_commit(void* addr, size_t size, bool* is_zero) { +bool _mi_os_commit_ex(void* addr, size_t size, bool* is_zero, size_t stat_size) { if (is_zero != NULL) { *is_zero = false; } - _mi_stat_increase(&os_stats->committed, size); // use size for precise commit vs. decommit - _mi_stat_counter_increase(&os_stats->commit_calls, 1); + mi_os_stat_increase(committed, stat_size); // use size for precise commit vs. decommit + mi_os_stat_counter_increase(commit_calls, 1); // page align range size_t csize; @@ -492,8 +495,8 @@ bool _mi_os_reset(void* addr, size_t size) { size_t csize; void* start = mi_os_page_align_area_conservative(addr, size, &csize); if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr) - _mi_stat_increase(&os_stats->reset, csize); - _mi_stat_counter_increase(&os_stats->reset_calls, 1); + mi_os_stat_increase(reset, csize); + mi_os_stat_counter_increase(reset_calls, 1); #if (MI_DEBUG>1) && !MI_SECURE && !MI_TRACK_ENABLED // && !MI_TSAN memset(start, 0, csize); // pretend it is eagerly reset @@ -509,17 +512,17 @@ bool _mi_os_reset(void* addr, size_t size) { // either resets or decommits memory, returns true if the memory needs // to be recommitted if it is to be re-used later on. -bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset) +bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, size_t stat_size) { if (mi_option_get(mi_option_purge_delay) < 0) return false; // is purging allowed? - _mi_stat_counter_increase(&os_stats->purge_calls, 1); - _mi_stat_increase(&os_stats->purged, size); + mi_os_stat_counter_increase(purge_calls, 1); + mi_os_stat_increase(purged, size); if (mi_option_is_enabled(mi_option_purge_decommits) && // should decommit? !_mi_preloading()) // don't decommit during preloading (unsafe) { bool needs_recommit = true; - mi_os_decommit_ex(p, size, &needs_recommit); + mi_os_decommit_ex(p, size, &needs_recommit, stat_size); return needs_recommit; } else { @@ -533,7 +536,7 @@ bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset) // either resets or decommits memory, returns true if the memory needs // to be recommitted if it is to be re-used later on. bool _mi_os_purge(void* p, size_t size) { - return _mi_os_purge_ex(p, size, true); + return _mi_os_purge_ex(p, size, true, size); } @@ -648,8 +651,8 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse // success, record it page++; // increase before timeout check (see issue #711) - _mi_stat_increase(&os_stats->committed, MI_HUGE_OS_PAGE_SIZE); - _mi_stat_increase(&os_stats->reserved, MI_HUGE_OS_PAGE_SIZE); + mi_os_stat_increase(committed, MI_HUGE_OS_PAGE_SIZE); + mi_os_stat_increase(reserved, MI_HUGE_OS_PAGE_SIZE); // check for timeout if (max_msecs > 0) { diff --git a/test/test-stress.c b/test/test-stress.c index 6284ad39..9b8eb2d0 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -64,6 +64,7 @@ static bool main_participates = false; // main thread participates as a #define custom_calloc(n,s) mi_calloc(n,s) #define custom_realloc(p,s) mi_realloc(p,s) #define custom_free(p) mi_free(p) + #ifndef NDEBUG #define HEAP_WALK // walk the heap objects? #endif @@ -223,7 +224,7 @@ static void test_stress(void) { run_os_threads(THREADS, &stress); #if !defined(NDEBUG) && !defined(USE_STD_MALLOC) // switch between arena and OS allocation for testing - mi_option_set_enabled(mi_option_disallow_arena_alloc, (n%2)==1); + // mi_option_set_enabled(mi_option_disallow_arena_alloc, (n%2)==1); #endif #ifdef HEAP_WALK size_t total = 0; From 63f47569f2c3211d13b8acac932ef78f4445f771 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 25 Dec 2024 13:35:54 -0800 Subject: [PATCH 187/305] fix debug_show_arenas parameters --- include/mimalloc.h | 2 +- src/arena.c | 22 +++++++++++----------- test/test-stress.c | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 5916228b..95a76c2d 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -276,7 +276,7 @@ mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size mi_decl_export int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept; mi_decl_export bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node) mi_attr_noexcept; -mi_decl_export void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge) mi_attr_noexcept; +mi_decl_export void mi_debug_show_arenas(bool show_inuse) mi_attr_noexcept; // Experimental: heaps associated with specific memory arena's typedef int mi_arena_id_t; diff --git a/src/arena.c b/src/arena.c index 5952c544..0e508115 100644 --- a/src/arena.c +++ b/src/arena.c @@ -911,11 +911,11 @@ static size_t mi_debug_show_bitmap(const char* prefix, const char* header, size_ return inuse_count; } -void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge) mi_attr_noexcept { +void mi_debug_show_arenas(bool show_inuse) mi_attr_noexcept { size_t max_arenas = mi_atomic_load_relaxed(&mi_arena_count); size_t inuse_total = 0; - size_t abandoned_total = 0; - size_t purge_total = 0; + //size_t abandoned_total = 0; + //size_t purge_total = 0; for (size_t i = 0; i < max_arenas; i++) { mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[i]); if (arena == NULL) break; @@ -926,16 +926,16 @@ void mi_debug_show_arenas(bool show_inuse, bool show_abandoned, bool show_purge) if (arena->blocks_committed != NULL) { mi_debug_show_bitmap(" ", "committed blocks", arena->block_count, arena->blocks_committed, arena->field_count); } - if (show_abandoned) { - abandoned_total += mi_debug_show_bitmap(" ", "abandoned blocks", arena->block_count, arena->blocks_abandoned, arena->field_count); - } - if (show_purge && arena->blocks_purge != NULL) { - purge_total += mi_debug_show_bitmap(" ", "purgeable blocks", arena->block_count, arena->blocks_purge, arena->field_count); - } + //if (show_abandoned) { + // abandoned_total += mi_debug_show_bitmap(" ", "abandoned blocks", arena->block_count, arena->blocks_abandoned, arena->field_count); + //} + //if (show_purge && arena->blocks_purge != NULL) { + // purge_total += mi_debug_show_bitmap(" ", "purgeable blocks", arena->block_count, arena->blocks_purge, arena->field_count); + //} } if (show_inuse) _mi_verbose_message("total inuse blocks : %zu\n", inuse_total); - if (show_abandoned) _mi_verbose_message("total abandoned blocks: %zu\n", abandoned_total); - if (show_purge) _mi_verbose_message("total purgeable blocks: %zu\n", purge_total); + //if (show_abandoned) _mi_verbose_message("total abandoned blocks: %zu\n", abandoned_total); + //if (show_purge) _mi_verbose_message("total purgeable blocks: %zu\n", purge_total); } diff --git a/test/test-stress.c b/test/test-stress.c index 9b8eb2d0..8c5fca9c 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -238,7 +238,7 @@ static void test_stress(void) { } #ifndef NDEBUG //mi_collect(false); - //mi_debug_show_arenas(); + //mi_debug_show_arenas(true); #endif #if !defined(NDEBUG) || defined(MI_TSAN) if ((n + 1) % 10 == 0) { printf("- iterations left: %3d\n", ITER - (n + 1)); } @@ -316,7 +316,7 @@ int main(int argc, char** argv) { #ifndef USE_STD_MALLOC #ifndef NDEBUG - mi_debug_show_arenas(true,true,true); + mi_debug_show_arenas(true); mi_collect(true); #endif #endif From 34cdf1a49f092b90b76bbc6a71cb743e1f1985c6 Mon Sep 17 00:00:00 2001 From: daanx Date: Wed, 25 Dec 2024 13:56:38 -0800 Subject: [PATCH 188/305] fix eager delayed setting --- src/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index a93ea218..1390e77a 100644 --- a/src/segment.c +++ b/src/segment.c @@ -886,7 +886,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, size_t page_alignment, mi // Commit eagerly only if not the first N lazy segments (to reduce impact of many threads that allocate just a little) const bool eager_delay = (// !_mi_os_has_overcommit() && // never delay on overcommit systems _mi_current_thread_count() > 1 && // do not delay for the first N threads - tld->count < (size_t)mi_option_get(mi_option_eager_commit_delay)); + tld->peak_count < (size_t)mi_option_get(mi_option_eager_commit_delay)); const bool eager = !eager_delay && mi_option_is_enabled(mi_option_eager_commit); bool commit = eager || (required > 0); From 47b5f48b2909055dfe0e3caea5ec13cad74369bb Mon Sep 17 00:00:00 2001 From: daanx Date: Thu, 26 Dec 2024 09:52:46 -0800 Subject: [PATCH 189/305] renamed vcxproj --- CMakeLists.txt | 16 ++- ...{mimalloc.vcxproj => mimalloc-lib.vcxproj} | 2 +- ....vcxproj => mimalloc-override-dll.vcxproj} | 2 +- ide/vs2022/mimalloc-override-test.vcxproj | 2 +- ide/vs2022/mimalloc-override.vcxproj.filters | 113 ------------------ ide/vs2022/mimalloc-test-api.vcxproj | 2 +- ide/vs2022/mimalloc-test-stress.vcxproj | 2 +- ide/vs2022/mimalloc-test.vcxproj | 2 +- ide/vs2022/mimalloc.sln | 4 +- ide/vs2022/mimalloc.vcxproj.filters | 105 ---------------- include/mimalloc/internal.h | 2 +- include/mimalloc/prim.h | 37 +++++- src/prim/windows/prim.c | 12 +- 13 files changed, 67 insertions(+), 234 deletions(-) rename ide/vs2022/{mimalloc.vcxproj => mimalloc-lib.vcxproj} (99%) rename ide/vs2022/{mimalloc-override.vcxproj => mimalloc-override-dll.vcxproj} (99%) delete mode 100644 ide/vs2022/mimalloc-override.vcxproj.filters delete mode 100644 ide/vs2022/mimalloc.vcxproj.filters diff --git a/CMakeLists.txt b/CMakeLists.txt index cde8144f..ca69fc6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON) option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON) option(MI_WIN_REDIRECT "Use redirection module ('mimalloc-redirect') on Windows if compiling mimalloc as a DLL" ON) +option(MI_WIN_USE_FIXED_TLS "Use a fixed TLS slot on Windows to avoid extra tests in the malloc fast path" OFF) option(MI_LOCAL_DYNAMIC_TLS "Use local-dynamic-tls, a slightly slower but dlopen-compatible thread local storage mechanism (Unix)" OFF) option(MI_LIBC_MUSL "Set this when linking with musl libc" OFF) option(MI_BUILD_SHARED "Build shared library" ON) @@ -35,7 +36,7 @@ option(MI_NO_THP "Disable transparent huge pages support on Linux/And option(MI_EXTRA_CPPDEFS "Extra pre-processor definitions (use as `-DMI_EXTRA_CPPDEFS=\"opt1=val1;opt2=val2\"`)" "") # deprecated options -option(MI_WIN_USE_FLS "Use Fiber local storage on Windows to detect thread termination" OFF) +option(MI_WIN_USE_FLS "Use Fiber local storage on Windows to detect thread termination (deprecated)" OFF) option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) option(MI_USE_LIBATOMIC "Explicitly link with -latomic (on older systems) (deprecated and detected automatically)" OFF) @@ -90,7 +91,7 @@ endif() if (CMAKE_GENERATOR MATCHES "^Visual Studio.*$") message(STATUS "Note: when building with Visual Studio the build type is specified when building.") - message(STATUS "For example: 'cmake --build . --config=Release") + message(STATUS "For example: 'cmake --build . --config=Release") endif() if("${CMAKE_BINARY_DIR}" MATCHES ".*(S|s)ecure$") @@ -322,10 +323,15 @@ if(MI_LIBC_MUSL) endif() if(MI_WIN_USE_FLS) - message(STATUS "Use the Fiber API to detect thread termination (MI_WIN_USE_FLS=ON)") + message(STATUS "Use the Fiber API to detect thread termination (deprecated) (MI_WIN_USE_FLS=ON)") list(APPEND mi_defines MI_WIN_USE_FLS=1) endif() +if(MI_WIN_USE_FIXED_TLS) + message(STATUS "Use fixed TLS slot on Windows to avoid extra tests in the malloc fast path (MI_WIN_USE_FIXED_TLS=ON)") + list(APPEND mi_defines MI_WIN_USE_FIXED_TLS=1) +endif() + # Determine architecture set(MI_OPT_ARCH_FLAGS "") set(MI_ARCH "unknown") @@ -543,7 +549,7 @@ if(MI_BUILD_SHARED) elseif(MI_ARCH STREQUAL "x64") set(MIMALLOC_REDIRECT_SUFFIX "") if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64") - message(STATUS "Note: x64 code emulated on Windows for arm64 should use an arm64ec build of 'mimalloc-override.dll'") + message(STATUS "Note: x64 code emulated on Windows for arm64 should use an arm64ec build of 'mimalloc-override.dll'") message(STATUS " with 'mimalloc-redirect-arm64ec.dll'. See the 'bin\\readme.md' for more information.") endif() elseif(MI_ARCH STREQUAL "x86") @@ -667,7 +673,7 @@ endif() # ----------------------------------------------------------------------------- if (MI_OVERRIDE) if (MI_BUILD_SHARED) - target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) + target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) endif() if(NOT WIN32) # It is only possible to override malloc on Windows when building as a DLL. diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc-lib.vcxproj similarity index 99% rename from ide/vs2022/mimalloc.vcxproj rename to ide/vs2022/mimalloc-lib.vcxproj index 9964310d..6c652b8a 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc-lib.vcxproj @@ -37,7 +37,7 @@ 15.0 {ABB5EAE7-B3E6-432E-B636-333449892EA6} - mimalloc + mimalloc-lib 10.0 mimalloc-lib diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override-dll.vcxproj similarity index 99% rename from ide/vs2022/mimalloc-override.vcxproj rename to ide/vs2022/mimalloc-override-dll.vcxproj index 1278cd0f..c1849bb2 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override-dll.vcxproj @@ -37,7 +37,7 @@ 15.0 {ABB5EAE7-B3E6-432E-B636-333449892EA7} - mimalloc-override + mimalloc-override-dll 10.0 mimalloc-override-dll diff --git a/ide/vs2022/mimalloc-override-test.vcxproj b/ide/vs2022/mimalloc-override-test.vcxproj index 0e87cf36..427a75ae 100644 --- a/ide/vs2022/mimalloc-override-test.vcxproj +++ b/ide/vs2022/mimalloc-override-test.vcxproj @@ -344,7 +344,7 @@ - + {abb5eae7-b3e6-432e-b636-333449892ea7} diff --git a/ide/vs2022/mimalloc-override.vcxproj.filters b/ide/vs2022/mimalloc-override.vcxproj.filters deleted file mode 100644 index a9f66c35..00000000 --- a/ide/vs2022/mimalloc-override.vcxproj.filters +++ /dev/null @@ -1,113 +0,0 @@ - - - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - - - {9ef1cf48-7bb2-4af1-8cc1-603486e08a7a} - - - {cfcf1674-81e3-487a-a8dd-5f956ae4007d} - - - - - Headers - - - \ No newline at end of file diff --git a/ide/vs2022/mimalloc-test-api.vcxproj b/ide/vs2022/mimalloc-test-api.vcxproj index 27247569..b7f97ad2 100644 --- a/ide/vs2022/mimalloc-test-api.vcxproj +++ b/ide/vs2022/mimalloc-test-api.vcxproj @@ -282,7 +282,7 @@ - + {abb5eae7-b3e6-432e-b636-333449892ea6} diff --git a/ide/vs2022/mimalloc-test-stress.vcxproj b/ide/vs2022/mimalloc-test-stress.vcxproj index fd88cd8e..cb761f94 100644 --- a/ide/vs2022/mimalloc-test-stress.vcxproj +++ b/ide/vs2022/mimalloc-test-stress.vcxproj @@ -279,7 +279,7 @@ - + {abb5eae7-b3e6-432e-b636-333449892ea6} diff --git a/ide/vs2022/mimalloc-test.vcxproj b/ide/vs2022/mimalloc-test.vcxproj index 6e4576fd..83202dbe 100644 --- a/ide/vs2022/mimalloc-test.vcxproj +++ b/ide/vs2022/mimalloc-test.vcxproj @@ -276,7 +276,7 @@ - + {abb5eae7-b3e6-432e-b636-333449892ea6} diff --git a/ide/vs2022/mimalloc.sln b/ide/vs2022/mimalloc.sln index 5a55c98b..040af3ac 100644 --- a/ide/vs2022/mimalloc.sln +++ b/ide/vs2022/mimalloc.sln @@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.12.35527.113 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-lib", "mimalloc-lib.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-dll", "mimalloc-override-dll.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" EndProject diff --git a/ide/vs2022/mimalloc.vcxproj.filters b/ide/vs2022/mimalloc.vcxproj.filters deleted file mode 100644 index 54ee0fcb..00000000 --- a/ide/vs2022/mimalloc.vcxproj.filters +++ /dev/null @@ -1,105 +0,0 @@ - - - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - Sources - - - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - Headers - - - - - {dd2da697-c33c-4348-bf80-a802ebaa06fb} - - - {8027057b-4b93-4321-b93c-d51dd0c8077b} - - - \ No newline at end of file diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 48ec3f1c..ecb49a4e 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -419,7 +419,7 @@ static inline bool mi_heap_is_backing(const mi_heap_t* heap) { static inline bool mi_heap_is_initialized(mi_heap_t* heap) { mi_assert_internal(heap != NULL); - return (heap != &_mi_heap_empty); + return (heap != NULL && heap != &_mi_heap_empty); } static inline uintptr_t _mi_ptr_cookie(const void* p) { diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index 56715df4..c21ffa63 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +Copyright (c) 2018-2024, 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. @@ -129,6 +129,7 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap); // for each thread (unequal to zero). //------------------------------------------------------------------- + // On some libc + platform combinations we can directly access a thread-local storage (TLS) slot. // The TLS layout depends on both the OS and libc implementation so we use specific tests for each main platform. // If you test on another platform and it works please send a PR :-) @@ -206,8 +207,40 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce #endif } +#elif _WIN32 && MI_WIN_USE_FIXED_TLS && !defined(MI_WIN_USE_FLS) + +// On windows we can store the thread-local heap at a fixed TLS slot to avoid +// thread-local initialization checks in the fast path. This use a fixed location +// in the TCB though (last user-reserved slot by default) which may clash with other applications. + +#define MI_HAS_TLS_SLOT 2 // 2 = we can reliable initialize the slot (saving a test on each malloc) + +#if MI_WIN_USE_FIXED_TLS > 1 +#define MI_TLS_SLOT (MI_WIN_USE_FIXED_TLS) +#elif MI_SIZE_SIZE == 4 +#define MI_TLS_SLOT (0x710) // Last user-reserved slot +// #define MI_TLS_SLOT (0xF0C) // Last TlsSlot (might clash with other app reserved slot) +#else +#define MI_TLS_SLOT (0x888) // Last user-reserved slot +// #define MI_TLS_SLOT (0x1678) // Last TlsSlot (might clash with other app reserved slot) #endif +static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept { + #if (_M_X64 || _M_AMD64) && !defined(_M_ARM64EC) + return (void*)__readgsqword((unsigned long)slot); // direct load at offset from gs + #elif _M_IX86 && !defined(_M_ARM64EC) + return (void*)__readfsdword((unsigned long)slot); // direct load at offset from fs + #else + return ((void**)NtCurrentTeb())[slot / sizeof(void*)]; + #endif +} +static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { + ((void**)NtCurrentTeb())[slot / sizeof(void*)] = value; +} + +#endif + + // Do we have __builtin_thread_pointer? This would be the preferred way to get a unique thread id // but unfortunately, it seems we cannot test for this reliably at this time (see issue #883) // Nevertheless, it seems needed on older graviton platforms (see issue #851). @@ -322,12 +355,14 @@ static inline mi_heap_t* mi_prim_get_default_heap(void); static inline mi_heap_t* mi_prim_get_default_heap(void) { mi_heap_t* heap = (mi_heap_t*)mi_prim_tls_slot(MI_TLS_SLOT); + #if MI_TLS_SLOT == 1 // check if the TLS slot is initialized if mi_unlikely(heap == NULL) { #ifdef __GNUC__ __asm(""); // prevent conditional load of the address of _mi_heap_empty #endif heap = (mi_heap_t*)&_mi_heap_empty; } + #endif return heap; } diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 1d3d6f41..ac228b53 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -622,6 +622,11 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) { static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { MI_UNUSED(reserved); MI_UNUSED(module); + #if MI_TLS_SLOT >= 2 + if ((reason==DLL_PROCESS_ATTACH || reason==DLL_THREAD_ATTACH) && mi_prim_get_default_heap() == NULL) { + _mi_heap_set_default_direct((mi_heap_t*)&_mi_heap_empty); + } + #endif if (reason==DLL_PROCESS_ATTACH) { _mi_process_load(); } @@ -630,7 +635,7 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { } else if (reason==DLL_THREAD_DETACH && !_mi_is_redirected()) { _mi_thread_done(NULL); - } + } } @@ -783,6 +788,11 @@ static void NTAPI mi_win_main(PVOID module, DWORD reason, LPVOID reserved) { #endif mi_decl_export void _mi_redirect_entry(DWORD reason) { // called on redirection; careful as this may be called before DllMain + #if MI_TLS_SLOT >= 2 + if ((reason==DLL_PROCESS_ATTACH || reason==DLL_THREAD_ATTACH) && mi_prim_get_default_heap() == NULL) { + _mi_heap_set_default_direct((mi_heap_t*)&_mi_heap_empty); + } + #endif if (reason == DLL_PROCESS_ATTACH) { mi_redirected = true; } From 783dcb4129730928ffb6a43da7d2df14a45a3e6f Mon Sep 17 00:00:00 2001 From: daanx Date: Thu, 26 Dec 2024 10:24:20 -0800 Subject: [PATCH 190/305] add comments about TLS --- include/mimalloc/prim.h | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index c21ffa63..aa0b188d 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -119,17 +119,15 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap); -//------------------------------------------------------------------- -// Thread id: `_mi_prim_thread_id()` -// -// Getting the thread id should be performant as it is called in the -// fast path of `_mi_free` and we specialize for various platforms as -// inlined definitions. Regular code should call `init.c:_mi_thread_id()`. -// We only require _mi_prim_thread_id() to return a unique id -// for each thread (unequal to zero). -//------------------------------------------------------------------- +//------------------------------------------------------------------- +// Access to TLS (thread local storage) slots. +// We need fast access to both a unique thread id (in `free.c:mi_free`) and +// to a thread-local heap pointer (in `alloc.c:mi_malloc`). +// To achieve this we use specialized code for various platforms. +//------------------------------------------------------------------- + // On some libc + platform combinations we can directly access a thread-local storage (TLS) slot. // The TLS layout depends on both the OS and libc implementation so we use specific tests for each main platform. // If you test on another platform and it works please send a PR :-) @@ -210,7 +208,7 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce #elif _WIN32 && MI_WIN_USE_FIXED_TLS && !defined(MI_WIN_USE_FLS) // On windows we can store the thread-local heap at a fixed TLS slot to avoid -// thread-local initialization checks in the fast path. This use a fixed location +// thread-local initialization checks in the fast path. This uses a fixed location // in the TCB though (last user-reserved slot by default) which may clash with other applications. #define MI_HAS_TLS_SLOT 2 // 2 = we can reliable initialize the slot (saving a test on each malloc) @@ -241,6 +239,18 @@ static inline void mi_prim_tls_slot_set(size_t slot, void* value) mi_attr_noexce #endif + +//------------------------------------------------------------------- +// Get a fast unique thread id. +// +// Getting the thread id should be performant as it is called in the +// fast path of `_mi_free` and we specialize for various platforms as +// inlined definitions. Regular code should call `init.c:_mi_thread_id()`. +// We only require _mi_prim_thread_id() to return a unique id +// for each thread (unequal to zero). +//------------------------------------------------------------------- + + // Do we have __builtin_thread_pointer? This would be the preferred way to get a unique thread id // but unfortunately, it seems we cannot test for this reliably at this time (see issue #883) // Nevertheless, it seems needed on older graviton platforms (see issue #851). @@ -311,7 +321,8 @@ static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept { /* ---------------------------------------------------------------------------------------- -The thread local default heap: `_mi_prim_get_default_heap()` +Get the thread local default heap: `_mi_prim_get_default_heap()` + This is inlined here as it is on the fast path for allocation functions. On most platforms (Windows, Linux, FreeBSD, NetBSD, etc), this just returns a @@ -404,7 +415,4 @@ static inline mi_heap_t* mi_prim_get_default_heap(void) { #endif // mi_prim_get_default_heap() - - - #endif // MIMALLOC_PRIM_H From e10d0d2dee8a7c4d010bea1af0f4ed6815d480f9 Mon Sep 17 00:00:00 2001 From: daanx Date: Thu, 26 Dec 2024 10:33:25 -0800 Subject: [PATCH 191/305] add declspec hidden to improve codegen on arm64 --- include/mimalloc/internal.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index ecb49a4e..1302e128 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -31,16 +31,19 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_decl_thread __declspec(thread) #define mi_decl_cache_align __declspec(align(MI_CACHE_LINE)) #define mi_decl_weak +#define mi_decl_hidden #elif (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) // 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))) #define mi_decl_weak __attribute__((weak)) +#define mi_decl_hidden __attribute__((visibility("hidden"))) #else #define mi_decl_noinline #define mi_decl_thread __thread // hope for the best :-) #define mi_decl_cache_align #define mi_decl_weak +#define mi_decl_hidden #endif #if defined(__EMSCRIPTEN__) && !defined(__wasi__) @@ -87,7 +90,7 @@ static inline uintptr_t _mi_random_shuffle(uintptr_t x); // init.c extern mi_decl_cache_align mi_stats_t _mi_stats_main; -extern mi_decl_cache_align const mi_page_t _mi_page_empty; +extern mi_decl_hidden mi_decl_cache_align const mi_page_t _mi_page_empty; void _mi_process_load(void); void mi_cdecl _mi_process_done(void); bool _mi_is_redirected(void); @@ -411,7 +414,7 @@ static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* tot Heap functions ------------------------------------------------------------------------------------------- */ -extern const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value of the thread local default heap +extern mi_decl_hidden const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value of the thread local default heap static inline bool mi_heap_is_backing(const mi_heap_t* heap) { return (heap->tld->heap_backing == heap); @@ -423,7 +426,7 @@ static inline bool mi_heap_is_initialized(mi_heap_t* heap) { } static inline uintptr_t _mi_ptr_cookie(const void* p) { - extern mi_heap_t _mi_heap_main; + extern mi_decl_hidden mi_heap_t _mi_heap_main; mi_assert_internal(_mi_heap_main.cookie != 0); return ((uintptr_t)p ^ _mi_heap_main.cookie); } @@ -808,7 +811,7 @@ static inline uintptr_t _mi_random_shuffle(uintptr_t x) { int _mi_os_numa_node_get(void); size_t _mi_os_numa_node_count_get(void); -extern _Atomic(size_t) _mi_numa_node_count; +extern mi_decl_hidden _Atomic(size_t) _mi_numa_node_count; static inline int _mi_os_numa_node(void) { if mi_likely(mi_atomic_load_relaxed(&_mi_numa_node_count) == 1) { return 0; } else return _mi_os_numa_node_get(); From 095abc9e3d71ced049d7b6a400cb3866cc2d5999 Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 26 Dec 2024 11:16:04 -0800 Subject: [PATCH 192/305] fix TLS slot on macOS --- include/mimalloc/prim.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index aa0b188d..9a1ab4f9 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -144,7 +144,7 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap); || (defined(__OpenBSD__) && (defined(__x86_64__) || defined(__i386__) || defined(__aarch64__))) \ ) -#define MI_HAS_TLS_SLOT +#define MI_HAS_TLS_SLOT 1 static inline void* mi_prim_tls_slot(size_t slot) mi_attr_noexcept { void* res; @@ -294,7 +294,7 @@ static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept { return (uintptr_t)__builtin_thread_pointer(); } -#elif defined(MI_HAS_TLS_SLOT) +#elif MI_HAS_TLS_SLOT static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept { #if defined(__BIONIC__) @@ -359,14 +359,14 @@ static inline mi_heap_t* mi_prim_get_default_heap(void); #endif -#if defined(MI_TLS_SLOT) +#if MI_TLS_SLOT # if !defined(MI_HAS_TLS_SLOT) # error "trying to use a TLS slot for the default heap, but the mi_prim_tls_slot primitives are not defined" # endif static inline mi_heap_t* mi_prim_get_default_heap(void) { mi_heap_t* heap = (mi_heap_t*)mi_prim_tls_slot(MI_TLS_SLOT); - #if MI_TLS_SLOT == 1 // check if the TLS slot is initialized + #if MI_HAS_TLS_SLOT == 1 // check if the TLS slot is initialized if mi_unlikely(heap == NULL) { #ifdef __GNUC__ __asm(""); // prevent conditional load of the address of _mi_heap_empty From 7bd1d72bfba01a5551d6fac0f104055fc5bfcc56 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 30 Dec 2024 10:33:13 -0800 Subject: [PATCH 193/305] Update readme.md to fix links (issue #978) --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 11f62da4..8cb9ffff 100644 --- a/readme.md +++ b/readme.md @@ -253,7 +253,7 @@ to link with the static library. See `test\CMakeLists.txt` for an example. For best performance in C++ programs, it is also recommended to override the global `new` and `delete` operators. For convenience, mimalloc provides -[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project. +[`mimalloc-new-delete.h`](include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project. In C++, mimalloc also provides the `mi_stl_allocator` struct which implements the `std::allocator` interface. @@ -458,7 +458,7 @@ There are four requirements to make the overriding work well: For best performance on Windows with C++, it is also recommended to also override the `new`/`delete` operations (by including -[`mimalloc-new-delete.h`](../include/mimalloc-new-delete.h) +[`mimalloc-new-delete.h`](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 @@ -487,7 +487,7 @@ object file. For example: Another way to override statically that works on all platforms, is to link statically to mimalloc (as shown in the introduction) and include a header file in each source file that re-defines `malloc` etc. to `mi_malloc`. -This is provided by [`mimalloc-override.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-override.h). This only works reliably though if all sources are +This is provided by [`mimalloc-override.h`](include/mimalloc-override.h). This only works reliably though if all sources are under your control or otherwise mixing of pointers from different heaps may occur! From 9561ae428612d8fa5d2d7683d2c5f2276e982175 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 30 Dec 2024 11:00:54 -0800 Subject: [PATCH 194/305] rename segment_map_destroy to segment_map_unsafe_destroy --- include/mimalloc/atomic.h | 3 +++ include/mimalloc/internal.h | 2 +- src/init.c | 2 +- src/segment-map.c | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index c4fac766..5725bfbf 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -72,6 +72,7 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_atomic_load_relaxed(p) mi_atomic(load_explicit)(p,mi_memory_order(relaxed)) #define mi_atomic_store_release(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(release)) #define mi_atomic_store_relaxed(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(relaxed)) +#define mi_atomic_exchange_relaxed(p,x) mi_atomic(exchange_explicit)(p,x,mi_memory_order(relaxed)) #define mi_atomic_exchange_release(p,x) mi_atomic(exchange_explicit)(p,x,mi_memory_order(release)) #define mi_atomic_exchange_acq_rel(p,x) mi_atomic(exchange_explicit)(p,x,mi_memory_order(acq_rel)) #define mi_atomic_cas_weak_release(p,exp,des) mi_atomic_cas_weak(p,exp,des,mi_memory_order(release),mi_memory_order(relaxed)) @@ -110,6 +111,7 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub); #define mi_atomic_cas_ptr_weak_release(tp,p,exp,des) mi_atomic_cas_weak_release(p,exp,(tp*)des) #define mi_atomic_cas_ptr_weak_acq_rel(tp,p,exp,des) mi_atomic_cas_weak_acq_rel(p,exp,(tp*)des) #define mi_atomic_cas_ptr_strong_release(tp,p,exp,des) mi_atomic_cas_strong_release(p,exp,(tp*)des) +#define mi_atomic_exchange_ptr_relaxed(tp,p,x) mi_atomic_exchange_relaxed(p,(tp*)x) #define mi_atomic_exchange_ptr_release(tp,p,x) mi_atomic_exchange_release(p,(tp*)x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) mi_atomic_exchange_acq_rel(p,(tp*)x) #else @@ -118,6 +120,7 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub); #define mi_atomic_cas_ptr_weak_release(tp,p,exp,des) mi_atomic_cas_weak_release(p,exp,des) #define mi_atomic_cas_ptr_weak_acq_rel(tp,p,exp,des) mi_atomic_cas_weak_acq_rel(p,exp,des) #define mi_atomic_cas_ptr_strong_release(tp,p,exp,des) mi_atomic_cas_strong_release(p,exp,des) +#define mi_atomic_exchange_ptr_relaxed(tp,p,x) mi_atomic_exchange_relaxed(p,x) #define mi_atomic_exchange_ptr_release(tp,p,x) mi_atomic_exchange_release(p,x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) mi_atomic_exchange_acq_rel(p,x) #endif diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 6f6e9dc3..0ede8f8c 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -167,7 +167,7 @@ void _mi_arena_field_cursor_done(mi_arena_field_cursor_t* current); // "segment-map.c" void _mi_segment_map_allocated_at(const mi_segment_t* segment); void _mi_segment_map_freed_at(const mi_segment_t* segment); -void _mi_segment_map_destroy(void); +void _mi_segment_map_unsafe_destroy(void); // "segment.c" mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_size, size_t page_alignment, mi_segments_tld_t* tld); diff --git a/src/init.c b/src/init.c index ab99a8f8..b8c01e51 100644 --- a/src/init.c +++ b/src/init.c @@ -682,7 +682,7 @@ void mi_cdecl _mi_process_done(void) { mi_collect(true /* force */); _mi_heap_unsafe_destroy_all(); // forcefully release all memory held by all heaps (of this thread only!) _mi_arena_unsafe_destroy_all(); - _mi_segment_map_destroy(); + _mi_segment_map_unsafe_destroy(); } if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) { diff --git a/src/segment-map.c b/src/segment-map.c index f6dff96d..ce754e98 100644 --- a/src/segment-map.c +++ b/src/segment-map.c @@ -126,9 +126,9 @@ mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_att return mi_is_valid_pointer(p); } -void _mi_segment_map_destroy(void) { +void _mi_segment_map_unsafe_destroy(void) { for (size_t i = 0; i < MI_SEGMENT_MAP_MAX_PARTS; i++) { - mi_segmap_part_t* part = mi_segment_map[i]; + mi_segmap_part_t* part = mi_atomic_exchange_ptr_relaxed(mi_segmap_part_t, &mi_segment_map[i], NULL); if (part != NULL) { _mi_os_free(part, sizeof(mi_segmap_part_t), part->memid); } From 485b69976f3227e19de699e0d280319921b1a995 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 30 Dec 2024 11:04:30 -0800 Subject: [PATCH 195/305] add filters for vs projects --- .gitignore | 1 - ide/vs2022/mimalloc-lib.vcxproj.filters | 105 ++++++++++++++++++ .../mimalloc-override-dll.vcxproj.filters | 3 + 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 ide/vs2022/mimalloc-lib.vcxproj.filters create mode 100644 ide/vs2022/mimalloc-override-dll.vcxproj.filters diff --git a/.gitignore b/.gitignore index df1d58eb..b2439f94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ ide/vs20??/*.db ide/vs20??/*.opendb ide/vs20??/*.user -ide/vs20??/*.vcxproj.filters ide/vs20??/.vs ide/vs20??/VTune* out/ diff --git a/ide/vs2022/mimalloc-lib.vcxproj.filters b/ide/vs2022/mimalloc-lib.vcxproj.filters new file mode 100644 index 00000000..90703da8 --- /dev/null +++ b/ide/vs2022/mimalloc-lib.vcxproj.filters @@ -0,0 +1,105 @@ + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + {1430490c-e711-4ace-a1b8-36f4d5105873} + + + {461c78ef-04b0-44d1-a0ca-7d488abaa592} + + + \ No newline at end of file diff --git a/ide/vs2022/mimalloc-override-dll.vcxproj.filters b/ide/vs2022/mimalloc-override-dll.vcxproj.filters new file mode 100644 index 00000000..0b07de1b --- /dev/null +++ b/ide/vs2022/mimalloc-override-dll.vcxproj.filters @@ -0,0 +1,3 @@ + + + \ No newline at end of file From d29372fda49313c9927cfdf5a917f3f9b84de34b Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 30 Dec 2024 11:15:57 -0800 Subject: [PATCH 196/305] remove older vs projects as they became stale --- ide/vs2017/mimalloc-override-test.vcxproj | 190 ------------- .../mimalloc-override-test.vcxproj.filters | 22 -- ide/vs2017/mimalloc-override.vcxproj | 260 ------------------ ide/vs2017/mimalloc-override.vcxproj.filters | 98 ------- ide/vs2017/mimalloc-test-stress.vcxproj | 159 ----------- .../mimalloc-test-stress.vcxproj.filters | 22 -- ide/vs2017/mimalloc-test.vcxproj | 158 ----------- ide/vs2017/mimalloc-test.vcxproj.filters | 22 -- ide/vs2017/mimalloc.sln | 71 ----- ide/vs2017/mimalloc.vcxproj | 260 ------------------ ide/vs2017/mimalloc.vcxproj.filters | 98 ------- ide/vs2019/mimalloc-override-test.vcxproj | 190 ------------- ide/vs2019/mimalloc-override.vcxproj | 260 ------------------ ide/vs2019/mimalloc-override.vcxproj.filters | 96 ------- ide/vs2019/mimalloc-test-api.vcxproj | 155 ----------- ide/vs2019/mimalloc-test-stress.vcxproj | 159 ----------- ide/vs2019/mimalloc-test.vcxproj | 158 ----------- ide/vs2019/mimalloc.sln | 81 ------ ide/vs2019/mimalloc.vcxproj | 258 ----------------- ide/vs2019/mimalloc.vcxproj.filters | 99 ------- 20 files changed, 2816 deletions(-) delete mode 100644 ide/vs2017/mimalloc-override-test.vcxproj delete mode 100644 ide/vs2017/mimalloc-override-test.vcxproj.filters delete mode 100644 ide/vs2017/mimalloc-override.vcxproj delete mode 100644 ide/vs2017/mimalloc-override.vcxproj.filters delete mode 100644 ide/vs2017/mimalloc-test-stress.vcxproj delete mode 100644 ide/vs2017/mimalloc-test-stress.vcxproj.filters delete mode 100644 ide/vs2017/mimalloc-test.vcxproj delete mode 100644 ide/vs2017/mimalloc-test.vcxproj.filters delete mode 100644 ide/vs2017/mimalloc.sln delete mode 100644 ide/vs2017/mimalloc.vcxproj delete mode 100644 ide/vs2017/mimalloc.vcxproj.filters delete mode 100644 ide/vs2019/mimalloc-override-test.vcxproj delete mode 100644 ide/vs2019/mimalloc-override.vcxproj delete mode 100644 ide/vs2019/mimalloc-override.vcxproj.filters delete mode 100644 ide/vs2019/mimalloc-test-api.vcxproj delete mode 100644 ide/vs2019/mimalloc-test-stress.vcxproj delete mode 100644 ide/vs2019/mimalloc-test.vcxproj delete mode 100644 ide/vs2019/mimalloc.sln delete mode 100644 ide/vs2019/mimalloc.vcxproj delete mode 100644 ide/vs2019/mimalloc.vcxproj.filters diff --git a/ide/vs2017/mimalloc-override-test.vcxproj b/ide/vs2017/mimalloc-override-test.vcxproj deleted file mode 100644 index 04c16a9f..00000000 --- a/ide/vs2017/mimalloc-override-test.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7868F-750E-4C21-A04D-22707CC66879} - mimalloc-override-test - mimalloc-override-test - 10.0.19041.0 - - - - Application - true - v141 - - - Application - false - v141 - true - - - Application - true - v141 - - - Application - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - false - Default - false - - - Console - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - Sync - Default - false - - - Console - - - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - {abb5eae7-b3e6-432e-b636-333449892ea7} - - - - - - - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc-override-test.vcxproj.filters b/ide/vs2017/mimalloc-override-test.vcxproj.filters deleted file mode 100644 index eb5e70b7..00000000 --- a/ide/vs2017/mimalloc-override-test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc-override.vcxproj b/ide/vs2017/mimalloc-override.vcxproj deleted file mode 100644 index 6d20eb57..00000000 --- a/ide/vs2017/mimalloc-override.vcxproj +++ /dev/null @@ -1,260 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA7} - mimalloc-override - mimalloc-override - 10.0.19041.0 - - - - DynamicLibrary - true - v141 - - - DynamicLibrary - false - v141 - - - DynamicLibrary - true - v141 - - - DynamicLibrary - false - v141 - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - - Level3 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)" - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;bcrypt.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)" - - - copy mimalloc-redirect.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)" - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;bcrypt.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)" - - - copy mimalloc-redirect.dll to the output directory - - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - - - - - - - - - - - true - true - true - true - - - - - - - - - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc-override.vcxproj.filters b/ide/vs2017/mimalloc-override.vcxproj.filters deleted file mode 100644 index 1adafcfa..00000000 --- a/ide/vs2017/mimalloc-override.vcxproj.filters +++ /dev/null @@ -1,98 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc-test-stress.vcxproj b/ide/vs2017/mimalloc-test-stress.vcxproj deleted file mode 100644 index 061b8605..00000000 --- a/ide/vs2017/mimalloc-test-stress.vcxproj +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7958F-750E-4C21-A04D-22707CC66878} - mimalloc-test-stress - mimalloc-test-stress - 10.0.19041.0 - - - - Application - true - v141 - - - Application - false - v141 - true - - - Application - true - v141 - - - Application - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - false - false - false - false - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc-test-stress.vcxproj.filters b/ide/vs2017/mimalloc-test-stress.vcxproj.filters deleted file mode 100644 index 7c5239e8..00000000 --- a/ide/vs2017/mimalloc-test-stress.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc-test.vcxproj b/ide/vs2017/mimalloc-test.vcxproj deleted file mode 100644 index 04bd6537..00000000 --- a/ide/vs2017/mimalloc-test.vcxproj +++ /dev/null @@ -1,158 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7858F-750E-4C21-A04D-22707CC66878} - mimalloctest - mimalloc-test - 10.0.19041.0 - - - - Application - true - v141 - - - Application - false - v141 - true - - - Application - true - v141 - - - Application - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp17 - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp14 - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc-test.vcxproj.filters b/ide/vs2017/mimalloc-test.vcxproj.filters deleted file mode 100644 index fca75e1c..00000000 --- a/ide/vs2017/mimalloc-test.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc.sln b/ide/vs2017/mimalloc.sln deleted file mode 100644 index 515c03f2..00000000 --- a/ide/vs2017/mimalloc.sln +++ /dev/null @@ -1,71 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.102 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {4297F93D-486A-4243-995F-7D32F59AE82A} - EndGlobalSection -EndGlobal diff --git a/ide/vs2017/mimalloc.vcxproj b/ide/vs2017/mimalloc.vcxproj deleted file mode 100644 index ece9a14d..00000000 --- a/ide/vs2017/mimalloc.vcxproj +++ /dev/null @@ -1,260 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA6} - mimalloc - 10.0.19041.0 - mimalloc - - - - StaticLibrary - true - v141 - - - StaticLibrary - false - v141 - true - - - StaticLibrary - true - v141 - - - StaticLibrary - false - v141 - true - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - false - - - false - - - false - - - false - - - - Level3 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsC - false - stdcpp17 - - - - - - - - - - - Level4 - Disabled - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp - false - stdcpp14 - - - - - - - - - - - - - - - - - - - Level3 - MaxSpeed - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsC - true - - - true - true - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsC - true - - - true - true - - - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - - - - - - - - - - true - true - true - true - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ide/vs2017/mimalloc.vcxproj.filters b/ide/vs2017/mimalloc.vcxproj.filters deleted file mode 100644 index 8359e0e4..00000000 --- a/ide/vs2017/mimalloc.vcxproj.filters +++ /dev/null @@ -1,98 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/ide/vs2019/mimalloc-override-test.vcxproj b/ide/vs2019/mimalloc-override-test.vcxproj deleted file mode 100644 index 7a9202f1..00000000 --- a/ide/vs2019/mimalloc-override-test.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7868F-750E-4C21-A04D-22707CC66879} - mimalloc-override-test - 10.0 - mimalloc-override-test - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - Sync - Default - false - - - Console - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - Disabled - true - true - ..\..\include - MultiThreadedDebugDLL - Sync - Default - false - - - Console - - - kernel32.lib;%(AdditionalDependencies) - - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - MultiThreadedDLL - - - true - true - Console - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - - - - {abb5eae7-b3e6-432e-b636-333449892ea7} - - - - - - \ No newline at end of file diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj deleted file mode 100644 index a84a5178..00000000 --- a/ide/vs2019/mimalloc-override.vcxproj +++ /dev/null @@ -1,260 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA7} - mimalloc-override - 10.0 - mimalloc-override - - - - DynamicLibrary - true - v142 - - - DynamicLibrary - false - v142 - - - DynamicLibrary - true - v142 - - - DynamicLibrary - false - v142 - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .dll - mimalloc-override - - - - Level3 - Disabled - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)" - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - Disabled - true - true - ../../include - MI_DEBUG=3;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); - MultiThreadedDebugDLL - false - Default - - - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) - - - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)" - - - copy mimalloc-redirect.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)" - - - Copy mimalloc-redirect32.dll to the output directory - - - - - Level3 - MaxSpeed - true - true - true - ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - MultiThreadedDLL - Default - false - - - true - true - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) - - - Default - false - - - COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)" - - - copy mimalloc-redirect.dll to the output directory - - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - - - - - - - - - - - true - true - true - true - - - - - - - - - - - \ No newline at end of file diff --git a/ide/vs2019/mimalloc-override.vcxproj.filters b/ide/vs2019/mimalloc-override.vcxproj.filters deleted file mode 100644 index 046e5603..00000000 --- a/ide/vs2019/mimalloc-override.vcxproj.filters +++ /dev/null @@ -1,96 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Source Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {f1fccf27-17b9-42dd-ba51-6070baff85c6} - - - {39cb7e38-69d0-43fb-8406-6a0f7cefc3b4} - - - \ No newline at end of file diff --git a/ide/vs2019/mimalloc-test-api.vcxproj b/ide/vs2019/mimalloc-test-api.vcxproj deleted file mode 100644 index 812a9cb1..00000000 --- a/ide/vs2019/mimalloc-test-api.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FFF7958F-750E-4C21-A04D-22707CC66878} - mimalloc-test-api - 10.0 - mimalloc-test-api - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - diff --git a/ide/vs2019/mimalloc-test-stress.vcxproj b/ide/vs2019/mimalloc-test-stress.vcxproj deleted file mode 100644 index ef7ab357..00000000 --- a/ide/vs2019/mimalloc-test-stress.vcxproj +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7958F-750E-4C21-A04D-22707CC66878} - mimalloc-test-stress - 10.0 - mimalloc-test-stress - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - %(PreprocessorDefinitions);NDEBUG - - - true - true - Console - - - - - false - false - false - false - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - \ No newline at end of file diff --git a/ide/vs2019/mimalloc-test.vcxproj b/ide/vs2019/mimalloc-test.vcxproj deleted file mode 100644 index 13af6ab4..00000000 --- a/ide/vs2019/mimalloc-test.vcxproj +++ /dev/null @@ -1,158 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {FEF7858F-750E-4C21-A04D-22707CC66878} - mimalloctest - 10.0 - mimalloc-test - - - - Application - true - v142 - - - Application - false - v142 - true - - - Application - true - v142 - - - Application - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp17 - - - Console - - - - - Level3 - Disabled - true - true - ..\..\include - stdcpp17 - - - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - Level3 - MaxSpeed - true - true - true - true - ..\..\include - _MBCS;%(PreprocessorDefinitions);NDEBUG - stdcpp17 - - - true - true - Console - - - - - {abb5eae7-b3e6-432e-b636-333449892ea6} - - - - - - - - - \ No newline at end of file diff --git a/ide/vs2019/mimalloc.sln b/ide/vs2019/mimalloc.sln deleted file mode 100644 index 6ff01d3b..00000000 --- a/ide/vs2019/mimalloc.sln +++ /dev/null @@ -1,81 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test", "mimalloc-test.vcxproj", "{FEF7858F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override", "mimalloc-override.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-override-test", "mimalloc-override-test.vcxproj", "{FEF7868F-750E-4C21-A04D-22707CC66879}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-stress", "mimalloc-test-stress.vcxproj", "{FEF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc-test-api", "mimalloc-test-api.vcxproj", "{FFF7958F-750E-4C21-A04D-22707CC66878}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|x86.Build.0 = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7858F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.ActiveCfg = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x64.Build.0 = Debug|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.ActiveCfg = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Debug|x86.Build.0 = Debug|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.ActiveCfg = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x64.Build.0 = Release|x64 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.ActiveCfg = Release|Win32 - {ABB5EAE7-B3E6-432E-B636-333449892EA7}.Release|x86.Build.0 = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x64.Build.0 = Debug|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Debug|x86.Build.0 = Debug|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.ActiveCfg = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x64.Build.0 = Release|x64 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.ActiveCfg = Release|Win32 - {FEF7868F-750E-4C21-A04D-22707CC66879}.Release|x86.Build.0 = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FEF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.ActiveCfg = Debug|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x64.Build.0 = Debug|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.ActiveCfg = Debug|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Debug|x86.Build.0 = Debug|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.ActiveCfg = Release|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x64.Build.0 = Release|x64 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.ActiveCfg = Release|Win32 - {FFF7958F-750E-4C21-A04D-22707CC66878}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {4297F93D-486A-4243-995F-7D32F59AE82A} - EndGlobalSection -EndGlobal diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj deleted file mode 100644 index 0076b1db..00000000 --- a/ide/vs2019/mimalloc.vcxproj +++ /dev/null @@ -1,258 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ABB5EAE7-B3E6-432E-B636-333449892EA6} - mimalloc - 10.0 - mimalloc - - - - StaticLibrary - true - v142 - - - StaticLibrary - false - v142 - true - - - StaticLibrary - true - v142 - - - StaticLibrary - false - v142 - true - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ - $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - .lib - mimalloc-static - - - - Level4 - Disabled - true - true - ../../include - MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp - false - Default - - - - - - - - - - - Level4 - Disabled - true - Default - ../../include - MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp - false - Default - - - - - - - - - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - %(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsCpp - true - Default - - - true - true - - - - - - - - - - - Level4 - MaxSpeed - true - true - ../../include - %(PreprocessorDefinitions);NDEBUG - AssemblyAndSourceCode - $(IntDir) - false - false - Default - CompileAsCpp - true - Default - - - true - true - - - - - - - - - - - - - - - - - false - false - false - false - - - true - true - true - true - - - - - - false - - - - - - - true - true - true - true - - - - true - true - true - true - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ide/vs2019/mimalloc.vcxproj.filters b/ide/vs2019/mimalloc.vcxproj.filters deleted file mode 100644 index 98f29289..00000000 --- a/ide/vs2019/mimalloc.vcxproj.filters +++ /dev/null @@ -1,99 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Source Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {2b556b10-f559-4b2d-896e-142652adbf0c} - - - {852a14ae-6dde-4e95-8077-ca705e97e5af} - - - \ No newline at end of file From e183384ad052e1f05f919ce5264cda17672b2bc2 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 30 Dec 2024 11:33:33 -0800 Subject: [PATCH 197/305] update vs project filter --- .../mimalloc-override-dll.vcxproj.filters | 112 +++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/ide/vs2022/mimalloc-override-dll.vcxproj.filters b/ide/vs2022/mimalloc-override-dll.vcxproj.filters index 0b07de1b..91bdf95c 100644 --- a/ide/vs2022/mimalloc-override-dll.vcxproj.filters +++ b/ide/vs2022/mimalloc-override-dll.vcxproj.filters @@ -1,3 +1,113 @@  - + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + {262c6c21-e270-4ba6-bd63-4ac999307e4e} + + + {94b40bdc-a741-45dd-81aa-c05fabcd2970} + + + + + Sources + + \ No newline at end of file From 9f70ce5fcd5e59d0b6eeb5094566b8b7711e4d13 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 30 Dec 2024 11:34:02 -0800 Subject: [PATCH 198/305] avoid accessing heap->tld after running thread_done (pr #974) --- include/mimalloc/internal.h | 2 +- src/heap.c | 7 ++++--- src/init.c | 11 ++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 0ede8f8c..a1791cd9 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -216,7 +216,7 @@ 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); bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid); -void _mi_heap_unsafe_destroy_all(void); +void _mi_heap_unsafe_destroy_all(mi_heap_t* heap); mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag); void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page); bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg); diff --git a/src/heap.c b/src/heap.c index c2b5ae42..7a14c1aa 100644 --- a/src/heap.c +++ b/src/heap.c @@ -393,9 +393,10 @@ void mi_heap_destroy(mi_heap_t* heap) { } // forcefully destroy all heaps in the current thread -void _mi_heap_unsafe_destroy_all(void) { - mi_heap_t* bheap = mi_heap_get_backing(); - mi_heap_t* curr = bheap->tld->heaps; +void _mi_heap_unsafe_destroy_all(mi_heap_t* heap) { + mi_assert_internal(heap != NULL); + if (heap == NULL) return; + mi_heap_t* curr = heap->tld->heaps; while (curr != NULL) { mi_heap_t* next = curr->next; if (curr->no_reclaim) { diff --git a/src/init.c b/src/init.c index b8c01e51..734bf5de 100644 --- a/src/init.c +++ b/src/init.c @@ -663,15 +663,20 @@ void mi_cdecl _mi_process_done(void) { if (process_done) return; process_done = true; + // get the default heap so we don't need to acces thread locals anymore + mi_heap_t* heap = mi_prim_get_default_heap(); // use prim to not initialize any heap + mi_assert_internal(heap != NULL); + // release any thread specific resources and ensure _mi_thread_done is called on all but the main thread _mi_prim_thread_done_auto_done(); + #ifndef MI_SKIP_COLLECT_ON_EXIT #if (MI_DEBUG || !defined(MI_SHARED_LIB)) // free all memory if possible on process exit. This is not needed for a stand-alone process // but should be done if mimalloc is statically linked into another shared library which // is repeatedly loaded/unloaded, see issue #281. - mi_collect(true /* force */ ); + mi_heap_collect(heap, true /* force */ ); #endif #endif @@ -679,8 +684,8 @@ void mi_cdecl _mi_process_done(void) { // since after process_done there might still be other code running that calls `free` (like at_exit routines, // or C-runtime termination code. if (mi_option_is_enabled(mi_option_destroy_on_exit)) { - mi_collect(true /* force */); - _mi_heap_unsafe_destroy_all(); // forcefully release all memory held by all heaps (of this thread only!) + mi_heap_collect(heap, true /* force */); + _mi_heap_unsafe_destroy_all(heap); // forcefully release all memory held by all heaps (of this thread only!) _mi_arena_unsafe_destroy_all(); _mi_segment_map_unsafe_destroy(); } From 2d94df860bec9bf8379f8af773c6986faf0dd2de Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 30 Dec 2024 11:44:03 -0800 Subject: [PATCH 199/305] fix potentially warning on gcc (pr #935) --- src/heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heap.c b/src/heap.c index 7a14c1aa..f856a426 100644 --- a/src/heap.c +++ b/src/heap.c @@ -59,7 +59,7 @@ static bool mi_heap_page_is_valid(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_ MI_UNUSED(pq); mi_assert_internal(mi_page_heap(page) == heap); mi_segment_t* segment = _mi_page_segment(page); - mi_assert_internal(segment->thread_id == heap->thread_id); + mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == heap->thread_id); mi_assert_expensive(_mi_page_is_valid(page)); return true; } From 81d69d525e07a4e0e65860085c4281fe1cfb8950 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Tue, 31 Dec 2024 14:13:01 -0800 Subject: [PATCH 200/305] add newline --- src/segment-map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment-map.c b/src/segment-map.c index ce754e98..5809342c 100644 --- a/src/segment-map.c +++ b/src/segment-map.c @@ -133,4 +133,4 @@ void _mi_segment_map_unsafe_destroy(void) { _mi_os_free(part, sizeof(mi_segmap_part_t), part->memid); } } -} \ No newline at end of file +} From b28e2bdd93cb14d961aa4ff6e505a8293c2bc059 Mon Sep 17 00:00:00 2001 From: daanx Date: Thu, 2 Jan 2025 15:02:40 -0800 Subject: [PATCH 201/305] fix pointer alignment for zero-sized large alignment case --- src/alloc-aligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 6b0a33c1..7304eb1d 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -78,7 +78,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_overalloc(mi_heap_t } else { // otherwise over-allocate - oversize = size + alignment - 1; + oversize = (size < MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : size) + alignment - 1; // adjust for size <= 16; with size 0 and aligment 64k, we would allocate a 64k block and pointing just beyond that. p = mi_heap_malloc_zero_no_guarded(heap, oversize, zero); if (p == NULL) return NULL; } From e8c27072a1b10cf8e28e8e6b86e68e216d6564e2 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 2 Jan 2025 17:21:34 -0800 Subject: [PATCH 202/305] fix alignment for mi_manage_os_memory (issue #980) --- src/arena.c | 16 ++++++++++++++-- test/main-override-static.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/arena.c b/src/arena.c index f430aa27..ce08d601 100644 --- a/src/arena.c +++ b/src/arena.c @@ -795,11 +795,23 @@ static bool mi_arena_add(mi_arena_t* arena, mi_arena_id_t* arena_id, mi_stats_t* static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int numa_node, bool exclusive, mi_memid_t memid, mi_arena_id_t* arena_id) mi_attr_noexcept { if (arena_id != NULL) *arena_id = _mi_arena_id_none(); - if (size < MI_ARENA_BLOCK_SIZE) return false; - + if (size < MI_ARENA_BLOCK_SIZE) { + _mi_warning_message("the arena size is too small (memory at %p with size %zu)\n", start, size); + return false; + } if (is_large) { mi_assert_internal(memid.initially_committed && memid.is_pinned); } + if (!_mi_is_aligned(start, MI_SEGMENT_ALIGN)) { + void* const aligned_start = mi_align_up_ptr(start, MI_SEGMENT_ALIGN); + const size_t diff = (uint8_t*)aligned_start - (uint8_t*)start; + if (diff >= size || (size - diff) < MI_ARENA_BLOCK_SIZE) { + _mi_warning_message("after alignment, the size of the arena becomes too small (memory at %p with size %zu)\n", start, size); + return false; + } + start = aligned_start; + size = size - diff; + } const size_t bcount = size / MI_ARENA_BLOCK_SIZE; const size_t fields = _mi_divide_up(bcount, MI_BITMAP_FIELD_BITS); diff --git a/test/main-override-static.c b/test/main-override-static.c index 34860717..6070794b 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -1,3 +1,6 @@ +#if _WIN32 +#include +#endif #include #include #include @@ -22,12 +25,14 @@ static void negative_stat(void); static void alloc_huge(void); static void test_heap_walk(void); static void test_canary_leak(void); +static void test_manage_os_memory(void); // static void test_large_pages(void); int main() { mi_version(); mi_stats_reset(); + test_manage_os_memory(); // test_large_pages(); // detect double frees and heap corruption // double_free1(); @@ -242,6 +247,34 @@ static void test_canary_leak(void) { free(p); } +#if _WIN32 +static void test_manage_os_memory(void) { + size_t size = 256 * 1024 * 1024; + void* ptr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + mi_arena_id_t arena_id; + mi_manage_os_memory_ex(ptr, size, true /* committed */, true /* pinned */, false /* is zero */, -1 /* numa node */, true /* exclusive */, &arena_id); + mi_heap_t* cuda_heap = mi_heap_new_in_arena(arena_id); // you can do this in any thread + + // now allocate only in the cuda arena + void* p1 = mi_heap_malloc(cuda_heap, 8); + int* p2 = mi_heap_malloc_tp(cuda_heap, int); + *p2 = 42; + + // and maybe set the cuda heap as the default heap? (but careful as now `malloc` will allocate in the cuda heap as well) + { + mi_heap_t* prev_default_heap = mi_heap_set_default(cuda_heap); + void* p3 = mi_malloc(8); // allocate in the cuda heap + mi_free(p3); + } + mi_free(p1); + mi_free(p2); +} +#else +static void test_manage_os_memory(void) { + // empty +} +#endif + // Experiment with huge OS pages #if 0 From a0a6ad3cf9568ca75269e51b43f60bdc0029f86b Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 3 Jan 2025 08:17:32 -0800 Subject: [PATCH 203/305] add thread_local for c++ --- include/mimalloc/internal.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index df358e39..4a798d0a 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -38,6 +38,12 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_decl_cache_align __attribute__((aligned(MI_CACHE_LINE))) #define mi_decl_weak __attribute__((weak)) #define mi_decl_hidden __attribute__((visibility("hidden"))) +#elif __cplusplus >= 201103L // c++11 +#define mi_decl_noinline +#define mi_decl_thread thread_local +#define mi_decl_cache_align alignas(MI_CACHE_LINE) +#define mi_decl_weak +#define mi_decl_hidden #else #define mi_decl_noinline #define mi_decl_thread __thread // hope for the best :-) From 98699c983a7f76fa8520d4658b44da8f37084204 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 3 Jan 2025 17:56:15 -0800 Subject: [PATCH 204/305] update to v1.8.8 --- LICENSE | 2 +- azure-pipelines.yml | 3 +- doc/mimalloc-doc.h | 53 +++--- docker/alpine-arm32v7/Dockerfile | 2 +- docker/alpine/Dockerfile | 2 +- docker/manylinux-x64/Dockerfile | 2 +- docs/annotated.html | 8 +- docs/bench.html | 6 +- docs/build.html | 6 +- docs/classes.html | 6 +- docs/doxygen.css | 38 +++-- docs/environment.html | 6 +- docs/functions.html | 6 +- docs/functions_vars.html | 6 +- docs/group__aligned.html | 29 ++-- docs/group__analysis.html | 39 ++--- docs/group__cpp.html | 25 +-- docs/group__extended.html | 84 +++++----- docs/group__heap.html | 31 ++-- docs/group__malloc.html | 94 +++++------ docs/group__options.html | 9 +- docs/group__posix.html | 12 +- docs/group__typed.html | 58 +++---- docs/group__zeroinit.html | 12 +- docs/index.html | 8 +- docs/jquery.js | 190 ++++++++++++++++++++-- docs/mimalloc-doc_8h_source.html | 266 ++++++++++++++++--------------- docs/navtree.js | 4 +- docs/navtreedata.js | 4 +- docs/overrides.html | 16 +- docs/pages.html | 6 +- docs/resize.js | 4 +- docs/using.html | 8 +- include/mimalloc/prim.h | 2 +- readme.md | 76 ++++++--- src/options.c | 4 +- 36 files changed, 694 insertions(+), 433 deletions(-) diff --git a/LICENSE b/LICENSE index 670b668a..53315ebe 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2021 Microsoft Corporation, Daan Leijen +Copyright (c) 2018-2025 Microsoft Corporation, Daan Leijen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bccf7a3f..0be85db1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,7 +8,8 @@ trigger: include: - master - dev - - dev-slice + - dev2 + - dev3 tags: include: - v* diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 698c5dbb..0c9da48a 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2021, Microsoft Research, Daan Leijen +Copyright (c) 2018-2025, 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. @@ -1303,25 +1303,31 @@ the [shell](https://stackoverflow.com/questions/43941322/dyld-insert-libraries-i ### Dynamic Override on Windows -Dynamically overriding on mimalloc 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. -As it intercepts all allocation calls on a low level, it can be used reliably +Dynamically overriding on mimalloc 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. As it intercepts all allocation calls on a low level, it can be used reliably on large programs that include other 3rd party components. -There are four requirements to make the overriding work robustly: +There are four requirements to make the overriding work well: 1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). -2. Link your program explicitly with `mimalloc-override.dll` library. - To ensure the `mimalloc-override.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. -3. The [`mimalloc-redirect.dll`](bin) (or `mimalloc-redirect32.dll`) must be put - in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). - The redirection DLL ensures that all calls to the C runtime malloc API get redirected to - mimalloc functions (which reside in `mimalloc-override.dll`). -4. Ensure the `mimalloc-override.dll` comes as early as possible in the import + +2. Link your program explicitly with the `mimalloc.lib` export library for the `mimalloc.dll`. + (which must be compiled with `-DMI_OVERRIDE=ON`, which is the default though). + To ensure the `mimalloc.dll` is actually 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 command, or + similarly, `#pragma comment(linker, "/include:mi_version")` in some source file). + See the `mimalloc-test-override` project for an example on how to use this. + +3. The `mimalloc-redirect.dll` must be put in the same directory as the main + `mimalloc.dll` at runtime (as it is a dependency of that DLL). + The redirection DLL ensures that all calls to the C runtime malloc API get + redirected to mimalloc functions (which reside in `mimalloc.dll`). + +4. Ensure the `mimalloc.dll` comes as early as possible in the import list of the final executable (so it can intercept all potential allocations). + You can use `minject -l ` to check this if needed. For best performance on Windows with C++, it is also recommended to also override the `new`/`delete` operations (by including @@ -1329,15 +1335,14 @@ is also recommended to also override the `new`/`delete` operations (by including 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. +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully +redirected. + +For different platforms than x64, you may need a specific [redirection dll](bin). +Furthermore, we cannot always re-link an executable or ensure `mimalloc.dll` comes +first in the import table. In such cases the [`minject`](bin) tool can be used +to patch the executable's import tables. -We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we cannot always -ensure the the DLL comes first in the import table of the final executable. -In many cases though we can 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) or -the [`minject`](bin) program. ## Static override diff --git a/docker/alpine-arm32v7/Dockerfile b/docker/alpine-arm32v7/Dockerfile index 1d7fd48b..f74934fb 100644 --- a/docker/alpine-arm32v7/Dockerfile +++ b/docker/alpine-arm32v7/Dockerfile @@ -15,7 +15,7 @@ RUN mkdir -p /home/dev WORKDIR /home/dev # Get mimalloc -RUN git clone https://github.com/microsoft/mimalloc -b dev-slice +RUN git clone https://github.com/microsoft/mimalloc -b dev2 RUN mkdir -p mimalloc/out/release RUN mkdir -p mimalloc/out/debug diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index b222b791..e1234a9b 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -10,7 +10,7 @@ RUN mkdir -p /home/dev WORKDIR /home/dev # Get mimalloc -RUN git clone https://github.com/microsoft/mimalloc -b dev-slice +RUN git clone https://github.com/microsoft/mimalloc -b dev2 RUN mkdir -p mimalloc/out/release RUN mkdir -p mimalloc/out/debug diff --git a/docker/manylinux-x64/Dockerfile b/docker/manylinux-x64/Dockerfile index 22d37e5a..ff54d674 100644 --- a/docker/manylinux-x64/Dockerfile +++ b/docker/manylinux-x64/Dockerfile @@ -10,7 +10,7 @@ RUN mkdir -p /home/dev WORKDIR /home/dev # Get mimalloc -RUN git clone https://github.com/microsoft/mimalloc -b dev-slice +RUN git clone https://github.com/microsoft/mimalloc -b dev2 RUN mkdir -p mimalloc/out/release RUN mkdir -p mimalloc/out/debug diff --git a/docs/annotated.html b/docs/annotated.html index e31fddc4..fbb3936e 100644 --- a/docs/annotated.html +++ b/docs/annotated.html @@ -3,7 +3,7 @@ - + mi-malloc: Data Structures @@ -54,7 +54,7 @@

    - +