From ccb51c6abeebeb2105cb74bad4f4a5ad9c873747 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:46:39 -0700 Subject: [PATCH 001/172] disable artifact uploading in dev --- azure-pipelines.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 954ec15d..c81e31bd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,8 +40,8 @@ jobs: cd $(BuildType) ctest displayName: CTest - - upload: $(Build.SourcesDirectory)/$(BuildType) - artifact: mimalloc-windows-$(BuildType) +# - upload: $(Build.SourcesDirectory)/$(BuildType) +# artifact: mimalloc-windows-$(BuildType) - job: displayName: Linux @@ -99,8 +99,8 @@ jobs: displayName: Make - script: make test -C $(BuildType) displayName: CTest - - upload: $(Build.SourcesDirectory)/$(BuildType) - artifact: mimalloc-ubuntu-$(BuildType) +# - upload: $(Build.SourcesDirectory)/$(BuildType) +# artifact: mimalloc-ubuntu-$(BuildType) - job: displayName: macOS @@ -127,5 +127,5 @@ jobs: displayName: Make - script: make test -C $(BuildType) displayName: CTest - - upload: $(Build.SourcesDirectory)/$(BuildType) - artifact: mimalloc-macos-$(BuildType) +# - upload: $(Build.SourcesDirectory)/$(BuildType) +# artifact: mimalloc-macos-$(BuildType) From cefc930f723ffdcb8b730655bfd25a389f790bbe Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:47:46 -0700 Subject: [PATCH 002/172] bump version to 1.6.4 for further development --- include/mimalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 0af04a94..f44f6d9a 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 163 // major + 2 digits minor +#define MI_MALLOC_VERSION 164 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes From 45974efdb7377514863f69445053f2d2b4a36745 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 19:37:50 -0700 Subject: [PATCH 003/172] use environ on posix systems to read environment variables before the C runtime is initialized (issue #241) --- src/options.c | 57 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/options.c b/src/options.c index 1a4633ee..9714d264 100644 --- a/src/options.c +++ b/src/options.c @@ -400,6 +400,14 @@ static void mi_strlcat(char* dest, const char* src, size_t dest_size) { dest[dest_size - 1] = 0; } +static inline int mi_strnicmp(const char* s, const char* t, size_t n) { + if (n==0) return 0; + for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) { + if (toupper(*s) != toupper(*t)) break; + } + return (n==0 ? 0 : *s - *t); +} + #if defined _WIN32 // On Windows use GetEnvironmentVariable instead of getenv to work // reliably even when this is invoked before the C runtime is initialized. @@ -411,11 +419,45 @@ static bool mi_getenv(const char* name, char* result, size_t result_size) { size_t len = GetEnvironmentVariableA(name, result, (DWORD)result_size); return (len > 0 && len < result_size); } -#else +#elif !defined(MI_USE_ENVIRON) || (MI_USE_ENVIRON!=0) +// On Posix systemsr use `environ` to acces environment variables +// even before the C runtime is initialized. +#if defined(__APPLE__) +#include +static char** mi_get_environ(void) { + return (*_NSGetEnviron()); +} +#else +extern char** environ; +static char** mi_get_environ(void) { + return environ; +} +#endif static bool mi_getenv(const char* name, char* result, size_t result_size) { + if (name==NULL) return false; + const size_t len = strlen(name); + if (len == 0) return false; + char** env = mi_get_environ(); + if (env == NULL) return false; + // compare all entries + for (; *env != NULL; env++) { + const char* s = *env; + if (mi_strnicmp(name, s, len) == 0 && s[len] == '=') { // case insensitive + // found it + mi_strlcpy(result, s + len + 1, result_size); + return true; + } + } + return false; +} +#else +// fallback: use standard C `getenv` but this cannot be used while initializing the C runtime +static bool mi_getenv(const char* name, char* result, size_t result_size) { + // cannot call getenv() when still initializing the C runtime. + if (_mi_preloading()) return false; const char* s = getenv(name); if (s == NULL) { - // in unix environments we check the upper case name too. + // we check the upper case name too. char buf[64+1]; size_t len = strlen(name); if (len >= sizeof(buf)) len = sizeof(buf) - 1; @@ -434,11 +476,8 @@ static bool mi_getenv(const char* name, char* result, size_t result_size) { } } #endif -static void mi_option_init(mi_option_desc_t* desc) { - #ifndef _WIN32 - // cannot call getenv() when still initializing the C runtime. - if (_mi_preloading()) return; - #endif + +static void mi_option_init(mi_option_desc_t* desc) { // Read option value from the environment char buf[64+1]; mi_strlcpy(buf, "mimalloc_", sizeof(buf)); @@ -471,9 +510,9 @@ static void mi_option_init(mi_option_desc_t* desc) { desc->init = DEFAULTED; } } + mi_assert_internal(desc->init != UNINIT); } - else { + else if (!_mi_preloading()) { desc->init = DEFAULTED; } - mi_assert_internal(desc->init != UNINIT); } From 4f020e5da4552fb254ce35db1adad5c63d68d09e Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 20:19:20 -0700 Subject: [PATCH 004/172] put a bound on the environment search --- src/options.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/options.c b/src/options.c index 9714d264..f29b387c 100644 --- a/src/options.c +++ b/src/options.c @@ -439,9 +439,9 @@ static bool mi_getenv(const char* name, char* result, size_t result_size) { if (len == 0) return false; char** env = mi_get_environ(); if (env == NULL) return false; - // compare all entries - for (; *env != NULL; env++) { - const char* s = *env; + // compare up to 256 entries + for (int i = 0; i < 256 && env[i] != NULL; i++) { + const char* s = env[i]; if (mi_strnicmp(name, s, len) == 0 && s[len] == '=') { // case insensitive // found it mi_strlcpy(result, s + len + 1, result_size); From 967513d5363cc298fc888fcb883421455a6bd62f Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 6 May 2020 11:35:35 -0700 Subject: [PATCH 005/172] add extra checks if unreset (commit) succeeds --- src/segment.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/segment.c b/src/segment.c index d36cf1c5..aa32c72c 100644 --- a/src/segment.c +++ b/src/segment.c @@ -240,7 +240,7 @@ static void mi_page_reset(mi_segment_t* segment, mi_page_t* page, size_t size, m if (reset_size > 0) _mi_mem_reset(start, reset_size, tld->os); } -static void mi_page_unreset(mi_segment_t* segment, mi_page_t* page, size_t size, mi_segments_tld_t* tld) +static bool mi_page_unreset(mi_segment_t* segment, mi_page_t* page, size_t size, mi_segments_tld_t* tld) { mi_assert_internal(page->is_reset); mi_assert_internal(page->is_committed); @@ -250,8 +250,12 @@ static void mi_page_unreset(mi_segment_t* segment, mi_page_t* page, size_t size, uint8_t* start = mi_segment_raw_page_start(segment, page, &psize); size_t unreset_size = (size == 0 || size > psize ? psize : size); bool is_zero = false; - if (unreset_size > 0) _mi_mem_unreset(start, unreset_size, &is_zero, tld->os); + bool ok = true; + if (unreset_size > 0) { + ok = _mi_mem_unreset(start, unreset_size, &is_zero, tld->os); + } if (is_zero) page->is_zero_init = true; + return ok; } @@ -630,7 +634,7 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ mi_segments_track_size((long)segment_size, tld); } mi_assert_internal(segment != NULL && (uintptr_t)segment % MI_SEGMENT_SIZE == 0); - + mi_assert_internal(segment->mem_is_fixed ? segment->mem_is_committed : true); if (!pages_still_good) { // zero the segment info (but not the `mem` fields) ptrdiff_t ofs = offsetof(mi_segment_t, next); @@ -731,7 +735,13 @@ static bool mi_segment_page_claim(mi_segment_t* segment, mi_page_t* page, mi_seg segment->used++; // check reset if (page->is_reset) { - mi_page_unreset(segment, page, 0, tld); // todo: only unreset the part that was reset? + mi_assert_internal(!segment->mem_is_fixed); + bool ok = mi_page_unreset(segment, page, 0, tld); + if (!ok) { + page->segment_in_use = false; + segment->used--; + return false; + } } mi_assert_internal(page->segment_in_use); mi_assert_internal(segment->used <= segment->capacity); From 0ea4e3f2796685792dfec68b59e096acfbe496a2 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 7 May 2020 20:09:16 +0100 Subject: [PATCH 006/172] IOS build fix, large pages unsupported. --- src/os.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/os.c b/src/os.c index f33cfbc3..53bd39dc 100644 --- a/src/os.c +++ b/src/os.c @@ -26,9 +26,12 @@ terms of the MIT license. A copy of the license can be found in the file #include // linux mmap flags #endif #if defined(__APPLE__) +#include +#if !TARGET_IOS_IPHONE && !TARGET_IOS_SIMULATOR #include #endif #endif +#endif /* ----------------------------------------------------------- Initialization. From bf6b781e40ceed8e40a122ca310987e19fad288f Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 18 May 2020 10:07:45 -0700 Subject: [PATCH 007/172] fix semicolon (#247) --- src/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index d36cf1c5..7960a176 100644 --- a/src/segment.c +++ b/src/segment.c @@ -427,7 +427,7 @@ static size_t mi_segment_size(size_t capacity, size_t required, size_t* pre_size guardsize = page_size; required = _mi_align_up(required, page_size); } -; + if (info_size != NULL) *info_size = isize; if (pre_size != NULL) *pre_size = isize + guardsize; return (required==0 ? MI_SEGMENT_SIZE : _mi_align_up( required + isize + 2*guardsize, MI_PAGE_HUGE_ALIGN) ); From c9ffe305130cdb90967719ee68419fd929474054 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 18 May 2020 10:17:58 -0700 Subject: [PATCH 008/172] weaken alignment requirement to not need to be a multiple of sizeof(void*); see #246 --- src/alloc-aligned.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 7eeb9e92..15ebd59d 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -17,8 +17,7 @@ terms of the MIT license. A copy of the license can be found in the file 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 { // note: we don't require `size > offset`, we just guarantee that // the address at offset is aligned regardless of the allocated size. - mi_assert(alignment > 0 && alignment % sizeof(void*) == 0); - + mi_assert(alignment > 0); if (mi_unlikely(size > PTRDIFF_MAX)) return NULL; // we don't allocate more than PTRDIFF_MAX (see ) if (mi_unlikely(alignment==0 || !_mi_is_power_of_two(alignment))) return NULL; // require power-of-two (see ) const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` From 74986c1dd141f1b255b82ae9e7950fe0614f1f95 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 19 May 2020 09:56:37 -0700 Subject: [PATCH 009/172] weaken aligmenment assertion (issue #245) --- 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 15ebd59d..ca16d367 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -53,7 +53,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t // .. and align within the allocation uintptr_t adjust = alignment - (((uintptr_t)p + offset) & align_mask); - mi_assert_internal(adjust % sizeof(uintptr_t) == 0); + mi_assert_internal(adjust <= alignment); void* aligned_p = (adjust == alignment ? p : (void*)((uintptr_t)p + adjust)); if (aligned_p != p) mi_page_set_has_aligned(_mi_ptr_page(p), true); mi_assert_internal(((uintptr_t)aligned_p + offset) % alignment == 0); From a7d2bc8ad63699a8b661c2048be69f4362126a65 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 19 May 2020 10:16:28 -0700 Subject: [PATCH 010/172] edit warning messages to be more consistent --- include/mimalloc-internal.h | 2 +- src/os.c | 5 ++++- src/page.c | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index d0c0b3f3..35413315 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -263,7 +263,7 @@ static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* tot return false; } else if (mi_unlikely(mi_mul_overflow(count, size, total))) { - _mi_error_message(EOVERFLOW, "allocation request too large (%zu * %zu bytes)\n", count, size); + _mi_error_message(EOVERFLOW, "allocation request is too large (%zu * %zu bytes)\n", count, size); *total = SIZE_MAX; return true; } diff --git a/src/os.c b/src/os.c index f33cfbc3..72214a9f 100644 --- a/src/os.c +++ b/src/os.c @@ -262,7 +262,7 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, p = mi_win_virtual_allocx(addr, size, try_alignment, flags); } if (p == NULL) { - _mi_warning_message("unable to allocate memory: error code: %i, addr: %p, size: 0x%x, large only: %d, allow_large: %d\n", GetLastError(), addr, size, large_only, allow_large); + _mi_warning_message("unable to allocate OS memory (%zu bytes, error code: %i, address: %p, large only: %d, allow large: %d)\n", size, GetLastError(), addr, large_only, allow_large); } return p; } @@ -399,6 +399,9 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro } #endif } + if (p == NULL) { + _mi_warning_message("unable to allocate OS memory (%zu bytes, error code: %i, address: %p, large only: %d, allow large: %d)\n", size, errno, addr, large_only, allow_large); + } return p; } #endif diff --git a/src/page.c b/src/page.c index 08aa88c7..18f1812e 100644 --- a/src/page.c +++ b/src/page.c @@ -792,7 +792,7 @@ static mi_page_t* mi_find_page(mi_heap_t* heap, size_t size) mi_attr_noexcept { 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) )) { if (mi_unlikely(req_size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see ) - _mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", req_size); + _mi_error_message(EOVERFLOW, "allocation request is too large (%zu bytes)\n", req_size); return NULL; } else { @@ -833,7 +833,8 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept } if (mi_unlikely(page == NULL)) { // out of memory - _mi_error_message(ENOMEM, "cannot allocate memory (%zu bytes requested)\n", size); + const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` + _mi_error_message(ENOMEM, "unable to allocate memory (%zu bytes)\n", req_size); return NULL; } From 66048cb6cc273dc8270f775209b01db0363ecee8 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 19 May 2020 13:31:24 -0700 Subject: [PATCH 011/172] fix return value for page_unreset --- src/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index b2521524..d53ecfd1 100644 --- a/src/segment.c +++ b/src/segment.c @@ -245,7 +245,7 @@ static bool mi_page_unreset(mi_segment_t* segment, mi_page_t* page, size_t size, mi_assert_internal(page->is_reset); mi_assert_internal(page->is_committed); mi_assert_internal(!segment->mem_is_fixed); - if (segment->mem_is_fixed || !page->is_committed || !page->is_reset) return; + if (segment->mem_is_fixed || !page->is_committed || !page->is_reset) return true; page->is_reset = false; size_t psize; uint8_t* start = mi_segment_raw_page_start(segment, page, &psize); From d5475a58a1a3cb7f0e5154e49cd7f94d1038a7d0 Mon Sep 17 00:00:00 2001 From: Wanja Vogel Date: Wed, 10 Jun 2020 07:47:50 +0200 Subject: [PATCH 012/172] fix: avoid warning warning C26451: Arithmetic overflow: Using operator '+' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '+' to avoid overflow (io.2). --- src/os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index f33cfbc3..f7d5f7b1 100644 --- a/src/os.c +++ b/src/os.c @@ -1036,7 +1036,7 @@ static size_t mi_os_numa_nodex() { static size_t mi_os_numa_node_countx(void) { ULONG numa_max = 0; GetNumaHighestNodeNumber(&numa_max); - return (numa_max + 1); + return ((size_t)numa_max + 1); } #elif defined(__linux__) #include // getcpu From 32b360858177bd8d78a2b35b9ced3c2c676fb4ac Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 17 Jun 2020 13:12:05 -0700 Subject: [PATCH 013/172] simplify initial main tld declaration --- src/init.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/init.c b/src/init.c index 132043e8..92115283 100644 --- a/src/init.c +++ b/src/init.c @@ -105,10 +105,6 @@ const mi_heap_t _mi_heap_empty = { // the thread-local default heap for allocation mi_decl_thread mi_heap_t* _mi_heap_default = (mi_heap_t*)&_mi_heap_empty; - -#define tld_main_stats ((mi_stats_t*)((uint8_t*)&tld_main + offsetof(mi_tld_t,stats))) -#define tld_main_os ((mi_os_tld_t*)((uint8_t*)&tld_main + offsetof(mi_tld_t,os))) - extern mi_heap_t _mi_heap_main; static mi_tld_t tld_main = { @@ -116,9 +112,9 @@ static mi_tld_t tld_main = { &_mi_heap_main, &_mi_heap_main, { { NULL, NULL }, {NULL ,NULL}, {NULL ,NULL, 0}, 0, 0, 0, 0, 0, 0, NULL, - tld_main_stats, tld_main_os + &tld_main.stats, &tld_main.os }, // segments - { 0, tld_main_stats }, // os + { 0, &tld_main.stats }, // os { MI_STATS_NULL } // stats }; From 5a6d9ba8079398fad3a1dd67bd749327fc977437 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 17 Jun 2020 19:07:32 -0700 Subject: [PATCH 014/172] fix handling of failing to allocate heap metadata on thread creation, issue #257 --- src/init.c | 14 ++++++++++---- src/page.c | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/init.c b/src/init.c index 92115283..622a5eb0 100644 --- a/src/init.c +++ b/src/init.c @@ -176,10 +176,15 @@ static bool _mi_heap_init(void) { } else { // use `_mi_os_alloc` to allocate directly from the OS - mi_thread_data_t* td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t),&_mi_stats_main); // Todo: more efficient allocation? + mi_thread_data_t* td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &_mi_stats_main); // Todo: more efficient allocation? if (td == NULL) { - _mi_error_message(ENOMEM, "failed to allocate thread local heap memory\n"); - return false; + // if this fails, try once more. (issue #257) + td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t), &_mi_stats_main); + 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)); + return false; + } } // OS allocated so already zero initialized mi_tld_t* tld = &td->tld; @@ -341,7 +346,8 @@ void mi_thread_init(void) mi_attr_noexcept // don't further initialize for the main thread if (_mi_is_main_thread()) return; - _mi_stat_increase(&mi_get_default_heap()->tld->stats.threads, 1); + mi_heap_t* heap = mi_get_default_heap(); + if (mi_heap_is_initialized(heap)) { _mi_stat_increase(&mi_get_default_heap()->tld->stats.threads, 1); } //_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); } diff --git a/src/page.c b/src/page.c index 18f1812e..c8a4e54b 100644 --- a/src/page.c +++ b/src/page.c @@ -816,6 +816,7 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept if (mi_unlikely(!mi_heap_is_initialized(heap))) { mi_thread_init(); // calls `_mi_heap_init` in turn heap = mi_get_default_heap(); + if (mi_unlikely(!mi_heap_is_initialized(heap))) { return NULL; } } mi_assert_internal(mi_heap_is_initialized(heap)); From 2599512e8f60a5d3bdd81e6590e5a2402a8aaff1 Mon Sep 17 00:00:00 2001 From: Wanja Vogel Date: Thu, 18 Jun 2020 18:20:26 +0200 Subject: [PATCH 015/172] use stored pointer #257 --- src/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.c b/src/init.c index 622a5eb0..602a2f7a 100644 --- a/src/init.c +++ b/src/init.c @@ -346,8 +346,8 @@ void mi_thread_init(void) mi_attr_noexcept // don't further initialize for the main thread if (_mi_is_main_thread()) return; - mi_heap_t* heap = mi_get_default_heap(); - if (mi_heap_is_initialized(heap)) { _mi_stat_increase(&mi_get_default_heap()->tld->stats.threads, 1); } + mi_heap_t* const heap = mi_get_default_heap(); + if (mi_heap_is_initialized(heap)) { _mi_stat_increase(&heap->tld->stats.threads, 1); } //_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); } From 7e48eb033cccccab87c3ee6e23841a75a3108936 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 28 Jun 2020 13:53:45 +0000 Subject: [PATCH 016/172] haiku support. TLS unsupported thus disabled. --- CMakeLists.txt | 2 +- src/os.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e37efcb0..43ceb7fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,7 +145,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "Intel") list(APPEND mi_cflags -Wall -fvisibility=hidden) endif() -if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel") +if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku") if(MI_LOCAL_DYNAMIC_TLS MATCHES "ON") list(APPEND mi_cflags -ftls-model=local-dynamic) else() diff --git a/src/os.c b/src/os.c index 1d6df907..86ea6cd1 100644 --- a/src/os.c +++ b/src/os.c @@ -31,6 +31,10 @@ terms of the MIT license. A copy of the license can be found in the file #include #endif #endif +#if defined(__HAIKU__) +#define madvise posix_madvise +#define MADV_DONTNEED POSIX_MADV_DONTNEED +#endif #endif /* ----------------------------------------------------------- @@ -882,7 +886,7 @@ static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) return VirtualAlloc(addr, size, flags, PAGE_READWRITE); } -#elif defined(MI_OS_USE_MMAP) && (MI_INTPTR_SIZE >= 8) +#elif defined(MI_OS_USE_MMAP) && (MI_INTPTR_SIZE >= 8) && !defined(__HAIKU__) #include #ifndef MPOL_PREFERRED #define MPOL_PREFERRED 1 From 82f4e5c48e7c73a36abef8f487aaf6b8440d2c02 Mon Sep 17 00:00:00 2001 From: Wanja Vogel Date: Wed, 8 Jul 2020 21:45:43 +0200 Subject: [PATCH 017/172] Update documentation-header to current source code after 03d9946 --- doc/mimalloc-doc.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 67f4fe95..2e74fb02 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -752,8 +752,8 @@ 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_stats, ///< Print statistics to `stderr` when the program is done. 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`. // the following options are experimental mi_option_eager_commit, ///< Eagerly commit segments (4MiB) (enabled by default). @@ -772,9 +772,11 @@ typedef enum mi_option_e { } mi_option_t; -bool mi_option_enabled(mi_option_t option); -void mi_option_enable(mi_option_t option, bool enable); -void mi_option_enable_default(mi_option_t option, bool enable); +bool mi_option_is_enabled(mi_option_t option); +void mi_option_enable(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_default(mi_option_t option, bool enable); long mi_option_get(mi_option_t option); void mi_option_set(mi_option_t option, long value); From a60824190092741ad7c82504d0c9655340d74bcc Mon Sep 17 00:00:00 2001 From: Wanja Vogel Date: Wed, 8 Jul 2020 21:45:43 +0200 Subject: [PATCH 018/172] Update documentation-header to current source code after 03d9946 fix #266 --- doc/mimalloc-doc.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 67f4fe95..2e74fb02 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -752,8 +752,8 @@ 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_stats, ///< Print statistics to `stderr` when the program is done. 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`. // the following options are experimental mi_option_eager_commit, ///< Eagerly commit segments (4MiB) (enabled by default). @@ -772,9 +772,11 @@ typedef enum mi_option_e { } mi_option_t; -bool mi_option_enabled(mi_option_t option); -void mi_option_enable(mi_option_t option, bool enable); -void mi_option_enable_default(mi_option_t option, bool enable); +bool mi_option_is_enabled(mi_option_t option); +void mi_option_enable(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_default(mi_option_t option, bool enable); long mi_option_get(mi_option_t option); void mi_option_set(mi_option_t option, long value); From b9a7f5cfaed087cc6a5b5fc02862234fa771eebf Mon Sep 17 00:00:00 2001 From: Tyler Young Date: Thu, 9 Jul 2020 10:58:47 -0400 Subject: [PATCH 019/172] fix mman.h ref --- src/os.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/os.c b/src/os.c index f7d5f7b1..3c14bb74 100644 --- a/src/os.c +++ b/src/os.c @@ -23,7 +23,12 @@ terms of the MIT license. A copy of the license can be found in the file #include // mmap #include // sysconf #if defined(__linux__) +#include +#if defined(__GLIBC__) #include // linux mmap flags +#else +#include +#endif #endif #if defined(__APPLE__) #include From 0c550d1626e2282a7dbd211342699abd6e4178f0 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Jul 2020 03:23:20 +0100 Subject: [PATCH 020/172] illumos support/build fix and large page support --- include/mimalloc-internal.h | 4 ++++ src/os.c | 10 ++++++++++ src/random.c | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 35413315..c0a084c2 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -241,6 +241,10 @@ static inline bool mi_malloc_satisfies_alignment(size_t alignment, size_t size) static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5 #include // UINT_MAX, ULONG_MAX +#if defined(_CLOCK_T) +#undef _CLOCK_T +#endif + #if (SIZE_MAX == UINT_MAX) return __builtin_umul_overflow(count, size, total); #elif (SIZE_MAX == ULONG_MAX) diff --git a/src/os.c b/src/os.c index 1d6df907..08283ef5 100644 --- a/src/os.c +++ b/src/os.c @@ -401,6 +401,16 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro }; } #endif + #if defined(__sun) + if (allow_large && use_large_os_page(size, try_alignment)) { + struct memcntl_mha cmd = {0}; + cmd.mha_pagesize = large_os_page_size; + cmd.mha_cmd = MHA_MAPSIZE_VA; + if (memcntl(p, size, MC_HAT_ADVISE, (caddr_t)&cmd, 0, 0) == 0) { + *is_large = true; + } + } + #endif } if (p == NULL) { _mi_warning_message("unable to allocate OS memory (%zu bytes, error code: %i, address: %p, large only: %d, allow large: %d)\n", size, errno, addr, large_only, allow_large); diff --git a/src/random.c b/src/random.c index b3dbf4f8..2a96ccf6 100644 --- a/src/random.c +++ b/src/random.c @@ -178,7 +178,7 @@ static bool os_random_buf(void* buf, size_t buf_len) { */ #elif defined(ANDROID) || defined(XP_DARWIN) || defined(__APPLE__) || defined(__DragonFly__) || \ defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ - defined(__wasi__) + defined(__sun) || defined(__wasi__) #include static bool os_random_buf(void* buf, size_t buf_len) { arc4random_buf(buf, buf_len); From 892ec12611bdcc9444eb814d232bdf8546845261 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Jul 2020 11:10:45 -0700 Subject: [PATCH 021/172] Support Windows Vista and XP for NUMA aware alloction (issue #277) --- src/os.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/os.c b/src/os.c index 1d6df907..83dce34b 100644 --- a/src/os.c +++ b/src/os.c @@ -93,6 +93,7 @@ size_t _mi_os_good_alloc_size(size_t size) { // We use VirtualAlloc2 for aligned allocation, but it is only supported on Windows 10 and Windows Server 2016. // So, we need to look it up dynamically to run on older systems. (use __stdcall for 32-bit compatibility) // NtAllocateVirtualAllocEx is used for huge OS page allocation (1GiB) +// // We hide MEM_EXTENDED_PARAMETER to compile with older SDK's. #include typedef PVOID (__stdcall *PVirtualAlloc2)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, /* MEM_EXTENDED_PARAMETER* */ void*, ULONG); @@ -100,6 +101,15 @@ typedef NTSTATUS (__stdcall *PNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, SIZE_T* static PVirtualAlloc2 pVirtualAlloc2 = NULL; static PNtAllocateVirtualMemoryEx pNtAllocateVirtualMemoryEx = NULL; +// Similarly, GetNumaProcesorNodeEx is only supported since Windows 7 +#if (_WIN32_WINNT < 0x601) // before Win7 +typedef struct _PROCESSOR_NUMBER { WORD Group; BYTE Number; BYTE Reserved; } PROCESSOR_NUMBER, *PPROCESSOR_NUMBER; +#endif +typedef VOID (__stdcall *PGetCurrentProcessorNumberEx)(PPROCESSOR_NUMBER ProcNumber); +typedef BOOL (__stdcall *PGetNumaProcessorNodeEx)(PPROCESSOR_NUMBER Processor, PUSHORT NodeNumber); +static PGetCurrentProcessorNumberEx pGetCurrentProcessorNumberEx = NULL; +static PGetNumaProcessorNodeEx pGetNumaProcessorNodeEx = NULL; + static bool mi_win_enable_large_os_pages() { if (large_os_page_size > 0) return true; @@ -150,11 +160,19 @@ void _mi_os_init(void) { if (pVirtualAlloc2==NULL) pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2"); FreeLibrary(hDll); } + // NtAllocateVirtualMemoryEx is used for huge page allocation hDll = LoadLibrary(TEXT("ntdll.dll")); if (hDll != NULL) { pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)(void (*)(void))GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); FreeLibrary(hDll); } + // Try to use Win7+ numa API + hDll = LoadLibrary(TEXT("kernel32.dll")); + if (hDll != NULL) { + pGetCurrentProcessorNumberEx = (PGetCurrentProcessorNumberEx)(void (*)(void))GetProcAddress(hDll, "GetCurrentProcessorNumberEx"); + pGetNumaProcessorNodeEx = (PGetNumaProcessorNodeEx)(void (*)(void))GetProcAddress(hDll, "GetNumaProcessorNodeEx"); + FreeLibrary(hDll); + } if (mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { mi_win_enable_large_os_pages(); } @@ -1025,17 +1043,24 @@ void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* stats) { /* ---------------------------------------------------------------------------- Support NUMA aware allocation -----------------------------------------------------------------------------*/ -#ifdef _WIN32 - #if (_WIN32_WINNT < 0x601) // before Win7 - typedef struct _PROCESSOR_NUMBER { WORD Group; BYTE Number; BYTE Reserved; } PROCESSOR_NUMBER, *PPROCESSOR_NUMBER; - WINBASEAPI VOID WINAPI GetCurrentProcessorNumberEx(_Out_ PPROCESSOR_NUMBER ProcNumber); - WINBASEAPI BOOL WINAPI GetNumaProcessorNodeEx(_In_ PPROCESSOR_NUMBER Processor, _Out_ PUSHORT NodeNumber); - #endif +#ifdef _WIN32 static size_t mi_os_numa_nodex() { - PROCESSOR_NUMBER pnum; USHORT numa_node = 0; - GetCurrentProcessorNumberEx(&pnum); - GetNumaProcessorNodeEx(&pnum,&numa_node); + if (pGetCurrentProcessorNumberEx != NULL && pGetNumaProcessorNodeEx != NULL) { + // Extended API is supported + PROCESSOR_NUMBER pnum; + (*pGetCurrentProcessorNumberEx)(&pnum); + USHORT nnode = 0; + BOOL ok = (*pGetNumaProcessorNodeEx)(&pnum, &nnode); + if (ok) numa_node = nnode; + } + else { + // Vista or earlier, use older API that is limited to 64 processors. Issue #277 + DWORD pnum = GetCurrentProcessorNumber(); + UCHAR nnode = 0; + BOOL ok = GetNumaProcessorNode((UCHAR)pnum, &nnode); + if (ok) numa_node = nnode; + } return numa_node; } From 5f51c97fbd438ad48dfd8bdf4b9b6166a864da22 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Jul 2020 11:27:42 -0700 Subject: [PATCH 022/172] override aligned_alloc always if using C compilation (issue #276) --- src/alloc-override.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/alloc-override.c b/src/alloc-override.c index a09153c5..ae7ad7dd 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -183,7 +183,8 @@ void* _aligned_malloc(size_t alignment, size_t size) { return mi_aligne // on some glibc `aligned_alloc` is declared `static inline` so we cannot override it (e.g. Conda). This happens // when _GLIBCXX_HAVE_ALIGNED_ALLOC is not defined. However, in those cases it will use `memalign`, `posix_memalign`, // or `_aligned_malloc` and we can avoid overriding it ourselves. -#if _GLIBCXX_HAVE_ALIGNED_ALLOC +// We should always override if using C compilation. (issue #276) +#if _GLIBCXX_HAVE_ALIGNED_ALLOC || !defined(__cplusplus) void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } #endif From 8769082d63e2b7caf392c62e25fda75f36604f90 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 20 Jul 2020 14:33:03 -0700 Subject: [PATCH 023/172] add pointer validity check in debug mode for mi_usable_size/mi_realloc/mi_expand. Issue #269 --- src/alloc.c | 77 ++++++++++++++++++++++--------------- test/main-override-static.c | 9 ++++- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 607d15b6..57034522 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -387,34 +387,45 @@ static void mi_decl_noinline mi_free_generic(const mi_segment_t* segment, bool l _mi_free_block(page, local, block); } +// Get the segment data belonging to a pointer +// This is just a single `and` in assembly but does further checks in debug mode +// (and secure mode) if this was a valid pointer. +static inline mi_segment_t* mi_checked_ptr_segment(const void* p, const char* msg) +{ + UNUSED(msg); +#if (MI_DEBUG>0) + if (mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0)) { + _mi_error_message(EINVAL, "%s: invalid (unaligned) pointer: %p\n", msg, p); + return NULL; + } +#endif + + mi_segment_t* const segment = _mi_ptr_segment(p); + if (mi_unlikely(segment == NULL)) return NULL; // checks also for (p==NULL) + +#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); + if (mi_likely(_mi_ptr_cookie(segment) == segment->cookie)) { + _mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p); + } + } +#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", p); + } +#endif + return segment; +} + + // Free a block void mi_free(void* p) mi_attr_noexcept { -#if (MI_DEBUG>0) - if (mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0)) { - _mi_error_message(EINVAL, "trying to free an invalid (unaligned) pointer: %p\n", p); - return; - } -#endif - - const mi_segment_t* const segment = _mi_ptr_segment(p); - if (mi_unlikely(segment == NULL)) return; // checks for (p==NULL) - -#if (MI_DEBUG!=0) - if (mi_unlikely(!mi_is_in_heap_region(p))) { - _mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: %p\n" - "(this may still be a valid very large allocation (over 64MiB))\n", p); - if (mi_likely(_mi_ptr_cookie(segment) == segment->cookie)) { - _mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p); - } - } -#endif -#if (MI_DEBUG!=0 || MI_SECURE>=4) - if (mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie)) { - _mi_error_message(EINVAL, "trying to free a pointer that does not point to a valid heap space: %p\n", p); - return; - } -#endif + const mi_segment_t* const segment = mi_checked_ptr_segment(p,"mi_free"); + if (mi_unlikely(segment == NULL)) return; const uintptr_t tid = _mi_thread_id(); mi_page_t* const page = _mi_segment_page_of(segment, p); @@ -473,9 +484,9 @@ bool _mi_free_delayed_block(mi_block_t* block) { } // Bytes available in a block -size_t mi_usable_size(const void* p) mi_attr_noexcept { - if (p==NULL) return 0; - const mi_segment_t* const segment = _mi_ptr_segment(p); +static 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 (segment==NULL) return 0; const mi_page_t* const page = _mi_segment_page_of(segment, p); const mi_block_t* block = (const mi_block_t*)p; if (mi_unlikely(mi_page_has_aligned(page))) { @@ -490,6 +501,10 @@ size_t mi_usable_size(const void* p) mi_attr_noexcept { } } +size_t mi_usable_size(const void* p) mi_attr_noexcept { + return _mi_usable_size(p, "mi_usable_size"); +} + // ------------------------------------------------------ // ensure explicit external inline definitions are emitted! @@ -513,7 +528,7 @@ void* _mi_externs[] = { void mi_free_size(void* p, size_t size) mi_attr_noexcept { UNUSED_RELEASE(size); - mi_assert(p == NULL || size <= mi_usable_size(p)); + mi_assert(p == NULL || size <= _mi_usable_size(p,"mi_free_size")); mi_free(p); } @@ -553,14 +568,14 @@ mi_decl_restrict void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept { // Expand in place or fail void* mi_expand(void* p, size_t newsize) mi_attr_noexcept { if (p == NULL) return NULL; - size_t size = mi_usable_size(p); + size_t size = _mi_usable_size(p,"mi_expand"); if (newsize > size) return NULL; return p; // it fits } void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) { if (p == NULL) return _mi_heap_malloc_zero(heap,newsize,zero); - size_t size = mi_usable_size(p); + size_t size = _mi_usable_size(p,"mi_realloc"); if (newsize <= size && newsize >= (size / 2)) { return p; // reallocation still fits and not more than 50% waste } diff --git a/test/main-override-static.c b/test/main-override-static.c index 9243fd21..f738c517 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 invalid_free(); int main() { mi_version(); @@ -19,7 +20,8 @@ int main() { // double_free1(); // double_free2(); // corrupt_free(); - block_overflow1(); + // block_overflow1(); + invalid_free(); void* p1 = malloc(78); void* p2 = malloc(24); @@ -43,6 +45,11 @@ int main() { return 0; } +static void invalid_free() { + free((void*)0xBADBEEF); + realloc((void*)0xBADBEEF,10); +} + static void block_overflow1() { uint8_t* p = (uint8_t*)mi_malloc(17); p[18] = 0; From 71160e2bac443c0dd35c7ee13993466efcee57b2 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 21 Jul 2020 08:49:21 -0700 Subject: [PATCH 024/172] Fix glibc version (issue #270) --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 7ec20d72..a8aee78c 100644 --- a/readme.md +++ b/readme.md @@ -409,7 +409,7 @@ as [mimalloc-bench](https://github.com/daanx/mimalloc-bench). Testing on a big Amazon EC2 compute instance ([c5.18xlarge](https://aws.amazon.com/ec2/instance-types/#Compute_Optimized)) consisting of a 72 processor Intel Xeon at 3GHz -with 144GiB ECC memory, running Ubuntu 18.04.1 with LibC 2.27 and GCC 7.4.0. +with 144GiB ECC memory, running Ubuntu 18.04.1 with glibc 2.27 and GCC 7.4.0. The measured allocators are _mimalloc_ (xmi, tag:v1.4.0, page reset enabled) and its secure build as _smi_, Google's [_tcmalloc_](https://github.com/gperftools/gperftools) (tc, tag:gperftools-2.7) used in Chrome, @@ -419,7 +419,7 @@ the Intel thread building blocks [allocator](https://github.com/intel/tbb) (tbb, the original scalable [_Hoard_](https://github.com/emeryberger/Hoard) (tag:3.13) allocator by Emery Berger \[1], the memory compacting [_Mesh_](https://github.com/plasma-umass/Mesh) (git:51222e7) allocator by Bobby Powers _et al_ \[8], -and finally the default system allocator (glibc, 2.7.0) (based on _PtMalloc2_). +and finally the default system allocator (glibc, 2.27) (based on _PtMalloc2_). From 01da02631456f659101875d34812bc8a08ec0690 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 21 Jul 2020 09:10:45 -0700 Subject: [PATCH 025/172] add option to build with thread sanitizer --- CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e37efcb0..4eeaccf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ option(MI_BUILD_SHARED "Build shared library" ON) option(MI_BUILD_STATIC "Build static library" ON) 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_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) include("cmake/mimalloc-config-version.cmake") @@ -133,6 +134,16 @@ if(MI_USE_CXX MATCHES "ON") endif() endif() +if(MI_DEBUG_TSAN MATCHES "ON") + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") + list(APPEND mi_cflags -fsanitize=thread -g) + list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=thread) + else() + message(WARNING "Can only use thread sanitizer with clang (MI_DEBUG_TSAN=ON but ignored)") + endif() +endif() + # Compiler flags if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") list(APPEND mi_cflags -Wall -Wextra -Wno-unknown-pragmas -fvisibility=hidden) From 76756ad63c30e04ccb361809026242f38a2d24d7 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 21 Jul 2020 18:27:54 -0700 Subject: [PATCH 026/172] update documentation --- doc/mimalloc-doc.h | 4 +- docs/group__extended.html | 18 ++-- docs/group__extended.js | 2 +- docs/group__options.html | 176 +++++++++++++++++++------------ docs/group__options.js | 12 ++- docs/mimalloc-doc_8h_source.html | 19 ++-- docs/navtreeindex0.js | 16 +-- docs/search/all_6.js | 11 +- docs/search/functions_0.js | 11 +- 9 files changed, 161 insertions(+), 108 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 2e74fb02..f11a97b0 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -298,7 +298,7 @@ size_t mi_good_size(size_t size); /// resource usage by calling this every once in a while. void mi_collect(bool force); -/// Print the main statistics. +/// Deprecated /// @param out Ignored, outputs to the registered output function or stderr by default. /// /// Most detailed when using a debug build. @@ -309,7 +309,7 @@ void mi_stats_print(void* out); /// @param arg Optional argument passed to \a out (if not \a NULL) /// /// Most detailed when using a debug build. -void mi_stats_print(mi_output_fun* out, void* arg); +void mi_stats_print_out(mi_output_fun* out, void* arg); /// Reset statistics. void mi_stats_reset(void); diff --git a/docs/group__extended.html b/docs/group__extended.html index 325d62bf..575288ab 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -146,11 +146,11 @@ Functions  Eagerly free memory. More...
  void mi_stats_print (void *out) - Print the main statistics. More...
+ Deprecated. More...
  -void mi_stats_print (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. More...
+  void mi_stats_reset (void)  Reset statistics. More...
  @@ -646,7 +646,7 @@ Functions -

◆ mi_stats_print() [1/2]

+

◆ mi_stats_print()

@@ -661,7 +661,7 @@ Functions
-

Print the main statistics.

+

Deprecated.

Parameters
@@ -672,14 +672,14 @@ Functions - -

◆ mi_stats_print() [2/2]

+ +

◆ mi_stats_print_out()

outIgnored, outputs to the registered output function or stderr by default.
- + diff --git a/docs/group__extended.js b/docs/group__extended.js index ff8891b2..594cadb9 100644 --- a/docs/group__extended.js +++ b/docs/group__extended.js @@ -16,7 +16,7 @@ var group__extended = [ "mi_reserve_huge_os_pages_interleave", "group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50", null ], [ "mi_stats_merge", "group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1", null ], [ "mi_stats_print", "group__extended.html#ga2d126e5c62d3badc35445e5d84166df2", null ], - [ "mi_stats_print", "group__extended.html#ga256cc6f13a142deabbadd954a217e228", null ], + [ "mi_stats_print_out", "group__extended.html#ga537f13b299ddf801e49a5a94fde02c79", null ], [ "mi_stats_reset", "group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99", null ], [ "mi_thread_done", "group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf", null ], [ "mi_thread_init", "group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17", null ], diff --git a/docs/group__options.html b/docs/group__options.html index 5e45d7bd..9425765e 100644 --- a/docs/group__options.html +++ b/docs/group__options.html @@ -112,8 +112,8 @@ $(document).ready(function(){initNavTree('group__options.html','');});
void mi_stats_print void mi_stats_print_out ( mi_output_fun out,

Enumerations

enum  mi_option_t {
-  mi_option_show_stats, -mi_option_show_errors, +  mi_option_show_errors, +mi_option_show_stats, mi_option_verbose, mi_option_eager_commit,
@@ -138,12 +138,16 @@ Enumerations
- - - - - - + + + + + + + + + + @@ -168,9 +172,9 @@ Functions

Runtime options.

Functions

bool mi_option_enabled (mi_option_t option)
 
void mi_option_enable (mi_option_t option, bool enable)
 
void mi_option_enable_default (mi_option_t option, bool enable)
 
bool mi_option_is_enabled (mi_option_t option)
 
void mi_option_enable (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_default (mi_option_t option, bool enable)
 
long mi_option_get (mi_option_t option)
 
void mi_option_set (mi_option_t option, long value)
- - @@ -204,8 +208,26 @@ Functions

Function Documentation

- -

◆ mi_option_enable()

+ +

◆ mi_option_disable()

+ +
+
+
Enumerator
mi_option_show_stats 

Print statistics to stderr when the program is done.

+
Enumerator
mi_option_show_errors 

Print error messages to stderr.

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.

+ + + + + + + +
void mi_option_disable (mi_option_t option)
+
+ +
+
+ +

◆ mi_option_enable()

@@ -214,62 +236,6 @@ Functions void mi_option_enable ( mi_option_t  - option, - - - - - bool  - enable  - - - - ) - - - -
- -
-
- -

◆ mi_option_enable_default()

- -
-
- - - - - - - - - - - - - - - - - - -
void mi_option_enable_default (mi_option_t option,
bool enable 
)
-
- -
-
- -

◆ mi_option_enabled()

- -
-
- - - - - @@ -294,6 +260,24 @@ Functions
bool mi_option_enabled (mi_option_t  option)
+
+
+ +

◆ mi_option_is_enabled()

+ +
+
+ + + + + + + + +
bool mi_option_is_enabled (mi_option_t option)
+
+
@@ -350,6 +334,62 @@ Functions
+
+ + +

◆ mi_option_set_enabled()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void mi_option_set_enabled (mi_option_t option,
bool enable 
)
+
+ +
+
+ +

◆ mi_option_set_enabled_default()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void mi_option_set_enabled_default (mi_option_t option,
bool enable 
)
+
+
diff --git a/docs/group__options.js b/docs/group__options.js index 1d84ea8b..9aaf2318 100644 --- a/docs/group__options.js +++ b/docs/group__options.js @@ -1,8 +1,8 @@ var group__options = [ [ "mi_option_t", "group__options.html#gafebf7ed116adb38ae5218bc3ce06884c", [ - [ "mi_option_show_stats", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda", null ], [ "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 ], @@ -18,10 +18,12 @@ var group__options = [ "mi_option_os_tag", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf", null ], [ "_mi_option_last", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a", null ] ] ], - [ "mi_option_enable", "group__options.html#ga6d45a20a3131f18bc351b69763b38ce4", null ], - [ "mi_option_enable_default", "group__options.html#ga37988264b915a7db92530cc02d5494cb", null ], - [ "mi_option_enabled", "group__options.html#gacebe3f6d91b4a50b54eb84e2a1da1b30", 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_is_enabled", "group__options.html#ga459ad98f18b3fc9275474807fe0ca188", null ], [ "mi_option_set", "group__options.html#gaf84921c32375e25754dc2ee6a911fa60", null ], - [ "mi_option_set_default", "group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90", null ] + [ "mi_option_set_default", "group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90", null ], + [ "mi_option_set_enabled", "group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed", null ], + [ "mi_option_set_enabled_default", "group__options.html#ga65518b69ec5d32336b50e07f74b3f629", null ] ]; \ No newline at end of file diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index 09c03b9b..c4637bad 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -102,22 +102,24 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
mimalloc-doc.h
-
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
83 
87 
91 void mi_free(void* p);
92 
97 void* mi_malloc(size_t size);
98 
103 void* mi_zalloc(size_t size);
104 
114 void* mi_calloc(size_t count, size_t size);
115 
128 void* mi_realloc(void* p, size_t newsize);
129 
140 void* mi_recalloc(void* p, size_t count, size_t size);
141 
155 void* mi_expand(void* p, size_t newsize);
156 
166 void* mi_mallocn(size_t count, size_t size);
167 
177 void* mi_reallocn(void* p, size_t count, size_t size);
178 
195 void* mi_reallocf(void* p, size_t newsize);
196 
197 
206 char* mi_strdup(const char* s);
207 
217 char* mi_strndup(const char* s, size_t n);
218 
231 char* mi_realpath(const char* fname, char* resolved_name);
232 
234 
235 // ------------------------------------------------------
236 // Extended functionality
237 // ------------------------------------------------------
238 
242 
245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
246 
254 void* mi_malloc_small(size_t size);
255 
263 void* mi_zalloc_small(size_t size);
264 
279 size_t mi_usable_size(void* p);
280 
290 size_t mi_good_size(size_t size);
291 
299 void mi_collect(bool force);
300 
305 void mi_stats_print(void* out);
306 
312 void mi_stats_print(mi_output_fun* out, void* arg);
313 
315 void mi_stats_reset(void);
316 
318 void mi_stats_merge(void);
319 
323 void mi_thread_init(void);
324 
329 void mi_thread_done(void);
330 
336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
337 
344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
345 
361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
362 
368 typedef void (mi_output_fun)(const char* msg, void* arg);
369 
376 void mi_register_output(mi_output_fun* out, void* arg);
377 
383 typedef void (mi_error_fun)(int err, void* arg);
384 
400 void mi_register_error(mi_error_fun* errfun, void* arg);
401 
406 bool mi_is_in_heap_region(const void* p);
407 
408 
421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
422 
435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
436 
437 
442 bool mi_is_redirected();
443 
444 
446 
447 // ------------------------------------------------------
448 // Aligned allocation
449 // ------------------------------------------------------
450 
456 
469 void* mi_malloc_aligned(size_t size, size_t alignment);
470 void* mi_zalloc_aligned(size_t size, size_t alignment);
471 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
472 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
473 
484 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
485 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
486 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
487 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
488 
490 
496 
501 struct mi_heap_s;
502 
507 typedef struct mi_heap_s mi_heap_t;
508 
511 
519 void mi_heap_delete(mi_heap_t* heap);
520 
528 void mi_heap_destroy(mi_heap_t* heap);
529 
534 
538 
545 
547 void mi_heap_collect(mi_heap_t* heap, bool force);
548 
551 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
552 
556 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
557 
560 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
561 
564 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
565 
568 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
569 
572 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
573 
576 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
577 
580 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
581 
582 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
583 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
584 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
585 
586 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
587 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
588 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
589 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
590 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
591 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
592 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
593 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
594 
596 
597 
606 
607 void* mi_rezalloc(void* p, size_t newsize);
608 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
609 
610 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
611 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
612 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
613 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
614 
615 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
616 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
617 
618 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
619 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
620 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
621 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
622 
624 
633 
645 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
646 
648 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
649 
651 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
652 
654 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
655 
657 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
658 
660 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
661 
663 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
664 
666 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
667 
669 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
670 
672 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
673 
675 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
676 
678 
684 
691 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
692 
701 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
702 
710 bool mi_check_owned(const void* p);
711 
714 typedef struct mi_heap_area_s {
715  void* blocks;
716  size_t reserved;
717  size_t committed;
718  size_t used;
719  size_t block_size;
721 
729 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
730 
742 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
743 
745 
751 
753 typedef enum mi_option_e {
754  // stable options
758  // the following options are experimental
772 } mi_option_t;
773 
774 
775 bool mi_option_enabled(mi_option_t option);
776 void mi_option_enable(mi_option_t option, bool enable);
777 void mi_option_enable_default(mi_option_t option, bool enable);
778 
779 long mi_option_get(mi_option_t option);
780 void mi_option_set(mi_option_t option, long value);
781 void mi_option_set_default(mi_option_t option, long value);
782 
783 
785 
792 
793 void* mi_recalloc(void* p, size_t count, size_t size);
794 size_t mi_malloc_size(const void* p);
795 size_t mi_malloc_usable_size(const void *p);
796 
798 void mi_cfree(void* p);
799 
800 int mi_posix_memalign(void** p, size_t alignment, size_t size);
801 int mi__posix_memalign(void** p, size_t alignment, size_t size);
802 void* mi_memalign(size_t alignment, size_t size);
803 void* mi_valloc(size_t size);
804 
805 void* mi_pvalloc(size_t size);
806 void* mi_aligned_alloc(size_t alignment, size_t size);
807 void* mi_reallocarray(void* p, size_t count, size_t size);
808 
809 void mi_free_size(void* p, size_t size);
810 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
811 void mi_free_aligned(void* p, size_t alignment);
812 
814 
827 
829 void* mi_new(std::size_t n) noexcept(false);
830 
832 void* mi_new_n(size_t count, size_t size) noexcept(false);
833 
835 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
836 
838 void* mi_new_nothrow(size_t n);
839 
841 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
842 
844 void* mi_new_realloc(void* p, size_t newsize);
845 
847 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
848 
856 template<class T> struct mi_stl_allocator { }
857 
859 
void mi_option_enable_default(mi_option_t option, bool enable)
-
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
+
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
83 
87 
91 void mi_free(void* p);
92 
97 void* mi_malloc(size_t size);
98 
103 void* mi_zalloc(size_t size);
104 
114 void* mi_calloc(size_t count, size_t size);
115 
128 void* mi_realloc(void* p, size_t newsize);
129 
140 void* mi_recalloc(void* p, size_t count, size_t size);
141 
155 void* mi_expand(void* p, size_t newsize);
156 
166 void* mi_mallocn(size_t count, size_t size);
167 
177 void* mi_reallocn(void* p, size_t count, size_t size);
178 
195 void* mi_reallocf(void* p, size_t newsize);
196 
197 
206 char* mi_strdup(const char* s);
207 
217 char* mi_strndup(const char* s, size_t n);
218 
231 char* mi_realpath(const char* fname, char* resolved_name);
232 
234 
235 // ------------------------------------------------------
236 // Extended functionality
237 // ------------------------------------------------------
238 
242 
245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
246 
254 void* mi_malloc_small(size_t size);
255 
263 void* mi_zalloc_small(size_t size);
264 
279 size_t mi_usable_size(void* p);
280 
290 size_t mi_good_size(size_t size);
291 
299 void mi_collect(bool force);
300 
305 void mi_stats_print(void* out);
306 
312 void mi_stats_print_out(mi_output_fun* out, void* arg);
313 
315 void mi_stats_reset(void);
316 
318 void mi_stats_merge(void);
319 
323 void mi_thread_init(void);
324 
329 void mi_thread_done(void);
330 
336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
337 
344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
345 
361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
362 
368 typedef void (mi_output_fun)(const char* msg, void* arg);
369 
376 void mi_register_output(mi_output_fun* out, void* arg);
377 
383 typedef void (mi_error_fun)(int err, void* arg);
384 
400 void mi_register_error(mi_error_fun* errfun, void* arg);
401 
406 bool mi_is_in_heap_region(const void* p);
407 
408 
421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
422 
435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
436 
437 
442 bool mi_is_redirected();
443 
444 
446 
447 // ------------------------------------------------------
448 // Aligned allocation
449 // ------------------------------------------------------
450 
456 
469 void* mi_malloc_aligned(size_t size, size_t alignment);
470 void* mi_zalloc_aligned(size_t size, size_t alignment);
471 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
472 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
473 
484 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
485 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
486 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
487 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
488 
490 
496 
501 struct mi_heap_s;
502 
507 typedef struct mi_heap_s mi_heap_t;
508 
511 
519 void mi_heap_delete(mi_heap_t* heap);
520 
528 void mi_heap_destroy(mi_heap_t* heap);
529 
534 
538 
545 
547 void mi_heap_collect(mi_heap_t* heap, bool force);
548 
551 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
552 
556 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
557 
560 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
561 
564 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
565 
568 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
569 
572 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
573 
576 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
577 
580 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
581 
582 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
583 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
584 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
585 
586 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
587 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
588 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
589 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
590 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
591 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
592 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
593 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
594 
596 
597 
606 
607 void* mi_rezalloc(void* p, size_t newsize);
608 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
609 
610 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
611 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
612 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
613 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
614 
615 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
616 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
617 
618 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
619 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
620 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
621 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
622 
624 
633 
645 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
646 
648 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
649 
651 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
652 
654 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
655 
657 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
658 
660 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
661 
663 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
664 
666 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
667 
669 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
670 
672 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
673 
675 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
676 
678 
684 
691 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
692 
701 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
702 
710 bool mi_check_owned(const void* p);
711 
714 typedef struct mi_heap_area_s {
715  void* blocks;
716  size_t reserved;
717  size_t committed;
718  size_t used;
719  size_t block_size;
721 
729 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
730 
742 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
743 
745 
751 
753 typedef enum mi_option_e {
754  // stable options
758  // the following options are experimental
772 } mi_option_t;
773 
774 
775 bool mi_option_is_enabled(mi_option_t option);
776 void mi_option_enable(mi_option_t option);
777 void mi_option_disable(mi_option_t option);
778 void mi_option_set_enabled(mi_option_t option, bool enable);
779 void mi_option_set_enabled_default(mi_option_t option, bool enable);
780 
781 long mi_option_get(mi_option_t option);
782 void mi_option_set(mi_option_t option, long value);
783 void mi_option_set_default(mi_option_t option, long value);
784 
785 
787 
794 
795 void* mi_recalloc(void* p, size_t count, size_t size);
796 size_t mi_malloc_size(const void* p);
797 size_t mi_malloc_usable_size(const void *p);
798 
800 void mi_cfree(void* p);
801 
802 int mi_posix_memalign(void** p, size_t alignment, size_t size);
803 int mi__posix_memalign(void** p, size_t alignment, size_t size);
804 void* mi_memalign(size_t alignment, size_t size);
805 void* mi_valloc(size_t size);
806 
807 void* mi_pvalloc(size_t size);
808 void* mi_aligned_alloc(size_t alignment, size_t size);
809 void* mi_reallocarray(void* p, size_t count, size_t size);
810 
811 void mi_free_size(void* p, size_t size);
812 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
813 void mi_free_aligned(void* p, size_t alignment);
814 
816 
829 
831 void* mi_new(std::size_t n) noexcept(false);
832 
834 void* mi_new_n(size_t count, size_t size) noexcept(false);
835 
837 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
838 
840 void* mi_new_nothrow(size_t n);
841 
843 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
844 
846 void* mi_new_realloc(void* p, size_t newsize);
847 
849 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
850 
858 template<class T> struct mi_stl_allocator { }
859 
861 
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
void * mi_new_nothrow(size_t n)
like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
void * mi_reallocn(void *p, size_t count, size_t size)
Re-allocate memory to count elements of size bytes.
void * mi_malloc_aligned(size_t size, size_t alignment)
Allocate size bytes aligned by alignment.
void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
void mi_stats_reset(void)
Reset statistics.
void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
+
bool mi_option_is_enabled(mi_option_t option)
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_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_mallocn(size_t count, size_t size)
Allocate count elements of size bytes.
size_t mi_malloc_size(const void *p)
+
void mi_option_set_enabled(mi_option_t option, bool enable)
int mi_posix_memalign(void **p, size_t alignment, size_t size)
void mi_stats_merge(void)
Merge thread local statistics with the main statistics and reset.
void * mi_new_n(size_t count, size_t size) noexcept(false)
like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
void mi_option_set_default(mi_option_t option, long value)
+
void mi_stats_print_out(mi_output_fun *out, void *arg)
Print the main statistics.
void() mi_error_fun(int err, void *arg)
Type of error callback functions.
Definition: mimalloc-doc.h:383
void * mi_rezalloc(void *p, size_t newsize)
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:759
@@ -130,6 +132,7 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:715
void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
+
void mi_option_enable(mi_option_t option)
int mi__posix_memalign(void **p, size_t alignment, size_t size)
void mi_free(void *p)
Free previously allocated memory.
char * mi_heap_strdup(mi_heap_t *heap, const char *s)
Duplicate a string in a specific heap.
@@ -141,6 +144,7 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
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.
void * mi_pvalloc(size_t size)
+
void mi_option_set_enabled_default(mi_option_t option, bool enable)
void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
void * mi_zalloc(size_t size)
Allocate zero-initialized size bytes.
void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
@@ -153,7 +157,6 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most t...
void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
Type of deferred free functions.
Definition: mimalloc-doc.h:344
bool mi_is_in_heap_region(const void *p)
Is a pointer part of our heap?
-
void mi_option_enable(mi_option_t option, bool enable)
void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc e...
void * mi_realloc(void *p, size_t newsize)
Re-allocate memory to newsize bytes.
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:762
@@ -165,7 +168,6 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
Visit all areas and blocks in a heap.
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:767
void * mi_malloc(size_t size)
Allocate size bytes.
-
bool mi_option_enabled(mi_option_t option)
void mi_register_error(mi_error_fun *errfun, void *arg)
Register an error callback function.
Experimental.
Definition: mimalloc-doc.h:768
char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
Duplicate a string of at most length n in a specific heap.
@@ -173,7 +175,7 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
char * mi_realpath(const char *fname, char *resolved_name)
Resolve a file path name.
-
Print error messages to stderr.
Definition: mimalloc-doc.h:756
+
Print error messages to stderr.
Definition: mimalloc-doc.h:755
Experimental.
Definition: mimalloc-doc.h:765
void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
void * mi_new_aligned_nothrow(size_t n, size_t alignment)
like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
@@ -189,17 +191,18 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:770
mi_heap_t * mi_heap_get_default()
Get the default heap that is used for mi_malloc() et al.
int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs ...
+
void mi_option_disable(mi_option_t option)
void * mi_aligned_alloc(size_t alignment, size_t size)
void * mi_valloc(size_t size)
void mi_thread_init(void)
Initialize mimalloc on a thread.
size_t mi_good_size(size_t size)
Return the used allocation size.
-
void mi_stats_print(void *out)
Print the main statistics.
+
void mi_stats_print(void *out)
Deprecated.
Experimental.
Definition: mimalloc-doc.h:769
void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
Allocate count elements in a specific heap.
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:714
void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
Print out heap statistics for this thread.
-
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:755
+
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:756
void * mi_zalloc_aligned(size_t size, size_t alignment)
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:716
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:507
@@ -213,7 +216,7 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:761
void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
void mi_register_output(mi_output_fun *out, void *arg)
Register an output function.
-
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:856
+
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:858
void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
Allocate a small object in a specific heap.
void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
size_t mi_malloc_usable_size(const void *p)
diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js index 047d6dbc..51be8fb7 100644 --- a/docs/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -43,13 +43,13 @@ var NAVTREEINDEX0 = "group__extended.html#ga1ea64283508718d9d645c38efc2f4305":[5,1,0], "group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,22], "group__extended.html#ga251d369cda3f1c2a955c555486ed90e5":[5,1,2], -"group__extended.html#ga256cc6f13a142deabbadd954a217e228":[5,1,16], "group__extended.html#ga299dae78d25ce112e384a98b7309c5be":[5,1,1], "group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,15], "group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,13], "group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,9], "group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,17], "group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,4], +"group__extended.html#ga537f13b299ddf801e49a5a94fde02c79":[5,1,16], "group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,6], "group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,8], "group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,12], @@ -104,14 +104,16 @@ var NAVTREEINDEX0 = "group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000":[5,0,12], "group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0":[5,0,6], "group__options.html":[5,7], -"group__options.html#ga37988264b915a7db92530cc02d5494cb":[5,7,2], -"group__options.html#ga6d45a20a3131f18bc351b69763b38ce4":[5,7,1], -"group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a":[5,7,4], +"group__options.html#ga04180ae41b0d601421dd62ced40ca050":[5,7,2], +"group__options.html#ga459ad98f18b3fc9275474807fe0ca188":[5,7,4], +"group__options.html#ga65518b69ec5d32336b50e07f74b3f629":[5,7,8], +"group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a":[5,7,3], "group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90":[5,7,6], -"group__options.html#gacebe3f6d91b4a50b54eb84e2a1da1b30":[5,7,3], +"group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed":[5,7,7], +"group__options.html#gaebf6ff707a2e688ebb1a2296ca564054":[5,7,1], "group__options.html#gaf84921c32375e25754dc2ee6a911fa60":[5,7,5], "group__options.html#gafebf7ed116adb38ae5218bc3ce06884c":[5,7,0], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda":[5,7,0,0], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda":[5,7,0,1], "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74":[5,7,0,11], "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5":[5,7,0,10], "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c":[5,7,0,13], @@ -126,7 +128,7 @@ var NAVTREEINDEX0 = "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2":[5,7,0,6], "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968":[5,7,0,8], "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d":[5,7,0,9], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0":[5,7,0,1], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0":[5,7,0,0], "group__posix.html":[5,8], "group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17":[5,8,7], "group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9":[5,8,3], diff --git a/docs/search/all_6.js b/docs/search/all_6.js index c757cbbf..5c2aa01e 100644 --- a/docs/search/all_6.js +++ b/docs/search/all_6.js @@ -80,13 +80,13 @@ var searchData= ['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]], ['mi_5fnew_5frealloc',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]], ['mi_5fnew_5freallocn',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], ['mi_5foption_5feager_5fcommit',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], ['mi_5foption_5feager_5fcommit_5fdelay',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], ['mi_5foption_5feager_5fregion_5fcommit',['mi_option_eager_region_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable',['mi_option_enable',['../group__options.html#ga6d45a20a3131f18bc351b69763b38ce4',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_5fdefault',['mi_option_enable_default',['../group__options.html#ga37988264b915a7db92530cc02d5494cb',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenabled',['mi_option_enabled',['../group__options.html#gacebe3f6d91b4a50b54eb84e2a1da1b30',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], ['mi_5foption_5fget',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], ['mi_5foption_5flarge_5fos_5fpages',['mi_option_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e',1,'mimalloc-doc.h']]], ['mi_5foption_5fos_5ftag',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], ['mi_5foption_5fpage_5freset',['mi_option_page_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968',1,'mimalloc-doc.h']]], @@ -97,6 +97,8 @@ var searchData= ['mi_5foption_5fsegment_5freset',['mi_option_segment_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d',1,'mimalloc-doc.h']]], ['mi_5foption_5fset',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], ['mi_5foption_5fset_5fdefault',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], ['mi_5foption_5fshow_5ferrors',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], ['mi_5foption_5fshow_5fstats',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], ['mi_5foption_5ft',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], @@ -126,7 +128,8 @@ var searchData= ['mi_5frezalloc_5faligned_5fat',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], ['mi_5fsmall_5fsize_5fmax',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], ['mi_5fstats_5fmerge',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mi_stats_print(void *out): mimalloc-doc.h'],['../group__extended.html#ga256cc6f13a142deabbadd954a217e228',1,'mi_stats_print(mi_output_fun *out, void *arg): mimalloc-doc.h']]], + ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], ['mi_5fstats_5freset',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], ['mi_5fstl_5fallocator',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]], ['mi_5fstrdup',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js index 6271797a..f2b65c2d 100644 --- a/docs/search/functions_0.js +++ b/docs/search/functions_0.js @@ -66,12 +66,14 @@ var searchData= ['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]], ['mi_5fnew_5frealloc',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]], ['mi_5fnew_5freallocn',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable',['mi_option_enable',['../group__options.html#ga6d45a20a3131f18bc351b69763b38ce4',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenable_5fdefault',['mi_option_enable_default',['../group__options.html#ga37988264b915a7db92530cc02d5494cb',1,'mimalloc-doc.h']]], - ['mi_5foption_5fenabled',['mi_option_enabled',['../group__options.html#gacebe3f6d91b4a50b54eb84e2a1da1b30',1,'mimalloc-doc.h']]], + ['mi_5foption_5fdisable',['mi_option_disable',['../group__options.html#gaebf6ff707a2e688ebb1a2296ca564054',1,'mimalloc-doc.h']]], + ['mi_5foption_5fenable',['mi_option_enable',['../group__options.html#ga04180ae41b0d601421dd62ced40ca050',1,'mimalloc-doc.h']]], ['mi_5foption_5fget',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], + ['mi_5foption_5fis_5fenabled',['mi_option_is_enabled',['../group__options.html#ga459ad98f18b3fc9275474807fe0ca188',1,'mimalloc-doc.h']]], ['mi_5foption_5fset',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], ['mi_5foption_5fset_5fdefault',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], + ['mi_5foption_5fset_5fenabled_5fdefault',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], ['mi_5fposix_5fmemalign',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], ['mi_5fpvalloc',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], ['mi_5frealloc',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], @@ -93,7 +95,8 @@ var searchData= ['mi_5frezalloc_5faligned',['mi_rezalloc_aligned',['../group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0',1,'mimalloc-doc.h']]], ['mi_5frezalloc_5faligned_5fat',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], ['mi_5fstats_5fmerge',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mi_stats_print(void *out): mimalloc-doc.h'],['../group__extended.html#ga256cc6f13a142deabbadd954a217e228',1,'mi_stats_print(mi_output_fun *out, void *arg): mimalloc-doc.h']]], + ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint_5fout',['mi_stats_print_out',['../group__extended.html#ga537f13b299ddf801e49a5a94fde02c79',1,'mimalloc-doc.h']]], ['mi_5fstats_5freset',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], ['mi_5fstrdup',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], ['mi_5fstrndup',['mi_strndup',['../group__malloc.html#gaaabf971c2571891433477e2d21a35266',1,'mimalloc-doc.h']]], From c5406f327e3742b24e451da36b651b8400ea19da Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 21 Jul 2020 18:51:25 -0700 Subject: [PATCH 027/172] move include 'limits.h' outside of definition --- include/mimalloc-internal.h | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index c0a084c2..ba322feb 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -238,27 +238,28 @@ static inline bool mi_malloc_satisfies_alignment(size_t alignment, size_t size) } // Overflow detecting multiply -static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5 -#include // UINT_MAX, ULONG_MAX -#if defined(_CLOCK_T) +#include // UINT_MAX, ULONG_MAX +#if defined(_CLOCK_T) // for Illumos #undef _CLOCK_T #endif - -#if (SIZE_MAX == UINT_MAX) - return __builtin_umul_overflow(count, size, total); -#elif (SIZE_MAX == ULONG_MAX) - return __builtin_umull_overflow(count, size, total); -#else - return __builtin_umulll_overflow(count, size, total); -#endif +static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { + #if (SIZE_MAX == UINT_MAX) + return __builtin_umul_overflow(count, size, total); + #elif (SIZE_MAX == ULONG_MAX) + return __builtin_umull_overflow(count, size, total); + #else + return __builtin_umulll_overflow(count, size, total); + #endif +} #else /* __builtin_umul_overflow is unavailable */ +static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) *total = count * size; return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW) - && size > 0 && (SIZE_MAX / size) < count); -#endif + && size > 0 && (SIZE_MAX / size) < count); } +#endif // Safe multiply `count*size` into `total`; return `true` on overflow. static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* total) { From 2254e20d4cc5d497cd8bcdb0fd50098408534e75 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 22 Jul 2020 10:54:58 +0100 Subject: [PATCH 028/172] some apis are available on Illumos which are not available on stock Solaris thus availability evelavated from cflags. discard some sporadically for large pages support mainly. --- src/os.c | 8 ++++++++ src/static.c | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/os.c b/src/os.c index 8079e5a0..24252c85 100644 --- a/src/os.c +++ b/src/os.c @@ -8,6 +8,14 @@ terms of the MIT license. A copy of the license can be found in the file #define _DEFAULT_SOURCE // ensure mmap flags are defined #endif +#if defined(__sun) +// illumos provides new mman.h api when any of these are defined +// otherwise the old api based on caddr_t which predates the void pointers one. +// stock solaris provides only the former, chose to atomically to discard those +// flags only here rather than project wide tough. +#undef _XOPEN_SOURCE +#undef _POSIX_C_SOURCE +#endif #include "mimalloc.h" #include "mimalloc-internal.h" #include "mimalloc-atomic.h" diff --git a/src/static.c b/src/static.c index bf86166d..4fafb4f5 100644 --- a/src/static.c +++ b/src/static.c @@ -5,6 +5,11 @@ terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. -----------------------------------------------------------------------------*/ #define _DEFAULT_SOURCE +#if defined(__sun) +// same remarks as os.c for the static's context. +#undef _XOPEN_SOURCE +#undef _POSIX_C_SOURCE +#endif #include "mimalloc.h" #include "mimalloc-internal.h" From 341048f61ebf01537db4260baf81ed1d838e5ece Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 22 Jul 2020 11:08:16 -0700 Subject: [PATCH 029/172] avoid atomic operations on statistics if zero --- src/stats.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stats.c b/src/stats.c index 478f8229..e0c7f01a 100644 --- a/src/stats.c +++ b/src/stats.c @@ -70,6 +70,7 @@ void _mi_stat_decrease(mi_stat_count_t* stat, size_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; + if (src->allocated==0 && src->freed==0) return; mi_atomic_addi64( &stat->allocated, src->allocated * unit); mi_atomic_addi64( &stat->current, src->current * unit); mi_atomic_addi64( &stat->freed, src->freed * unit); From 529d74a28243fc82b5f8841f1173a264fa5e92bf Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 22 Jul 2020 12:45:53 -0700 Subject: [PATCH 030/172] use O1 with thread sanitizer --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 711af552..0082c448 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ endif() if(MI_DEBUG_TSAN MATCHES "ON") if(CMAKE_C_COMPILER_ID MATCHES "Clang") message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") - list(APPEND mi_cflags -fsanitize=thread -g) + list(APPEND mi_cflags -fsanitize=thread -g -O1) list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=thread) else() message(WARNING "Can only use thread sanitizer with clang (MI_DEBUG_TSAN=ON but ignored)") From 2e1b4f512d4abe0817222fbc839187448860fbf6 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 22 Jul 2020 13:45:04 -0700 Subject: [PATCH 031/172] make max update in the stats atomic --- include/mimalloc-atomic.h | 26 ++++++++++++++++++++++---- src/stats.c | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 8577dbc5..a0452f5c 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -27,10 +27,6 @@ terms of the MIT license. A copy of the license can be found in the file // Atomic operations specialized for mimalloc // ------------------------------------------------------ -// Atomically add a 64-bit value; returns the previous value. -// Note: not using _Atomic(int64_t) as it is only used for statistics. -static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add); - // Atomically add a value; returns the previous value. Memory ordering is relaxed. static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add); @@ -65,6 +61,14 @@ static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x); // Yield static inline void mi_atomic_yield(void); +// Atomically add a 64-bit value; returns the previous value. +// Note: not using _Atomic(int64_t) as it is only used for statistics. +static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add); + +// Atomically take the maximum a 64-bit value; returns the previous value. +// Note: not using _Atomic(int64_t) as it is only used for statistics. +static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x); + // Atomically subtract a value; returns the previous value. static inline uintptr_t mi_atomic_sub(volatile _Atomic(uintptr_t)* p, uintptr_t sub) { @@ -177,6 +181,13 @@ static inline void mi_atomic_addi64(volatile _Atomic(int64_t)* p, int64_t add) { #endif } +static inline void mi_atomic_maxi64(volatile _Atomic(int64_t)*p, int64_t x) { + int64_t current; + do { + current = *p; + } while (current < x && _InterlockedCompareExchange64(p, x, current) != current); +} + #else #ifdef __cplusplus #define MI_USING_STD using namespace std; @@ -187,6 +198,13 @@ static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add) { MI_USING_STD atomic_fetch_add_explicit((volatile _Atomic(int64_t)*)p, add, memory_order_relaxed); } +static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x) { + MI_USING_STD + int64_t current; + do { + current = atomic_load_explicit((volatile _Atomic(int64_t)*)p, memory_order_relaxed); + } while (current < x && !atomic_compare_exchange_weak_explicit((volatile _Atomic(int64_t)*)p, ¤t, x, memory_order_acq_rel, memory_order_relaxed)); +} static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add) { MI_USING_STD return atomic_fetch_add_explicit(p, add, memory_order_relaxed); diff --git a/src/stats.c b/src/stats.c index e0c7f01a..06858d1c 100644 --- a/src/stats.c +++ b/src/stats.c @@ -27,7 +27,7 @@ static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) { { // add atomically (for abandoned pages) mi_atomic_addi64(&stat->current,amount); - if (stat->current > stat->peak) stat->peak = stat->current; // racing.. it's ok + mi_atomic_maxi64(&stat->peak, stat->current); if (amount > 0) { mi_atomic_addi64(&stat->allocated,amount); } From 444afa934ff8d53bf8c53602246bfc65828dc1d9 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 22 Jul 2020 13:58:00 -0700 Subject: [PATCH 032/172] fix memory order for weak CAS, issue #130, thanks @mary3000! --- include/mimalloc-atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index a0452f5c..ae9fbbdf 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -219,7 +219,7 @@ static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x } static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { MI_USING_STD - return atomic_compare_exchange_weak_explicit(p, &expected, desired, memory_order_release, memory_order_relaxed); + return atomic_compare_exchange_weak_explicit(p, &expected, desired, memory_order_acq_rel, memory_order_relaxed); } static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { MI_USING_STD From 8aa18d3661e73349fa4fee0a647dbe42a66fd5af Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 22 Jul 2020 14:16:18 -0700 Subject: [PATCH 033/172] fix TSAN warning for statistics maximum, issue #130 --- include/mimalloc-atomic.h | 45 ++++++++++++++++++++++++++++----------- src/stats.c | 2 +- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index ae9fbbdf..b3732e89 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -65,10 +65,13 @@ static inline void mi_atomic_yield(void); // Note: not using _Atomic(int64_t) as it is only used for statistics. static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add); -// Atomically take the maximum a 64-bit value; returns the previous value. -// Note: not using _Atomic(int64_t) as it is only used for statistics. +// Atomically update `*p` with the maximum of `*p` and `x` as a 64-bit value. +// Returns the previous value. Note: not using _Atomic(int64_t) as it is only used for statistics. static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x); +// Atomically read a 64-bit value +// Note: not using _Atomic(int64_t) as it is only used for statistics. +static inline int64_t mi_atomic_readi64(volatile int64_t* p); // Atomically subtract a value; returns the previous value. static inline uintptr_t mi_atomic_sub(volatile _Atomic(uintptr_t)* p, uintptr_t sub) { @@ -188,23 +191,24 @@ static inline void mi_atomic_maxi64(volatile _Atomic(int64_t)*p, int64_t x) { } while (current < x && _InterlockedCompareExchange64(p, x, current) != current); } +static inline int64_t mi_atomic_readi64(volatile _Atomic(int64_t)*p) { + #ifdef _WIN64 + return *p; + #else + int64_t current; + do { + current = *p; + } while (_InterlockedCompareExchange64(p, current, current) != current); + return current; + #endif +} + #else #ifdef __cplusplus #define MI_USING_STD using namespace std; #else #define MI_USING_STD #endif -static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add) { - MI_USING_STD - atomic_fetch_add_explicit((volatile _Atomic(int64_t)*)p, add, memory_order_relaxed); -} -static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x) { - MI_USING_STD - int64_t current; - do { - current = atomic_load_explicit((volatile _Atomic(int64_t)*)p, memory_order_relaxed); - } while (current < x && !atomic_compare_exchange_weak_explicit((volatile _Atomic(int64_t)*)p, ¤t, x, memory_order_acq_rel, memory_order_relaxed)); -} static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add) { MI_USING_STD return atomic_fetch_add_explicit(p, add, memory_order_relaxed); @@ -241,6 +245,21 @@ static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x) MI_USING_STD return atomic_store_explicit(p, x, memory_order_release); } +static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add) { + MI_USING_STD + atomic_fetch_add_explicit((volatile _Atomic(int64_t)*)p, add, memory_order_relaxed); +} +static inline int64_t mi_atomic_readi64(volatile int64_t* p) { + MI_USING_STD + return atomic_load_explicit((volatile _Atomic(int64_t)*) p, memory_order_relaxed); +} +static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x) { + MI_USING_STD + int64_t current; + do { + current = mi_atomic_readi64(p); + } while (current < x && !atomic_compare_exchange_weak_explicit((volatile _Atomic(int64_t)*)p, ¤t, x, memory_order_acq_rel, memory_order_relaxed)); +} #if defined(__cplusplus) #include diff --git a/src/stats.c b/src/stats.c index 06858d1c..172a3c0a 100644 --- a/src/stats.c +++ b/src/stats.c @@ -27,7 +27,7 @@ static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) { { // add atomically (for abandoned pages) mi_atomic_addi64(&stat->current,amount); - mi_atomic_maxi64(&stat->peak, stat->current); + mi_atomic_maxi64(&stat->peak, mi_atomic_readi64(&stat->current)); if (amount > 0) { mi_atomic_addi64(&stat->allocated,amount); } From 70be91d6b8099bdc57fd20ce3f7c60b4efb15f72 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 22 Jul 2020 15:28:14 -0700 Subject: [PATCH 034/172] reduce tsan warning by ensuring a require edge; issue #130 --- src/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index d53ecfd1..8a5ba8c0 100644 --- a/src/segment.c +++ b/src/segment.c @@ -978,7 +978,7 @@ static mi_segment_t* mi_abandoned_pop(void) { mi_atomic_increment(&abandoned_readers); // ensure no segment gets decommitted mi_tagged_segment_t next = 0; do { - ts = mi_atomic_read_relaxed(&abandoned); + ts = mi_atomic_read(&abandoned); segment = mi_tagged_segment_ptr(ts); if (segment != NULL) { next = mi_tagged_segment(segment->abandoned_next, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted From b74caddcc1307008c4f383b73fc45d0dc05aea3a Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 23 Jul 2020 15:00:49 -0700 Subject: [PATCH 035/172] fix memory order to acq_rel for atomic and/or, issue #130, thanks @mpoeter! --- ide/vs2019/mimalloc-test-stress.vcxproj | 4 ++-- include/mimalloc-atomic.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ide/vs2019/mimalloc-test-stress.vcxproj b/ide/vs2019/mimalloc-test-stress.vcxproj index ef7ab357..afbb6666 100644 --- a/ide/vs2019/mimalloc-test-stress.vcxproj +++ b/ide/vs2019/mimalloc-test-stress.vcxproj @@ -149,8 +149,8 @@ - - {abb5eae7-b3e6-432e-b636-333449892ea6} + + {abb5eae7-b3e6-432e-b636-333449892ea7} diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index b3732e89..86deaf76 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -215,11 +215,11 @@ static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t } static inline uintptr_t mi_atomic_and(volatile _Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD - return atomic_fetch_and_explicit(p, x, memory_order_relaxed); + return atomic_fetch_and_explicit(p, x, memory_order_acq_rel); } static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD - return atomic_fetch_or_explicit(p, x, memory_order_relaxed); + return atomic_fetch_or_explicit(p, x, memory_order_acq_rel); } static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { MI_USING_STD From a9a21f39d8de1990255d061bfdd5588cc86d24fc Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 23 Jul 2020 15:52:02 -0700 Subject: [PATCH 036/172] fix memory order for CAS failure, issue #130 --- include/mimalloc-atomic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 86deaf76..722b6ad6 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -223,11 +223,11 @@ static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x } static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { MI_USING_STD - return atomic_compare_exchange_weak_explicit(p, &expected, desired, memory_order_acq_rel, memory_order_relaxed); + return atomic_compare_exchange_weak_explicit(p, &expected, desired, memory_order_acq_rel, memory_order_acquire); } static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { MI_USING_STD - return atomic_compare_exchange_strong_explicit(p, &expected, desired, memory_order_acq_rel, memory_order_relaxed); + return atomic_compare_exchange_strong_explicit(p, &expected, desired, memory_order_acq_rel, memory_order_acquire); } static inline uintptr_t mi_atomic_exchange(volatile _Atomic(uintptr_t)* p, uintptr_t exchange) { MI_USING_STD From afe29cb8f5e6550438565dc02574fd307d0e983c Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 25 Jul 2020 19:33:02 -0700 Subject: [PATCH 037/172] fix ub on shift, issue #279 --- include/mimalloc-internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index ba322feb..2dc7e36a 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -574,11 +574,11 @@ static inline bool mi_is_in_same_page(const void* p, const void* q) { static inline uintptr_t mi_rotl(uintptr_t x, uintptr_t shift) { shift %= MI_INTPTR_BITS; - return ((x << shift) | (x >> (MI_INTPTR_BITS - shift))); + return (shift==0 ? x : ((x << shift) | (x >> (MI_INTPTR_BITS - shift)))); } static inline uintptr_t mi_rotr(uintptr_t x, uintptr_t shift) { shift %= MI_INTPTR_BITS; - return ((x >> shift) | (x << (MI_INTPTR_BITS - shift))); + return (shift==0 ? x : ((x >> shift) | (x << (MI_INTPTR_BITS - shift)))); } static inline void* mi_ptr_decode(const void* null, const mi_encoded_t x, const uintptr_t* keys) { From 73c109a04e8e1859627b002d2a5e206a4ac13650 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 25 Jul 2020 19:55:36 -0700 Subject: [PATCH 038/172] add cmake option to build with ubsan --- CMakeLists.txt | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0082c448..37616eb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ option(MI_BUILD_STATIC "Build static library" ON) 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_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) include("cmake/mimalloc-config-version.cmake") @@ -122,6 +123,34 @@ if(MI_SHOW_ERRORS MATCHES "ON") list(APPEND mi_defines MI_SHOW_ERRORS=1) endif() +if(MI_DEBUG_TSAN MATCHES "ON") + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") + list(APPEND mi_cflags -fsanitize=thread -g -O1) + list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=thread) + else() + message(WARNING "Can only use thread sanitizer with clang (MI_DEBUG_TSAN=ON but ignored)") + endif() +endif() + +if(MI_DEBUG_UBSAN MATCHES "ON") + 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_cflags -fsanitize=undefined -g) + list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=undefined) + if (MI_USE_CXX MATCHES "OFF") + message(STATUS "(switch to use C++ due to MI_DEBUG_UBSAN)") + set(MI_USE_CXX "ON") + endif() + else() + message(WARNING "Can only use undefined-behavior sanitizer with clang++ (MI_DEBUG_UBSAN=ON but ignored)") + endif() + else() + message(WARNING "Can only use thread sanitizer with a debug build (CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})") + endif() +endif() + if(MI_USE_CXX MATCHES "ON") message(STATUS "Use the C++ compiler to compile (MI_USE_CXX=ON)") set_source_files_properties(${mi_sources} PROPERTIES LANGUAGE CXX ) @@ -134,16 +163,6 @@ if(MI_USE_CXX MATCHES "ON") endif() endif() -if(MI_DEBUG_TSAN MATCHES "ON") - if(CMAKE_C_COMPILER_ID MATCHES "Clang") - message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") - list(APPEND mi_cflags -fsanitize=thread -g -O1) - list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=thread) - else() - message(WARNING "Can only use thread sanitizer with clang (MI_DEBUG_TSAN=ON but ignored)") - endif() -endif() - # Compiler flags if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") list(APPEND mi_cflags -Wall -Wextra -Wno-unknown-pragmas -fvisibility=hidden) From e27422adca7285bdcace8a6052860122eaa1bff7 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 25 Jul 2020 20:55:45 -0700 Subject: [PATCH 039/172] switch to using C++ atomics in MSVC as well --- include/mimalloc-atomic.h | 10 +++++----- src/bitmap.inc.c | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 722b6ad6..c3d0ad23 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -13,12 +13,12 @@ terms of the MIT license. A copy of the license can be found in the file // We need to be portable between C, C++, and MSVC. // ------------------------------------------------------ -#if defined(_MSC_VER) -#define _Atomic(tp) tp -#define ATOMIC_VAR_INIT(x) x -#elif defined(__cplusplus) +#if defined(__cplusplus) #include #define _Atomic(tp) std::atomic +#elif defined(_MSC_VER) +#define _Atomic(tp) tp +#define ATOMIC_VAR_INIT(x) x #else #include #endif @@ -126,7 +126,7 @@ static inline intptr_t mi_atomic_subi(volatile _Atomic(intptr_t)* p, intptr_t su (T*)mi_atomic_exchange((volatile _Atomic(uintptr_t)*)(p), (uintptr_t)((T*)exchange)) -#ifdef _MSC_VER +#if !defined(__cplusplus) && defined(_MSC_VER) #define WIN32_LEAN_AND_MEAN #include #include diff --git a/src/bitmap.inc.c b/src/bitmap.inc.c index c3813a44..99e8fa6f 100644 --- a/src/bitmap.inc.c +++ b/src/bitmap.inc.c @@ -72,6 +72,14 @@ static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) { #if defined(_MSC_VER) #define MI_HAVE_BITSCAN #include +#ifndef MI_64 +#if MI_INTPTR_SIZE==8 +#define MI_64(f) f##64 +#else +#define MI_64(f) f +#endif +#endif + static inline size_t mi_bsf(uintptr_t x) { if (x==0) return 8*MI_INTPTR_SIZE; DWORD idx; From 09ade024298000157729c877c2087cfe2d762454 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 25 Jul 2020 22:52:27 -0700 Subject: [PATCH 040/172] bring inline with C11 atomics; no volatile and cas order of expected/desired --- include/mimalloc-atomic.h | 166 +++++++++++++++++--------------------- include/mimalloc-types.h | 36 ++++----- src/alloc.c | 15 ++-- src/arena.c | 2 +- src/bitmap.inc.c | 11 ++- src/options.c | 6 +- src/os.c | 19 ++--- src/page.c | 26 +++--- src/random.c | 2 +- src/region.c | 14 ++-- src/segment.c | 37 +++++---- src/stats.c | 24 +++--- 12 files changed, 170 insertions(+), 188 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index c3d0ad23..beb0f12c 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -27,103 +27,99 @@ terms of the MIT license. A copy of the license can be found in the file // Atomic operations specialized for mimalloc // ------------------------------------------------------ -// Atomically add a value; returns the previous value. Memory ordering is relaxed. -static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add); +// Atomically add a value; returns the previous value. Memory ordering is acquire-release. +static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add); -// Atomically "and" a value; returns the previous value. Memory ordering is relaxed. -static inline uintptr_t mi_atomic_and(volatile _Atomic(uintptr_t)* p, uintptr_t x); +// Atomically "and" a value; returns the previous value. Memory ordering is acquire-release. +static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x); -// Atomically "or" a value; returns the previous value. Memory ordering is relaxed. -static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x); +// Atomically "or" a value; returns the previous value. Memory ordering is acquire-release. +static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x); // Atomically compare and exchange a value; returns `true` if successful. -// May fail spuriously. Memory ordering as release on success, and relaxed on failure. -// (Note: expected and desired are in opposite order from atomic_compare_exchange) -static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected); +// May fail spuriously. Memory ordering is acquire-release; with acquire on failure. +static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired); // Atomically compare and exchange a value; returns `true` if successful. -// Memory ordering is acquire-release -// (Note: expected and desired are in opposite order from atomic_compare_exchange) -static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected); +// Memory ordering is acquire-release; with acquire on failure. +static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired); // Atomically exchange a value. Memory ordering is acquire-release. -static inline uintptr_t mi_atomic_exchange(volatile _Atomic(uintptr_t)* p, uintptr_t exchange); +static inline uintptr_t mi_atomic_exchange(_Atomic(uintptr_t)* p, uintptr_t exchange); // Atomically read a value. Memory ordering is relaxed. -static inline uintptr_t mi_atomic_read_relaxed(const volatile _Atomic(uintptr_t)* p); +static inline uintptr_t mi_atomic_read_relaxed(const _Atomic(uintptr_t)* p); // Atomically read a value. Memory ordering is acquire. -static inline uintptr_t mi_atomic_read(const volatile _Atomic(uintptr_t)* p); +static inline uintptr_t mi_atomic_read(const _Atomic(uintptr_t)* p); // Atomically write a value. Memory ordering is release. -static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x); +static inline void mi_atomic_write(_Atomic(uintptr_t)* p, uintptr_t x); // Yield static inline void mi_atomic_yield(void); -// Atomically add a 64-bit value; returns the previous value. +// Atomically add a 64-bit value; returns the previous value. Memory ordering is relaxed. // Note: not using _Atomic(int64_t) as it is only used for statistics. -static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add); +static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add); // Atomically update `*p` with the maximum of `*p` and `x` as a 64-bit value. // Returns the previous value. Note: not using _Atomic(int64_t) as it is only used for statistics. -static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x); +static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x); -// Atomically read a 64-bit value -// Note: not using _Atomic(int64_t) as it is only used for statistics. -static inline int64_t mi_atomic_readi64(volatile int64_t* p); // Atomically subtract a value; returns the previous value. -static inline uintptr_t mi_atomic_sub(volatile _Atomic(uintptr_t)* p, uintptr_t sub) { +static inline uintptr_t mi_atomic_sub(_Atomic(uintptr_t)* p, uintptr_t sub) { return mi_atomic_add(p, (uintptr_t)(-((intptr_t)sub))); } // Atomically increment a value; returns the incremented result. -static inline uintptr_t mi_atomic_increment(volatile _Atomic(uintptr_t)* p) { +static inline uintptr_t mi_atomic_increment(_Atomic(uintptr_t)* p) { return mi_atomic_add(p, 1); } // Atomically decrement a value; returns the decremented result. -static inline uintptr_t mi_atomic_decrement(volatile _Atomic(uintptr_t)* p) { +static inline uintptr_t mi_atomic_decrement(_Atomic(uintptr_t)* p) { return mi_atomic_sub(p, 1); } // Atomically add a signed value; returns the previous value. -static inline intptr_t mi_atomic_addi(volatile _Atomic(intptr_t)* p, intptr_t add) { - return (intptr_t)mi_atomic_add((volatile _Atomic(uintptr_t)*)p, (uintptr_t)add); +static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)* p, intptr_t add) { + return (intptr_t)mi_atomic_add((_Atomic(uintptr_t)*)p, (uintptr_t)add); } // Atomically subtract a signed value; returns the previous value. -static inline intptr_t mi_atomic_subi(volatile _Atomic(intptr_t)* p, intptr_t sub) { +static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub) { return (intptr_t)mi_atomic_addi(p,-sub); } // Atomically read a pointer; Memory order is relaxed (i.e. no fence, only atomic). #define mi_atomic_read_ptr_relaxed(T,p) \ - (T*)(mi_atomic_read_relaxed((const volatile _Atomic(uintptr_t)*)(p))) + (T*)(mi_atomic_read_relaxed((const _Atomic(uintptr_t)*)(p))) // Atomically read a pointer; Memory order is acquire. #define mi_atomic_read_ptr(T,p) \ - (T*)(mi_atomic_read((const volatile _Atomic(uintptr_t)*)(p))) + (T*)(mi_atomic_read((const _Atomic(uintptr_t)*)(p))) // Atomically write a pointer; Memory order is acquire. #define mi_atomic_write_ptr(T,p,x) \ - mi_atomic_write((volatile _Atomic(uintptr_t)*)(p), (uintptr_t)((T*)x)) + mi_atomic_write((_Atomic(uintptr_t)*)(p), (uintptr_t)((T*)x)) + + +static inline bool mi_atomic_cas_weak_voidp(_Atomic(void*)*p, void** expected, void* desired, void* unused) { + (void)(unused); + return mi_atomic_cas_weak((_Atomic(uintptr_t)*)p, (uintptr_t*)expected, (uintptr_t)desired); +} // Atomically compare and exchange a pointer; returns `true` if successful. May fail spuriously. // Memory order is release. (like a write) -// (Note: expected and desired are in opposite order from atomic_compare_exchange) -#define mi_atomic_cas_ptr_weak(T,p,desired,expected) \ - mi_atomic_cas_weak((volatile _Atomic(uintptr_t)*)(p), (uintptr_t)((T*)(desired)), (uintptr_t)((T*)(expected))) +#define mi_atomic_cas_ptr_weak(T,p,expected,desired) \ + mi_atomic_cas_weak_voidp((_Atomic(void*)*)(p), (void**)(expected), desired, *(expected)) -// Atomically compare and exchange a pointer; returns `true` if successful. Memory order is acquire_release. -// (Note: expected and desired are in opposite order from atomic_compare_exchange) -#define mi_atomic_cas_ptr_strong(T,p,desired,expected) \ - mi_atomic_cas_strong((volatile _Atomic(uintptr_t)*)(p),(uintptr_t)((T*)(desired)), (uintptr_t)((T*)(expected))) // Atomically exchange a pointer value. #define mi_atomic_exchange_ptr(T,p,exchange) \ - (T*)mi_atomic_exchange((volatile _Atomic(uintptr_t)*)(p), (uintptr_t)((T*)exchange)) + (T*)mi_atomic_exchange((_Atomic(uintptr_t)*)(p), (uintptr_t)((T*)exchange)) #if !defined(__cplusplus) && defined(_MSC_VER) @@ -137,31 +133,38 @@ typedef LONG64 msc_intptr_t; typedef LONG msc_intptr_t; #define MI_64(f) f #endif -static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add) { +static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add) { return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, (msc_intptr_t)add); } -static inline uintptr_t mi_atomic_and(volatile _Atomic(uintptr_t)* p, uintptr_t x) { +static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x) { return (uintptr_t)MI_64(_InterlockedAnd)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } -static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x) { +static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x) { return (uintptr_t)MI_64(_InterlockedOr)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } -static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { - return (expected == (uintptr_t)MI_64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)expected)); +static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { + uintptr_t read = (uintptr_t)MI_64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)(*expected)); + if (read == *expected) { + return true; + } + else { + *expected = read; + return false; + } } -static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { - return mi_atomic_cas_strong(p,desired,expected); +static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { + return mi_atomic_cas_strong(p,expected,desired); } -static inline uintptr_t mi_atomic_exchange(volatile _Atomic(uintptr_t)* p, uintptr_t exchange) { +static inline uintptr_t mi_atomic_exchange(_Atomic(uintptr_t)* p, uintptr_t exchange) { return (uintptr_t)MI_64(_InterlockedExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)exchange); } -static inline uintptr_t mi_atomic_read(volatile _Atomic(uintptr_t) const* p) { +static inline uintptr_t mi_atomic_read(_Atomic(uintptr_t) const* p) { return *p; } -static inline uintptr_t mi_atomic_read_relaxed(volatile _Atomic(uintptr_t) const* p) { +static inline uintptr_t mi_atomic_read_relaxed(_Atomic(uintptr_t) const* p) { return *p; } -static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x) { +static inline void mi_atomic_write(_Atomic(uintptr_t)* p, uintptr_t x) { #if defined(_M_IX86) || defined(_M_X64) *p = x; #else @@ -171,9 +174,9 @@ static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x) static inline void mi_atomic_yield(void) { YieldProcessor(); } -static inline void mi_atomic_addi64(volatile _Atomic(int64_t)* p, int64_t add) { +static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int64_t add) { #ifdef _WIN64 - mi_atomic_addi(p,add); + return (int64_t)mi_atomic_addi((int64_t*)p,add); #else int64_t current; int64_t sum; @@ -181,84 +184,67 @@ static inline void mi_atomic_addi64(volatile _Atomic(int64_t)* p, int64_t add) { current = *p; sum = current + add; } while (_InterlockedCompareExchange64(p, sum, current) != current); + return current; #endif } -static inline void mi_atomic_maxi64(volatile _Atomic(int64_t)*p, int64_t x) { +static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t x) { int64_t current; do { current = *p; } while (current < x && _InterlockedCompareExchange64(p, x, current) != current); } -static inline int64_t mi_atomic_readi64(volatile _Atomic(int64_t)*p) { - #ifdef _WIN64 - return *p; - #else - int64_t current; - do { - current = *p; - } while (_InterlockedCompareExchange64(p, current, current) != current); - return current; - #endif -} - #else #ifdef __cplusplus #define MI_USING_STD using namespace std; #else #define MI_USING_STD #endif -static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add) { +static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add) { MI_USING_STD - return atomic_fetch_add_explicit(p, add, memory_order_relaxed); + return atomic_fetch_add_explicit(p, add, memory_order_acq_rel); } -static inline uintptr_t mi_atomic_and(volatile _Atomic(uintptr_t)* p, uintptr_t x) { +static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD return atomic_fetch_and_explicit(p, x, memory_order_acq_rel); } -static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x) { +static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD return atomic_fetch_or_explicit(p, x, memory_order_acq_rel); } -static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { +static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { MI_USING_STD - return atomic_compare_exchange_weak_explicit(p, &expected, desired, memory_order_acq_rel, memory_order_acquire); + return atomic_compare_exchange_weak_explicit(p, expected, desired, memory_order_acq_rel, memory_order_acquire); } -static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { +static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { MI_USING_STD - return atomic_compare_exchange_strong_explicit(p, &expected, desired, memory_order_acq_rel, memory_order_acquire); + return atomic_compare_exchange_strong_explicit(p, expected, desired, memory_order_acq_rel, memory_order_acquire); } -static inline uintptr_t mi_atomic_exchange(volatile _Atomic(uintptr_t)* p, uintptr_t exchange) { +static inline uintptr_t mi_atomic_exchange(_Atomic(uintptr_t)* p, uintptr_t exchange) { MI_USING_STD return atomic_exchange_explicit(p, exchange, memory_order_acq_rel); } -static inline uintptr_t mi_atomic_read_relaxed(const volatile _Atomic(uintptr_t)* p) { +static inline uintptr_t mi_atomic_read_relaxed(const _Atomic(uintptr_t)* p) { MI_USING_STD - return atomic_load_explicit((volatile _Atomic(uintptr_t)*) p, memory_order_relaxed); + return atomic_load_explicit((_Atomic(uintptr_t)*) p, memory_order_relaxed); } -static inline uintptr_t mi_atomic_read(const volatile _Atomic(uintptr_t)* p) { +static inline uintptr_t mi_atomic_read(const _Atomic(uintptr_t)* p) { MI_USING_STD - return atomic_load_explicit((volatile _Atomic(uintptr_t)*) p, memory_order_acquire); + return atomic_load_explicit((_Atomic(uintptr_t)*) p, memory_order_acquire); } -static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x) { +static inline void mi_atomic_write(_Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD return atomic_store_explicit(p, x, memory_order_release); } -static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add) { +static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add) { MI_USING_STD - atomic_fetch_add_explicit((volatile _Atomic(int64_t)*)p, add, memory_order_relaxed); + return atomic_fetch_add_explicit((_Atomic(int64_t)*)p, add, memory_order_relaxed); } -static inline int64_t mi_atomic_readi64(volatile int64_t* p) { +static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { MI_USING_STD - return atomic_load_explicit((volatile _Atomic(int64_t)*) p, memory_order_relaxed); -} -static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x) { - MI_USING_STD - int64_t current; - do { - current = mi_atomic_readi64(p); - } while (current < x && !atomic_compare_exchange_weak_explicit((volatile _Atomic(int64_t)*)p, ¤t, x, memory_order_acq_rel, memory_order_relaxed)); + int64_t current = atomic_load_explicit((_Atomic(int64_t)*)p, memory_order_relaxed); + while (current < x && !atomic_compare_exchange_weak_explicit((_Atomic(int64_t)*)p, ¤t, x, memory_order_acq_rel, memory_order_acquire)) { /* nothing */ }; } #if defined(__cplusplus) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 449e2e41..5b31f6f3 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -222,8 +222,8 @@ typedef struct mi_page_s { uint32_t xblock_size; // size available in each block (always `>0`) mi_block_t* local_free; // list of deferred free blocks by this thread (migrates to `free`) - volatile _Atomic(mi_thread_free_t) xthread_free; // list of deferred free blocks freed by other threads - volatile _Atomic(uintptr_t) xheap; + _Atomic(mi_thread_free_t) xthread_free; // list of deferred free blocks freed by other threads + _Atomic(uintptr_t) xheap; struct mi_page_s* next; // next page owned by this thread with the same `block_size` struct mi_page_s* prev; // previous page owned by this thread with the same `block_size` @@ -243,28 +243,28 @@ typedef enum mi_page_kind_e { // contain blocks. typedef struct mi_segment_s { // memory fields - size_t memid; // id for the os-level memory manager - bool mem_is_fixed; // `true` if we cannot decommit/reset/protect in this memory (i.e. when allocated using large OS pages) - bool mem_is_committed; // `true` if the whole segment is eagerly committed + size_t memid; // id for the os-level memory manager + bool mem_is_fixed; // `true` if we cannot decommit/reset/protect in this memory (i.e. when allocated using large OS pages) + bool mem_is_committed; // `true` if the whole segment is eagerly committed // segment fields - struct mi_segment_s* next; // must be the first segment field -- see `segment.c:segment_alloc` + struct mi_segment_s* next; // must be the first segment field -- see `segment.c:segment_alloc` struct mi_segment_s* prev; struct mi_segment_s* abandoned_next; - 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 it it is too long) + 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 it it is too long) - size_t used; // count of pages in use (`used <= capacity`) - size_t capacity; // count of available pages (`#free + used`) - size_t segment_size;// for huge pages this may be different from `MI_SEGMENT_SIZE` - 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` + size_t used; // count of pages in use (`used <= capacity`) + size_t capacity; // count of available pages (`#free + used`) + size_t segment_size; // for huge pages this may be different from `MI_SEGMENT_SIZE` + 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` // layout like this to optimize access in `mi_free` - size_t page_shift; // `1 << page_shift` == the page sizes == `page->block_size * page->reserved` (unless the first page, then `-segment_info_size`). - volatile _Atomic(uintptr_t) thread_id; // unique id of the thread owning this segment - mi_page_kind_t page_kind; // kind of pages: small, large, or huge - mi_page_t pages[1]; // up to `MI_SMALL_PAGES_PER_SEGMENT` pages + size_t page_shift; // `1 << page_shift` == the page sizes == `page->block_size * page->reserved` (unless the first page, then `-segment_info_size`). + _Atomic(uintptr_t) thread_id; // unique id of the thread owning this segment + mi_page_kind_t page_kind; // kind of pages: small, large, or huge + mi_page_t pages[1]; // up to `MI_SMALL_PAGES_PER_SEGMENT` pages } mi_segment_t; @@ -322,7 +322,7 @@ struct mi_heap_s { mi_tld_t* tld; 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") - volatile _Atomic(mi_block_t*) thread_delayed_free; + _Atomic(mi_block_t*) thread_delayed_free; uintptr_t thread_id; // thread this heap belongs too uintptr_t cookie; // random cookie to verify pointers (see `_mi_ptr_cookie`) uintptr_t keys[2]; // two random keys used to encode the `thread_delayed_free` list diff --git a/src/alloc.c b/src/alloc.c index 57034522..62c3c018 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -305,11 +305,10 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc } // Try to put the block on either the page-local thread free list, or the heap delayed free list. - mi_thread_free_t tfree; mi_thread_free_t tfreex; bool use_delayed; + mi_thread_free_t tfree = mi_atomic_read_relaxed(&page->xthread_free); do { - tfree = mi_atomic_read_relaxed(&page->xthread_free); use_delayed = (mi_tf_delayed(tfree) == MI_USE_DELAYED_FREE); if (mi_unlikely(use_delayed)) { // unlikely: this only happens on the first concurrent free in a page that is in the full list @@ -320,7 +319,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc mi_block_set_next(page, block, mi_tf_block(tfree)); tfreex = mi_tf_set_block(tfree,block); } - } while (!mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree)); + } while (!mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); if (mi_unlikely(use_delayed)) { // racy read on `heap`, but ok because MI_DELAYED_FREEING is set (see `mi_heap_delete` and `mi_heap_collect_abandon`) @@ -328,19 +327,19 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc mi_assert_internal(heap != NULL); if (heap != NULL) { // add to the delayed free list of this heap. (do this atomically as the lock only protects heap memory validity) - mi_block_t* dfree; + mi_block_t* dfree = mi_atomic_read_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); do { - dfree = mi_atomic_read_ptr_relaxed(mi_block_t,&heap->thread_delayed_free); mi_block_set_nextx(heap,block,dfree, heap->keys); - } while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, block, dfree)); + } while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, &dfree, block)); } // and reset the MI_DELAYED_FREEING flag + tfree = mi_atomic_read_relaxed(&page->xthread_free); do { - tfreex = tfree = mi_atomic_read_relaxed(&page->xthread_free); + tfreex = tfree; mi_assert_internal(mi_tf_delayed(tfree) == MI_DELAYED_FREEING); tfreex = mi_tf_set_delayed(tfree,MI_NO_DELAYED_FREE); - } while (!mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree)); + } while (!mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); } } diff --git a/src/arena.c b/src/arena.c index bb9fc174..1c1fc1a0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -63,7 +63,7 @@ typedef struct mi_arena_s { bool is_zero_init; // is the arena zero initialized? bool is_committed; // is the memory committed bool is_large; // large OS page allocated - volatile _Atomic(uintptr_t) search_idx; // optimization to start the search for free blocks + _Atomic(uintptr_t) search_idx; // optimization to start the search for free blocks mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? mi_bitmap_field_t* blocks_committed; // if `!is_committed`, are the blocks committed? mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) diff --git a/src/bitmap.inc.c b/src/bitmap.inc.c index 99e8fa6f..b9953a4f 100644 --- a/src/bitmap.inc.c +++ b/src/bitmap.inc.c @@ -30,7 +30,7 @@ and that the sequence must be smaller or equal to the bits in a field. #define MI_BITMAP_FIELD_FULL (~((uintptr_t)0)) // all bits set // An atomic bitmap of `uintptr_t` fields -typedef volatile _Atomic(uintptr_t) mi_bitmap_field_t; +typedef _Atomic(uintptr_t) mi_bitmap_field_t; typedef mi_bitmap_field_t* mi_bitmap_t; // A bitmap index is the index of the bit in a bitmap. @@ -123,7 +123,7 @@ static inline bool mi_bitmap_try_claim_field(mi_bitmap_t bitmap, size_t bitmap_f uintptr_t field = mi_atomic_read_relaxed(&bitmap[idx]); if ((field & mask) == 0) { // free? - if (mi_atomic_cas_strong(&bitmap[idx], (field|mask), field)) { + if (mi_atomic_cas_strong(&bitmap[idx], &field, (field|mask))) { // claimed! return true; } @@ -137,7 +137,7 @@ static inline bool mi_bitmap_try_claim_field(mi_bitmap_t bitmap, size_t bitmap_f static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx) { mi_assert_internal(bitmap_idx != NULL); - volatile _Atomic(uintptr_t)* field = &bitmap[idx]; + _Atomic(uintptr_t)* field = &bitmap[idx]; uintptr_t map = mi_atomic_read(field); if (map==MI_BITMAP_FIELD_FULL) return false; // short cut @@ -158,9 +158,8 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx mi_assert_internal((m >> bitidx) == mask); // no overflow? const uintptr_t newmap = map | m; mi_assert_internal((newmap^map) >> bitidx == mask); - if (!mi_atomic_cas_weak(field, newmap, map)) { // TODO: use strong cas here? - // no success, another thread claimed concurrently.. keep going - map = mi_atomic_read(field); + if (!mi_atomic_cas_weak(field, &map, newmap)) { // TODO: use strong cas here? + // no success, another thread claimed concurrently.. keep going (with updated `map`) continue; } else { diff --git a/src/options.c b/src/options.c index f29b387c..78c01456 100644 --- a/src/options.c +++ b/src/options.c @@ -217,7 +217,7 @@ static void mi_out_buf_stderr(const char* msg, void* arg) { // For now, don't register output from multiple threads. #pragma warning(suppress:4180) static mi_output_fun* volatile mi_out_default; // = NULL -static volatile _Atomic(void*) mi_out_arg; // = NULL +static _Atomic(void*) mi_out_arg; // = NULL static mi_output_fun* mi_out_get_default(void** parg) { if (parg != NULL) { *parg = mi_atomic_read_ptr(void,&mi_out_arg); } @@ -241,7 +241,7 @@ static void mi_add_stderr_output() { // -------------------------------------------------------- // Messages, all end up calling `_mi_fputs`. // -------------------------------------------------------- -static volatile _Atomic(uintptr_t) error_count; // = 0; // when MAX_ERROR_COUNT stop emitting errors and warnings +static _Atomic(uintptr_t) error_count; // = 0; // when MAX_ERROR_COUNT stop emitting errors and warnings // When overriding malloc, we may recurse into mi_vfprintf if an allocation // inside the C runtime causes another message. @@ -339,7 +339,7 @@ void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, co // -------------------------------------------------------- static mi_error_fun* volatile mi_error_handler; // = NULL -static volatile _Atomic(void*) mi_error_arg; // = NULL +static _Atomic(void*) mi_error_arg; // = NULL static void mi_error_default(int err) { UNUSED(err); diff --git a/src/os.c b/src/os.c index 8079e5a0..29a76a88 100644 --- a/src/os.c +++ b/src/os.c @@ -266,7 +266,7 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, DWORD flags, bool large_only, bool allow_large, bool* is_large) { mi_assert_internal(!(large_only && !allow_large)); - static volatile _Atomic(uintptr_t) large_page_try_ok; // = 0; + static _Atomic(uintptr_t) large_page_try_ok; // = 0; void* p = NULL; if ((large_only || use_large_os_page(size, try_alignment)) && allow_large && (flags&MEM_COMMIT)!=0 && (flags&MEM_RESERVE)!=0) { @@ -274,7 +274,7 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, if (!large_only && try_ok > 0) { // if a large page allocation fails, it seems the calls to VirtualAlloc get very expensive. // therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times. - mi_atomic_cas_weak(&large_page_try_ok, try_ok - 1, try_ok); + mi_atomic_cas_strong(&large_page_try_ok, &try_ok, try_ok - 1); } else { // large OS pages must always reserve and commit. @@ -360,14 +360,14 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro fd = VM_MAKE_TAG(os_tag); #endif if ((large_only || use_large_os_page(size, try_alignment)) && allow_large) { - static volatile _Atomic(uintptr_t) large_page_try_ok; // = 0; + static _Atomic(uintptr_t) large_page_try_ok; // = 0; uintptr_t try_ok = mi_atomic_read(&large_page_try_ok); if (!large_only && try_ok > 0) { // If the OS is not configured for large OS pages, or the user does not have // enough permission, the `mmap` will always fail (but it might also fail for other reasons). // Therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times // to avoid too many failing calls to mmap. - mi_atomic_cas_weak(&large_page_try_ok, try_ok - 1, try_ok); + mi_atomic_cas_strong(&large_page_try_ok, &try_ok, try_ok - 1); } else { int lflags = flags & ~MAP_NORESERVE; // using NORESERVE on huge pages seems to fail on Linux @@ -449,7 +449,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro // On 64-bit systems, we can do efficient aligned allocation by using // the 4TiB to 30TiB area to allocate them. #if (MI_INTPTR_SIZE >= 8) && (defined(_WIN32) || (defined(MI_OS_USE_MMAP) && !defined(MAP_ALIGNED))) -static volatile mi_decl_cache_align _Atomic(uintptr_t) aligned_base; +static mi_decl_cache_align _Atomic(uintptr_t) aligned_base; // Return a 4MiB aligned address that is probably available static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { @@ -462,7 +462,8 @@ static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { uintptr_t r = _mi_heap_random_next(mi_get_default_heap()); init = init + (MI_SEGMENT_SIZE * ((r>>17) & 0xFFFFF)); // (randomly 20 bits)*4MiB == 0 to 4TiB #endif - mi_atomic_cas_strong(&aligned_base, init, hint + size); + uintptr_t expected = hint + size; + mi_atomic_cas_strong(&aligned_base, &expected, init); hint = mi_atomic_add(&aligned_base, size); // this may still give 0 or > 30TiB but that is ok, it is a hint after all } if (hint%try_alignment != 0) return NULL; @@ -969,9 +970,9 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { uintptr_t start = 0; uintptr_t end = 0; - uintptr_t expected; + uintptr_t huge_start = mi_atomic_read_relaxed(&mi_huge_start); do { - start = expected = mi_atomic_read_relaxed(&mi_huge_start); + start = huge_start; if (start == 0) { // Initialize the start address after the 32TiB area start = ((uintptr_t)32 << 40); // 32TiB virtual start address @@ -982,7 +983,7 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { } end = start + size; mi_assert_internal(end % MI_SEGMENT_SIZE == 0); - } while (!mi_atomic_cas_strong(&mi_huge_start, end, expected)); + } while (!mi_atomic_cas_strong(&mi_huge_start, &huge_start, end)); if (total_size != NULL) *total_size = size; return (uint8_t*)start; diff --git a/src/page.c b/src/page.c index c8a4e54b..6b92d4c9 100644 --- a/src/page.c +++ b/src/page.c @@ -122,11 +122,11 @@ bool _mi_page_is_valid(mi_page_t* page) { #endif void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never) { - mi_thread_free_t tfree; mi_thread_free_t tfreex; mi_delayed_t old_delay; + mi_thread_free_t tfree; do { - tfree = mi_atomic_read(&page->xthread_free); // note: must acquire as we can break this loop and not do a CAS + tfree = mi_atomic_read(&page->xthread_free); // note: must acquire as we can break/repeat this loop and not do a CAS; tfreex = mi_tf_set_delayed(tfree, delay); old_delay = mi_tf_delayed(tfree); if (mi_unlikely(old_delay == MI_DELAYED_FREEING)) { @@ -140,7 +140,7 @@ void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool overrid break; // leave never-delayed flag set } } while ((old_delay == MI_DELAYED_FREEING) || - !mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree)); + !mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); } /* ----------------------------------------------------------- @@ -154,13 +154,12 @@ void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool overrid static void _mi_page_thread_free_collect(mi_page_t* page) { mi_block_t* head; - mi_thread_free_t tfree; mi_thread_free_t tfreex; + mi_thread_free_t tfree = mi_atomic_read_relaxed(&page->xthread_free); do { - tfree = mi_atomic_read_relaxed(&page->xthread_free); head = mi_tf_block(tfree); tfreex = mi_tf_set_block(tfree,NULL); - } while (!mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree)); + } while (!mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); // return if the list is empty if (head == NULL) return; @@ -273,11 +272,9 @@ static mi_page_t* mi_page_fresh(mi_heap_t* heap, mi_page_queue_t* pq) { (put there by other threads if they deallocated in a full page) ----------------------------------------------------------- */ void _mi_heap_delayed_free(mi_heap_t* heap) { - // take over the list (note: no atomic exchange is it is often NULL) - mi_block_t* block; - do { - block = mi_atomic_read_ptr_relaxed(mi_block_t,&heap->thread_delayed_free); - } while (block != NULL && !mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, NULL, block)); + // take over the list (note: no atomic exchange since it is often NULL) + mi_block_t* block = mi_atomic_read_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); + while (block != NULL && !mi_atomic_cas_ptr_weak(mi_block_t, &heap->thread_delayed_free, &block, NULL)) { /* nothing */ }; // and free them all while(block != NULL) { @@ -286,11 +283,10 @@ void _mi_heap_delayed_free(mi_heap_t* heap) { if (!_mi_free_delayed_block(block)) { // we might already start delayed freeing while another thread has not yet // reset the delayed_freeing flag; in that case delay it further by reinserting. - mi_block_t* dfree; + mi_block_t* dfree = mi_atomic_read_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); do { - dfree = mi_atomic_read_ptr_relaxed(mi_block_t,&heap->thread_delayed_free); mi_block_set_nextx(heap, block, dfree, heap->keys); - } while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, block, dfree)); + } while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, &dfree, block)); } block = next; } @@ -734,7 +730,7 @@ static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) { ----------------------------------------------------------- */ static mi_deferred_free_fun* volatile deferred_free = NULL; -static volatile _Atomic(void*) deferred_arg; // = NULL +static _Atomic(void*) deferred_arg; // = NULL void _mi_deferred_free(mi_heap_t* heap, bool force) { heap->tld->heartbeat++; diff --git a/src/random.c b/src/random.c index 2a96ccf6..5c093a91 100644 --- a/src/random.c +++ b/src/random.c @@ -200,7 +200,7 @@ static bool os_random_buf(void* buf, size_t buf_len) { #ifndef GRND_NONBLOCK #define GRND_NONBLOCK (1) #endif - static volatile _Atomic(uintptr_t) no_getrandom; // = 0 + static _Atomic(uintptr_t) no_getrandom; // = 0 if (mi_atomic_read(&no_getrandom)==0) { ssize_t ret = syscall(SYS_getrandom, buf, buf_len, GRND_NONBLOCK); if (ret >= 0) return (buf_len == (size_t)ret); diff --git a/src/region.c b/src/region.c index ae3a799a..d2904687 100644 --- a/src/region.c +++ b/src/region.c @@ -86,13 +86,13 @@ typedef union mi_region_info_u { // A region owns a chunk of REGION_SIZE (256MiB) (virtual) memory with // a bit map with one bit per MI_SEGMENT_SIZE (4MiB) block. typedef struct mem_region_s { - volatile _Atomic(uintptr_t) info; // mi_region_info_t.value - volatile _Atomic(void*) start; // start of the memory area + _Atomic(uintptr_t) info; // mi_region_info_t.value + _Atomic(void*) start; // start of the memory area mi_bitmap_field_t in_use; // bit per in-use block mi_bitmap_field_t dirty; // track if non-zero per block mi_bitmap_field_t commit; // track if committed per block mi_bitmap_field_t reset; // track if reset per block - volatile _Atomic(uintptr_t) arena_memid; // if allocated from a (huge page) arena + _Atomic(uintptr_t) arena_memid; // if allocated from a (huge page) arena uintptr_t padding; // round to 8 fields } mem_region_t; @@ -100,7 +100,7 @@ typedef struct mem_region_s { static mem_region_t regions[MI_REGION_MAX]; // Allocated regions -static volatile _Atomic(uintptr_t) regions_count; // = 0; +static _Atomic(uintptr_t) regions_count; // = 0; /* ---------------------------------------------------------------------------- @@ -447,10 +447,8 @@ void _mi_mem_collect(mi_os_tld_t* tld) { mem_region_t* region = ®ions[i]; if (mi_atomic_read_relaxed(®ion->info) != 0) { // if no segments used, try to claim the whole region - uintptr_t m; - do { - m = mi_atomic_read_relaxed(®ion->in_use); - } while(m == 0 && !mi_atomic_cas_weak(®ion->in_use, MI_BITMAP_FIELD_FULL, 0 )); + uintptr_t m = mi_atomic_read_relaxed(®ion->in_use); + while (m == 0 && !mi_atomic_cas_weak(®ion->in_use, &m, MI_BITMAP_FIELD_FULL)) { /* nothing */ }; if (m == 0) { // on success, free the whole region uint8_t* start = mi_atomic_read_ptr(uint8_t,®ions[i].start); diff --git a/src/segment.c b/src/segment.c index 8a5ba8c0..58c227bb 100644 --- a/src/segment.c +++ b/src/segment.c @@ -877,15 +877,15 @@ static mi_tagged_segment_t mi_tagged_segment(mi_segment_t* segment, mi_tagged_se // This is a list of visited abandoned pages that were full at the time. // this list migrates to `abandoned` when that becomes NULL. The use of // this list reduces contention and the rate at which segments are visited. -static mi_decl_cache_align volatile _Atomic(mi_segment_t*) abandoned_visited; // = NULL +static mi_decl_cache_align _Atomic(mi_segment_t*) abandoned_visited; // = NULL // The abandoned page list (tagged as it supports pop) -static mi_decl_cache_align volatile _Atomic(mi_tagged_segment_t) abandoned; // = NULL +static mi_decl_cache_align _Atomic(mi_tagged_segment_t) abandoned; // = NULL // We also maintain a count of current readers of the abandoned list // in order to prevent resetting/decommitting segment memory if it might // still be read. -static mi_decl_cache_align volatile _Atomic(uintptr_t) abandoned_readers; // = 0 +static mi_decl_cache_align _Atomic(uintptr_t) abandoned_readers; // = 0 // Push on the visited list static void mi_abandoned_visited_push(mi_segment_t* segment) { @@ -893,11 +893,10 @@ static void mi_abandoned_visited_push(mi_segment_t* segment) { mi_assert_internal(segment->abandoned_next == NULL); mi_assert_internal(segment->next == NULL && segment->prev == NULL); mi_assert_internal(segment->used > 0); - mi_segment_t* anext; + mi_segment_t* anext = mi_atomic_read_ptr_relaxed(mi_segment_t, &abandoned_visited); do { - anext = mi_atomic_read_ptr_relaxed(mi_segment_t, &abandoned_visited); segment->abandoned_next = anext; - } while (!mi_atomic_cas_ptr_weak(mi_segment_t, &abandoned_visited, segment, anext)); + } while (!mi_atomic_cas_ptr_weak(mi_segment_t, &abandoned_visited, &anext, segment)); } // Move the visited list to the abandoned list. @@ -911,11 +910,11 @@ static bool mi_abandoned_visited_revisit(void) if (first == NULL) return false; // first try to swap directly if the abandoned list happens to be NULL - const mi_tagged_segment_t ts = mi_atomic_read_relaxed(&abandoned); mi_tagged_segment_t afirst; + mi_tagged_segment_t ts = mi_atomic_read_relaxed(&abandoned); if (mi_tagged_segment_ptr(ts)==NULL) { afirst = mi_tagged_segment(first, ts); - if (mi_atomic_cas_strong(&abandoned, afirst, ts)) return true; + if (mi_atomic_cas_strong(&abandoned, &ts, afirst)) return true; } // find the last element of the visited list: O(n) @@ -926,12 +925,11 @@ static bool mi_abandoned_visited_revisit(void) // and atomically prepend to the abandoned list // (no need to increase the readers as we don't access the abandoned segments) - mi_tagged_segment_t anext; + mi_tagged_segment_t anext = mi_atomic_read_relaxed(&abandoned); do { - anext = mi_atomic_read_relaxed(&abandoned); last->abandoned_next = mi_tagged_segment_ptr(anext); afirst = mi_tagged_segment(first, anext); - } while (!mi_atomic_cas_weak(&abandoned, afirst, anext)); + } while (!mi_atomic_cas_weak(&abandoned, &anext, afirst)); return true; } @@ -941,13 +939,12 @@ static void mi_abandoned_push(mi_segment_t* segment) { mi_assert_internal(segment->abandoned_next == NULL); mi_assert_internal(segment->next == NULL && segment->prev == NULL); mi_assert_internal(segment->used > 0); - mi_tagged_segment_t ts; mi_tagged_segment_t next; + mi_tagged_segment_t ts = mi_atomic_read_relaxed(&abandoned); do { - ts = mi_atomic_read_relaxed(&abandoned); segment->abandoned_next = mi_tagged_segment_ptr(ts); next = mi_tagged_segment(segment, ts); - } while (!mi_atomic_cas_weak(&abandoned, next, ts)); + } while (!mi_atomic_cas_weak(&abandoned, &ts, next)); } // Wait until there are no more pending reads on segments that used to be in the abandoned list @@ -977,13 +974,13 @@ static mi_segment_t* mi_abandoned_pop(void) { // (this is called from `memory.c:_mi_mem_free` for example) mi_atomic_increment(&abandoned_readers); // ensure no segment gets decommitted mi_tagged_segment_t next = 0; + ts = mi_atomic_read(&abandoned); do { - ts = mi_atomic_read(&abandoned); segment = mi_tagged_segment_ptr(ts); if (segment != NULL) { next = mi_tagged_segment(segment->abandoned_next, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted } - } while (segment != NULL && !mi_atomic_cas_weak(&abandoned, next, ts)); + } while (segment != NULL && !mi_atomic_cas_weak(&abandoned, &ts, next)); mi_atomic_decrement(&abandoned_readers); // release reader lock if (segment != NULL) { segment->abandoned_next = NULL; @@ -1298,7 +1295,8 @@ void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block // claim it and free mi_heap_t* heap = mi_heap_get_default(); // issue #221; don't use the internal get_default_heap as we need to ensure the thread is initialized. // paranoia: if this it the last reference, the cas should always succeed - if (mi_atomic_cas_strong(&segment->thread_id, heap->thread_id, 0)) { + uintptr_t expected_tid = 0; + if (mi_atomic_cas_strong(&segment->thread_id, &expected_tid, heap->thread_id)) { mi_block_set_next(page, block, page->free); page->free = block; page->used--; @@ -1315,6 +1313,11 @@ void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block mi_segments_track_size((long)segment->segment_size, &tld->segments); _mi_segment_page_free(page, true, &tld->segments); } +#if (MI_DEBUG!=0) + else { + mi_assert_internal(false); + } +#endif } /* ----------------------------------------------------------- diff --git a/src/stats.c b/src/stats.c index 172a3c0a..96f57a47 100644 --- a/src/stats.c +++ b/src/stats.c @@ -26,13 +26,13 @@ static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) { if (mi_is_in_main(stat)) { // add atomically (for abandoned pages) - mi_atomic_addi64(&stat->current,amount); - mi_atomic_maxi64(&stat->peak, mi_atomic_readi64(&stat->current)); + int64_t current = mi_atomic_addi64_relaxed(&stat->current, amount); + mi_atomic_maxi64_relaxed(&stat->peak, current + amount); if (amount > 0) { - mi_atomic_addi64(&stat->allocated,amount); + mi_atomic_addi64_relaxed(&stat->allocated,amount); } else { - mi_atomic_addi64(&stat->freed, -amount); + mi_atomic_addi64_relaxed(&stat->freed, -amount); } } else { @@ -50,8 +50,8 @@ static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) { void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount) { if (mi_is_in_main(stat)) { - mi_atomic_addi64( &stat->count, 1 ); - mi_atomic_addi64( &stat->total, (int64_t)amount ); + mi_atomic_addi64_relaxed( &stat->count, 1 ); + mi_atomic_addi64_relaxed( &stat->total, (int64_t)amount ); } else { stat->count++; @@ -71,17 +71,17 @@ void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount) { static void mi_stat_add(mi_stat_count_t* stat, const mi_stat_count_t* src, int64_t unit) { if (stat==src) return; if (src->allocated==0 && src->freed==0) return; - mi_atomic_addi64( &stat->allocated, src->allocated * unit); - mi_atomic_addi64( &stat->current, src->current * unit); - mi_atomic_addi64( &stat->freed, src->freed * unit); + mi_atomic_addi64_relaxed( &stat->allocated, src->allocated * unit); + mi_atomic_addi64_relaxed( &stat->current, src->current * unit); + mi_atomic_addi64_relaxed( &stat->freed, src->freed * unit); // peak scores do not work across threads.. - mi_atomic_addi64( &stat->peak, src->peak * unit); + mi_atomic_addi64_relaxed( &stat->peak, src->peak * unit); } static void mi_stat_counter_add(mi_stat_counter_t* stat, const mi_stat_counter_t* src, int64_t unit) { if (stat==src) return; - mi_atomic_addi64( &stat->total, src->total * unit); - mi_atomic_addi64( &stat->count, src->count * unit); + mi_atomic_addi64_relaxed( &stat->total, src->total * unit); + mi_atomic_addi64_relaxed( &stat->count, src->count * unit); } // must be thread safe as it is called from stats_merge From 95afd0509face89d311830b4b13c6db1dec09685 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 25 Jul 2020 23:50:22 -0700 Subject: [PATCH 041/172] make segment abandoned_next atomic; tsan passes without warnings now (issue #130) --- CMakeLists.txt | 1 + include/mimalloc-types.h | 16 ++++++++++++++-- src/segment.c | 30 ++++++++++++++++-------------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37616eb4..5a228036 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,7 @@ endif() if(MI_DEBUG_TSAN MATCHES "ON") if(CMAKE_C_COMPILER_ID MATCHES "Clang") message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") + list(APPEND mi_defines MI_TSAN=1) list(APPEND mi_cflags -fsanitize=thread -g -O1) list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=thread) else() diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 5b31f6f3..17b33bc6 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -155,6 +155,7 @@ typedef enum mi_delayed_e { // The `in_full` and `has_aligned` page flags are put in a union to efficiently // test if both are false (`full_aligned == 0`) in the `mi_free` routine. +#if !MI_TSAN typedef union mi_page_flags_s { uint8_t full_aligned; struct { @@ -162,6 +163,16 @@ typedef union mi_page_flags_s { uint8_t has_aligned : 1; } 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; + struct { + uint8_t in_full; + uint8_t has_aligned; + } x; +} mi_page_flags_t; +#endif // Thread free list. // We use the bottom 2 bits of the pointer for mi_delayed_t flags @@ -245,12 +256,13 @@ typedef struct mi_segment_s { // memory fields size_t memid; // id for the os-level memory manager bool mem_is_fixed; // `true` if we cannot decommit/reset/protect in this memory (i.e. when allocated using large OS pages) - bool mem_is_committed; // `true` if the whole segment is eagerly committed + bool mem_is_committed; // `true` if the whole segment is eagerly committed // segment fields struct mi_segment_s* next; // must be the first segment field -- see `segment.c:segment_alloc` struct mi_segment_s* prev; - struct mi_segment_s* abandoned_next; + _Atomic(struct mi_segment_s*) abandoned_next; + 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 it it is too long) diff --git a/src/segment.c b/src/segment.c index 58c227bb..5af98b1e 100644 --- a/src/segment.c +++ b/src/segment.c @@ -890,12 +890,12 @@ static mi_decl_cache_align _Atomic(uintptr_t) abandoned_readers; // = // Push on the visited list static void mi_abandoned_visited_push(mi_segment_t* segment) { mi_assert_internal(segment->thread_id == 0); - mi_assert_internal(segment->abandoned_next == NULL); + mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t,&segment->abandoned_next) == NULL); mi_assert_internal(segment->next == NULL && segment->prev == NULL); mi_assert_internal(segment->used > 0); mi_segment_t* anext = mi_atomic_read_ptr_relaxed(mi_segment_t, &abandoned_visited); do { - segment->abandoned_next = anext; + mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, anext); } while (!mi_atomic_cas_ptr_weak(mi_segment_t, &abandoned_visited, &anext, segment)); } @@ -903,7 +903,7 @@ static void mi_abandoned_visited_push(mi_segment_t* segment) { static bool mi_abandoned_visited_revisit(void) { // quick check if the visited list is empty - if (mi_atomic_read_ptr_relaxed(mi_segment_t,&abandoned_visited)==NULL) return false; + if (mi_atomic_read_ptr_relaxed(mi_segment_t, &abandoned_visited) == NULL) return false; // grab the whole visited list mi_segment_t* first = mi_atomic_exchange_ptr(mi_segment_t, &abandoned_visited, NULL); @@ -919,15 +919,16 @@ static bool mi_abandoned_visited_revisit(void) // find the last element of the visited list: O(n) mi_segment_t* last = first; - while (last->abandoned_next != NULL) { - last = last->abandoned_next; + mi_segment_t* next; + while ((next = mi_atomic_read_ptr_relaxed(mi_segment_t, &last->abandoned_next)) != NULL) { + last = next; } // and atomically prepend to the abandoned list // (no need to increase the readers as we don't access the abandoned segments) mi_tagged_segment_t anext = mi_atomic_read_relaxed(&abandoned); do { - last->abandoned_next = mi_tagged_segment_ptr(anext); + mi_atomic_write_ptr(mi_segment_t, &last->abandoned_next, mi_tagged_segment_ptr(anext)); afirst = mi_tagged_segment(first, anext); } while (!mi_atomic_cas_weak(&abandoned, &anext, afirst)); return true; @@ -936,13 +937,13 @@ static bool mi_abandoned_visited_revisit(void) // Push on the abandoned list. static void mi_abandoned_push(mi_segment_t* segment) { mi_assert_internal(segment->thread_id == 0); - mi_assert_internal(segment->abandoned_next == NULL); + mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); mi_assert_internal(segment->next == NULL && segment->prev == NULL); mi_assert_internal(segment->used > 0); mi_tagged_segment_t next; mi_tagged_segment_t ts = mi_atomic_read_relaxed(&abandoned); do { - segment->abandoned_next = mi_tagged_segment_ptr(ts); + mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, mi_tagged_segment_ptr(ts)); next = mi_tagged_segment(segment, ts); } while (!mi_atomic_cas_weak(&abandoned, &ts, next)); } @@ -971,19 +972,20 @@ static mi_segment_t* mi_abandoned_pop(void) { // Do a pop. We use a reader count to prevent // a segment to be decommitted while a read is still pending, // and a tagged pointer to prevent A-B-A link corruption. - // (this is called from `memory.c:_mi_mem_free` for example) + // (this is called from `region.c:_mi_mem_free` for example) mi_atomic_increment(&abandoned_readers); // ensure no segment gets decommitted mi_tagged_segment_t next = 0; ts = mi_atomic_read(&abandoned); do { segment = mi_tagged_segment_ptr(ts); if (segment != NULL) { - next = mi_tagged_segment(segment->abandoned_next, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted + mi_segment_t* anext = mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next); + next = mi_tagged_segment(anext, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted } } while (segment != NULL && !mi_atomic_cas_weak(&abandoned, &ts, next)); mi_atomic_decrement(&abandoned_readers); // release reader lock if (segment != NULL) { - segment->abandoned_next = NULL; + mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, NULL); } return segment; } @@ -995,7 +997,7 @@ static mi_segment_t* mi_abandoned_pop(void) { static void mi_segment_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) { mi_assert_internal(segment->used == segment->abandoned); mi_assert_internal(segment->used > 0); - mi_assert_internal(segment->abandoned_next == NULL); + mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); mi_assert_expensive(mi_segment_is_valid(segment, tld)); // remove the segment from the free page queue if needed @@ -1008,8 +1010,8 @@ static void mi_segment_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) { _mi_stat_increase(&tld->stats->segments_abandoned, 1); mi_segments_track_size(-((long)segment->segment_size), tld); segment->thread_id = 0; - segment->abandoned_next = NULL; segment->abandoned_visits = 0; + mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, NULL); mi_abandoned_push(segment); } @@ -1073,7 +1075,7 @@ static bool mi_segment_check_free(mi_segment_t* segment, size_t block_size, bool // Reclaim a segment; returns NULL if the segment was freed // set `right_page_reclaimed` to `true` if it reclaimed a page of the right `block_size` that was not full. static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, size_t requested_block_size, bool* right_page_reclaimed, mi_segments_tld_t* tld) { - mi_assert_internal(segment->abandoned_next == NULL); + mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); if (right_page_reclaimed != NULL) { *right_page_reclaimed = false; } segment->thread_id = _mi_thread_id(); From ebf951e851de13ecae6e92a6ad1657b61adefac5 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 26 Jul 2020 00:15:57 -0700 Subject: [PATCH 042/172] extra checks for atomic ptr exchange; extend mi_atomic_yield for win32 --- include/mimalloc-atomic.h | 108 ++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 40 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index beb0f12c..30d1e4f8 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -93,33 +93,58 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub) { return (intptr_t)mi_atomic_addi(p,-sub); } -// Atomically read a pointer; Memory order is relaxed (i.e. no fence, only atomic). -#define mi_atomic_read_ptr_relaxed(T,p) \ - (T*)(mi_atomic_read_relaxed((const _Atomic(uintptr_t)*)(p))) - -// Atomically read a pointer; Memory order is acquire. -#define mi_atomic_read_ptr(T,p) \ - (T*)(mi_atomic_read((const _Atomic(uintptr_t)*)(p))) - -// Atomically write a pointer; Memory order is acquire. -#define mi_atomic_write_ptr(T,p,x) \ - mi_atomic_write((_Atomic(uintptr_t)*)(p), (uintptr_t)((T*)x)) - - -static inline bool mi_atomic_cas_weak_voidp(_Atomic(void*)*p, void** expected, void* desired, void* unused) { - (void)(unused); +// Atomically compare and exchange a void pointer; returns `true` if successful. May fail spuriously. +// Memory order is release. (like a write) +static inline bool mi_atomic_cas_weak_voidp(_Atomic(void*)* p, void** expected, void* desired, void* unused1, void* unused2) { + (void)unused1; (void)unused2; // for extra type check return mi_atomic_cas_weak((_Atomic(uintptr_t)*)p, (uintptr_t*)expected, (uintptr_t)desired); } +// Atomically read a void pointer; Memory order is relaxed (i.e. no fence, only atomic). +static inline void* mi_atomic_read_voidp(const _Atomic(void*)* p, void* unused) { + (void)unused; // for extra type check + return (void*)mi_atomic_read((const _Atomic(uintptr_t)*) p); +} + +// Atomically read a void pointer; Memory order is acquire. +static inline void* mi_atomic_read_voidp_relaxed(const _Atomic(void*)*p, void* unused) { + (void)unused; // for extra type check + return (void*)mi_atomic_read_relaxed((const _Atomic(uintptr_t)*) p); +} + +// Atomically write a void pointer; Memory order is acquire. +static inline void mi_atomic_write_voidp(_Atomic(void*)* p, void* exchange, void* unused) { + (void)unused; // for extra type check + mi_atomic_write((_Atomic(uintptr_t)*) p, (uintptr_t)exchange); +} + +// Atomically exchange a void pointer; Memory order is release-acquire. +static inline void* mi_atomic_exchange_voidp(_Atomic(void*)*p, void* exchange, void* unused) { + (void)unused; // for extra type check + return (void*)mi_atomic_exchange((_Atomic(uintptr_t)*) p, (uintptr_t)exchange); +} + // Atomically compare and exchange a pointer; returns `true` if successful. May fail spuriously. // Memory order is release. (like a write) #define mi_atomic_cas_ptr_weak(T,p,expected,desired) \ - mi_atomic_cas_weak_voidp((_Atomic(void*)*)(p), (void**)(expected), desired, *(expected)) - + mi_atomic_cas_weak_voidp((_Atomic(void*)*)(p), (void**)(expected), desired, *(p), *(expected)) +// Atomically read a pointer; Memory order is relaxed (i.e. no fence, only atomic). +#define mi_atomic_read_ptr_relaxed(T,p) \ + (T*)(mi_atomic_read_voidp_relaxed((const _Atomic(void*)*)(p), *(p))) + +// Atomically read a pointer; Memory order is acquire. +#define mi_atomic_read_ptr(T,p) \ + (T*)(mi_atomic_read_voidp((const _Atomic(void*)*)(p), *(p))) + +// Atomically write a pointer; Memory order is acquire. +#define mi_atomic_write_ptr(T,p,x) \ + mi_atomic_write_voidp((_Atomic(void*)*)(p), x, *(p)) + // Atomically exchange a pointer value. #define mi_atomic_exchange_ptr(T,p,exchange) \ - (T*)mi_atomic_exchange((_Atomic(uintptr_t)*)(p), (uintptr_t)((T*)exchange)) + (T*)(mi_atomic_exchange_voidp((_Atomic(void*)*)(p), exchange, *(p))) + #if !defined(__cplusplus) && defined(_MSC_VER) @@ -171,9 +196,6 @@ static inline void mi_atomic_write(_Atomic(uintptr_t)* p, uintptr_t x) { mi_atomic_exchange(p,x); #endif } -static inline void mi_atomic_yield(void) { - YieldProcessor(); -} static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int64_t add) { #ifdef _WIN64 return (int64_t)mi_atomic_addi((int64_t*)p,add); @@ -246,35 +268,41 @@ static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { int64_t current = atomic_load_explicit((_Atomic(int64_t)*)p, memory_order_relaxed); while (current < x && !atomic_compare_exchange_weak_explicit((_Atomic(int64_t)*)p, ¤t, x, memory_order_acq_rel, memory_order_acquire)) { /* nothing */ }; } +#endif #if defined(__cplusplus) - #include - static inline void mi_atomic_yield(void) { - std::this_thread::yield(); - } +#include +static inline void mi_atomic_yield(void) { + std::this_thread::yield(); +} +#elif defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +static inline void mi_atomic_yield(void) { + YieldProcessor(); +} #elif (defined(__GNUC__) || defined(__clang__)) && \ (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)) #if defined(__x86_64__) || defined(__i386__) - static inline void mi_atomic_yield(void) { - asm volatile ("pause" ::: "memory"); - } +static inline void mi_atomic_yield(void) { + asm volatile ("pause" ::: "memory"); +} #elif defined(__arm__) || defined(__aarch64__) - static inline void mi_atomic_yield(void) { - asm volatile("yield"); - } +static inline void mi_atomic_yield(void) { + asm volatile("yield"); +} #endif #elif defined(__wasi__) - #include - static inline void mi_atomic_yield(void) { - sched_yield(); - } +#include +static inline void mi_atomic_yield(void) { + sched_yield(); +} #else - #include - static inline void mi_atomic_yield(void) { - sleep(0); - } +#include +static inline void mi_atomic_yield(void) { + sleep(0); +} #endif -#endif #endif // __MIMALLOC_ATOMIC_H From 28014ee2bc049921effdd9a39fe983a43108cbdc Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 26 Jul 2020 00:16:17 -0700 Subject: [PATCH 043/172] fix atomic access for MADV_FREE in os_reset --- src/os.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/os.c b/src/os.c index 29a76a88..0b959a9c 100644 --- a/src/os.c +++ b/src/os.c @@ -759,12 +759,12 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) if (p != start) return false; #else #if defined(MADV_FREE) - static int advice = MADV_FREE; - int err = madvise(start, csize, advice); + static _Atomic(uintptr_t) advice = ATOMIC_VAR_INIT(MADV_FREE); + int err = madvise(start, csize, (int)mi_atomic_read_relaxed(&advice)); if (err != 0 && errno == EINVAL && advice == MADV_FREE) { // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on - advice = MADV_DONTNEED; - err = madvise(start, csize, advice); + mi_atomic_write(&advice, MADV_DONTNEED); + err = madvise(start, csize, MADV_DONTNEED); } #elif defined(__wasi__) int err = 0; From 53cbc68de3c65f90787641d2ab2c564a5662244f Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 26 Jul 2020 00:21:10 -0700 Subject: [PATCH 044/172] display compiler in cmake summary --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a228036..98b55ae0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,6 +231,11 @@ endif() message(STATUS "") message(STATUS "Library base name: ${mi_basename}") message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}") +if(MI_USE_CXX MATCHES "ON") + message(STATUS "Compiler : ${CMAKE_CXX_COMPILER}") +else() + message(STATUS "Compiler : ${CMAKE_C_COMPILER}") +endif() message(STATUS "Install directory: ${mi_install_dir}") message(STATUS "Build targets : ${mi_build_targets}") message(STATUS "") From eb1188a1ddfa15130227e51b52a718dd93bcee6d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 26 Jul 2020 17:00:54 +0000 Subject: [PATCH 045/172] Enables subset of stats for haiku. --- src/stats.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/stats.c b/src/stats.c index 172a3c0a..4c4f2486 100644 --- a/src/stats.c +++ b/src/stats.c @@ -466,7 +466,7 @@ static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_r *page_reclaim = 0; } -#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__) #include #include #include @@ -482,6 +482,7 @@ static mi_msecs_t timeval_secs(const struct timeval* tv) { static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit) { struct rusage rusage; getrusage(RUSAGE_SELF, &rusage); +#if !defined(__HAIKU__) #if defined(__APPLE__) && defined(__MACH__) *peak_rss = rusage.ru_maxrss; #else @@ -490,6 +491,14 @@ static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_r *page_faults = rusage.ru_majflt; *page_reclaim = rusage.ru_minflt; *peak_commit = 0; +#else +// Haiku does not have (yet?) a way to +// get these stats per process + *peak_rss = 0; + *page_faults = 0; + *page_reclaim = 0; + *peak_commit = 0; +#endif *utime = timeval_secs(&rusage.ru_utime); *stime = timeval_secs(&rusage.ru_stime); } From d964be2caa5a1f9837f9b0bb45e6296259e94a19 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 26 Jul 2020 18:56:10 +0000 Subject: [PATCH 046/172] getting resident mem at least --- src/stats.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/stats.c b/src/stats.c index 4c4f2486..203bad81 100644 --- a/src/stats.c +++ b/src/stats.c @@ -475,6 +475,10 @@ static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_r #include #endif +#if defined(__HAIKU__) +#include +#endif + static mi_msecs_t timeval_secs(const struct timeval* tv) { return ((mi_msecs_t)tv->tv_sec * 1000L) + ((mi_msecs_t)tv->tv_usec / 1000L); } @@ -494,10 +498,18 @@ static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_r #else // Haiku does not have (yet?) a way to // get these stats per process + thread_info tid; + area_info mem; + ssize_t c; *peak_rss = 0; *page_faults = 0; *page_reclaim = 0; *peak_commit = 0; + get_thread_info(find_thread(0), &tid); + + while (get_next_area_info(tid.team, &c, &mem) == B_OK) { + *peak_rss += mem.ram_size; + } #endif *utime = timeval_secs(&rusage.ru_utime); *stime = timeval_secs(&rusage.ru_stime); From 116159cd40d64fa9e1e50a6c54dd322e2a482659 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 26 Jul 2020 11:57:14 -0700 Subject: [PATCH 047/172] use RtlGenRandom on windows to enable compilation as C++ even with dynamic override --- src/random.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/random.c b/src/random.c index 5c093a91..be95fc46 100644 --- a/src/random.c +++ b/src/random.c @@ -162,20 +162,29 @@ If we cannot get good randomness, we fall back to weak randomness based on a tim -----------------------------------------------------------------------------*/ #if defined(_WIN32) +/* +// We prefer BCryptGenRandom over RtlGenRandom but it leads to a crash a when using dynamic override combined with the C++ runtime :-( #pragma comment (lib,"bcrypt.lib") #include static bool os_random_buf(void* buf, size_t buf_len) { return (BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); } -/* -#define SystemFunction036 NTAPI SystemFunction036 -#include -#undef SystemFunction036 -static bool os_random_buf(void* buf, size_t buf_len) { - RtlGenRandom(buf, (ULONG)buf_len); - return true; -} */ +#define RtlGenRandom SystemFunction036 +#ifdef __cplusplus +extern "C" { +#endif +BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); +#ifdef __cplusplus +} +#endif +static bool os_random_buf(void* buf, size_t buf_len) { + mi_assert_internal(buf_len >= sizeof(uintptr_t)); + memset(buf, 0, buf_len); + RtlGenRandom(buf, (ULONG)buf_len); + return (((uintptr_t*)buf)[0] != 0); // sanity check (but RtlGenRandom should never fail) +} + #elif defined(ANDROID) || defined(XP_DARWIN) || defined(__APPLE__) || defined(__DragonFly__) || \ defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__sun) || defined(__wasi__) From a9f46dc86f94e5a91eb3315ce2e8b9be6beea55a Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 26 Jul 2020 11:58:02 -0700 Subject: [PATCH 048/172] reduce memory order constraints for better efficiency on ARM etc --- include/mimalloc-atomic.h | 27 +++++++++++++++++++-------- src/page.c | 2 +- src/segment.c | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 30d1e4f8..b9935cb3 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -27,19 +27,23 @@ terms of the MIT license. A copy of the license can be found in the file // Atomic operations specialized for mimalloc // ------------------------------------------------------ -// Atomically add a value; returns the previous value. Memory ordering is acquire-release. +// Atomically add a value; returns the previous value. Memory ordering is relaxed. static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add); -// Atomically "and" a value; returns the previous value. Memory ordering is acquire-release. +// Atomically "and" a value; returns the previous value. Memory ordering is release. static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x); -// Atomically "or" a value; returns the previous value. Memory ordering is acquire-release. +// Atomically "or" a value; returns the previous value. Memory ordering is release. static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x); // Atomically compare and exchange a value; returns `true` if successful. -// May fail spuriously. Memory ordering is acquire-release; with acquire on failure. +// May fail spuriously. Memory ordering is release; with relaxed on failure. static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired); +// Atomically compare and exchange a value; returns `true` if successful. +// May fail spuriously. Memory ordering is acquire-release; with acquire on failure. +static inline bool mi_atomic_cas_weak_acq_rel(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired); + // Atomically compare and exchange a value; returns `true` if successful. // Memory ordering is acquire-release; with acquire on failure. static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired); @@ -180,6 +184,9 @@ static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expect static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { return mi_atomic_cas_strong(p,expected,desired); } +static inline bool mi_atomic_cas_weak_acq_rel(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired) { + return mi_atomic_cas_strong(p, expected, desired); +} static inline uintptr_t mi_atomic_exchange(_Atomic(uintptr_t)* p, uintptr_t exchange) { return (uintptr_t)MI_64(_InterlockedExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)exchange); } @@ -225,17 +232,21 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t #endif static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add) { MI_USING_STD - return atomic_fetch_add_explicit(p, add, memory_order_acq_rel); + return atomic_fetch_add_explicit(p, add, memory_order_relaxed); } static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD - return atomic_fetch_and_explicit(p, x, memory_order_acq_rel); + return atomic_fetch_and_explicit(p, x, memory_order_release); } static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD - return atomic_fetch_or_explicit(p, x, memory_order_acq_rel); + return atomic_fetch_or_explicit(p, x, memory_order_release); } static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { + MI_USING_STD + return atomic_compare_exchange_weak_explicit(p, expected, desired, memory_order_release, memory_order_relaxed); +} +static inline bool mi_atomic_cas_weak_acq_rel(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired) { MI_USING_STD return atomic_compare_exchange_weak_explicit(p, expected, desired, memory_order_acq_rel, memory_order_acquire); } @@ -266,7 +277,7 @@ static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add) static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { MI_USING_STD int64_t current = atomic_load_explicit((_Atomic(int64_t)*)p, memory_order_relaxed); - while (current < x && !atomic_compare_exchange_weak_explicit((_Atomic(int64_t)*)p, ¤t, x, memory_order_acq_rel, memory_order_acquire)) { /* nothing */ }; + while (current < x && !atomic_compare_exchange_weak_explicit((_Atomic(int64_t)*)p, ¤t, x, memory_order_release, memory_order_relaxed)) { /* nothing */ }; } #endif diff --git a/src/page.c b/src/page.c index 6b92d4c9..92faf9f2 100644 --- a/src/page.c +++ b/src/page.c @@ -159,7 +159,7 @@ static void _mi_page_thread_free_collect(mi_page_t* page) do { head = mi_tf_block(tfree); tfreex = mi_tf_set_block(tfree,NULL); - } while (!mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); + } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tfree, tfreex)); // return if the list is empty if (head == NULL) return; diff --git a/src/segment.c b/src/segment.c index 5af98b1e..55230553 100644 --- a/src/segment.c +++ b/src/segment.c @@ -982,7 +982,7 @@ static mi_segment_t* mi_abandoned_pop(void) { mi_segment_t* anext = mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next); next = mi_tagged_segment(anext, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted } - } while (segment != NULL && !mi_atomic_cas_weak(&abandoned, &ts, next)); + } while (segment != NULL && !mi_atomic_cas_weak_acq_rel(&abandoned, &ts, next)); mi_atomic_decrement(&abandoned_readers); // release reader lock if (segment != NULL) { mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, NULL); From a468430772a687085054e8380a94f794bd740f5c Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 26 Jul 2020 14:19:30 -0700 Subject: [PATCH 049/172] strengthen memory order of bit operations; insert memory fences --- include/mimalloc-atomic.h | 6 +++--- src/alloc.c | 2 +- src/segment.c | 8 +++++--- test/test-stress.c | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index b9935cb3..cb247b09 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -232,15 +232,15 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t #endif static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add) { MI_USING_STD - return atomic_fetch_add_explicit(p, add, memory_order_relaxed); + return atomic_fetch_add_explicit(p, add, memory_order_acq_rel); } static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD - return atomic_fetch_and_explicit(p, x, memory_order_release); + return atomic_fetch_and_explicit(p, x, memory_order_acq_rel); } static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x) { MI_USING_STD - return atomic_fetch_or_explicit(p, x, memory_order_release); + return atomic_fetch_or_explicit(p, x, memory_order_acq_rel); } static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { MI_USING_STD diff --git a/src/alloc.c b/src/alloc.c index 62c3c018..e1c54bed 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -323,7 +323,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc if (mi_unlikely(use_delayed)) { // racy read on `heap`, but ok because MI_DELAYED_FREEING is set (see `mi_heap_delete` and `mi_heap_collect_abandon`) - mi_heap_t* const heap = mi_page_heap(page); + mi_heap_t* const heap = (mi_heap_t*)(mi_atomic_read(&page->xheap)); //mi_page_heap(page); mi_assert_internal(heap != NULL); if (heap != NULL) { // add to the delayed free list of this heap. (do this atomically as the lock only protects heap memory validity) diff --git a/src/segment.c b/src/segment.c index 55230553..b5fd13d3 100644 --- a/src/segment.c +++ b/src/segment.c @@ -472,7 +472,6 @@ static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_se if (any_reset && mi_option_is_enabled(mi_option_reset_decommits)) { fully_committed = false; } - _mi_mem_free(segment, segment_size, segment->memid, fully_committed, any_reset, tld->os); } @@ -629,6 +628,7 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ return NULL; } } + atomic_thread_fence(memory_order_acq_rel); segment->memid = memid; segment->mem_is_fixed = mem_large; segment->mem_is_committed = commit; @@ -638,6 +638,7 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ mi_assert_internal(segment->mem_is_fixed ? segment->mem_is_committed : true); if (!pages_still_good) { // zero the segment info (but not the `mem` fields) + atomic_thread_fence(memory_order_release); // with read of `abandoned_next` in `mi_abandoned_pop` ptrdiff_t ofs = offsetof(mi_segment_t, next); memset((uint8_t*)segment + ofs, 0, info_size - ofs); @@ -791,6 +792,7 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, bool a uint16_t reserved = page->reserved; ptrdiff_t ofs = offsetof(mi_page_t,capacity); memset((uint8_t*)page + ofs, 0, sizeof(*page) - ofs); + atomic_thread_fence(memory_order_release); page->capacity = capacity; page->reserved = reserved; page->xblock_size = block_size; @@ -801,7 +803,7 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, bool a mi_pages_reset_add(segment, page, tld); } - page->capacity = 0; // after reset there can be zero'd now + page->capacity = 0; // after reset these can be zero'd now page->reserved = 0; } @@ -979,7 +981,7 @@ static mi_segment_t* mi_abandoned_pop(void) { do { segment = mi_tagged_segment_ptr(ts); if (segment != NULL) { - mi_segment_t* anext = mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next); + mi_segment_t* anext = mi_atomic_read_ptr(mi_segment_t, &segment->abandoned_next); next = mi_tagged_segment(anext, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted } } while (segment != NULL && !mi_atomic_cas_weak_acq_rel(&abandoned, &ts, next)); diff --git a/test/test-stress.c b/test/test-stress.c index 7d8993a0..33ec674b 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -189,7 +189,7 @@ static void test_stress(void) { } } // mi_collect(false); -#ifndef NDEBUG +#if !defined(NDEBUG) || defined(MI_TSAN) if ((n + 1) % 10 == 0) { printf("- iterations left: %3d\n", ITER - (n + 1)); } #endif } From ef8e5d18a65f653bbef9cf57694aff37d2e85b9d Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 26 Jul 2020 18:00:38 -0700 Subject: [PATCH 050/172] replace atomics with C11/C++ atomics with explicit memory order; passes tsan. Issue #130 --- include/mimalloc-atomic.h | 319 ++++++++++++++---------------------- include/mimalloc-internal.h | 8 +- include/mimalloc-types.h | 4 +- src/alloc.c | 14 +- src/arena.c | 18 +- src/bitmap.inc.c | 14 +- src/heap.c | 2 +- src/options.c | 18 +- src/os.c | 26 +-- src/page-queue.c | 6 +- src/page.c | 18 +- src/random.c | 4 +- src/region.c | 50 +++--- src/segment.c | 62 ++++--- 14 files changed, 248 insertions(+), 315 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index cb247b09..e1fdda16 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018,2020 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. @@ -8,150 +8,97 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MIMALLOC_ATOMIC_H #define MIMALLOC_ATOMIC_H -// ------------------------------------------------------ +// -------------------------------------------------------------------------------------------- // 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. +// 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. +// ----------------------------------------------------------------------------------------------- #if defined(__cplusplus) +// Use C++ atomics #include -#define _Atomic(tp) std::atomic +#define _Atomic(tp) std::atomic +#define mi_atomic(name) std::atomic_##name +#define mi_memory_order(name) std::memory_order_##name #elif defined(_MSC_VER) +// Use MSVC C wrapper for C11 atomics #define _Atomic(tp) tp #define ATOMIC_VAR_INIT(x) x +#define mi_atomic(name) mi_atomic_##name +#define mi_memory_order(name) mi_memory_order_##name #else +// Use C11 atomics #include +#define mi_atomic(name) atomic_##name +#define mi_memory_order(name) memory_order_##name #endif -// ------------------------------------------------------ -// Atomic operations specialized for mimalloc -// ------------------------------------------------------ +// Various defines for all used memory orders in mimalloc +#define mi_atomic_cas_weak(p,expected,desired,mem_success,mem_fail) \ + mi_atomic(compare_exchange_weak_explicit)(p,expected,desired,mem_success,mem_fail) -// Atomically add a value; returns the previous value. Memory ordering is relaxed. -static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add); +#define mi_atomic_cas_strong(p,expected,desired,mem_success,mem_fail) \ + mi_atomic(compare_exchange_strong_explicit)(p,expected,desired,mem_success,mem_fail) -// Atomically "and" a value; returns the previous value. Memory ordering is release. -static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x); +#define mi_atomic_load_acquire(p) mi_atomic(load_explicit)(p,mi_memory_order(acquire)) +#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_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)) +#define mi_atomic_cas_weak_acq_rel(p,exp,des) mi_atomic_cas_weak(p,exp,des,mi_memory_order(acq_rel),mi_memory_order(acquire)) +#define mi_atomic_cas_strong_release(p,exp,des) mi_atomic_cas_strong(p,exp,des,mi_memory_order(release),mi_memory_order(relaxed)) +#define mi_atomic_cas_strong_acq_rel(p,exp,des) mi_atomic_cas_strong(p,exp,des,mi_memory_order(acq_rel),mi_memory_order(acquire)) -// Atomically "or" a value; returns the previous value. Memory ordering is release. -static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x); +#define mi_atomic_add_relaxed(p,x) mi_atomic(fetch_add_explicit)(p,x,mi_memory_order(relaxed)) +#define mi_atomic_sub_relaxed(p,x) mi_atomic(fetch_sub_explicit)(p,x,mi_memory_order(relaxed)) +#define mi_atomic_add_acq_rel(p,x) mi_atomic(fetch_add_explicit)(p,x,mi_memory_order(acq_rel)) +#define mi_atomic_sub_acq_rel(p,x) mi_atomic(fetch_sub_explicit)(p,x,mi_memory_order(acq_rel)) +#define mi_atomic_and_acq_rel(p,x) mi_atomic(fetch_and_explicit)(p,x,mi_memory_order(acq_rel)) +#define mi_atomic_or_acq_rel(p,x) mi_atomic(fetch_or_explicit)(p,x,mi_memory_order(acq_rel)) -// Atomically compare and exchange a value; returns `true` if successful. -// May fail spuriously. Memory ordering is release; with relaxed on failure. -static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired); +#define mi_atomic_increment_relaxed(p) mi_atomic_add_relaxed(p,1) +#define mi_atomic_decrement_relaxed(p) mi_atomic_sub_relaxed(p,1) +#define mi_atomic_increment_acq_rel(p) mi_atomic_add_acq_rel(p,1) +#define mi_atomic_decrement_acq_rel(p) mi_atomic_sub_acq_rel(p,1) -// Atomically compare and exchange a value; returns `true` if successful. -// May fail spuriously. Memory ordering is acquire-release; with acquire on failure. -static inline bool mi_atomic_cas_weak_acq_rel(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired); - -// Atomically compare and exchange a value; returns `true` if successful. -// Memory ordering is acquire-release; with acquire on failure. -static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired); - -// Atomically exchange a value. Memory ordering is acquire-release. -static inline uintptr_t mi_atomic_exchange(_Atomic(uintptr_t)* p, uintptr_t exchange); - -// Atomically read a value. Memory ordering is relaxed. -static inline uintptr_t mi_atomic_read_relaxed(const _Atomic(uintptr_t)* p); - -// Atomically read a value. Memory ordering is acquire. -static inline uintptr_t mi_atomic_read(const _Atomic(uintptr_t)* p); - -// Atomically write a value. Memory ordering is release. -static inline void mi_atomic_write(_Atomic(uintptr_t)* p, uintptr_t x); - -// Yield static inline void mi_atomic_yield(void); - -// Atomically add a 64-bit value; returns the previous value. Memory ordering is relaxed. -// Note: not using _Atomic(int64_t) as it is only used for statistics. -static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add); - -// Atomically update `*p` with the maximum of `*p` and `x` as a 64-bit value. -// Returns the previous value. Note: not using _Atomic(int64_t) as it is only used for statistics. -static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x); +static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)* p, intptr_t add); +static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub); -// Atomically subtract a value; returns the previous value. -static inline uintptr_t mi_atomic_sub(_Atomic(uintptr_t)* p, uintptr_t sub) { - return mi_atomic_add(p, (uintptr_t)(-((intptr_t)sub))); +#if defined(__cplusplus) || !defined(_MSC_VER) + +// In C++/C11 atomics we have polymorpic atomics so can use the typed `ptr` variants +// (where `tp` is the type of atomic value) +// We use these macros so we can provide a typed wrapper in MSVC in C compilation mode as well +#define mi_atomic_load_ptr_acquire(tp,p) mi_atomic_load_acquire(p) +#define mi_atomic_load_ptr_relaxed(tp,p) mi_atomic_load_relaxed(p) +#define mi_atomic_store_ptr_release(tp,p,x) mi_atomic_store_release(p,x) +#define mi_atomic_store_ptr_relaxed(tp,p,x) mi_atomic_store_relaxed(p,x) +#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_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) + +// These are used by the statistics +static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add) { + return mi_atomic(fetch_add_explicit)((_Atomic(int64_t)*)p, add, mi_memory_order(relaxed)); +} +static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { + int64_t current = mi_atomic_load_relaxed((_Atomic(int64_t)*)p); + while (current < x && !mi_atomic_cas_weak_release((_Atomic(int64_t)*)p, ¤t, x)) { /* nothing */ }; } -// Atomically increment a value; returns the incremented result. -static inline uintptr_t mi_atomic_increment(_Atomic(uintptr_t)* p) { - return mi_atomic_add(p, 1); -} -// Atomically decrement a value; returns the decremented result. -static inline uintptr_t mi_atomic_decrement(_Atomic(uintptr_t)* p) { - return mi_atomic_sub(p, 1); -} +#elif defined(_MSC_VER) -// Atomically add a signed value; returns the previous value. -static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)* p, intptr_t add) { - return (intptr_t)mi_atomic_add((_Atomic(uintptr_t)*)p, (uintptr_t)add); -} - -// Atomically subtract a signed value; returns the previous value. -static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub) { - return (intptr_t)mi_atomic_addi(p,-sub); -} - -// Atomically compare and exchange a void pointer; returns `true` if successful. May fail spuriously. -// Memory order is release. (like a write) -static inline bool mi_atomic_cas_weak_voidp(_Atomic(void*)* p, void** expected, void* desired, void* unused1, void* unused2) { - (void)unused1; (void)unused2; // for extra type check - return mi_atomic_cas_weak((_Atomic(uintptr_t)*)p, (uintptr_t*)expected, (uintptr_t)desired); -} - -// Atomically read a void pointer; Memory order is relaxed (i.e. no fence, only atomic). -static inline void* mi_atomic_read_voidp(const _Atomic(void*)* p, void* unused) { - (void)unused; // for extra type check - return (void*)mi_atomic_read((const _Atomic(uintptr_t)*) p); -} - -// Atomically read a void pointer; Memory order is acquire. -static inline void* mi_atomic_read_voidp_relaxed(const _Atomic(void*)*p, void* unused) { - (void)unused; // for extra type check - return (void*)mi_atomic_read_relaxed((const _Atomic(uintptr_t)*) p); -} - -// Atomically write a void pointer; Memory order is acquire. -static inline void mi_atomic_write_voidp(_Atomic(void*)* p, void* exchange, void* unused) { - (void)unused; // for extra type check - mi_atomic_write((_Atomic(uintptr_t)*) p, (uintptr_t)exchange); -} - -// Atomically exchange a void pointer; Memory order is release-acquire. -static inline void* mi_atomic_exchange_voidp(_Atomic(void*)*p, void* exchange, void* unused) { - (void)unused; // for extra type check - return (void*)mi_atomic_exchange((_Atomic(uintptr_t)*) p, (uintptr_t)exchange); -} - -// Atomically compare and exchange a pointer; returns `true` if successful. May fail spuriously. -// Memory order is release. (like a write) -#define mi_atomic_cas_ptr_weak(T,p,expected,desired) \ - mi_atomic_cas_weak_voidp((_Atomic(void*)*)(p), (void**)(expected), desired, *(p), *(expected)) - -// Atomically read a pointer; Memory order is relaxed (i.e. no fence, only atomic). -#define mi_atomic_read_ptr_relaxed(T,p) \ - (T*)(mi_atomic_read_voidp_relaxed((const _Atomic(void*)*)(p), *(p))) - -// Atomically read a pointer; Memory order is acquire. -#define mi_atomic_read_ptr(T,p) \ - (T*)(mi_atomic_read_voidp((const _Atomic(void*)*)(p), *(p))) - -// Atomically write a pointer; Memory order is acquire. -#define mi_atomic_write_ptr(T,p,x) \ - mi_atomic_write_voidp((_Atomic(void*)*)(p), x, *(p)) - -// Atomically exchange a pointer value. -#define mi_atomic_exchange_ptr(T,p,exchange) \ - (T*)(mi_atomic_exchange_voidp((_Atomic(void*)*)(p), exchange, *(p))) - - - -#if !defined(__cplusplus) && defined(_MSC_VER) +// MSVC C compilation wrapper that uses Interlocked operations to model C11 atomics. #define WIN32_LEAN_AND_MEAN #include #include @@ -162,16 +109,29 @@ typedef LONG64 msc_intptr_t; typedef LONG msc_intptr_t; #define MI_64(f) f #endif -static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add) { + +typedef enum mi_memory_order_e { + mi_memory_order_relaxed, + mi_memory_order_consume, + mi_memory_order_acquire, + mi_memory_order_release, + mi_memory_order_acq_rel, + mi_memory_order_seq_cst +} mi_memory_order; + +static inline uintptr_t mi_atomic_fetch_add_explicit(_Atomic(uintptr_t)* p, uintptr_t add, mi_memory_order mo) { return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, (msc_intptr_t)add); } -static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x) { +static inline uintptr_t mi_atomic_fetch_sub_explicit(_Atomic(uintptr_t)*p, uintptr_t sub, mi_memory_order mo) { + return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, -((msc_intptr_t)sub)); +} +static inline uintptr_t mi_atomic_fetch_and_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { return (uintptr_t)MI_64(_InterlockedAnd)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } -static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x) { +static inline uintptr_t mi_atomic_fetch_or_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { return (uintptr_t)MI_64(_InterlockedOr)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } -static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { +static inline bool mi_atomic_compare_exchange_strong_explicit(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired, mi_memory_order mo1, mi_memory_order mo2) { uintptr_t read = (uintptr_t)MI_64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)(*expected)); if (read == *expected) { return true; @@ -181,28 +141,36 @@ static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expect return false; } } -static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { - return mi_atomic_cas_strong(p,expected,desired); +static inline bool mi_atomic_compare_exchange_weak_explicit(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired, mi_memory_order mo1, mi_memory_order mo2) { + return mi_atomic_compare_exchange_strong_explicit(p, expected, desired, mo1, mo2); } -static inline bool mi_atomic_cas_weak_acq_rel(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired) { - return mi_atomic_cas_strong(p, expected, desired); -} -static inline uintptr_t mi_atomic_exchange(_Atomic(uintptr_t)* p, uintptr_t exchange) { +static inline uintptr_t mi_atomic_exchange_explicit(_Atomic(uintptr_t)* p, uintptr_t exchange, mi_memory_order mo) { return (uintptr_t)MI_64(_InterlockedExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)exchange); } -static inline uintptr_t mi_atomic_read(_Atomic(uintptr_t) const* p) { - return *p; +static inline mi_atomic_thread_fence(mi_memory_order mo) { + _Atomic(uintptr_t)x = 0; + mi_atomic_exchange_explicit(&x, 1, mo); } -static inline uintptr_t mi_atomic_read_relaxed(_Atomic(uintptr_t) const* p) { +static inline uintptr_t mi_atomic_load_explicit(_Atomic(uintptr_t) const* p, mi_memory_order mo) { + #if defined(_M_IX86) || defined(_M_X64) return *p; + #else + uintptr_t x = *p; + if (mo > mi_memory_order_relaxed) { + while (!mi_atomic_compare_exchange_weak_explicit(p, &x, x, mo, mi_memory_order_relaxed)) { /* nothing */ }; + } + return x; + #endif } -static inline void mi_atomic_write(_Atomic(uintptr_t)* p, uintptr_t x) { +static inline void mi_atomic_store_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { #if defined(_M_IX86) || defined(_M_X64) *p = x; #else - mi_atomic_exchange(p,x); + mi_atomic_exchange_explicit(p,x,mo); #endif } + +// These are used by the statistics static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int64_t add) { #ifdef _WIN64 return (int64_t)mi_atomic_addi((int64_t*)p,add); @@ -216,7 +184,6 @@ static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int return current; #endif } - static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t x) { int64_t current; do { @@ -224,63 +191,31 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t } while (current < x && _InterlockedCompareExchange64(p, x, current) != current); } -#else -#ifdef __cplusplus -#define MI_USING_STD using namespace std; -#else -#define MI_USING_STD -#endif -static inline uintptr_t mi_atomic_add(_Atomic(uintptr_t)* p, uintptr_t add) { - MI_USING_STD - return atomic_fetch_add_explicit(p, add, memory_order_acq_rel); -} -static inline uintptr_t mi_atomic_and(_Atomic(uintptr_t)* p, uintptr_t x) { - MI_USING_STD - return atomic_fetch_and_explicit(p, x, memory_order_acq_rel); -} -static inline uintptr_t mi_atomic_or(_Atomic(uintptr_t)* p, uintptr_t x) { - MI_USING_STD - return atomic_fetch_or_explicit(p, x, memory_order_acq_rel); -} -static inline bool mi_atomic_cas_weak(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { - MI_USING_STD - return atomic_compare_exchange_weak_explicit(p, expected, desired, memory_order_release, memory_order_relaxed); -} -static inline bool mi_atomic_cas_weak_acq_rel(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired) { - MI_USING_STD - return atomic_compare_exchange_weak_explicit(p, expected, desired, memory_order_acq_rel, memory_order_acquire); -} -static inline bool mi_atomic_cas_strong(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired) { - MI_USING_STD - return atomic_compare_exchange_strong_explicit(p, expected, desired, memory_order_acq_rel, memory_order_acquire); -} -static inline uintptr_t mi_atomic_exchange(_Atomic(uintptr_t)* p, uintptr_t exchange) { - MI_USING_STD - return atomic_exchange_explicit(p, exchange, memory_order_acq_rel); -} -static inline uintptr_t mi_atomic_read_relaxed(const _Atomic(uintptr_t)* p) { - MI_USING_STD - return atomic_load_explicit((_Atomic(uintptr_t)*) p, memory_order_relaxed); -} -static inline uintptr_t mi_atomic_read(const _Atomic(uintptr_t)* p) { - MI_USING_STD - return atomic_load_explicit((_Atomic(uintptr_t)*) p, memory_order_acquire); -} -static inline void mi_atomic_write(_Atomic(uintptr_t)* p, uintptr_t x) { - MI_USING_STD - return atomic_store_explicit(p, x, memory_order_release); -} -static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add) { - MI_USING_STD - return atomic_fetch_add_explicit((_Atomic(int64_t)*)p, add, memory_order_relaxed); -} -static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { - MI_USING_STD - int64_t current = atomic_load_explicit((_Atomic(int64_t)*)p, memory_order_relaxed); - while (current < x && !atomic_compare_exchange_weak_explicit((_Atomic(int64_t)*)p, ¤t, x, memory_order_release, memory_order_relaxed)) { /* nothing */ }; -} +// The pointer macros cast to `uintptr_t`. +#define mi_atomic_load_ptr_acquire(tp,p) (tp*)mi_atomic_load_acquire((_Atomic(uintptr_t)*)(p)) +#define mi_atomic_load_ptr_relaxed(tp,p) (tp*)mi_atomic_load_relaxed((_Atomic(uintptr_t)*)(p)) +#define mi_atomic_store_ptr_release(tp,p,x) mi_atomic_store_release((_Atomic(uintptr_t)*)(p),(uintptr_t)(x)) +#define mi_atomic_store_ptr_relaxed(tp,p,x) mi_atomic_store_relaxed((_Atomic(uintptr_t)*)(p),(uintptr_t)(x)) +#define mi_atomic_cas_ptr_weak_release(tp,p,exp,des) mi_atomic_cas_weak_release((_Atomic(uintptr_t)*)(p),(uintptr_t*)exp,(uintptr_t)des) +#define mi_atomic_cas_ptr_weak_acq_rel(tp,p,exp,des) mi_atomic_cas_weak_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t*)exp,(uintptr_t)des) +#define mi_atomic_cas_ptr_strong_release(tp,p,exp,des) mi_atomic_cas_strong_release((_Atomic(uintptr_t)*)(p),(uintptr_t*)exp,(uintptr_t)des) +#define mi_atomic_exchange_ptr_release(tp,p,x) (tp*)mi_atomic_exchange_release((_Atomic(uintptr_t)*)(p),(uintptr_t)x) +#define mi_atomic_exchange_ptr_acq_rel(tp,p,x) (tp*)mi_atomic_exchange_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t)x) + #endif + +// Atomically add a signed value; returns the previous value. +static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)*p, intptr_t add) { + return (intptr_t)mi_atomic_add_acq_rel((_Atomic(uintptr_t)*)p, (uintptr_t)add); +} + +// Atomically subtract a signed value; returns the previous value. +static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub) { + return (intptr_t)mi_atomic_addi(p, -sub); +} + +// Yield #if defined(__cplusplus) #include static inline void mi_atomic_yield(void) { diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 2dc7e36a..1afdae9c 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -448,21 +448,21 @@ static inline size_t mi_page_usable_block_size(const mi_page_t* page) { // Thread free access static inline mi_block_t* mi_page_thread_free(const mi_page_t* page) { - return (mi_block_t*)(mi_atomic_read_relaxed(&page->xthread_free) & ~3); + return (mi_block_t*)(mi_atomic_load_relaxed(&((mi_page_t*)page)->xthread_free) & ~3); } static inline mi_delayed_t mi_page_thread_free_flag(const mi_page_t* page) { - return (mi_delayed_t)(mi_atomic_read_relaxed(&page->xthread_free) & 3); + return (mi_delayed_t)(mi_atomic_load_relaxed(&((mi_page_t*)page)->xthread_free) & 3); } // Heap access static inline mi_heap_t* mi_page_heap(const mi_page_t* page) { - return (mi_heap_t*)(mi_atomic_read_relaxed(&page->xheap)); + return (mi_heap_t*)(mi_atomic_load_relaxed(&((mi_page_t*)page)->xheap)); } static inline void mi_page_set_heap(mi_page_t* page, mi_heap_t* heap) { mi_assert_internal(mi_page_thread_free_flag(page) != MI_DELAYED_FREEING); - mi_atomic_write(&page->xheap,(uintptr_t)heap); + mi_atomic_store_release(&page->xheap,(uintptr_t)heap); } // Thread free flag helpers diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 17b33bc6..18c415eb 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -259,9 +259,9 @@ typedef struct mi_segment_s { bool mem_is_committed; // `true` if the whole segment is eagerly committed // segment fields - struct mi_segment_s* next; // must be the first segment field -- see `segment.c:segment_alloc` - struct mi_segment_s* prev; _Atomic(struct mi_segment_s*) abandoned_next; + struct mi_segment_s* next; // must be the first segment field after abandoned_next -- see `segment.c:segment_init` + struct mi_segment_s* prev; 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 it it is too long) diff --git a/src/alloc.c b/src/alloc.c index e1c54bed..ebf90ebc 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -307,7 +307,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc // Try to put the block on either the page-local thread free list, or the heap delayed free list. mi_thread_free_t tfreex; bool use_delayed; - mi_thread_free_t tfree = mi_atomic_read_relaxed(&page->xthread_free); + mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free); do { use_delayed = (mi_tf_delayed(tfree) == MI_USE_DELAYED_FREE); if (mi_unlikely(use_delayed)) { @@ -319,27 +319,27 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc mi_block_set_next(page, block, mi_tf_block(tfree)); tfreex = mi_tf_set_block(tfree,block); } - } while (!mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); + } while (!mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex)); if (mi_unlikely(use_delayed)) { // racy read on `heap`, but ok because MI_DELAYED_FREEING is set (see `mi_heap_delete` and `mi_heap_collect_abandon`) - mi_heap_t* const heap = (mi_heap_t*)(mi_atomic_read(&page->xheap)); //mi_page_heap(page); + mi_heap_t* const heap = (mi_heap_t*)(mi_atomic_load_acquire(&page->xheap)); //mi_page_heap(page); mi_assert_internal(heap != NULL); if (heap != NULL) { // add to the delayed free list of this heap. (do this atomically as the lock only protects heap memory validity) - mi_block_t* dfree = mi_atomic_read_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); + mi_block_t* dfree = mi_atomic_load_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); do { mi_block_set_nextx(heap,block,dfree, heap->keys); - } while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, &dfree, block)); + } while (!mi_atomic_cas_ptr_weak_release(mi_block_t,&heap->thread_delayed_free, &dfree, block)); } // and reset the MI_DELAYED_FREEING flag - tfree = mi_atomic_read_relaxed(&page->xthread_free); + tfree = mi_atomic_load_relaxed(&page->xthread_free); do { tfreex = tfree; mi_assert_internal(mi_tf_delayed(tfree) == MI_DELAYED_FREEING); tfreex = mi_tf_set_delayed(tfree,MI_NO_DELAYED_FREE); - } while (!mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); + } while (!mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex)); } } diff --git a/src/arena.c b/src/arena.c index 1c1fc1a0..73a7e704 100644 --- a/src/arena.c +++ b/src/arena.c @@ -105,12 +105,12 @@ static size_t mi_block_count_of_size(size_t size) { static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx) { const size_t fcount = arena->field_count; - size_t idx = mi_atomic_read(&arena->search_idx); // start from last search + size_t idx = mi_atomic_load_acquire(&arena->search_idx); // start from last search for (size_t visited = 0; visited < fcount; visited++, idx++) { if (idx >= fcount) idx = 0; // wrap around // try to atomically claim a range of bits if (mi_bitmap_try_find_claim_field(arena->blocks_inuse, idx, blocks, bitmap_idx)) { - mi_atomic_write(&arena->search_idx, idx); // start search from here next time + mi_atomic_store_release(&arena->search_idx, idx); // start search from here next time return true; } } @@ -175,7 +175,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, mi_assert_internal(size <= bcount*MI_ARENA_BLOCK_SIZE); // try numa affine allocation for (size_t i = 0; i < MI_MAX_ARENAS; i++) { - mi_arena_t* arena = mi_atomic_read_ptr_relaxed(mi_arena_t, &mi_arenas[i]); + mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[i]); if (arena==NULL) break; // end reached if ((arena->numa_node<0 || arena->numa_node==numa_node) && // numa local? (*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages @@ -187,7 +187,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, } // try from another numa node instead.. for (size_t i = 0; i < MI_MAX_ARENAS; i++) { - mi_arena_t* arena = mi_atomic_read_ptr_relaxed(mi_arena_t, &mi_arenas[i]); + mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t, &mi_arenas[i]); if (arena==NULL) break; // end reached if ((arena->numa_node>=0 && arena->numa_node!=numa_node) && // not numa local! (*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages @@ -228,7 +228,7 @@ void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_s size_t bitmap_idx; mi_arena_id_indices(memid, &arena_idx, &bitmap_idx); mi_assert_internal(arena_idx < MI_MAX_ARENAS); - mi_arena_t* arena = mi_atomic_read_ptr_relaxed(mi_arena_t,&mi_arenas[arena_idx]); + mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t,&mi_arenas[arena_idx]); mi_assert_internal(arena != NULL); if (arena == NULL) { _mi_error_message(EINVAL, "trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid); @@ -254,15 +254,15 @@ void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_s static bool mi_arena_add(mi_arena_t* arena) { mi_assert_internal(arena != NULL); - mi_assert_internal((uintptr_t)mi_atomic_read_ptr_relaxed(uint8_t,&arena->start) % MI_SEGMENT_ALIGN == 0); + mi_assert_internal((uintptr_t)mi_atomic_load_ptr_relaxed(uint8_t,&arena->start) % MI_SEGMENT_ALIGN == 0); mi_assert_internal(arena->block_count > 0); - uintptr_t i = mi_atomic_increment(&mi_arena_count); + uintptr_t i = mi_atomic_increment_acq_rel(&mi_arena_count); if (i >= MI_MAX_ARENAS) { - mi_atomic_decrement(&mi_arena_count); + mi_atomic_decrement_acq_rel(&mi_arena_count); return false; } - mi_atomic_write_ptr(mi_arena_t,&mi_arenas[i], arena); + mi_atomic_store_ptr_release(mi_arena_t,&mi_arenas[i], arena); return true; } diff --git a/src/bitmap.inc.c b/src/bitmap.inc.c index b9953a4f..2d6df46e 100644 --- a/src/bitmap.inc.c +++ b/src/bitmap.inc.c @@ -121,9 +121,9 @@ static inline bool mi_bitmap_try_claim_field(mi_bitmap_t bitmap, size_t bitmap_f mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields); mi_assert_internal(bitidx + count <= MI_BITMAP_FIELD_BITS); - uintptr_t field = mi_atomic_read_relaxed(&bitmap[idx]); + uintptr_t field = mi_atomic_load_relaxed(&bitmap[idx]); if ((field & mask) == 0) { // free? - if (mi_atomic_cas_strong(&bitmap[idx], &field, (field|mask))) { + if (mi_atomic_cas_strong_acq_rel(&bitmap[idx], &field, (field|mask))) { // claimed! return true; } @@ -138,7 +138,7 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx { mi_assert_internal(bitmap_idx != NULL); _Atomic(uintptr_t)* field = &bitmap[idx]; - uintptr_t map = mi_atomic_read(field); + uintptr_t map = mi_atomic_load_relaxed(field); if (map==MI_BITMAP_FIELD_FULL) return false; // short cut // search for 0-bit sequence of length count @@ -158,7 +158,7 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx mi_assert_internal((m >> bitidx) == mask); // no overflow? const uintptr_t newmap = map | m; mi_assert_internal((newmap^map) >> bitidx == mask); - if (!mi_atomic_cas_weak(field, &map, newmap)) { // TODO: use strong cas here? + if (!mi_atomic_cas_weak_acq_rel(field, &map, newmap)) { // TODO: use strong cas here? // no success, another thread claimed concurrently.. keep going (with updated `map`) continue; } @@ -204,7 +204,7 @@ static inline bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, s const uintptr_t mask = mi_bitmap_mask_(count, bitidx); mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields); // mi_assert_internal((bitmap[idx] & mask) == mask); - uintptr_t prev = mi_atomic_and(&bitmap[idx], ~mask); + uintptr_t prev = mi_atomic_and_acq_rel(&bitmap[idx], ~mask); return ((prev & mask) == mask); } @@ -217,7 +217,7 @@ static inline bool mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, siz const uintptr_t mask = mi_bitmap_mask_(count, bitidx); mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields); //mi_assert_internal(any_zero != NULL || (bitmap[idx] & mask) == 0); - uintptr_t prev = mi_atomic_or(&bitmap[idx], mask); + uintptr_t prev = mi_atomic_or_acq_rel(&bitmap[idx], mask); if (any_zero != NULL) *any_zero = ((prev & mask) != mask); return ((prev & mask) == 0); } @@ -228,7 +228,7 @@ static inline bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_field const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); const uintptr_t mask = mi_bitmap_mask_(count, bitidx); mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields); - uintptr_t field = mi_atomic_read_relaxed(&bitmap[idx]); + uintptr_t field = mi_atomic_load_relaxed(&bitmap[idx]); if (any_ones != NULL) *any_ones = ((field & mask) != 0); return ((field & mask) == mask); } diff --git a/src/heap.c b/src/heap.c index 5d0d4b8a..526c93ed 100644 --- a/src/heap.c +++ b/src/heap.c @@ -143,7 +143,7 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) // collect all pages owned by this thread mi_heap_visit_pages(heap, &mi_heap_page_collect, &collect, NULL); - mi_assert_internal( collect != MI_ABANDON || mi_atomic_read_ptr(mi_block_t,&heap->thread_delayed_free) == NULL ); + mi_assert_internal( collect != MI_ABANDON || mi_atomic_load_ptr_acquire(mi_block_t,&heap->thread_delayed_free) == NULL ); // collect segment caches if (collect >= MI_FORCE) { diff --git a/src/options.c b/src/options.c index 78c01456..85cbf7f6 100644 --- a/src/options.c +++ b/src/options.c @@ -173,11 +173,11 @@ static _Atomic(uintptr_t) out_len; static void mi_out_buf(const char* msg, void* arg) { UNUSED(arg); if (msg==NULL) return; - if (mi_atomic_read_relaxed(&out_len)>=MI_MAX_DELAY_OUTPUT) return; + if (mi_atomic_load_relaxed(&out_len)>=MI_MAX_DELAY_OUTPUT) return; size_t n = strlen(msg); if (n==0) return; // claim space - uintptr_t start = mi_atomic_add(&out_len, n); + uintptr_t start = mi_atomic_add_acq_rel(&out_len, n); if (start >= MI_MAX_DELAY_OUTPUT) return; // check bound if (start+n >= MI_MAX_DELAY_OUTPUT) { @@ -189,7 +189,7 @@ static void mi_out_buf(const char* msg, void* arg) { static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf, void* arg) { if (out==NULL) return; // claim (if `no_more_buf == true`, no more output will be added after this point) - size_t count = mi_atomic_add(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1)); + size_t count = mi_atomic_add_acq_rel(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1)); // and output the current contents if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT; out_buf[count] = 0; @@ -220,14 +220,14 @@ static mi_output_fun* volatile mi_out_default; // = NULL static _Atomic(void*) mi_out_arg; // = NULL static mi_output_fun* mi_out_get_default(void** parg) { - if (parg != NULL) { *parg = mi_atomic_read_ptr(void,&mi_out_arg); } + if (parg != NULL) { *parg = mi_atomic_load_ptr_acquire(void,&mi_out_arg); } mi_output_fun* out = mi_out_default; return (out == NULL ? &mi_out_buf : out); } void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept { mi_out_default = (out == NULL ? &mi_out_stderr : out); // stop using the delayed output buffer - mi_atomic_write_ptr(void,&mi_out_arg, arg); + mi_atomic_store_ptr_release(void,&mi_out_arg, arg); if (out!=NULL) mi_out_buf_flush(out,true,arg); // output all the delayed output now } @@ -313,13 +313,13 @@ void _mi_verbose_message(const char* fmt, ...) { static void mi_show_error_message(const char* fmt, va_list args) { if (!mi_option_is_enabled(mi_option_show_errors) && !mi_option_is_enabled(mi_option_verbose)) return; - if (mi_atomic_increment(&error_count) > mi_max_error_count) return; + if (mi_atomic_increment_acq_rel(&error_count) > mi_max_error_count) return; mi_vfprintf(NULL, NULL, "mimalloc: error: ", fmt, args); } void _mi_warning_message(const char* fmt, ...) { if (!mi_option_is_enabled(mi_option_show_errors) && !mi_option_is_enabled(mi_option_verbose)) return; - if (mi_atomic_increment(&error_count) > mi_max_error_count) return; + if (mi_atomic_increment_acq_rel(&error_count) > mi_max_error_count) return; va_list args; va_start(args,fmt); mi_vfprintf(NULL, NULL, "mimalloc: warning: ", fmt, args); @@ -365,7 +365,7 @@ static void mi_error_default(int err) { void mi_register_error(mi_error_fun* fun, void* arg) { mi_error_handler = fun; // can be NULL - mi_atomic_write_ptr(void,&mi_error_arg, arg); + mi_atomic_store_ptr_release(void,&mi_error_arg, arg); } void _mi_error_message(int err, const char* fmt, ...) { @@ -376,7 +376,7 @@ void _mi_error_message(int err, const char* fmt, ...) { va_end(args); // and call the error handler which may abort (or return normally) if (mi_error_handler != NULL) { - mi_error_handler(err, mi_atomic_read_ptr(void,&mi_error_arg)); + mi_error_handler(err, mi_atomic_load_ptr_acquire(void,&mi_error_arg)); } else { mi_error_default(err); diff --git a/src/os.c b/src/os.c index 0b959a9c..8d0c8237 100644 --- a/src/os.c +++ b/src/os.c @@ -270,11 +270,11 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, void* p = NULL; if ((large_only || use_large_os_page(size, try_alignment)) && allow_large && (flags&MEM_COMMIT)!=0 && (flags&MEM_RESERVE)!=0) { - uintptr_t try_ok = mi_atomic_read(&large_page_try_ok); + uintptr_t try_ok = mi_atomic_load_acquire(&large_page_try_ok); if (!large_only && try_ok > 0) { // if a large page allocation fails, it seems the calls to VirtualAlloc get very expensive. // therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times. - mi_atomic_cas_strong(&large_page_try_ok, &try_ok, try_ok - 1); + mi_atomic_cas_strong_acq_rel(&large_page_try_ok, &try_ok, try_ok - 1); } else { // large OS pages must always reserve and commit. @@ -283,7 +283,7 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, if (large_only) return p; // fall back to non-large page allocation on error (`p == NULL`). if (p == NULL) { - mi_atomic_write(&large_page_try_ok,10); // on error, don't try again for the next N allocations + mi_atomic_store_release(&large_page_try_ok,10); // on error, don't try again for the next N allocations } } } @@ -361,13 +361,13 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro #endif if ((large_only || use_large_os_page(size, try_alignment)) && allow_large) { static _Atomic(uintptr_t) large_page_try_ok; // = 0; - uintptr_t try_ok = mi_atomic_read(&large_page_try_ok); + uintptr_t try_ok = mi_atomic_load_acquire(&large_page_try_ok); if (!large_only && try_ok > 0) { // If the OS is not configured for large OS pages, or the user does not have // enough permission, the `mmap` will always fail (but it might also fail for other reasons). // Therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times // to avoid too many failing calls to mmap. - mi_atomic_cas_strong(&large_page_try_ok, &try_ok, try_ok - 1); + mi_atomic_cas_strong_acq_rel(&large_page_try_ok, &try_ok, try_ok - 1); } else { int lflags = flags & ~MAP_NORESERVE; // using NORESERVE on huge pages seems to fail on Linux @@ -407,7 +407,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro #endif if (large_only) return p; if (p == NULL) { - mi_atomic_write(&large_page_try_ok, 10); // on error, don't try again for the next N allocations + mi_atomic_store_release(&large_page_try_ok, 10); // on error, don't try again for the next N allocations } } } @@ -455,7 +455,7 @@ static mi_decl_cache_align _Atomic(uintptr_t) aligned_base; static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { if (try_alignment == 0 || try_alignment > MI_SEGMENT_SIZE) return NULL; if ((size%MI_SEGMENT_SIZE) != 0) return NULL; - uintptr_t hint = mi_atomic_add(&aligned_base, size); + uintptr_t hint = mi_atomic_add_acq_rel(&aligned_base, size); if (hint == 0 || hint > ((intptr_t)30<<40)) { // try to wrap around after 30TiB (area after 32TiB is used for huge OS pages) uintptr_t init = ((uintptr_t)4 << 40); // start at 4TiB area #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of aligned allocations unless in debug mode @@ -463,8 +463,8 @@ static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { init = init + (MI_SEGMENT_SIZE * ((r>>17) & 0xFFFFF)); // (randomly 20 bits)*4MiB == 0 to 4TiB #endif uintptr_t expected = hint + size; - mi_atomic_cas_strong(&aligned_base, &expected, init); - hint = mi_atomic_add(&aligned_base, size); // this may still give 0 or > 30TiB but that is ok, it is a hint after all + mi_atomic_cas_strong_acq_rel(&aligned_base, &expected, init); + hint = mi_atomic_add_acq_rel(&aligned_base, size); // this may still give 0 or > 30TiB but that is ok, it is a hint after all } if (hint%try_alignment != 0) return NULL; return (void*)hint; @@ -760,10 +760,10 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) #else #if defined(MADV_FREE) static _Atomic(uintptr_t) advice = ATOMIC_VAR_INIT(MADV_FREE); - int err = madvise(start, csize, (int)mi_atomic_read_relaxed(&advice)); + int err = madvise(start, csize, (int)mi_atomic_load_relaxed(&advice)); if (err != 0 && errno == EINVAL && advice == MADV_FREE) { // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on - mi_atomic_write(&advice, MADV_DONTNEED); + mi_atomic_store_release(&advice, MADV_DONTNEED); err = madvise(start, csize, MADV_DONTNEED); } #elif defined(__wasi__) @@ -970,7 +970,7 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { uintptr_t start = 0; uintptr_t end = 0; - uintptr_t huge_start = mi_atomic_read_relaxed(&mi_huge_start); + uintptr_t huge_start = mi_atomic_load_relaxed(&mi_huge_start); do { start = huge_start; if (start == 0) { @@ -983,7 +983,7 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) { } end = start + size; mi_assert_internal(end % MI_SEGMENT_SIZE == 0); - } while (!mi_atomic_cas_strong(&mi_huge_start, &huge_start, end)); + } while (!mi_atomic_cas_strong_acq_rel(&mi_huge_start, &huge_start, end)); if (total_size != NULL) *total_size = size; return (uint8_t*)start; diff --git a/src/page-queue.c b/src/page-queue.c index ea213019..37719e02 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -260,7 +260,7 @@ static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) { heap->page_count--; page->next = NULL; page->prev = NULL; - // mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), NULL); + // mi_atomic_store_ptr_release(mi_atomic_cast(void*, &page->heap), NULL); mi_page_set_in_full(page,false); } @@ -274,7 +274,7 @@ static void mi_page_queue_push(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_ (mi_page_is_in_full(page) && mi_page_queue_is_full(queue))); mi_page_set_in_full(page, mi_page_queue_is_full(queue)); - // mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), heap); + // mi_atomic_store_ptr_release(mi_atomic_cast(void*, &page->heap), heap); page->next = queue->first; page->prev = NULL; if (queue->first != NULL) { @@ -341,7 +341,7 @@ size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue for (mi_page_t* page = append->first; page != NULL; page = page->next) { // inline `mi_page_set_heap` to avoid wrong assertion during absorption; // in this case it is ok to be delayed freeing since both "to" and "from" heap are still alive. - mi_atomic_write(&page->xheap, (uintptr_t)heap); + mi_atomic_store_release(&page->xheap, (uintptr_t)heap); // set the flag to delayed free (not overriding NEVER_DELAYED_FREE) which has as a // side effect that it spins until any DELAYED_FREEING is finished. This ensures // that after appending only the new heap will be used for delayed free operations. diff --git a/src/page.c b/src/page.c index 92faf9f2..cd96bb90 100644 --- a/src/page.c +++ b/src/page.c @@ -126,7 +126,7 @@ void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool overrid mi_delayed_t old_delay; mi_thread_free_t tfree; do { - tfree = mi_atomic_read(&page->xthread_free); // note: must acquire as we can break/repeat this loop and not do a CAS; + tfree = mi_atomic_load_acquire(&page->xthread_free); // note: must acquire as we can break/repeat this loop and not do a CAS; tfreex = mi_tf_set_delayed(tfree, delay); old_delay = mi_tf_delayed(tfree); if (mi_unlikely(old_delay == MI_DELAYED_FREEING)) { @@ -140,7 +140,7 @@ void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool overrid break; // leave never-delayed flag set } } while ((old_delay == MI_DELAYED_FREEING) || - !mi_atomic_cas_weak(&page->xthread_free, &tfree, tfreex)); + !mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex)); } /* ----------------------------------------------------------- @@ -155,7 +155,7 @@ static void _mi_page_thread_free_collect(mi_page_t* page) { mi_block_t* head; mi_thread_free_t tfreex; - mi_thread_free_t tfree = mi_atomic_read_relaxed(&page->xthread_free); + mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free); do { head = mi_tf_block(tfree); tfreex = mi_tf_set_block(tfree,NULL); @@ -273,8 +273,8 @@ static mi_page_t* mi_page_fresh(mi_heap_t* heap, mi_page_queue_t* pq) { ----------------------------------------------------------- */ void _mi_heap_delayed_free(mi_heap_t* heap) { // take over the list (note: no atomic exchange since it is often NULL) - mi_block_t* block = mi_atomic_read_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); - while (block != NULL && !mi_atomic_cas_ptr_weak(mi_block_t, &heap->thread_delayed_free, &block, NULL)) { /* nothing */ }; + mi_block_t* block = mi_atomic_load_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); + while (block != NULL && !mi_atomic_cas_ptr_weak_acq_rel(mi_block_t, &heap->thread_delayed_free, &block, NULL)) { /* nothing */ }; // and free them all while(block != NULL) { @@ -283,10 +283,10 @@ void _mi_heap_delayed_free(mi_heap_t* heap) { if (!_mi_free_delayed_block(block)) { // we might already start delayed freeing while another thread has not yet // reset the delayed_freeing flag; in that case delay it further by reinserting. - mi_block_t* dfree = mi_atomic_read_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); + mi_block_t* dfree = mi_atomic_load_ptr_relaxed(mi_block_t, &heap->thread_delayed_free); do { mi_block_set_nextx(heap, block, dfree, heap->keys); - } while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, &dfree, block)); + } while (!mi_atomic_cas_ptr_weak_release(mi_block_t,&heap->thread_delayed_free, &dfree, block)); } block = next; } @@ -736,14 +736,14 @@ void _mi_deferred_free(mi_heap_t* heap, bool force) { heap->tld->heartbeat++; if (deferred_free != NULL && !heap->tld->recurse) { heap->tld->recurse = true; - deferred_free(force, heap->tld->heartbeat, mi_atomic_read_ptr_relaxed(void,&deferred_arg)); + deferred_free(force, heap->tld->heartbeat, mi_atomic_load_ptr_relaxed(void,&deferred_arg)); heap->tld->recurse = false; } } void mi_register_deferred_free(mi_deferred_free_fun* fn, void* arg) mi_attr_noexcept { deferred_free = fn; - mi_atomic_write_ptr(void,&deferred_arg, arg); + mi_atomic_store_ptr_release(void,&deferred_arg, arg); } diff --git a/src/random.c b/src/random.c index be95fc46..836f83a2 100644 --- a/src/random.c +++ b/src/random.c @@ -210,11 +210,11 @@ static bool os_random_buf(void* buf, size_t buf_len) { #define GRND_NONBLOCK (1) #endif static _Atomic(uintptr_t) no_getrandom; // = 0 - if (mi_atomic_read(&no_getrandom)==0) { + if (mi_atomic_load_acquire(&no_getrandom)==0) { ssize_t ret = syscall(SYS_getrandom, buf, buf_len, GRND_NONBLOCK); if (ret >= 0) return (buf_len == (size_t)ret); if (ret != ENOSYS) return false; - mi_atomic_write(&no_getrandom,1); // don't call again, and fall back to /dev/urandom + mi_atomic_store_release(&no_getrandom,1); // don't call again, and fall back to /dev/urandom } #endif int flags = O_RDONLY; diff --git a/src/region.c b/src/region.c index d2904687..e916e452 100644 --- a/src/region.c +++ b/src/region.c @@ -123,9 +123,9 @@ static size_t mi_good_commit_size(size_t size) { // Return if a pointer points into a region reserved by us. bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { if (p==NULL) return false; - size_t count = mi_atomic_read_relaxed(®ions_count); + size_t count = mi_atomic_load_relaxed(®ions_count); for (size_t i = 0; i < count; i++) { - uint8_t* start = mi_atomic_read_ptr_relaxed(uint8_t,®ions[i].start); + uint8_t* start = (uint8_t*)mi_atomic_load_ptr_relaxed(uint8_t, ®ions[i].start); if (start != NULL && (uint8_t*)p >= start && (uint8_t*)p < start + MI_REGION_SIZE) return true; } return false; @@ -133,7 +133,7 @@ bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { static void* mi_region_blocks_start(const mem_region_t* region, mi_bitmap_index_t bit_idx) { - uint8_t* start = mi_atomic_read_ptr(uint8_t,®ion->start); + uint8_t* start = (uint8_t*)mi_atomic_load_ptr_acquire(uint8_t, &((mem_region_t*)region)->start); mi_assert_internal(start != NULL); return (start + (bit_idx * MI_SEGMENT_SIZE)); } @@ -171,7 +171,7 @@ static bool mi_memid_is_arena(size_t id, mem_region_t** region, mi_bitmap_index_ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, mem_region_t** region, mi_bitmap_index_t* bit_idx, mi_os_tld_t* tld) { // not out of regions yet? - if (mi_atomic_read_relaxed(®ions_count) >= MI_REGION_MAX - 1) return false; + if (mi_atomic_load_relaxed(®ions_count) >= MI_REGION_MAX - 1) return false; // try to allocate a fresh region from the OS bool region_commit = (commit && mi_option_is_enabled(mi_option_eager_region_commit)); @@ -184,9 +184,9 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, mi_assert_internal(!region_large || region_commit); // claim a fresh slot - const uintptr_t idx = mi_atomic_increment(®ions_count); + const uintptr_t idx = mi_atomic_increment_acq_rel(®ions_count); if (idx >= MI_REGION_MAX) { - mi_atomic_decrement(®ions_count); + mi_atomic_decrement_acq_rel(®ions_count); _mi_arena_free(start, MI_REGION_SIZE, arena_memid, region_commit, tld->stats); _mi_warning_message("maximum regions used: %zu GiB (perhaps recompile with a larger setting for MI_HEAP_REGION_MAX_SIZE)", _mi_divide_up(MI_HEAP_REGION_MAX_SIZE, GiB)); return false; @@ -195,13 +195,13 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, // allocated, initialize and claim the initial blocks mem_region_t* r = ®ions[idx]; r->arena_memid = arena_memid; - mi_atomic_write(&r->in_use, 0); - mi_atomic_write(&r->dirty, (is_zero ? 0 : MI_BITMAP_FIELD_FULL)); - mi_atomic_write(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0)); - mi_atomic_write(&r->reset, 0); + mi_atomic_store_release(&r->in_use, 0); + mi_atomic_store_release(&r->dirty, (is_zero ? 0 : MI_BITMAP_FIELD_FULL)); + mi_atomic_store_release(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0)); + mi_atomic_store_release(&r->reset, 0); *bit_idx = 0; mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL); - mi_atomic_write_ptr(uint8_t*,&r->start, start); + mi_atomic_store_ptr_release(uint8_t*,&r->start, start); // and share it mi_region_info_t info; @@ -209,7 +209,7 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, info.x.valid = true; info.x.is_large = region_large; info.x.numa_node = (short)_mi_os_numa_node(tld); - mi_atomic_write(&r->info, info.value); // now make it available to others + mi_atomic_store_release(&r->info, info.value); // now make it available to others *region = r; return true; } @@ -221,7 +221,7 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, static bool mi_region_is_suitable(const mem_region_t* region, int numa_node, bool allow_large ) { // initialized at all? mi_region_info_t info; - info.value = mi_atomic_read_relaxed(®ion->info); + info.value = mi_atomic_load_relaxed(&((mem_region_t*)region)->info); if (info.value==0) return false; // numa correct @@ -240,7 +240,7 @@ static bool mi_region_is_suitable(const mem_region_t* region, int numa_node, boo static bool mi_region_try_claim(int numa_node, size_t blocks, bool allow_large, mem_region_t** region, mi_bitmap_index_t* bit_idx, mi_os_tld_t* tld) { // try all regions for a free slot - const size_t count = mi_atomic_read(®ions_count); + const size_t count = mi_atomic_load_acquire(®ions_count); size_t idx = tld->region_idx; // Or start at 0 to reuse low addresses? Starting at 0 seems to increase latency though for (size_t visited = 0; visited < count; visited++, idx++) { if (idx >= count) idx = 0; // wrap around @@ -280,8 +280,8 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo mi_assert_internal(mi_bitmap_is_claimed(®ion->in_use, 1, blocks, bit_idx)); mi_region_info_t info; - info.value = mi_atomic_read(®ion->info); - uint8_t* start = mi_atomic_read_ptr(uint8_t,®ion->start); + info.value = mi_atomic_load_acquire(®ion->info); + uint8_t* start = (uint8_t*)mi_atomic_load_ptr_acquire(uint8_t,®ion->start); mi_assert_internal(!(info.x.is_large && !*is_large)); mi_assert_internal(start != NULL); @@ -400,7 +400,7 @@ void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_re const size_t blocks = mi_region_block_count(size); mi_assert_internal(blocks + bit_idx <= MI_BITMAP_FIELD_BITS); mi_region_info_t info; - info.value = mi_atomic_read(®ion->info); + info.value = mi_atomic_load_acquire(®ion->info); mi_assert_internal(info.value != 0); void* blocks_start = mi_region_blocks_start(region, bit_idx); mi_assert_internal(blocks_start == p); // not a pointer in our area? @@ -442,21 +442,21 @@ void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_re -----------------------------------------------------------------------------*/ void _mi_mem_collect(mi_os_tld_t* tld) { // free every region that has no segments in use. - uintptr_t rcount = mi_atomic_read_relaxed(®ions_count); + uintptr_t rcount = mi_atomic_load_relaxed(®ions_count); for (size_t i = 0; i < rcount; i++) { mem_region_t* region = ®ions[i]; - if (mi_atomic_read_relaxed(®ion->info) != 0) { + if (mi_atomic_load_relaxed(®ion->info) != 0) { // if no segments used, try to claim the whole region - uintptr_t m = mi_atomic_read_relaxed(®ion->in_use); - while (m == 0 && !mi_atomic_cas_weak(®ion->in_use, &m, MI_BITMAP_FIELD_FULL)) { /* nothing */ }; + uintptr_t m = mi_atomic_load_relaxed(®ion->in_use); + while (m == 0 && !mi_atomic_cas_weak_release(®ion->in_use, &m, MI_BITMAP_FIELD_FULL)) { /* nothing */ }; if (m == 0) { // on success, free the whole region - uint8_t* start = mi_atomic_read_ptr(uint8_t,®ions[i].start); - size_t arena_memid = mi_atomic_read_relaxed(®ions[i].arena_memid); - uintptr_t commit = mi_atomic_read_relaxed(®ions[i].commit); + uint8_t* start = (uint8_t*)mi_atomic_load_ptr_acquire(uint8_t,®ions[i].start); + size_t arena_memid = mi_atomic_load_relaxed(®ions[i].arena_memid); + uintptr_t commit = mi_atomic_load_relaxed(®ions[i].commit); memset(®ions[i], 0, sizeof(mem_region_t)); // and release the whole region - mi_atomic_write(®ion->info, 0); + mi_atomic_store_release(®ion->info, 0); if (start != NULL) { // && !_mi_os_is_huge_reserved(start)) { _mi_abandoned_await_readers(); // ensure no pending reads _mi_arena_free(start, MI_REGION_SIZE, arena_memid, (~commit == 0), tld->stats); diff --git a/src/segment.c b/src/segment.c index b5fd13d3..2416dadd 100644 --- a/src/segment.c +++ b/src/segment.c @@ -628,17 +628,16 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ return NULL; } } - atomic_thread_fence(memory_order_acq_rel); segment->memid = memid; segment->mem_is_fixed = mem_large; - segment->mem_is_committed = commit; + segment->mem_is_committed = commit; mi_segments_track_size((long)segment_size, tld); } mi_assert_internal(segment != NULL && (uintptr_t)segment % MI_SEGMENT_SIZE == 0); mi_assert_internal(segment->mem_is_fixed ? segment->mem_is_committed : true); + mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); // tsan if (!pages_still_good) { // zero the segment info (but not the `mem` fields) - atomic_thread_fence(memory_order_release); // with read of `abandoned_next` in `mi_abandoned_pop` ptrdiff_t ofs = offsetof(mi_segment_t, next); memset((uint8_t*)segment + ofs, 0, info_size - ofs); @@ -792,7 +791,6 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, bool a uint16_t reserved = page->reserved; ptrdiff_t ofs = offsetof(mi_page_t,capacity); memset((uint8_t*)page + ofs, 0, sizeof(*page) - ofs); - atomic_thread_fence(memory_order_release); page->capacity = capacity; page->reserved = reserved; page->xblock_size = block_size; @@ -892,69 +890,69 @@ static mi_decl_cache_align _Atomic(uintptr_t) abandoned_readers; // = // Push on the visited list static void mi_abandoned_visited_push(mi_segment_t* segment) { mi_assert_internal(segment->thread_id == 0); - mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t,&segment->abandoned_next) == NULL); + mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t,&segment->abandoned_next) == NULL); mi_assert_internal(segment->next == NULL && segment->prev == NULL); mi_assert_internal(segment->used > 0); - mi_segment_t* anext = mi_atomic_read_ptr_relaxed(mi_segment_t, &abandoned_visited); + mi_segment_t* anext = mi_atomic_load_ptr_relaxed(mi_segment_t, &abandoned_visited); do { - mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, anext); - } while (!mi_atomic_cas_ptr_weak(mi_segment_t, &abandoned_visited, &anext, segment)); + mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, anext); + } while (!mi_atomic_cas_ptr_weak_release(mi_segment_t, &abandoned_visited, &anext, segment)); } // Move the visited list to the abandoned list. static bool mi_abandoned_visited_revisit(void) { // quick check if the visited list is empty - if (mi_atomic_read_ptr_relaxed(mi_segment_t, &abandoned_visited) == NULL) return false; + if (mi_atomic_load_ptr_relaxed(mi_segment_t, &abandoned_visited) == NULL) return false; // grab the whole visited list - mi_segment_t* first = mi_atomic_exchange_ptr(mi_segment_t, &abandoned_visited, NULL); + mi_segment_t* first = mi_atomic_exchange_ptr_acq_rel(mi_segment_t, &abandoned_visited, NULL); if (first == NULL) return false; // first try to swap directly if the abandoned list happens to be NULL mi_tagged_segment_t afirst; - mi_tagged_segment_t ts = mi_atomic_read_relaxed(&abandoned); + mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); if (mi_tagged_segment_ptr(ts)==NULL) { afirst = mi_tagged_segment(first, ts); - if (mi_atomic_cas_strong(&abandoned, &ts, afirst)) return true; + if (mi_atomic_cas_strong_acq_rel(&abandoned, &ts, afirst)) return true; } // find the last element of the visited list: O(n) mi_segment_t* last = first; mi_segment_t* next; - while ((next = mi_atomic_read_ptr_relaxed(mi_segment_t, &last->abandoned_next)) != NULL) { + while ((next = mi_atomic_load_ptr_relaxed(mi_segment_t, &last->abandoned_next)) != NULL) { last = next; } // and atomically prepend to the abandoned list // (no need to increase the readers as we don't access the abandoned segments) - mi_tagged_segment_t anext = mi_atomic_read_relaxed(&abandoned); + mi_tagged_segment_t anext = mi_atomic_load_relaxed(&abandoned); do { - mi_atomic_write_ptr(mi_segment_t, &last->abandoned_next, mi_tagged_segment_ptr(anext)); + mi_atomic_store_ptr_release(mi_segment_t, &last->abandoned_next, mi_tagged_segment_ptr(anext)); afirst = mi_tagged_segment(first, anext); - } while (!mi_atomic_cas_weak(&abandoned, &anext, afirst)); + } while (!mi_atomic_cas_weak_release(&abandoned, &anext, afirst)); return true; } // Push on the abandoned list. static void mi_abandoned_push(mi_segment_t* segment) { mi_assert_internal(segment->thread_id == 0); - mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); + mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); mi_assert_internal(segment->next == NULL && segment->prev == NULL); mi_assert_internal(segment->used > 0); mi_tagged_segment_t next; - mi_tagged_segment_t ts = mi_atomic_read_relaxed(&abandoned); + mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); do { - mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, mi_tagged_segment_ptr(ts)); + mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, mi_tagged_segment_ptr(ts)); next = mi_tagged_segment(segment, ts); - } while (!mi_atomic_cas_weak(&abandoned, &ts, next)); + } while (!mi_atomic_cas_weak_release(&abandoned, &ts, next)); } // Wait until there are no more pending reads on segments that used to be in the abandoned list void _mi_abandoned_await_readers(void) { uintptr_t n; do { - n = mi_atomic_read(&abandoned_readers); + n = mi_atomic_load_acquire(&abandoned_readers); if (n != 0) mi_atomic_yield(); } while (n != 0); } @@ -963,7 +961,7 @@ void _mi_abandoned_await_readers(void) { static mi_segment_t* mi_abandoned_pop(void) { mi_segment_t* segment; // Check efficiently if it is empty (or if the visited list needs to be moved) - mi_tagged_segment_t ts = mi_atomic_read_relaxed(&abandoned); + mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); segment = mi_tagged_segment_ptr(ts); if (mi_likely(segment == NULL)) { if (mi_likely(!mi_abandoned_visited_revisit())) { // try to swap in the visited list on NULL @@ -975,19 +973,19 @@ static mi_segment_t* mi_abandoned_pop(void) { // a segment to be decommitted while a read is still pending, // and a tagged pointer to prevent A-B-A link corruption. // (this is called from `region.c:_mi_mem_free` for example) - mi_atomic_increment(&abandoned_readers); // ensure no segment gets decommitted + mi_atomic_increment_relaxed(&abandoned_readers); // ensure no segment gets decommitted mi_tagged_segment_t next = 0; - ts = mi_atomic_read(&abandoned); + ts = mi_atomic_load_acquire(&abandoned); do { segment = mi_tagged_segment_ptr(ts); if (segment != NULL) { - mi_segment_t* anext = mi_atomic_read_ptr(mi_segment_t, &segment->abandoned_next); + mi_segment_t* anext = mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next); next = mi_tagged_segment(anext, ts); // note: reads the segment's `abandoned_next` field so should not be decommitted } } while (segment != NULL && !mi_atomic_cas_weak_acq_rel(&abandoned, &ts, next)); - mi_atomic_decrement(&abandoned_readers); // release reader lock + mi_atomic_decrement_relaxed(&abandoned_readers); // release reader lock if (segment != NULL) { - mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, NULL); + mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); } return segment; } @@ -999,7 +997,7 @@ static mi_segment_t* mi_abandoned_pop(void) { static void mi_segment_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) { mi_assert_internal(segment->used == segment->abandoned); mi_assert_internal(segment->used > 0); - mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); + mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); mi_assert_expensive(mi_segment_is_valid(segment, tld)); // remove the segment from the free page queue if needed @@ -1013,7 +1011,7 @@ static void mi_segment_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) { mi_segments_track_size(-((long)segment->segment_size), tld); segment->thread_id = 0; segment->abandoned_visits = 0; - mi_atomic_write_ptr(mi_segment_t, &segment->abandoned_next, NULL); + mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); mi_abandoned_push(segment); } @@ -1077,7 +1075,7 @@ static bool mi_segment_check_free(mi_segment_t* segment, size_t block_size, bool // Reclaim a segment; returns NULL if the segment was freed // set `right_page_reclaimed` to `true` if it reclaimed a page of the right `block_size` that was not full. static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, size_t requested_block_size, bool* right_page_reclaimed, mi_segments_tld_t* tld) { - mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); + mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_segment_t, &segment->abandoned_next) == NULL); if (right_page_reclaimed != NULL) { *right_page_reclaimed = false; } segment->thread_id = _mi_thread_id(); @@ -1294,13 +1292,13 @@ void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block // huge page segments are always abandoned and can be freed immediately by any thread mi_assert_internal(segment->page_kind==MI_PAGE_HUGE); mi_assert_internal(segment == _mi_page_segment(page)); - mi_assert_internal(mi_atomic_read_relaxed(&segment->thread_id)==0); + mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id)==0); // claim it and free mi_heap_t* heap = mi_heap_get_default(); // issue #221; don't use the internal get_default_heap as we need to ensure the thread is initialized. // paranoia: if this it the last reference, the cas should always succeed uintptr_t expected_tid = 0; - if (mi_atomic_cas_strong(&segment->thread_id, &expected_tid, heap->thread_id)) { + if (mi_atomic_cas_strong_acq_rel(&segment->thread_id, &expected_tid, heap->thread_id)) { mi_block_set_next(page, block, page->free); page->free = block; page->used--; From ac0c121c68c5441168e011cac14104bea5b55996 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 27 Jul 2020 08:55:26 -0700 Subject: [PATCH 051/172] update documentation for 1.6.4 release --- include/mimalloc.h | 2 +- readme.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index f44f6d9a..8dd318cb 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2020, 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. diff --git a/readme.md b/readme.md index 7ec20d72..18a49c3d 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent [performance](#performance) characteristics. Initially developed by Daan Leijen for the run-time systems of the [Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages. -Latest release:`v1.6.3` (2020-05-05). +Latest release:`v1.6.4` (2020-07-27). It is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: @@ -57,6 +57,8 @@ Enjoy! ### Releases +* 2020-07-27, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, + support for IllumOS and Haiku, NUMA support for Vista/XP, ubsan support. * 2020-05-05, `v1.6.3`: stable release 1.6: improved behavior in out-of-memory situations, improved malloc zones on macOS, build PIC static libraries by default, add option to abort on out-of-memory, line buffered statistics. * 2020-04-20, `v1.6.2`: stable release 1.6: fix compilation on Android, MingW, Raspberry, and Conda, From 47572acecac18edb9895b0ac1fd84bad3fa84b94 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 29 Jul 2020 14:36:21 -0700 Subject: [PATCH 052/172] improved NUMA node detection on Windows (for AMD Ryzen), issue #282 --- src/os.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/os.c b/src/os.c index 24252c85..fe30cf43 100644 --- a/src/os.c +++ b/src/os.c @@ -124,8 +124,10 @@ typedef struct _PROCESSOR_NUMBER { WORD Group; BYTE Number; BYTE Reserved; } PRO #endif typedef VOID (__stdcall *PGetCurrentProcessorNumberEx)(PPROCESSOR_NUMBER ProcNumber); typedef BOOL (__stdcall *PGetNumaProcessorNodeEx)(PPROCESSOR_NUMBER Processor, PUSHORT NodeNumber); +typedef BOOL (__stdcall* PGetNumaNodeProcessorMaskEx)(USHORT Node, PGROUP_AFFINITY ProcessorMask); static PGetCurrentProcessorNumberEx pGetCurrentProcessorNumberEx = NULL; static PGetNumaProcessorNodeEx pGetNumaProcessorNodeEx = NULL; +static PGetNumaNodeProcessorMaskEx pGetNumaNodeProcessorMaskEx = NULL; static bool mi_win_enable_large_os_pages() { @@ -188,6 +190,7 @@ void _mi_os_init(void) { if (hDll != NULL) { pGetCurrentProcessorNumberEx = (PGetCurrentProcessorNumberEx)(void (*)(void))GetProcAddress(hDll, "GetCurrentProcessorNumberEx"); pGetNumaProcessorNodeEx = (PGetNumaProcessorNodeEx)(void (*)(void))GetProcAddress(hDll, "GetNumaProcessorNodeEx"); + pGetNumaNodeProcessorMaskEx = (PGetNumaNodeProcessorMaskEx)(void (*)(void))GetProcAddress(hDll, "GetNumaNodeProcessorMaskEx"); FreeLibrary(hDll); } if (mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { @@ -1094,6 +1097,25 @@ static size_t mi_os_numa_nodex() { static size_t mi_os_numa_node_countx(void) { ULONG numa_max = 0; GetNumaHighestNodeNumber(&numa_max); + // find the highest node number that has actual processors assigned to it. Issue #282 + while(numa_max > 0) { + if (pGetNumaNodeProcessorMaskEx != NULL) { + // Extended API is supported + GROUP_AFFINITY affinity; + if ((*pGetNumaNodeProcessorMaskEx)((USHORT)numa_max, &affinity)) { + if (affinity.Mask != 0) break; // found the maximum non-empty node + } + } + else { + // Vista or earlier, use older API that is limited to 64 processors. + ULONGLONG mask; + if (GetNumaNodeProcessorMask((UCHAR)numa_max, &mask)) { + if (mask != 0) break; // found the maximum non-empty node + }; + } + // max node was invalid or had no processor assigned, try again + numa_max--; + } return ((size_t)numa_max + 1); } #elif defined(__linux__) From 9e7322f900ecddb641afc56e33bc642342d60ec2 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 29 Jul 2020 21:27:01 -0700 Subject: [PATCH 053/172] collect memory on process exit for statically linked library (issue #281 --- src/heap.c | 5 +---- src/init.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/heap.c b/src/heap.c index 5d0d4b8a..aab7e126 100644 --- a/src/heap.c +++ b/src/heap.c @@ -128,7 +128,6 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) _mi_abandoned_reclaim_all(heap, &heap->tld->segments); } - // if abandoning, mark all pages to no longer add to delayed_free if (collect == MI_ABANDON) { mi_heap_visit_pages(heap, &mi_heap_page_never_delayed_free, NULL, NULL); @@ -150,12 +149,10 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) _mi_segment_thread_collect(&heap->tld->segments); } - #ifndef NDEBUG - // collect regions + // collect regions on program-exit (or shared library unload) if (collect >= MI_FORCE && _mi_is_main_thread() && mi_heap_is_backing(heap)) { _mi_mem_collect(&heap->tld->os); } - #endif } void _mi_heap_collect_abandon(mi_heap_t* heap) { diff --git a/src/init.c b/src/init.c index 602a2f7a..1724bd21 100644 --- a/src/init.c +++ b/src/init.c @@ -503,11 +503,15 @@ static void mi_process_done(void) { FlsSetValue(mi_fls_key, NULL); // don't call main-thread callback FlsFree(mi_fls_key); // call thread-done on all threads to prevent dangling callback pointer if statically linked with a DLL; Issue #208 #endif - #ifndef NDEBUG - mi_collect(true); + + #if (MI_DEBUG != 0) || !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 */ ); #endif - if (mi_option_is_enabled(mi_option_show_stats) || - mi_option_is_enabled(mi_option_verbose)) { + + if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) { mi_stats_print(NULL); } mi_allocator_done(); From 1583a73c66b0bf7a2271003240ad7ff2e27f19c7 Mon Sep 17 00:00:00 2001 From: Gal Ben David Date: Thu, 6 Aug 2020 14:29:25 +0300 Subject: [PATCH 054/172] Adding conditional _DEFAULT_SOURCE definition In order to avoid `_DEFAULT_SOURCE` redefinition warnings, I've wrapped the define statement with an `ifndef`. --- src/static.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/static.c b/src/static.c index bf86166d..0b8caa2c 100644 --- a/src/static.c +++ b/src/static.c @@ -4,7 +4,9 @@ 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. -----------------------------------------------------------------------------*/ +#ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE +#endif #include "mimalloc.h" #include "mimalloc-internal.h" From 0de92e406cb2641eceb0156d5d592f626f24bb5a Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 6 Aug 2020 13:29:09 -0700 Subject: [PATCH 055/172] prepare readme for release --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 8ce00961..daf57f39 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent [performance](#performance) characteristics. Initially developed by Daan Leijen for the run-time systems of the [Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages. -Latest release:`v1.6.4` (2020-07-27). +Latest release:`v1.6.4` (2020-08-06). It is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: @@ -57,8 +57,8 @@ Enjoy! ### Releases -* 2020-07-27, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, - support for IllumOS and Haiku, NUMA support for Vista/XP, ubsan support. +* 2020-08-06, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, + support for IllumOS and Haiku, NUMA support for Vista/XP, improved NUMA detection for AMD Ryzen, ubsan support. * 2020-05-05, `v1.6.3`: stable release 1.6: improved behavior in out-of-memory situations, improved malloc zones on macOS, build PIC static libraries by default, add option to abort on out-of-memory, line buffered statistics. * 2020-04-20, `v1.6.2`: stable release 1.6: fix compilation on Android, MingW, Raspberry, and Conda, From a9686d6ecf00e4467e772f7c0b4ef76a15f325f6 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 6 Aug 2020 13:37:11 -0700 Subject: [PATCH 056/172] avoid link error on non-windows --- test/main-override.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/main-override.cpp b/test/main-override.cpp index 8743fd0f..16c40281 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -14,7 +14,9 @@ #include #include +#ifdef _WIN32 #include +#endif #ifdef _WIN32 #include From 5805c399168a8a6c02d787741239481f69f920dc Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 9 Aug 2020 17:55:17 -0700 Subject: [PATCH 057/172] enable --std=c99 compilation; fix mingw compilation --- include/mimalloc-atomic.h | 4 ++-- include/mimalloc-internal.h | 8 ++++---- src/segment.c | 16 ++++++++-------- src/stats.c | 3 ++- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 722b6ad6..b6b06cbc 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -270,11 +270,11 @@ static inline void mi_atomic_maxi64(volatile int64_t* p, int64_t x) { (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)) #if defined(__x86_64__) || defined(__i386__) static inline void mi_atomic_yield(void) { - asm volatile ("pause" ::: "memory"); + __asm__ volatile ("pause" ::: "memory"); } #elif defined(__arm__) || defined(__aarch64__) static inline void mi_atomic_yield(void) { - asm volatile("yield"); + __asm__ volatile("yield"); } #endif #elif defined(__wasi__) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 2dc7e36a..146bf5c0 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -703,11 +703,11 @@ static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept { __asm__("movq %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 Linux, BSD uses FS #elif defined(__arm__) void** tcb; UNUSED(ofs); - asm volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); + __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); res = tcb[slot]; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); - asm volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); + __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); res = tcb[slot]; #endif return res; @@ -724,11 +724,11 @@ static inline void mi_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { __asm__("movq %1,%%fs:%1" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 Linux, BSD uses FS #elif defined(__arm__) void** tcb; UNUSED(ofs); - asm volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); + __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3\nbic %0, %0, #3" : "=r" (tcb)); tcb[slot] = value; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); - asm volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); + __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); tcb[slot] = value; #endif } diff --git a/src/segment.c b/src/segment.c index 8a5ba8c0..371a83a3 100644 --- a/src/segment.c +++ b/src/segment.c @@ -198,26 +198,26 @@ static void mi_segment_protect(mi_segment_t* segment, bool protect, mi_os_tld_t* // 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 - const size_t os_page_size = _mi_os_page_size(); - mi_assert_internal((segment->segment_info_size - os_page_size) >= (sizeof(mi_segment_t) + ((segment->capacity - 1) * sizeof(mi_page_t)))); - mi_assert_internal(((uintptr_t)segment + segment->segment_info_size) % os_page_size == 0); - mi_segment_protect_range((uint8_t*)segment + segment->segment_info_size - os_page_size, os_page_size, protect); + const size_t os_psize = _mi_os_page_size(); + mi_assert_internal((segment->segment_info_size - os_psize) >= (sizeof(mi_segment_t) + ((segment->capacity - 1) * sizeof(mi_page_t)))); + mi_assert_internal(((uintptr_t)segment + segment->segment_info_size) % os_psize == 0); + mi_segment_protect_range((uint8_t*)segment + segment->segment_info_size - os_psize, os_psize, protect); if (MI_SECURE <= 1 || segment->capacity == 1) { // and protect the last (or only) page too mi_assert_internal(MI_SECURE <= 1 || segment->page_kind >= MI_PAGE_LARGE); - uint8_t* start = (uint8_t*)segment + segment->segment_size - os_page_size; + uint8_t* start = (uint8_t*)segment + segment->segment_size - os_psize; if (protect && !segment->mem_is_committed) { // ensure secure page is committed - _mi_mem_commit(start, os_page_size, NULL, tld); + _mi_mem_commit(start, os_psize, NULL, tld); } - mi_segment_protect_range(start, os_page_size, protect); + mi_segment_protect_range(start, os_psize, protect); } else { // or protect every page const size_t page_size = mi_segment_page_size(segment); for (size_t i = 0; i < segment->capacity; i++) { if (segment->pages[i].is_committed) { - mi_segment_protect_range((uint8_t*)segment + (i+1)*page_size - os_page_size, os_page_size, protect); + mi_segment_protect_range((uint8_t*)segment + (i+1)*page_size - os_psize, os_psize, protect); } } } diff --git a/src/stats.c b/src/stats.c index 203bad81..6f12454e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -278,7 +278,8 @@ static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_r static void _mi_stats_print(mi_stats_t* stats, mi_msecs_t elapsed, mi_output_fun* out0, void* arg0) mi_attr_noexcept { // wrap the output function to be line buffered char buf[256]; - buffered_t buffer = { out0, arg0, buf, 0, 255 }; + buffered_t buffer = { out0, arg0, NULL, 0, 255 }; + buffer.buf = buf; mi_output_fun* out = &mi_buffered_out; void* arg = &buffer; From 3f8ff12e66b7c31a3fe97e551f506719429ba01b Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 15 Aug 2020 11:42:28 -0700 Subject: [PATCH 058/172] avoid use of %z format specifier --- src/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stats.c b/src/stats.c index 6f12454e..321c9097 100644 --- a/src/stats.c +++ b/src/stats.c @@ -223,7 +223,7 @@ static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bin if (bins[i].allocated > 0) { found = true; int64_t unit = _mi_bin_size((uint8_t)i); - snprintf(buf, 64, "%s %3zu", fmt, i); + snprintf(buf, 64, "%s %3lu", fmt, (long)i); mi_stat_add(all, &bins[i], unit); mi_stat_print(&bins[i], buf, unit, out, arg); } From 1190e0c053b92d752db7d9d49f51bbba5c93f475 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 26 Aug 2020 11:47:24 +0800 Subject: [PATCH 059/172] iOS compile fix `crt_externs.h` is available only available with iOS-13 sdk. we therefore add a `__has_include` check to see if it is actually available --- src/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.c b/src/options.c index f29b387c..68aeb1df 100644 --- a/src/options.c +++ b/src/options.c @@ -422,7 +422,7 @@ static bool mi_getenv(const char* name, char* result, size_t result_size) { #elif !defined(MI_USE_ENVIRON) || (MI_USE_ENVIRON!=0) // On Posix systemsr use `environ` to acces environment variables // even before the C runtime is initialized. -#if defined(__APPLE__) +#if defined(__APPLE__) && defined(__has_include) && __has_include() #include static char** mi_get_environ(void) { return (*_NSGetEnviron()); From 8033b629799de7ca909bea76152f70dddb32c9d8 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 29 Aug 2020 09:59:15 -0700 Subject: [PATCH 060/172] allow overriding MI_MAX_ALIGN_SIZE --- include/mimalloc-types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 449e2e41..525a1a77 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -14,7 +14,9 @@ terms of the MIT license. A copy of the license can be found in the file // Minimal alignment necessary. On most platforms 16 bytes are needed // due to SSE registers for example. This must be at least `MI_INTPTR_SIZE` +#ifndef MI_MAX_ALIGN_SIZE #define MI_MAX_ALIGN_SIZE 16 // sizeof(max_align_t) +#endif // ------------------------------------------------------ // Variants From b4825372abf9c86186a53eda6b1e243aebdc2c68 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 29 Aug 2020 19:30:38 -0700 Subject: [PATCH 061/172] small compilation warning fixes (extra semicolon etc) --- include/mimalloc-atomic.h | 2 +- include/mimalloc.h | 4 ++-- src/alloc.c | 6 +++--- src/init.c | 10 +++++----- src/options.c | 2 +- src/os.c | 2 +- src/random.c | 2 +- src/stats.c | 4 ++-- test/main-override.cpp | 2 +- test/test-stress.c | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index b6b06cbc..be8d35a8 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -128,7 +128,7 @@ static inline intptr_t mi_atomic_subi(volatile _Atomic(intptr_t)* p, intptr_t su #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN -#include +#include #include #ifdef _WIN64 typedef LONG64 msc_intptr_t; diff --git a/include/mimalloc.h b/include/mimalloc.h index 8dd318cb..31dcfaf2 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -192,7 +192,7 @@ mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_mallocn(mi_heap_ mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); mi_decl_nodiscard mi_decl_export void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3); -mi_decl_nodiscard mi_decl_export void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(3,4);; +mi_decl_nodiscard mi_decl_export void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(3,4); mi_decl_nodiscard mi_decl_export void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3); mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_heap_strdup(mi_heap_t* heap, const char* s) mi_attr_noexcept mi_attr_malloc; @@ -256,7 +256,7 @@ mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_b // Experimental mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept; -mi_decl_nodiscard mi_decl_export bool mi_is_redirected() mi_attr_noexcept; +mi_decl_nodiscard mi_decl_export bool mi_is_redirected(void) mi_attr_noexcept; mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept; mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept; diff --git a/src/alloc.c b/src/alloc.c index 57034522..eff71fd4 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -684,7 +684,7 @@ mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_attr_noexcept { #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif -#include +#include 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]; @@ -765,12 +765,12 @@ typedef void (*std_new_handler_t)(); std_new_handler_t __attribute((weak)) _ZSt15get_new_handlerv() { return NULL; } -std_new_handler_t mi_get_new_handler() { +static std_new_handler_t mi_get_new_handler() { return _ZSt15get_new_handlerv(); } #else // note: on windows we could dynamically link to `?get_new_handler@std@@YAP6AXXZXZ`. -std_new_handler_t mi_get_new_handler() { +static std_new_handler_t mi_get_new_handler() { return NULL; } #endif diff --git a/src/init.c b/src/init.c index 1724bd21..0a99c049 100644 --- a/src/init.c +++ b/src/init.c @@ -285,7 +285,7 @@ static void _mi_thread_done(mi_heap_t* default_heap); // nothing to do as it is done in DllMain #elif defined(_WIN32) && !defined(MI_SHARED_LIB) // use thread local storage keys to detect thread ending - #include + #include #include #if (_WIN32_WINNT < 0x600) // before Windows Vista WINBASEAPI DWORD WINAPI FlsAlloc( _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback ); @@ -405,11 +405,11 @@ 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_preloading() { +bool _mi_preloading(void) { return os_preloading; } -bool mi_is_redirected() mi_attr_noexcept { +bool mi_is_redirected(void) mi_attr_noexcept { return mi_redirected; } @@ -431,7 +431,7 @@ mi_decl_export void _mi_redirect_entry(DWORD reason) { } } __declspec(dllimport) bool mi_allocator_init(const char** message); -__declspec(dllimport) void mi_allocator_done(); +__declspec(dllimport) void mi_allocator_done(void); #ifdef __cplusplus } #endif @@ -440,7 +440,7 @@ static bool mi_allocator_init(const char** message) { if (message != NULL) *message = NULL; return true; } -static void mi_allocator_done() { +static void mi_allocator_done(void) { // nothing to do } #endif diff --git a/src/options.c b/src/options.c index f29b387c..7e16483e 100644 --- a/src/options.c +++ b/src/options.c @@ -413,7 +413,7 @@ static inline int mi_strnicmp(const char* s, const char* t, size_t n) { // reliably even when this is invoked before the C runtime is initialized. // i.e. when `_mi_preloading() == true`. // Note: on windows, environment names are not case sensitive. -#include +#include static bool mi_getenv(const char* name, char* result, size_t result_size) { result[0] = 0; size_t len = GetEnvironmentVariableA(name, result, (DWORD)result_size); diff --git a/src/os.c b/src/os.c index fe30cf43..64a3016b 100644 --- a/src/os.c +++ b/src/os.c @@ -24,7 +24,7 @@ terms of the MIT license. A copy of the license can be found in the file #if defined(_WIN32) -#include +#include #elif defined(__wasi__) // stdlib.h is all we need, and has already been included in mimalloc.h #else diff --git a/src/random.c b/src/random.c index 2a96ccf6..d2437006 100644 --- a/src/random.c +++ b/src/random.c @@ -234,7 +234,7 @@ static bool os_random_buf(void* buf, size_t buf_len) { #endif #if defined(_WIN32) -#include +#include #elif defined(__APPLE__) #include #else diff --git a/src/stats.c b/src/stats.c index 321c9097..fc65d645 100644 --- a/src/stats.c +++ b/src/stats.c @@ -384,7 +384,7 @@ void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept { // Basic timer for convenience; use milli-seconds to avoid doubles // ---------------------------------------------------------------- #ifdef _WIN32 -#include +#include static mi_msecs_t mi_to_msecs(LARGE_INTEGER t) { static LARGE_INTEGER mfreq; // = 0 if (mfreq.QuadPart == 0LL) { @@ -439,7 +439,7 @@ mi_msecs_t _mi_clock_end(mi_msecs_t start) { // -------------------------------------------------------- #if defined(_WIN32) -#include +#include #include #pragma comment(lib,"psapi.lib") diff --git a/test/main-override.cpp b/test/main-override.cpp index 16c40281..fe5403d1 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 diff --git a/test/test-stress.c b/test/test-stress.c index 7d8993a0..5291a9e2 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -260,7 +260,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 76a68cd7af539625dea3ce349aa7742bc02e1ebc Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 3 Sep 2020 09:45:53 -0700 Subject: [PATCH 062/172] bump version to 1.6.6 with new atomics --- include/mimalloc-atomic.h | 4 ++-- include/mimalloc.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index e1fdda16..e3e3186d 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -25,8 +25,8 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_memory_order(name) std::memory_order_##name #elif defined(_MSC_VER) // Use MSVC C wrapper for C11 atomics -#define _Atomic(tp) tp -#define ATOMIC_VAR_INIT(x) x +#define _Atomic(tp) tp +#define ATOMIC_VAR_INIT(x) x #define mi_atomic(name) mi_atomic_##name #define mi_memory_order(name) mi_memory_order_##name #else diff --git a/include/mimalloc.h b/include/mimalloc.h index f44f6d9a..4b0a911f 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 164 // major + 2 digits minor +#define MI_MALLOC_VERSION 166 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes From ff0d98883ed57e242173a023fefe95046617c969 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 3 Sep 2020 10:00:01 -0700 Subject: [PATCH 063/172] update comments --- src/options.c | 4 ++-- src/random.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/options.c b/src/options.c index 49ffec43..f93b6771 100644 --- a/src/options.c +++ b/src/options.c @@ -60,7 +60,7 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(verbose) }, // the following options are experimental and not all combinations make sense. - { 1, UNINIT, MI_OPTION(eager_commit) }, // commit on demand + { 1, UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`) #if defined(_WIN32) || (MI_INTPTR_SIZE <= 4) // and other OS's without overcommit? { 0, UNINIT, MI_OPTION(eager_region_commit) }, { 1, UNINIT, MI_OPTION(reset_decommits) }, // reset decommits memory @@ -77,7 +77,7 @@ static mi_option_desc_t options[_mi_option_last] = #if defined(__NetBSD__) { 0, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed #else - { 1, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed + { 1, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed (but per page in the segment on demand) #endif { 100, UNINIT, MI_OPTION(reset_delay) }, // reset delay in milli-seconds { 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes. diff --git a/src/random.c b/src/random.c index 1634dc44..4736a0ba 100644 --- a/src/random.c +++ b/src/random.c @@ -155,7 +155,7 @@ uintptr_t _mi_random_next(mi_random_ctx_t* ctx) { /* ---------------------------------------------------------------------------- To initialize a fresh random context we rely on the OS: -- Windows : BCryptGenRandom +- Windows : RtlGenRandom - osX,bsd,wasi: arc4random_buf - Linux : getrandom,/dev/urandom If we cannot get good randomness, we fall back to weak randomness based on a timer and ASLR. From f107acb3c822718aae685f35aa8f0a3cffddab63 Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 4 Sep 2020 10:40:05 -0700 Subject: [PATCH 064/172] fix __cplusplus test (pr #287) --- include/mimalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 80cee2be..c9127e1f 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -24,7 +24,7 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_attr_noexcept #endif -#if (__cplusplus >= 201703) +#if defined(__cplusplus) && (__cplusplus >= 201703) #define mi_decl_nodiscard [[nodiscard]] #elif (__GNUC__ >= 4) || defined(__clang__) // includes clang, icc, and clang-cl #define mi_decl_nodiscard __attribute__((warn_unused_result)) From d73d6beb71df5478f081be7fd1108a619ebba461 Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 4 Sep 2020 10:41:10 -0700 Subject: [PATCH 065/172] add aslr test (issue #289) --- test/main-override-static.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/main-override-static.c b/test/main-override-static.c index f738c517..82feb37c 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -12,6 +12,8 @@ static void double_free2(); static void corrupt_free(); static void block_overflow1(); static void invalid_free(); +static void test_aslr(void); + int main() { mi_version(); @@ -21,6 +23,7 @@ int main() { // double_free2(); // corrupt_free(); // block_overflow1(); + // test_aslr(); invalid_free(); void* p1 = malloc(78); @@ -121,3 +124,10 @@ static void corrupt_free() { malloc(SZ); } } + +static void test_aslr(void) { + void* p[256]; + p[0] = malloc(378200); + p[1] = malloc(1134626); + printf("p1: %p, p2: %p\n", p[0], p[1]); +} From 032eb2a75a868534e8130ea8eb32914f8040d211 Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 4 Sep 2020 13:06:18 -0700 Subject: [PATCH 066/172] use pragma warning only on msvc (issue #291) --- src/alloc-posix.c | 10 ++++++---- src/options.c | 8 +++++--- src/os.c | 5 ++++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/alloc-posix.c b/src/alloc-posix.c index 4395893b..1ba1509b 100644 --- a/src/alloc-posix.c +++ b/src/alloc-posix.c @@ -20,6 +20,10 @@ terms of the MIT license. A copy of the license can be found in the file #include // memcpy #include // getenv +#ifdef _MSC_VER +#pragma warning(disable:4996) // getenv _wgetenv +#endif + #ifndef EINVAL #define EINVAL 22 #endif @@ -111,8 +115,7 @@ mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexc int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept { if (buf==NULL || name==NULL) return EINVAL; if (size != NULL) *size = 0; - #pragma warning(suppress:4996) - char* p = getenv(name); + char* p = getenv(name); // mscver warning 4996 if (p==NULL) { *buf = NULL; } @@ -132,8 +135,7 @@ int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name) *buf = NULL; return EINVAL; #else - #pragma warning(suppress:4996) - unsigned short* p = (unsigned short*)_wgetenv((const wchar_t*)name); + unsigned short* p = (unsigned short*)_wgetenv((const wchar_t*)name); // msvc warning 4996 if (p==NULL) { *buf = NULL; } diff --git a/src/options.c b/src/options.c index a2432aa3..baaef460 100644 --- a/src/options.c +++ b/src/options.c @@ -14,6 +14,11 @@ terms of the MIT license. A copy of the license can be found in the file #include // toupper #include +#ifdef _MSC_VER +#pragma warning(disable:4996) // strncpy, strncat +#endif + + static uintptr_t mi_max_error_count = 16; // stop outputting errors after this static void mi_add_stderr_output(); @@ -215,7 +220,6 @@ static void mi_out_buf_stderr(const char* msg, void* arg) { // Should be atomic but gives errors on many platforms as generally we cannot cast a function pointer to a uintptr_t. // For now, don't register output from multiple threads. -#pragma warning(suppress:4180) static mi_output_fun* volatile mi_out_default; // = NULL static _Atomic(void*) mi_out_arg; // = NULL @@ -389,13 +393,11 @@ void _mi_error_message(int err, const char* fmt, ...) { static void mi_strlcpy(char* dest, const char* src, size_t dest_size) { dest[0] = 0; - #pragma warning(suppress:4996) strncpy(dest, src, dest_size - 1); dest[dest_size - 1] = 0; } static void mi_strlcat(char* dest, const char* src, size_t dest_size) { - #pragma warning(suppress:4996) strncat(dest, src, dest_size - 1); dest[dest_size - 1] = 0; } diff --git a/src/os.c b/src/os.c index e35fc82a..3de708d1 100644 --- a/src/os.c +++ b/src/os.c @@ -22,6 +22,10 @@ terms of the MIT license. A copy of the license can be found in the file #include // strerror +#ifdef _MSC_VER +#pragma warning(disable:4996) // strerror +#endif + #if defined(_WIN32) #include @@ -233,7 +237,6 @@ static bool mi_os_mem_free(void* addr, size_t size, bool was_committed, mi_stats if (was_committed) _mi_stat_decrease(&stats->committed, size); _mi_stat_decrease(&stats->reserved, size); if (err) { - #pragma warning(suppress:4996) _mi_warning_message("munmap failed: %s, addr 0x%8li, size %lu\n", strerror(errno), (size_t)addr, size); return false; } From ec2c83a6339430f9a9a598d9c18fcdd0dd3def68 Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 4 Sep 2020 14:20:13 -0700 Subject: [PATCH 067/172] fix whitespace --- src/region.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/region.c b/src/region.c index e916e452..db2871d6 100644 --- a/src/region.c +++ b/src/region.c @@ -88,12 +88,12 @@ typedef union mi_region_info_u { typedef struct mem_region_s { _Atomic(uintptr_t) info; // mi_region_info_t.value _Atomic(void*) start; // start of the memory area - mi_bitmap_field_t in_use; // bit per in-use block - mi_bitmap_field_t dirty; // track if non-zero per block - mi_bitmap_field_t commit; // track if committed per block - mi_bitmap_field_t reset; // track if reset per block + mi_bitmap_field_t in_use; // bit per in-use block + mi_bitmap_field_t dirty; // track if non-zero per block + mi_bitmap_field_t commit; // track if committed per block + mi_bitmap_field_t reset; // track if reset per block _Atomic(uintptr_t) arena_memid; // if allocated from a (huge page) arena - uintptr_t padding; // round to 8 fields + uintptr_t padding; // round to 8 fields } mem_region_t; // The region map From b19bdfac872f2f5fd03ada55fc27f07f01e2a826 Mon Sep 17 00:00:00 2001 From: Shivam7-1 <55046031+Shivam7-1@users.noreply.github.com> Date: Sat, 5 Sep 2020 08:01:09 +0530 Subject: [PATCH 068/172] Updated readme.md --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index daf57f39..4c1c1c40 100644 --- a/readme.md +++ b/readme.md @@ -215,7 +215,7 @@ completely and redirect all calls to the _mimalloc_ library instead . ## 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. +or via environment variables: - `MIMALLOC_SHOW_STATS=1`: show statistics when the program terminates. - `MIMALLOC_VERBOSE=1`: show verbose messages. @@ -265,11 +265,11 @@ _mimalloc_ can be build in secure mode by using the `-DMI_SECURE=ON` flags in `c to make mimalloc more robust against exploits. In particular: - All internal mimalloc pages are surrounded by guard pages and the heap metadata is behind a guard page as well (so a buffer overflow - exploit cannot reach into the metadata), + exploit cannot reach into the metadata). - All free list pointers are [encoded](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af43a0793910a9f2d01ac7863/include/mimalloc-internal.h#L396) - with per-page keys which is used both to prevent overwrites with a known pointer, as well as to detect heap corruption, -- Double free's are detected (and ignored), + with per-page keys which is used both to prevent overwrites with a known pointer, as well as to detect heap corruption. +- Double free's are detected (and ignored). - The free lists are initialized in a random order and allocation randomly chooses between extension and reuse within a page to mitigate against attacks that rely on a predicable allocation order. Similarly, the larger heap blocks allocated by mimalloc from the OS are also address randomized. From 2594b37c56221679c48985e9e340248d5727521b Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 08:36:34 -0700 Subject: [PATCH 069/172] fix build warning on C++ template deduction on Linux --- src/os.c | 4 ++-- src/random.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/os.c b/src/os.c index 3de708d1..740b8954 100644 --- a/src/os.c +++ b/src/os.c @@ -297,7 +297,7 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, if (large_only) return p; // fall back to non-large page allocation on error (`p == NULL`). if (p == NULL) { - mi_atomic_store_release(&large_page_try_ok,10); // on error, don't try again for the next N allocations + mi_atomic_store_release(&large_page_try_ok,10UL); // on error, don't try again for the next N allocations } } } @@ -421,7 +421,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro #endif if (large_only) return p; if (p == NULL) { - mi_atomic_store_release(&large_page_try_ok, 10); // on error, don't try again for the next N allocations + mi_atomic_store_release(&large_page_try_ok, 10UL); // on error, don't try again for the next N allocations } } } diff --git a/src/random.c b/src/random.c index 4736a0ba..a604b49b 100644 --- a/src/random.c +++ b/src/random.c @@ -214,7 +214,7 @@ static bool os_random_buf(void* buf, size_t buf_len) { ssize_t ret = syscall(SYS_getrandom, buf, buf_len, GRND_NONBLOCK); if (ret >= 0) return (buf_len == (size_t)ret); if (ret != ENOSYS) return false; - mi_atomic_store_release(&no_getrandom,1); // don't call again, and fall back to /dev/urandom + mi_atomic_store_release(&no_getrandom, 1UL); // don't call again, and fall back to /dev/urandom } #endif int flags = O_RDONLY; From 50de0d23582cfd2be63ed62722e395777e817f89 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 09:17:42 -0700 Subject: [PATCH 070/172] fix C++ compilation with new atomics --- include/mimalloc-atomic.h | 23 +++++++++++++++++------ src/options.c | 2 +- src/os.c | 2 +- src/region.c | 8 ++++---- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 2c08680b..fa7443af 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -61,10 +61,10 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_atomic_and_acq_rel(p,x) mi_atomic(fetch_and_explicit)(p,x,mi_memory_order(acq_rel)) #define mi_atomic_or_acq_rel(p,x) mi_atomic(fetch_or_explicit)(p,x,mi_memory_order(acq_rel)) -#define mi_atomic_increment_relaxed(p) mi_atomic_add_relaxed(p,1) -#define mi_atomic_decrement_relaxed(p) mi_atomic_sub_relaxed(p,1) -#define mi_atomic_increment_acq_rel(p) mi_atomic_add_acq_rel(p,1) -#define mi_atomic_decrement_acq_rel(p) mi_atomic_sub_acq_rel(p,1) +#define mi_atomic_increment_relaxed(p) mi_atomic_add_relaxed(p,(uintptr_t)1) +#define mi_atomic_decrement_relaxed(p) mi_atomic_sub_relaxed(p,(uintptr_t)1) +#define mi_atomic_increment_acq_rel(p) mi_atomic_add_acq_rel(p,(uintptr_t)1) +#define mi_atomic_decrement_acq_rel(p) mi_atomic_sub_acq_rel(p,(uintptr_t)1) static inline void mi_atomic_yield(void); static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)* p, intptr_t add); @@ -73,11 +73,21 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub); #if defined(__cplusplus) || !defined(_MSC_VER) -// In C++/C11 atomics we have polymorpic atomics so can use the typed `ptr` variants -// (where `tp` is the type of atomic value) +// In C++/C11 atomics we have polymorphic atomics so can use the typed `ptr` variants (where `tp` is the type of atomic value) // We use these macros so we can provide a typed wrapper in MSVC in C compilation mode as well #define mi_atomic_load_ptr_acquire(tp,p) mi_atomic_load_acquire(p) #define mi_atomic_load_ptr_relaxed(tp,p) mi_atomic_load_relaxed(p) + +// In C++ we need to add casts to help resolve templates if NULL is passed +#if defined(__cplusplus) +#define mi_atomic_store_ptr_release(tp,p,x) mi_atomic_store_release(p,(tp*)x) +#define mi_atomic_store_ptr_relaxed(tp,p,x) mi_atomic_store_relaxed(p,(tp*)x) +#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_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 #define mi_atomic_store_ptr_release(tp,p,x) mi_atomic_store_release(p,x) #define mi_atomic_store_ptr_relaxed(tp,p,x) mi_atomic_store_relaxed(p,x) #define mi_atomic_cas_ptr_weak_release(tp,p,exp,des) mi_atomic_cas_weak_release(p,exp,des) @@ -85,6 +95,7 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub); #define mi_atomic_cas_ptr_strong_release(tp,p,exp,des) mi_atomic_cas_strong_release(p,exp,des) #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 // These are used by the statistics static inline int64_t mi_atomic_addi64_relaxed(volatile int64_t* p, int64_t add) { diff --git a/src/options.c b/src/options.c index baaef460..9da3a9bd 100644 --- a/src/options.c +++ b/src/options.c @@ -170,7 +170,7 @@ static void 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 (32*1024) +#define MI_MAX_DELAY_OUTPUT ((uintptr_t)(32*1024)) #endif static char out_buf[MI_MAX_DELAY_OUTPUT+1]; static _Atomic(uintptr_t) out_len; diff --git a/src/os.c b/src/os.c index 740b8954..87151981 100644 --- a/src/os.c +++ b/src/os.c @@ -777,7 +777,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) int err = madvise(start, csize, (int)mi_atomic_load_relaxed(&advice)); if (err != 0 && errno == EINVAL && advice == MADV_FREE) { // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on - mi_atomic_store_release(&advice, MADV_DONTNEED); + mi_atomic_store_release(&advice, (uintptr_t)MADV_DONTNEED); err = madvise(start, csize, MADV_DONTNEED); } #elif defined(__wasi__) diff --git a/src/region.c b/src/region.c index db2871d6..bebc29fd 100644 --- a/src/region.c +++ b/src/region.c @@ -195,13 +195,13 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, // allocated, initialize and claim the initial blocks mem_region_t* r = ®ions[idx]; r->arena_memid = arena_memid; - mi_atomic_store_release(&r->in_use, 0); + mi_atomic_store_release(&r->in_use, (uintptr_t)0); mi_atomic_store_release(&r->dirty, (is_zero ? 0 : MI_BITMAP_FIELD_FULL)); mi_atomic_store_release(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0)); - mi_atomic_store_release(&r->reset, 0); + mi_atomic_store_release(&r->reset, (uintptr_t)0); *bit_idx = 0; mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL); - mi_atomic_store_ptr_release(uint8_t*,&r->start, start); + mi_atomic_store_ptr_release(void,&r->start, start); // and share it mi_region_info_t info; @@ -456,7 +456,7 @@ void _mi_mem_collect(mi_os_tld_t* tld) { uintptr_t commit = mi_atomic_load_relaxed(®ions[i].commit); memset(®ions[i], 0, sizeof(mem_region_t)); // and release the whole region - mi_atomic_store_release(®ion->info, 0); + mi_atomic_store_release(®ion->info, (uintptr_t)0); if (start != NULL) { // && !_mi_os_is_huge_reserved(start)) { _mi_abandoned_await_readers(); // ensure no pending reads _mi_arena_free(start, MI_REGION_SIZE, arena_memid, (~commit == 0), tld->stats); From 2e311f341bbfbe1e09716e3e20b893c3f5555add Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 09:37:09 -0700 Subject: [PATCH 071/172] fix msvc compilation in C mode --- ide/vs2017/mimalloc.vcxproj | 2 +- include/mimalloc-atomic.h | 11 ++++++++++- include/mimalloc-types.h | 4 ++++ src/heap.c | 5 ++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ide/vs2017/mimalloc.vcxproj b/ide/vs2017/mimalloc.vcxproj index 770a87b2..1e39f917 100644 --- a/ide/vs2017/mimalloc.vcxproj +++ b/ide/vs2017/mimalloc.vcxproj @@ -257,4 +257,4 @@ - + \ No newline at end of file diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index fa7443af..e6f4ba0d 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -131,18 +131,23 @@ typedef enum mi_memory_order_e { } mi_memory_order; static inline uintptr_t mi_atomic_fetch_add_explicit(_Atomic(uintptr_t)* p, uintptr_t add, mi_memory_order mo) { + (void)(mo); return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, (msc_intptr_t)add); } static inline uintptr_t mi_atomic_fetch_sub_explicit(_Atomic(uintptr_t)*p, uintptr_t sub, mi_memory_order mo) { + (void)(mo); return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, -((msc_intptr_t)sub)); } static inline uintptr_t mi_atomic_fetch_and_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { + (void)(mo); return (uintptr_t)MI_64(_InterlockedAnd)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } static inline uintptr_t mi_atomic_fetch_or_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { + (void)(mo); return (uintptr_t)MI_64(_InterlockedOr)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } static inline bool mi_atomic_compare_exchange_strong_explicit(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired, mi_memory_order mo1, mi_memory_order mo2) { + (void)(mo1); (void)(mo2); uintptr_t read = (uintptr_t)MI_64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)(*expected)); if (read == *expected) { return true; @@ -156,13 +161,16 @@ static inline bool mi_atomic_compare_exchange_weak_explicit(_Atomic(uintptr_t)*p return mi_atomic_compare_exchange_strong_explicit(p, expected, desired, mo1, mo2); } static inline uintptr_t mi_atomic_exchange_explicit(_Atomic(uintptr_t)* p, uintptr_t exchange, mi_memory_order mo) { + (void)(mo); return (uintptr_t)MI_64(_InterlockedExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)exchange); } -static inline mi_atomic_thread_fence(mi_memory_order mo) { +static inline void mi_atomic_thread_fence(mi_memory_order mo) { + (void)(mo); _Atomic(uintptr_t)x = 0; mi_atomic_exchange_explicit(&x, 1, mo); } static inline uintptr_t mi_atomic_load_explicit(_Atomic(uintptr_t) const* p, mi_memory_order mo) { + (void)(mo); #if defined(_M_IX86) || defined(_M_X64) return *p; #else @@ -174,6 +182,7 @@ static inline uintptr_t mi_atomic_load_explicit(_Atomic(uintptr_t) const* p, mi_ #endif } static inline void mi_atomic_store_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { + (void)(mo); #if defined(_M_IX86) || defined(_M_X64) *p = x; #else diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 5893edee..d9bd14eb 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -12,6 +12,10 @@ terms of the MIT license. A copy of the license can be found in the file #include // uintptr_t, uint16_t, etc #include // _Atomic +#ifdef _MSC_VER +#pragma warning(disable:4214) // bitfield is not int +#endif + // Minimal alignment necessary. On most platforms 16 bytes are needed // due to SSE registers for example. This must be at least `MI_INTPTR_SIZE` #ifndef MI_MAX_ALIGN_SIZE diff --git a/src/heap.c b/src/heap.c index bd46688f..76a90911 100644 --- a/src/heap.c +++ b/src/heap.c @@ -550,6 +550,9 @@ static bool mi_heap_area_visitor(const mi_heap_t* heap, const mi_heap_area_ex_t* // Visit all blocks in a heap bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { - mi_visit_blocks_args_t args = { visit_blocks, visitor, arg }; + mi_visit_blocks_args_t args = { 0 }; + args.visit_blocks = visit_blocks; + args.visitor = visitor; + args.arg = arg; return mi_heap_visit_areas(heap, &mi_heap_area_visitor, &args); } From 551831ba1c3108249ae74155791ba3a2fe55008f Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 10:30:54 -0700 Subject: [PATCH 072/172] ctest output verbose on windows pipeline --- azure-pipelines.yml | 2 +- ide/vs2019/mimalloc-test-stress.vcxproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c81e31bd..e4534b37 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -38,7 +38,7 @@ jobs: configuration: '$(MSBuildConfiguration)' - script: | cd $(BuildType) - ctest + ctest --verbose displayName: CTest # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-windows-$(BuildType) diff --git a/ide/vs2019/mimalloc-test-stress.vcxproj b/ide/vs2019/mimalloc-test-stress.vcxproj index afbb6666..ef7ab357 100644 --- a/ide/vs2019/mimalloc-test-stress.vcxproj +++ b/ide/vs2019/mimalloc-test-stress.vcxproj @@ -149,8 +149,8 @@ - - {abb5eae7-b3e6-432e-b636-333449892ea7} + + {abb5eae7-b3e6-432e-b636-333449892ea6} From 2236b712f45a16f657863802ae9012307998cc6e Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 10:34:41 -0700 Subject: [PATCH 073/172] add test timeout on windows pipeline --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e4534b37..79e5fff5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -38,7 +38,7 @@ jobs: configuration: '$(MSBuildConfiguration)' - script: | cd $(BuildType) - ctest --verbose + ctest --verbose --timeout 120 displayName: CTest # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-windows-$(BuildType) From 39948bce7865c7bf04e874d62d440c9aba1a9a95 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 11:04:55 -0700 Subject: [PATCH 074/172] upload test artifact for the windows pipeline build --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 79e5fff5..fe872efa 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,8 +40,8 @@ jobs: cd $(BuildType) ctest --verbose --timeout 120 displayName: CTest -# - upload: $(Build.SourcesDirectory)/$(BuildType) -# artifact: mimalloc-windows-$(BuildType) + - upload: $(Build.SourcesDirectory)/$(BuildType) + artifact: mimalloc-windows-$(BuildType) - job: displayName: Linux From 694315fbe413ed9b75119edaff7726788ecc2ee5 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 11:08:41 -0700 Subject: [PATCH 075/172] disable test in windows pipeline --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fe872efa..f17a6fee 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,10 +36,10 @@ jobs: inputs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' - - script: | - cd $(BuildType) - ctest --verbose --timeout 120 - displayName: CTest + #- script: | + # cd $(BuildType) + # ctest --verbose --timeout 120 + # displayName: CTest - upload: $(Build.SourcesDirectory)/$(BuildType) artifact: mimalloc-windows-$(BuildType) From 78f1f9bd5e627638db6e637bd2cf29b1d06c105f Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 11:16:40 -0700 Subject: [PATCH 076/172] reduce stress workload for windows pipeline --- azure-pipelines.yml | 8 ++++---- test/test-stress.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f17a6fee..fe872efa 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,10 +36,10 @@ jobs: inputs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' - #- script: | - # cd $(BuildType) - # ctest --verbose --timeout 120 - # displayName: CTest + - script: | + cd $(BuildType) + ctest --verbose --timeout 120 + displayName: CTest - upload: $(Build.SourcesDirectory)/$(BuildType) artifact: mimalloc-windows-$(BuildType) diff --git a/test/test-stress.c b/test/test-stress.c index 29a9d2e5..31a4f709 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -25,9 +25,9 @@ terms of the MIT license. // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // // argument defaults -static int THREADS = 32; // more repeatable if THREADS <= #processors +static int THREADS = 8; // more repeatable if THREADS <= #processors static int SCALE = 10; // scaling factor -static int ITER = 50; // N full iterations destructing and re-creating all threads +static int ITER =100; // N full iterations destructing and re-creating all threads // static int THREADS = 8; // more repeatable if THREADS <= #processors // static int SCALE = 100; // scaling factor From 0d0b5e3fade77ec5d9f6674d5016aa0a69374c72 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 11:19:35 -0700 Subject: [PATCH 077/172] restore stress workload for windows pipeline --- test/test-stress.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-stress.c b/test/test-stress.c index 31a4f709..29a9d2e5 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -25,9 +25,9 @@ terms of the MIT license. // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // // argument defaults -static int THREADS = 8; // more repeatable if THREADS <= #processors +static int THREADS = 32; // more repeatable if THREADS <= #processors static int SCALE = 10; // scaling factor -static int ITER =100; // N full iterations destructing and re-creating all threads +static int ITER = 50; // N full iterations destructing and re-creating all threads // static int THREADS = 8; // more repeatable if THREADS <= #processors // static int SCALE = 100; // scaling factor From 102a85937e7d76bd5628e594f27fcdd3adb93f4d Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 11:27:06 -0700 Subject: [PATCH 078/172] experiment with using non-c++ atomics on msvc --- include/mimalloc-atomic.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index e6f4ba0d..f7fc15ec 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -17,7 +17,7 @@ terms of the MIT license. A copy of the license can be found in the file // instead of passing the memory order as a parameter. // ----------------------------------------------------------------------------------------------- -#if defined(__cplusplus) +#if defined(__cplusplus) && !defined(_MSC_VER) // Use C++ atomics #include #define _Atomic(tp) std::atomic @@ -71,7 +71,7 @@ static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)* p, intptr_t add); static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub); -#if defined(__cplusplus) || !defined(_MSC_VER) +#if (!defined(_MSC_VER)) // defined(__cplusplus) || !defined(_MSC_VER) // In C++/C11 atomics we have polymorphic atomics so can use the typed `ptr` variants (where `tp` is the type of atomic value) // We use these macros so we can provide a typed wrapper in MSVC in C compilation mode as well @@ -193,7 +193,7 @@ static inline void mi_atomic_store_explicit(_Atomic(uintptr_t)* p, uintptr_t x, // These are used by the statistics static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int64_t add) { #ifdef _WIN64 - return (int64_t)mi_atomic_addi((int64_t*)p,add); + return (int64_t)mi_atomic_addi((_Atomic(intptr_t)*)p,add); #else int64_t current; int64_t sum; @@ -208,7 +208,7 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t int64_t current; do { current = *p; - } while (current < x && _InterlockedCompareExchange64(p, x, current) != current); + } while (current < x && _InterlockedCompareExchange64((int64_t*)p, x, current) != current); } // The pointer macros cast to `uintptr_t`. @@ -222,6 +222,8 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t #define mi_atomic_exchange_ptr_release(tp,p,x) (tp*)mi_atomic_exchange_release((_Atomic(uintptr_t)*)(p),(uintptr_t)x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) (tp*)mi_atomic_exchange_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t)x) +#else +#pragma message("define atomics for this platform (not C11, C++, msvc)") #endif From 83bd352f37115e8f44bcbd329d9e28d4b5a14092 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 11:29:38 -0700 Subject: [PATCH 079/172] roll back previous commit (use standard C++ atomics on msvc --- include/mimalloc-atomic.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index f7fc15ec..e6f4ba0d 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -17,7 +17,7 @@ terms of the MIT license. A copy of the license can be found in the file // instead of passing the memory order as a parameter. // ----------------------------------------------------------------------------------------------- -#if defined(__cplusplus) && !defined(_MSC_VER) +#if defined(__cplusplus) // Use C++ atomics #include #define _Atomic(tp) std::atomic @@ -71,7 +71,7 @@ static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)* p, intptr_t add); static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub); -#if (!defined(_MSC_VER)) // defined(__cplusplus) || !defined(_MSC_VER) +#if defined(__cplusplus) || !defined(_MSC_VER) // In C++/C11 atomics we have polymorphic atomics so can use the typed `ptr` variants (where `tp` is the type of atomic value) // We use these macros so we can provide a typed wrapper in MSVC in C compilation mode as well @@ -193,7 +193,7 @@ static inline void mi_atomic_store_explicit(_Atomic(uintptr_t)* p, uintptr_t x, // These are used by the statistics static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int64_t add) { #ifdef _WIN64 - return (int64_t)mi_atomic_addi((_Atomic(intptr_t)*)p,add); + return (int64_t)mi_atomic_addi((int64_t*)p,add); #else int64_t current; int64_t sum; @@ -208,7 +208,7 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t int64_t current; do { current = *p; - } while (current < x && _InterlockedCompareExchange64((int64_t*)p, x, current) != current); + } while (current < x && _InterlockedCompareExchange64(p, x, current) != current); } // The pointer macros cast to `uintptr_t`. @@ -222,8 +222,6 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t #define mi_atomic_exchange_ptr_release(tp,p,x) (tp*)mi_atomic_exchange_release((_Atomic(uintptr_t)*)(p),(uintptr_t)x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) (tp*)mi_atomic_exchange_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t)x) -#else -#pragma message("define atomics for this platform (not C11, C++, msvc)") #endif From 44ba0d254b21c59df724a73a3db098082319e60f Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 11:47:27 -0700 Subject: [PATCH 080/172] disable windows test in azure pipeline for now until we can reproduce --- azure-pipelines.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fe872efa..68c150df 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,12 +36,12 @@ jobs: inputs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' - - script: | - cd $(BuildType) - ctest --verbose --timeout 120 - displayName: CTest - - upload: $(Build.SourcesDirectory)/$(BuildType) - artifact: mimalloc-windows-$(BuildType) + #- script: | + # cd $(BuildType) + # ctest --verbose --timeout 120 + # displayName: CTest + #- upload: $(Build.SourcesDirectory)/$(BuildType) + # artifact: mimalloc-windows-$(BuildType) - job: displayName: Linux From 9d82b15d8759b9a6d97db2e9d3251489adae26ce Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 12:04:25 -0700 Subject: [PATCH 081/172] fix warnings on vs2017 --- ide/vs2017/mimalloc.vcxproj | 8 ++++---- ide/vs2019/mimalloc-test-stress.vcxproj | 4 ++-- src/heap.c | 8 ++++---- src/stats.c | 3 +++ 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ide/vs2017/mimalloc.vcxproj b/ide/vs2017/mimalloc.vcxproj index 1e39f917..1ff1af9c 100644 --- a/ide/vs2017/mimalloc.vcxproj +++ b/ide/vs2017/mimalloc.vcxproj @@ -110,7 +110,7 @@ true ../../include _CRT_SECURE_NO_WARNINGS;MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp + CompileAsC false stdcpp17 @@ -129,7 +129,7 @@ true ../../include _CRT_SECURE_NO_WARNINGS;MI_DEBUG=3;%(PreprocessorDefinitions); - CompileAsCpp + CompileAsC false stdcpp17 @@ -161,7 +161,7 @@ false false Default - CompileAsCpp + CompileAsC true @@ -188,7 +188,7 @@ false false Default - CompileAsCpp + CompileAsC true diff --git a/ide/vs2019/mimalloc-test-stress.vcxproj b/ide/vs2019/mimalloc-test-stress.vcxproj index ef7ab357..afbb6666 100644 --- a/ide/vs2019/mimalloc-test-stress.vcxproj +++ b/ide/vs2019/mimalloc-test-stress.vcxproj @@ -149,8 +149,8 @@ - - {abb5eae7-b3e6-432e-b636-333449892ea6} + + {abb5eae7-b3e6-432e-b636-333449892ea7} diff --git a/src/heap.c b/src/heap.c index 76a90911..b1079e14 100644 --- a/src/heap.c +++ b/src/heap.c @@ -11,6 +11,9 @@ terms of the MIT license. A copy of the license can be found in the file #include // memset, memcpy +#if defined(_MSC_VER) && (_MSC_VER < 1920) +#pragma warning(disable:4204) // non-constant aggregate initializer +#endif /* ----------------------------------------------------------- Helpers @@ -550,9 +553,6 @@ static bool mi_heap_area_visitor(const mi_heap_t* heap, const mi_heap_area_ex_t* // Visit all blocks in a heap bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) { - mi_visit_blocks_args_t args = { 0 }; - args.visit_blocks = visit_blocks; - args.visitor = visitor; - args.arg = arg; + mi_visit_blocks_args_t args = { visit_blocks, visitor, arg }; return mi_heap_visit_areas(heap, &mi_heap_area_visitor, &args); } diff --git a/src/stats.c b/src/stats.c index b484efb1..2fe914c8 100644 --- a/src/stats.c +++ b/src/stats.c @@ -11,6 +11,9 @@ terms of the MIT license. A copy of the license can be found in the file #include // fputs, stderr #include // memset +#if defined(_MSC_VER) && (_MSC_VER < 1920) +#pragma warning(disable:4204) // non-constant aggregate initializer +#endif /* ----------------------------------------------------------- Statistics operations From 7d9a878a9d4b08423f593d56f90df4265ee0eb70 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 12:38:25 -0700 Subject: [PATCH 082/172] test stress in windows pipeline --- azure-pipelines.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 68c150df..397dffe1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,6 +40,8 @@ jobs: # cd $(BuildType) # ctest --verbose --timeout 120 # displayName: CTest + - script: $(BuildType)\$(BuildType)\mimalloc-test-stress + displayName: TestStress #- upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-windows-$(BuildType) From cc32ede5d2f8cd676f52ed605ba864594d95938b Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 12:41:06 -0700 Subject: [PATCH 083/172] disable test stress on windows pipeline again --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 397dffe1..59c7d817 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,8 +40,8 @@ jobs: # cd $(BuildType) # ctest --verbose --timeout 120 # displayName: CTest - - script: $(BuildType)\$(BuildType)\mimalloc-test-stress - displayName: TestStress + #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress + # displayName: TestStress #- upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-windows-$(BuildType) From 1ce2e4cb05c98f66362fe63538353c6c16f5a9ed Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 17:44:15 -0700 Subject: [PATCH 084/172] use main stats for os statistics --- src/os.c | 38 ++++++++++++++++++++++++++------------ src/stats.c | 2 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/os.c b/src/os.c index 87151981..f41844e2 100644 --- a/src/os.c +++ b/src/os.c @@ -100,12 +100,14 @@ static bool use_large_os_page(size_t size, size_t alignment) { // round to a good OS allocation size (bounded by max 12.5% waste) size_t _mi_os_good_alloc_size(size_t size) { - size_t align_size; + size_t align_size = _mi_os_page_size(); + /* if (size < 512*KiB) align_size = _mi_os_page_size(); else if (size < 2*MiB) align_size = 64*KiB; else if (size < 8*MiB) align_size = 256*KiB; else if (size < 32*MiB) align_size = 1*MiB; else align_size = 4*MiB; + */ if (size >= (SIZE_MAX - align_size)) return size; // possible overflow? return _mi_align_up(size, align_size); } @@ -602,14 +604,18 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, OS API: alloc, free, alloc_aligned ----------------------------------------------------------- */ -void* _mi_os_alloc(size_t size, mi_stats_t* stats) { +void* _mi_os_alloc(size_t size, mi_stats_t* tld_stats) { + UNUSED(tld_stats); + mi_stats_t* stats = &_mi_stats_main; if (size == 0) return NULL; size = _mi_os_good_alloc_size(size); bool is_large = false; return mi_os_mem_alloc(size, 0, true, false, &is_large, stats); } -void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats) { +void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* tld_stats) { + UNUSED(tld_stats); + mi_stats_t* stats = &_mi_stats_main; if (size == 0 || p == NULL) return; size = _mi_os_good_alloc_size(size); mi_os_mem_free(p, size, was_committed, stats); @@ -629,7 +635,7 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* lar allow_large = *large; *large = false; } - return mi_os_mem_alloc_aligned(size, alignment, commit, allow_large, (large!=NULL?large:&allow_large), tld->stats); + return mi_os_mem_alloc_aligned(size, alignment, commit, allow_large, (large!=NULL?large:&allow_large), &_mi_stats_main /*tld->stats*/ ); } @@ -686,11 +692,11 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr)) int err = 0; if (commit) { - _mi_stat_increase(&stats->committed, csize); + _mi_stat_increase(&stats->committed, size); // use size for precise commit vs. decommit _mi_stat_counter_increase(&stats->commit_calls, 1); } else { - _mi_stat_decrease(&stats->committed, csize); + _mi_stat_decrease(&stats->committed, size); } #if defined(_WIN32) @@ -729,16 +735,20 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ return (err == 0); } -bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { +bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats) { + UNUSED(tld_stats); + mi_stats_t* stats = &_mi_stats_main; return mi_os_commitx(addr, size, true, false /* liberal */, is_zero, stats); } -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats) { +bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* tld_stats) { + UNUSED(tld_stats); + mi_stats_t* stats = &_mi_stats_main; bool is_zero; return mi_os_commitx(addr, size, false, true /* conservative */, &is_zero, stats); } -bool _mi_os_commit_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { +static bool mi_os_commit_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { return mi_os_commitx(addr, size, true, true /* conservative */, is_zero, stats); } @@ -798,7 +808,9 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* 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, mi_stats_t* tld_stats) { + UNUSED(tld_stats); + mi_stats_t* stats = &_mi_stats_main; if (mi_option_is_enabled(mi_option_reset_decommits)) { return _mi_os_decommit(addr, size, stats); } @@ -807,9 +819,11 @@ bool _mi_os_reset(void* addr, size_t size, mi_stats_t* stats) { } } -bool _mi_os_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { +bool _mi_os_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats) { + UNUSED(tld_stats); + mi_stats_t* stats = &_mi_stats_main; if (mi_option_is_enabled(mi_option_reset_decommits)) { - return _mi_os_commit_unreset(addr, size, is_zero, stats); // re-commit it (conservatively!) + return mi_os_commit_unreset(addr, size, is_zero, stats); // re-commit it (conservatively!) } else { *is_zero = false; diff --git a/src/stats.c b/src/stats.c index 2fe914c8..6427a1ad 100644 --- a/src/stats.c +++ b/src/stats.c @@ -77,7 +77,7 @@ static void mi_stat_add(mi_stat_count_t* stat, const mi_stat_count_t* src, int64 mi_atomic_addi64_relaxed( &stat->allocated, src->allocated * unit); mi_atomic_addi64_relaxed( &stat->current, src->current * unit); mi_atomic_addi64_relaxed( &stat->freed, src->freed * unit); - // peak scores do not work across threads.. + // peak scores do not work across threads.. mi_atomic_addi64_relaxed( &stat->peak, src->peak * unit); } From f09549c98f32a2f02d0a308bf811f7d4f5ccfb97 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 18:00:36 -0700 Subject: [PATCH 085/172] use main stats for thread count --- src/init.c | 23 +++++++---------------- src/os.c | 4 +--- test/test-stress.c | 2 +- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/init.c b/src/init.c index 0a99c049..07a34f57 100644 --- a/src/init.c +++ b/src/init.c @@ -201,7 +201,7 @@ static bool _mi_heap_init(void) { tld->segments.stats = &tld->stats; tld->segments.os = &tld->os; tld->os.stats = &tld->stats; - _mi_heap_set_default_direct(heap); + _mi_heap_set_default_direct(heap); } return false; } @@ -235,9 +235,8 @@ static bool _mi_heap_done(mi_heap_t* heap) { _mi_heap_collect_abandon(heap); } - // merge stats - _mi_stats_done(&heap->tld->stats); + _mi_stats_done(&heap->tld->stats); // free if not the main thread if (heap != &_mi_heap_main) { @@ -337,18 +336,13 @@ void mi_thread_init(void) mi_attr_noexcept { // ensure our process has started already mi_process_init(); - + // initialize the thread local default heap // (this will call `_mi_heap_set_default_direct` and thus set the // fiber/pthread key to a non-zero value, ensuring `_mi_thread_done` is called) if (_mi_heap_init()) return; // returns true if already initialized - // don't further initialize for the main thread - if (_mi_is_main_thread()) return; - - mi_heap_t* const heap = mi_get_default_heap(); - if (mi_heap_is_initialized(heap)) { _mi_stat_increase(&heap->tld->stats.threads, 1); } - + _mi_stat_increase(&_mi_stats_main.threads, 1); //_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); } @@ -357,14 +351,11 @@ void mi_thread_done(void) mi_attr_noexcept { } static void _mi_thread_done(mi_heap_t* heap) { + _mi_stat_decrease(&_mi_stats_main.threads, 1); + // check thread-id as on Windows shutdown with FLS the main (exit) thread may call this on thread-local heaps... if (heap->thread_id != _mi_thread_id()) return; - - // stats - if (!_mi_is_main_thread() && mi_heap_is_initialized(heap)) { - _mi_stat_decrease(&heap->tld->stats.threads, 1); - } - + // abandon the thread local heap if (_mi_heap_done(heap)) return; // returns true if already ran } diff --git a/src/os.c b/src/os.c index f41844e2..93e022ac 100644 --- a/src/os.c +++ b/src/os.c @@ -100,14 +100,12 @@ static bool use_large_os_page(size_t size, size_t alignment) { // round to a good OS allocation size (bounded by max 12.5% waste) size_t _mi_os_good_alloc_size(size_t size) { - size_t align_size = _mi_os_page_size(); - /* + size_t align_size; if (size < 512*KiB) align_size = _mi_os_page_size(); else if (size < 2*MiB) align_size = 64*KiB; else if (size < 8*MiB) align_size = 256*KiB; else if (size < 32*MiB) align_size = 1*MiB; else align_size = 4*MiB; - */ if (size >= (SIZE_MAX - align_size)) return size; // possible overflow? return _mi_align_up(size, align_size); } diff --git a/test/test-stress.c b/test/test-stress.c index 29a9d2e5..05dbd4b4 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -272,7 +272,7 @@ static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { DWORD* tids = (DWORD*)custom_calloc(nthreads,sizeof(DWORD)); HANDLE* thandles = (HANDLE*)custom_calloc(nthreads,sizeof(HANDLE)); for (uintptr_t i = 0; i < nthreads; i++) { - thandles[i] = CreateThread(0, 4096, &thread_entry, (void*)(i), 0, &tids[i]); + thandles[i] = CreateThread(0, 8*1024, &thread_entry, (void*)(i), 0, &tids[i]); } for (size_t i = 0; i < nthreads; i++) { WaitForSingleObject(thandles[i], INFINITE); From 33a45f3f47308defb60ba3985c249b973a0e48b6 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 18:02:21 -0700 Subject: [PATCH 086/172] try ctest in windows pipeline again with increased stack per thread --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 59c7d817..51b07686 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,10 +36,10 @@ jobs: inputs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' - #- script: | - # cd $(BuildType) - # ctest --verbose --timeout 120 - # displayName: CTest + - script: | + cd $(BuildType) + ctest --verbose --timeout 120 + displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress # displayName: TestStress #- upload: $(Build.SourcesDirectory)/$(BuildType) From aec70a04a642b30c8d82199c309d18416c55da3a Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 18:04:34 -0700 Subject: [PATCH 087/172] disable win pipeline again --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 51b07686..59c7d817 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,10 +36,10 @@ jobs: inputs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' - - script: | - cd $(BuildType) - ctest --verbose --timeout 120 - displayName: CTest + #- script: | + # cd $(BuildType) + # ctest --verbose --timeout 120 + # displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress # displayName: TestStress #- upload: $(Build.SourcesDirectory)/$(BuildType) From f3f8afb5801d3ce691c6837451e2fc8423a9c275 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 18:17:07 -0700 Subject: [PATCH 088/172] add abandoned counter for debug purposes --- src/segment.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index daa47383..a5077711 100644 --- a/src/segment.c +++ b/src/segment.c @@ -882,6 +882,10 @@ static mi_decl_cache_align _Atomic(mi_segment_t*) abandoned_visited; // = // The abandoned page list (tagged as it supports pop) static mi_decl_cache_align _Atomic(mi_tagged_segment_t) abandoned; // = NULL +// Maintain these for debug purposes (these counts may be a bit off) +static mi_decl_cache_align _Atomic(uintptr_t) abandoned_count; +static mi_decl_cache_align _Atomic(uintptr_t) abandoned_visited_count; + // We also maintain a count of current readers of the abandoned list // in order to prevent resetting/decommitting segment memory if it might // still be read. @@ -897,6 +901,7 @@ static void mi_abandoned_visited_push(mi_segment_t* segment) { do { mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, anext); } while (!mi_atomic_cas_ptr_weak_release(mi_segment_t, &abandoned_visited, &anext, segment)); + mi_atomic_increment_relaxed(&abandoned_visited_count); } // Move the visited list to the abandoned list. @@ -913,8 +918,13 @@ static bool mi_abandoned_visited_revisit(void) mi_tagged_segment_t afirst; mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); if (mi_tagged_segment_ptr(ts)==NULL) { + uintptr_t count = mi_atomic_load_relaxed(&abandoned_visited_count); afirst = mi_tagged_segment(first, ts); - if (mi_atomic_cas_strong_acq_rel(&abandoned, &ts, afirst)) return true; + if (mi_atomic_cas_strong_acq_rel(&abandoned, &ts, afirst)) { + mi_atomic_add_relaxed(&abandoned_count, count); + mi_atomic_sub_relaxed(&abandoned_visited_count, count); + return true; + } } // find the last element of the visited list: O(n) @@ -927,10 +937,14 @@ static bool mi_abandoned_visited_revisit(void) // and atomically prepend to the abandoned list // (no need to increase the readers as we don't access the abandoned segments) mi_tagged_segment_t anext = mi_atomic_load_relaxed(&abandoned); + uintptr_t count; do { + count = mi_atomic_load_relaxed(&abandoned_visited_count); mi_atomic_store_ptr_release(mi_segment_t, &last->abandoned_next, mi_tagged_segment_ptr(anext)); afirst = mi_tagged_segment(first, anext); } while (!mi_atomic_cas_weak_release(&abandoned, &anext, afirst)); + mi_atomic_add_relaxed(&abandoned_count, count); + mi_atomic_sub_relaxed(&abandoned_visited_count, count); return true; } @@ -946,6 +960,7 @@ static void mi_abandoned_push(mi_segment_t* segment) { mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, mi_tagged_segment_ptr(ts)); next = mi_tagged_segment(segment, ts); } while (!mi_atomic_cas_weak_release(&abandoned, &ts, next)); + mi_atomic_increment_relaxed(&abandoned_count); } // Wait until there are no more pending reads on segments that used to be in the abandoned list @@ -986,6 +1001,7 @@ static mi_segment_t* mi_abandoned_pop(void) { mi_atomic_decrement_relaxed(&abandoned_readers); // release reader lock if (segment != NULL) { mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); + mi_atomic_decrement_relaxed(&abandoned_count); } return segment; } From 1b571aea06612945f7590bd87bd943037b789270 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 22:03:47 -0700 Subject: [PATCH 089/172] remove unused local warning --- src/os.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/os.c b/src/os.c index 93e022ac..6985587c 100644 --- a/src/os.c +++ b/src/os.c @@ -625,6 +625,7 @@ void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld) { + UNUSED(tld); if (size == 0) return NULL; size = _mi_os_good_alloc_size(size); alignment = _mi_align_up(alignment, _mi_os_page_size()); From c34f303aa03bcecfec71a5e1dc1e1fc94e133738 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 22:20:46 -0700 Subject: [PATCH 090/172] add vs2017 pipeline --- azure-pipelines.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 59c7d817..5a9f6dfb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,6 +8,39 @@ trigger: - dev jobs: +- job: + displayName: Windows-2017 + pool: + vmImage: + windows-2017 + strategy: + matrix: + Debug: + BuildType: debug + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + MSBuildConfiguration: Debug + Release: + BuildType: release + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + MSBuildConfiguration: Release + Secure: + BuildType: secure + cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON + MSBuildConfiguration: Release + steps: + - task: CMake@1 + inputs: + workingDirectory: $(BuildType) + cmakeArgs: .. $(cmakeExtraArgs) + - task: MSBuild@1 + inputs: + solution: $(BuildType)/libmimalloc.sln + configuration: '$(MSBuildConfiguration)' + - script: | + cd $(BuildType) + ctest --verbose --timeout 120 + displayName: CTest + - job: displayName: Windows pool: From d3aeb6253bb008d5a1aaf4b584423c782f4a7f3b Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 22:22:37 -0700 Subject: [PATCH 091/172] fix vs2017 pipeline vmimage --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5a9f6dfb..961fd34f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,7 +12,7 @@ jobs: displayName: Windows-2017 pool: vmImage: - windows-2017 + vs2017-win2016 strategy: matrix: Debug: @@ -82,7 +82,7 @@ jobs: displayName: Linux pool: vmImage: - ubuntu-16.04 + ubuntu-18.04 strategy: matrix: Debug: From dd0ce3c4147ddcbd6f15796b566f164c694b905b Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 22:31:59 -0700 Subject: [PATCH 092/172] specify x64 for vs2017 pipeline --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 961fd34f..e0c888bb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,15 +17,15 @@ jobs: matrix: Debug: BuildType: debug - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON + cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON MSBuildConfiguration: Debug Release: BuildType: release - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release + cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release MSBuildConfiguration: Release Secure: BuildType: secure - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON + cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON MSBuildConfiguration: Release steps: - task: CMake@1 From a9ad0cb68da1451f672c0f29b4476e6be755b154 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 5 Sep 2020 22:36:59 -0700 Subject: [PATCH 093/172] comment out vs2017 pipeline --- azure-pipelines.yml | 68 ++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e0c888bb..5ffb1ef3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,40 +7,7 @@ trigger: - master - dev -jobs: -- 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 120 - displayName: CTest - +jobs: - job: displayName: Windows pool: @@ -164,3 +131,36 @@ jobs: displayName: CTest # - 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 120 +# displayName: CTest From e740242978b9f74a090570738035ea4d5a45602c Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 08:29:08 -0700 Subject: [PATCH 094/172] link with advapi32 on windows --- CMakeLists.txt | 2 +- azure-pipelines.yml | 8 ++++---- src/random.c | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98b55ae0..81362175 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,7 +191,7 @@ endif() # extra needed libraries if(WIN32) - list(APPEND mi_libraries psapi shell32 user32 bcrypt) + list(APPEND mi_libraries psapi shell32 user32 advapi32) else() if(NOT ${CMAKE_C_COMPILER} MATCHES "android") list(APPEND mi_libraries pthread) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5ffb1ef3..43f128f0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,10 +36,10 @@ jobs: inputs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' - #- script: | - # cd $(BuildType) - # ctest --verbose --timeout 120 - # displayName: CTest + - script: | + cd $(BuildType) + ctest --verbose --timeout 120 + displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress # displayName: TestStress #- upload: $(Build.SourcesDirectory)/$(BuildType) diff --git a/src/random.c b/src/random.c index a604b49b..2d15c187 100644 --- a/src/random.c +++ b/src/random.c @@ -170,6 +170,7 @@ static bool os_random_buf(void* buf, size_t buf_len) { return (BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); } */ +#pragma comment (lib,"advapi32.lib") #define RtlGenRandom SystemFunction036 #ifdef __cplusplus extern "C" { @@ -181,8 +182,8 @@ BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); static bool os_random_buf(void* buf, size_t buf_len) { mi_assert_internal(buf_len >= sizeof(uintptr_t)); memset(buf, 0, buf_len); - RtlGenRandom(buf, (ULONG)buf_len); - return (((uintptr_t*)buf)[0] != 0); // sanity check (but RtlGenRandom should never fail) + bool ok = (RtlGenRandom(buf, (ULONG)buf_len) != 0); + return ok; } #elif defined(ANDROID) || defined(XP_DARWIN) || defined(__APPLE__) || defined(__DragonFly__) || \ From f7b94fe21c41d5890cda86f689973e554eb945df Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 08:33:27 -0700 Subject: [PATCH 095/172] experiment with bcrypt api again --- CMakeLists.txt | 2 +- src/random.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81362175..35460e85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,7 +191,7 @@ endif() # extra needed libraries if(WIN32) - list(APPEND mi_libraries psapi shell32 user32 advapi32) + list(APPEND mi_libraries psapi shell32 user32 advapi32 bcrypt) else() if(NOT ${CMAKE_C_COMPILER} MATCHES "android") list(APPEND mi_libraries pthread) diff --git a/src/random.c b/src/random.c index 2d15c187..a03e80c4 100644 --- a/src/random.c +++ b/src/random.c @@ -162,14 +162,13 @@ If we cannot get good randomness, we fall back to weak randomness based on a tim -----------------------------------------------------------------------------*/ #if defined(_WIN32) -/* // We prefer BCryptGenRandom over RtlGenRandom but it leads to a crash a when using dynamic override combined with the C++ runtime :-( #pragma comment (lib,"bcrypt.lib") #include static bool os_random_buf(void* buf, size_t buf_len) { return (BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); } -*/ +/* #pragma comment (lib,"advapi32.lib") #define RtlGenRandom SystemFunction036 #ifdef __cplusplus @@ -185,7 +184,7 @@ static bool os_random_buf(void* buf, size_t buf_len) { bool ok = (RtlGenRandom(buf, (ULONG)buf_len) != 0); return ok; } - +*/ #elif defined(ANDROID) || defined(XP_DARWIN) || defined(__APPLE__) || defined(__DragonFly__) || \ defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__sun) || defined(__wasi__) From 9113281165d40d86025f32641f8c14a64e5fd21d Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 08:50:23 -0700 Subject: [PATCH 096/172] switch back to using bcryptrandom number generation on Windows to fix azure pipeline tests --- src/random.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/random.c b/src/random.c index a03e80c4..b9485ea0 100644 --- a/src/random.c +++ b/src/random.c @@ -155,20 +155,23 @@ uintptr_t _mi_random_next(mi_random_ctx_t* ctx) { /* ---------------------------------------------------------------------------- To initialize a fresh random context we rely on the OS: -- Windows : RtlGenRandom +- Windows : BCryptGenRandom (or RtlGenRandom) - osX,bsd,wasi: arc4random_buf - Linux : getrandom,/dev/urandom If we cannot get good randomness, we fall back to weak randomness based on a timer and ASLR. -----------------------------------------------------------------------------*/ #if defined(_WIN32) -// We prefer BCryptGenRandom over RtlGenRandom but it leads to a crash a when using dynamic override combined with the C++ runtime :-( + +#if !defined(MI_USE_RTLGENRANDOM) +// We prefer BCryptGenRandom over RtlGenRandom #pragma comment (lib,"bcrypt.lib") #include static bool os_random_buf(void* buf, size_t buf_len) { return (BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0); } -/* +#else +// Use (unofficial) RtlGenRandom #pragma comment (lib,"advapi32.lib") #define RtlGenRandom SystemFunction036 #ifdef __cplusplus @@ -179,12 +182,10 @@ BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); } #endif static bool os_random_buf(void* buf, size_t buf_len) { - mi_assert_internal(buf_len >= sizeof(uintptr_t)); - memset(buf, 0, buf_len); - bool ok = (RtlGenRandom(buf, (ULONG)buf_len) != 0); - return ok; + return (RtlGenRandom(buf, (ULONG)buf_len) != 0); } -*/ +#endif + #elif defined(ANDROID) || defined(XP_DARWIN) || defined(__APPLE__) || defined(__DragonFly__) || \ defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__sun) || defined(__wasi__) @@ -252,6 +253,7 @@ static bool os_random_buf(void* buf, size_t buf_len) { uintptr_t _os_random_weak(uintptr_t extra_seed) { uintptr_t x = (uintptr_t)&_os_random_weak ^ extra_seed; // ASLR makes the address random + #if defined(_WIN32) LARGE_INTEGER pcount; QueryPerformanceCounter(&pcount); From f28f41f530686c49771ebc88cceecc6ddd41f268 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 09:09:00 -0700 Subject: [PATCH 097/172] better ctest invocation on pipelines --- azure-pipelines.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 43f128f0..0cd08485 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,7 +12,7 @@ jobs: displayName: Windows pool: vmImage: - windows-2019 + windows-2019 strategy: matrix: Debug: @@ -36,10 +36,10 @@ jobs: inputs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' - - script: | - cd $(BuildType) - ctest --verbose --timeout 120 - displayName: CTest + msbuildArguments: -m +- script: ctest --verbose --timeout 120 + workingDirectory: $(BuildType) + displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress # displayName: TestStress #- upload: $(Build.SourcesDirectory)/$(BuildType) @@ -99,7 +99,8 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(nproc) -C $(BuildType) displayName: Make - - script: make test -C $(BuildType) + - script: ctest --verbose --timeout 120 + workingDirectory: $(BuildType) displayName: CTest # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-ubuntu-$(BuildType) @@ -127,7 +128,8 @@ jobs: cmakeArgs: .. $(cmakeExtraArgs) - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) displayName: Make - - script: make test -C $(BuildType) + - script: ctest --verbose --timeout 120 + workingDirectory: $(BuildType) displayName: CTest # - upload: $(Build.SourcesDirectory)/$(BuildType) # artifact: mimalloc-macos-$(BuildType) From e1b4f036cacb742c3796c54c3346d21d403cb155 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 09:10:38 -0700 Subject: [PATCH 098/172] fix indentation in pipeline script --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0cd08485..85e89420 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,9 +37,9 @@ jobs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' msbuildArguments: -m -- script: ctest --verbose --timeout 120 - workingDirectory: $(BuildType) - displayName: CTest + - script: ctest --verbose --timeout 120 + workingDirectory: $(BuildType) + displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress # displayName: TestStress #- upload: $(Build.SourcesDirectory)/$(BuildType) From 4355ab7d2099994212fccc69518c2d936377f749 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 13:21:02 -0700 Subject: [PATCH 099/172] add i64 atomics --- include/mimalloc-atomic.h | 88 +++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index e6f4ba0d..b6506075 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -67,8 +67,8 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_atomic_decrement_acq_rel(p) mi_atomic_sub_acq_rel(p,(uintptr_t)1) static inline void mi_atomic_yield(void); -static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)* p, intptr_t add); -static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)* p, intptr_t sub); +static inline intptr_t mi_atomic_addi(_Atomic(intptr_t)*p, intptr_t add); +static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub); #if defined(__cplusplus) || !defined(_MSC_VER) @@ -106,6 +106,13 @@ static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) { while (current < x && !mi_atomic_cas_weak_release((_Atomic(int64_t)*)p, ¤t, x)) { /* nothing */ }; } +// Used by timers +#define mi_atomic_loadi64_acquire(p) mi_atomic(load_explicit)(p,mi_memory_order(acquire)) +#define mi_atomic_loadi64_relaxed(p) mi_atomic(load_explicit)(p,mi_memory_order(relaxed)) +#define mi_atomic_storei64_release(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(release)) +#define mi_atomic_storei64_relaxed(p,x) mi_atomic(store_explicit)(p,x,mi_memory_order(relaxed)) + + #elif defined(_MSC_VER) @@ -130,7 +137,7 @@ typedef enum mi_memory_order_e { mi_memory_order_seq_cst } mi_memory_order; -static inline uintptr_t mi_atomic_fetch_add_explicit(_Atomic(uintptr_t)* p, uintptr_t add, mi_memory_order mo) { +static inline uintptr_t mi_atomic_fetch_add_explicit(_Atomic(uintptr_t)*p, uintptr_t add, mi_memory_order mo) { (void)(mo); return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, (msc_intptr_t)add); } @@ -138,15 +145,15 @@ static inline uintptr_t mi_atomic_fetch_sub_explicit(_Atomic(uintptr_t)*p, uintp (void)(mo); return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, -((msc_intptr_t)sub)); } -static inline uintptr_t mi_atomic_fetch_and_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { +static inline uintptr_t mi_atomic_fetch_and_explicit(_Atomic(uintptr_t)*p, uintptr_t x, mi_memory_order mo) { (void)(mo); return (uintptr_t)MI_64(_InterlockedAnd)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } -static inline uintptr_t mi_atomic_fetch_or_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { +static inline uintptr_t mi_atomic_fetch_or_explicit(_Atomic(uintptr_t)*p, uintptr_t x, mi_memory_order mo) { (void)(mo); return (uintptr_t)MI_64(_InterlockedOr)((volatile msc_intptr_t*)p, (msc_intptr_t)x); } -static inline bool mi_atomic_compare_exchange_strong_explicit(_Atomic(uintptr_t)* p, uintptr_t* expected, uintptr_t desired, mi_memory_order mo1, mi_memory_order mo2) { +static inline bool mi_atomic_compare_exchange_strong_explicit(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired, mi_memory_order mo1, mi_memory_order mo2) { (void)(mo1); (void)(mo2); uintptr_t read = (uintptr_t)MI_64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)(*expected)); if (read == *expected) { @@ -160,7 +167,7 @@ static inline bool mi_atomic_compare_exchange_strong_explicit(_Atomic(uintptr_t) static inline bool mi_atomic_compare_exchange_weak_explicit(_Atomic(uintptr_t)*p, uintptr_t* expected, uintptr_t desired, mi_memory_order mo1, mi_memory_order mo2) { return mi_atomic_compare_exchange_strong_explicit(p, expected, desired, mo1, mo2); } -static inline uintptr_t mi_atomic_exchange_explicit(_Atomic(uintptr_t)* p, uintptr_t exchange, mi_memory_order mo) { +static inline uintptr_t mi_atomic_exchange_explicit(_Atomic(uintptr_t)*p, uintptr_t exchange, mi_memory_order mo) { (void)(mo); return (uintptr_t)MI_64(_InterlockedExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)exchange); } @@ -171,30 +178,51 @@ static inline void mi_atomic_thread_fence(mi_memory_order mo) { } static inline uintptr_t mi_atomic_load_explicit(_Atomic(uintptr_t) const* p, mi_memory_order mo) { (void)(mo); - #if defined(_M_IX86) || defined(_M_X64) +#if defined(_M_IX86) || defined(_M_X64) return *p; - #else +#else uintptr_t x = *p; if (mo > mi_memory_order_relaxed) { while (!mi_atomic_compare_exchange_weak_explicit(p, &x, x, mo, mi_memory_order_relaxed)) { /* nothing */ }; } return x; - #endif +#endif } -static inline void mi_atomic_store_explicit(_Atomic(uintptr_t)* p, uintptr_t x, mi_memory_order mo) { +static inline void mi_atomic_store_explicit(_Atomic(uintptr_t)*p, uintptr_t x, mi_memory_order mo) { (void)(mo); - #if defined(_M_IX86) || defined(_M_X64) +#if defined(_M_IX86) || defined(_M_X64) *p = x; - #else - mi_atomic_exchange_explicit(p,x,mo); - #endif +#else + mi_atomic_exchange_explicit(p, x, mo); +#endif +} +static inline int64_t mi_atomic_loadi64_explicit(_Atomic(int64_t)*p, mi_memory_order mo) { + (void)(mo); +#if defined(_M_X64) + return *p; +#else + int64_t old = *p; + int64_t x = old; + while ((old = InterlockedCompareExchange64(p, x, old)) != x) { + x = old; + } + return x; +#endif +} +static inline void mi_atomic_storei64_explicit(_Atomic(int64_t)*p, int64_t x, mi_memory_order mo) { + (void)(mo); +#if defined(x_M_IX86) || defined(_M_X64) + *p = x; +#else + InterlockedExchange64(p, x); +#endif } // These are used by the statistics -static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int64_t add) { - #ifdef _WIN64 - return (int64_t)mi_atomic_addi((int64_t*)p,add); - #else +static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)*p, int64_t add) { +#ifdef _WIN64 + return (int64_t)mi_atomic_addi((int64_t*)p, add); +#else int64_t current; int64_t sum; do { @@ -202,7 +230,7 @@ static inline int64_t mi_atomic_addi64_relaxed(volatile _Atomic(int64_t)* p, int sum = current + add; } while (_InterlockedCompareExchange64(p, sum, current) != current); return current; - #endif +#endif } static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t x) { int64_t current; @@ -222,6 +250,12 @@ static inline void mi_atomic_maxi64_relaxed(volatile _Atomic(int64_t)*p, int64_t #define mi_atomic_exchange_ptr_release(tp,p,x) (tp*)mi_atomic_exchange_release((_Atomic(uintptr_t)*)(p),(uintptr_t)x) #define mi_atomic_exchange_ptr_acq_rel(tp,p,x) (tp*)mi_atomic_exchange_acq_rel((_Atomic(uintptr_t)*)(p),(uintptr_t)x) +#define mi_atomic_loadi64_acquire(p) mi_atomic(loadi64_explicit)(p,mi_memory_order(acquire)) +#define mi_atomic_loadi64_relaxed(p) mi_atomic(loadi64_explicit)(p,mi_memory_order(relaxed)) +#define mi_atomic_storei64_release(p,x) mi_atomic(storei64_explicit)(p,x,mi_memory_order(release)) +#define mi_atomic_storei64_relaxed(p,x) mi_atomic(storei64_explicit)(p,x,mi_memory_order(relaxed)) + + #endif @@ -250,13 +284,13 @@ static inline void mi_atomic_yield(void) { #elif (defined(__GNUC__) || defined(__clang__)) && \ (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)) #if defined(__x86_64__) || defined(__i386__) - static inline void mi_atomic_yield(void) { - __asm__ volatile ("pause" ::: "memory"); - } +static inline void mi_atomic_yield(void) { + __asm__ volatile ("pause" ::: "memory"); +} #elif defined(__arm__) || defined(__aarch64__) - static inline void mi_atomic_yield(void) { - __asm__ volatile("yield"); - } +static inline void mi_atomic_yield(void) { + __asm__ volatile("yield"); +} #endif #elif defined(__wasi__) #include @@ -271,4 +305,4 @@ static inline void mi_atomic_yield(void) { #endif -#endif // __MIMALLOC_ATOMIC_H +#endif // __MIMALLOC_ATOMIC_H \ No newline at end of file From ee286919d9b82aecbc941dd9e428fa1c6ed9ab55 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 13:21:19 -0700 Subject: [PATCH 100/172] add mi_process_info api call --- include/mimalloc.h | 1 + src/stats.c | 102 +++++++++++++++++++++++------------- test/main-override-static.c | 15 +++++- 3 files changed, 80 insertions(+), 38 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index c9127e1f..d58e15fd 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -153,6 +153,7 @@ mi_decl_export void mi_thread_init(void) mi_attr_noexcept; mi_decl_export void mi_thread_done(void) mi_attr_noexcept; mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; +mi_decl_export void mi_process_info(double* user_time, double* system_time, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept; // ------------------------------------------------------------------------------------- // Aligned allocation diff --git a/src/stats.c b/src/stats.c index 6427a1ad..b8e0ba77 100644 --- a/src/stats.c +++ b/src/stats.c @@ -276,7 +276,7 @@ static void mi_buffered_out(const char* msg, void* arg) { // Print statistics //------------------------------------------------------------ -static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit); +static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults); static void _mi_stats_print(mi_stats_t* stats, mi_msecs_t elapsed, mi_output_fun* out0, void* arg0) mi_attr_noexcept { // wrap the output function to be line buffered @@ -323,15 +323,17 @@ static void _mi_stats_print(mi_stats_t* stats, mi_msecs_t elapsed, mi_output_fun mi_msecs_t user_time; mi_msecs_t sys_time; + size_t current_rss; size_t peak_rss; - size_t page_faults; - size_t page_reclaim; + size_t current_commit; size_t peak_commit; - mi_process_info(&user_time, &sys_time, &peak_rss, &page_faults, &page_reclaim, &peak_commit); - _mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, reclaims: %lu, rss: ", "process", user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, (unsigned long)page_faults, (unsigned long)page_reclaim ); + size_t page_faults; + mi_stat_process_info(&user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); + _mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, rss: ", "process", + user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, (unsigned long)page_faults ); mi_printf_amount((int64_t)peak_rss, 1, out, arg, "%s"); if (peak_commit > 0) { - _mi_fprintf(out, arg, ", commit charge: "); + _mi_fprintf(out, arg, ", commit: "); mi_printf_amount((int64_t)peak_commit, 1, out, arg, "%s"); } _mi_fprintf(out, arg, "\n"); @@ -453,7 +455,9 @@ static mi_msecs_t filetime_msecs(const FILETIME* ftime) { mi_msecs_t msecs = (i.QuadPart / 10000); // FILETIME is in 100 nano seconds return msecs; } -static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit) { + +static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) +{ FILETIME ct; FILETIME ut; FILETIME st; @@ -461,13 +465,13 @@ static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_r GetProcessTimes(GetCurrentProcess(), &ct, &et, &st, &ut); *utime = filetime_msecs(&ut); *stime = filetime_msecs(&st); - PROCESS_MEMORY_COUNTERS info; GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); - *peak_rss = (size_t)info.PeakWorkingSetSize; - *page_faults = (size_t)info.PageFaultCount; - *peak_commit = (size_t)info.PeakPagefileUsage; - *page_reclaim = 0; + *current_rss = (size_t)info.WorkingSetSize; + *peak_rss = (size_t)info.PeakWorkingSetSize; + *current_commit = (size_t)info.PagefileUsage; + *peak_commit = (size_t)info.PeakPagefileUsage; + *page_faults = (size_t)info.PageFaultCount; } #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__) @@ -487,36 +491,37 @@ static mi_msecs_t timeval_secs(const struct timeval* tv) { return ((mi_msecs_t)tv->tv_sec * 1000L) + ((mi_msecs_t)tv->tv_usec / 1000L); } -static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit) { +static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) +{ struct rusage rusage; getrusage(RUSAGE_SELF, &rusage); -#if !defined(__HAIKU__) -#if defined(__APPLE__) && defined(__MACH__) - *peak_rss = rusage.ru_maxrss; -#else - *peak_rss = rusage.ru_maxrss * 1024; -#endif + *utime = timeval_secs(&rusage.ru_utime); + *stime = timeval_secs(&rusage.ru_stime); *page_faults = rusage.ru_majflt; - *page_reclaim = rusage.ru_minflt; - *peak_commit = 0; -#else -// Haiku does not have (yet?) a way to -// get these stats per process + // estimate commit using our stats + *peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.peak)); + *current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.current)); + *current_rss = *current_commit; // estimate +#if defined(__HAIKU__) + // Haiku does not have (yet?) a way to + // get these stats per process thread_info tid; area_info mem; ssize_t c; - *peak_rss = 0; - *page_faults = 0; - *page_reclaim = 0; - *peak_commit = 0; get_thread_info(find_thread(0), &tid); - while (get_next_area_info(tid.team, &c, &mem) == B_OK) { - *peak_rss += mem.ram_size; + *peak_rss += mem.ram_size; } -#endif - *utime = timeval_secs(&rusage.ru_utime); - *stime = timeval_secs(&rusage.ru_stime); +#elif defined(__APPLE__) && defined(__MACH__) + *peak_rss = rusage.ru_maxrss; // BSD reports in bytes + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS) { + *current_rss = (size_t)info.resident_size; + } +#else + *peak_rss = rusage.ru_maxrss * 1024; // Linux reports in KiB +#endif } #else @@ -525,12 +530,35 @@ static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_r #pragma message("define a way to get process info") #endif -static void mi_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit) { - *peak_rss = 0; +static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) +{ + *peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.peak)); + *current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.current)); + *peak_rss = *peak_commit; + *current_rss = *current_commit; *page_faults = 0; - *page_reclaim = 0; - *peak_commit = 0; *utime = 0; *stime = 0; } #endif + + +mi_decl_export void mi_process_info(double* user_time, double* system_time, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept +{ + mi_msecs_t utime = 0; + mi_msecs_t stime = 0; + size_t current_rss0 = 0; + size_t peak_rss0 = 0; + size_t current_commit0 = 0; + size_t peak_commit0 = 0; + size_t page_faults0 = 0; + mi_stat_process_info(&utime, &stime, ¤t_rss0, &peak_rss0, ¤t_commit0, &peak_commit0, &page_faults0); + if (user_time!=NULL) *user_time = ((double)(utime/1000)) + (((double)(utime%1000))*1e-3); + if (system_time!=NULL) *system_time = ((double)(stime/1000)) + (((double)(stime%1000))*1e-3); + if (current_rss!=NULL) *current_rss = current_rss0; + if (peak_rss!=NULL) *peak_rss = peak_rss0; + if (current_commit!=NULL) *current_commit = current_commit0; + if (peak_commit!=NULL) *peak_commit = peak_commit0; + if (page_faults!=NULL) *page_faults = page_faults0; +} + diff --git a/test/main-override-static.c b/test/main-override-static.c index 82feb37c..992a822e 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -13,7 +13,7 @@ static void corrupt_free(); static void block_overflow1(); static void invalid_free(); static void test_aslr(void); - +static void test_process_info(void); int main() { mi_version(); @@ -45,6 +45,7 @@ int main() { //p2 = malloc(32); //mi_free(p2); mi_stats_print(NULL); + test_process_info(); return 0; } @@ -131,3 +132,15 @@ static void test_aslr(void) { p[1] = malloc(1134626); printf("p1: %p, p2: %p\n", p[0], p[1]); } + +static void test_process_info(void) { + double utime = 0; + double stime = 0; + size_t current_rss = 0; + size_t peak_rss = 0; + size_t current_commit = 0; + size_t peak_commit = 0; + size_t page_faults = 0; + mi_process_info(&utime, &stime, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); + printf("process info: user: %.3f s, rss: %zd b, commit: %zd b\n\n", utime, peak_rss, peak_commit); +} \ No newline at end of file From 46ee8952eb6194f02adafce5d96b56f160b3f1ea Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 13:53:02 -0700 Subject: [PATCH 101/172] update mi_process_info to not use doubles --- include/mimalloc.h | 2 +- src/stats.c | 6 +++--- test/main-override-static.c | 14 +++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index d58e15fd..5b3d13ed 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -153,7 +153,7 @@ mi_decl_export void mi_thread_init(void) mi_attr_noexcept; mi_decl_export void mi_thread_done(void) mi_attr_noexcept; mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; -mi_decl_export void mi_process_info(double* user_time, double* system_time, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept; +mi_decl_export void mi_process_info(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) mi_attr_noexcept; // ------------------------------------------------------------------------------------- // Aligned allocation diff --git a/src/stats.c b/src/stats.c index b8e0ba77..842e2009 100644 --- a/src/stats.c +++ b/src/stats.c @@ -543,7 +543,7 @@ static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* c #endif -mi_decl_export void mi_process_info(double* user_time, double* system_time, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept +mi_decl_export void mi_process_info(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) mi_attr_noexcept { mi_msecs_t utime = 0; mi_msecs_t stime = 0; @@ -553,8 +553,8 @@ mi_decl_export void mi_process_info(double* user_time, double* system_time, size size_t peak_commit0 = 0; size_t page_faults0 = 0; mi_stat_process_info(&utime, &stime, ¤t_rss0, &peak_rss0, ¤t_commit0, &peak_commit0, &page_faults0); - if (user_time!=NULL) *user_time = ((double)(utime/1000)) + (((double)(utime%1000))*1e-3); - if (system_time!=NULL) *system_time = ((double)(stime/1000)) + (((double)(stime%1000))*1e-3); + if (user_msecs!=NULL) *user_msecs = (utime < 0 ? 0 : (utime < (mi_msecs_t)SIZE_MAX ? (size_t)utime : SIZE_MAX)); + if (system_msecs!=NULL) *system_msecs = (stime < 0 ? 0 : (stime < (mi_msecs_t)SIZE_MAX ? (size_t)stime : SIZE_MAX)); if (current_rss!=NULL) *current_rss = current_rss0; if (peak_rss!=NULL) *peak_rss = peak_rss0; if (current_commit!=NULL) *current_commit = current_commit0; diff --git a/test/main-override-static.c b/test/main-override-static.c index 992a822e..0b73bb61 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -134,13 +134,17 @@ static void test_aslr(void) { } static void test_process_info(void) { - double utime = 0; - double stime = 0; + size_t user_msecs = 0; + size_t system_msecs = 0; size_t current_rss = 0; size_t peak_rss = 0; size_t current_commit = 0; size_t peak_commit = 0; - size_t page_faults = 0; - mi_process_info(&utime, &stime, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); - printf("process info: user: %.3f s, rss: %zd b, commit: %zd b\n\n", utime, peak_rss, peak_commit); + size_t page_faults = 0; + for (int i = 0; i < 100000; i++) { + void* p = calloc(100,10); + free(p); + } + mi_process_info(&user_msecs, &system_msecs, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); + printf("\n\n*** process info: user: %3zd.%03zd s, rss: %zd b, commit: %zd b\n\n", user_msecs/1000, user_msecs%1000, peak_rss, peak_commit); } \ No newline at end of file From d8f8159ddae3b7391c035e02581f22a6bdb4be47 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 6 Sep 2020 13:53:13 -0700 Subject: [PATCH 102/172] update documentation --- doc/mimalloc-doc.h | 13 ++++++ docs/group__extended.html | 76 ++++++++++++++++++++++++++++++++ docs/group__extended.js | 1 + docs/mimalloc-doc_8h_source.html | 55 +++++++++++------------ docs/navtreeindex0.js | 29 ++++++------ docs/search/all_6.js | 1 + docs/search/functions_0.js | 1 + 7 files changed, 135 insertions(+), 41 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index f11a97b0..c9cb580d 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -441,6 +441,19 @@ int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msec /// Currenty only used on Windows. bool mi_is_redirected(); +/// Return process information (time and memory usage). +/// @param user_msecs Optional. User time in milli-seconds. +/// @param system_msecs Optional. System time in milli-seconds. +/// @param current_rss Optional. Current working set size (touched pages). +/// @param peak_rss Optional. Peak working set size (touched pages). +/// @param current_commit Optional. Current committed memory (backed by the page file). +/// @param peak_commit Optional. Peak committed memory (backed by the page file). +/// @param page_faults Optional. Count of hard page faults. +/// +/// The \a current_rss is precise on Windows and MacOSX; other systems estimate +/// this using \a current_commit. The \a commit is precise on Windows but estimated +/// on other systems as the amount of read/write accessible memory reserved by mimalloc. +void mi_process_info(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); /// \} diff --git a/docs/group__extended.html b/docs/group__extended.html index 575288ab..c9145660 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -187,6 +187,9 @@ Functions bool mi_is_redirected ()  Is the C runtime malloc API redirected? More...
  +void mi_process_info (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...

Detailed Description

Extended functionality.

@@ -411,6 +414,79 @@ Functions
Returns
a pointer to newly allocated memory of at least size bytes, or NULL if out of memory. This function is meant for use in run-time systems for best performance and does not check if size was indeed small – use with care!
+
+
+ +

◆ mi_process_info()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void mi_process_info (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).

+
Parameters
+ + + + + + + + +
user_msecsOptional. User time in milli-seconds.
system_msecsOptional. System time in milli-seconds.
current_rssOptional. Current working set size (touched pages).
peak_rssOptional. Peak working set size (touched pages).
current_commitOptional. Current committed memory (backed by the page file).
peak_commitOptional. Peak committed memory (backed by the page file).
page_faultsOptional. Count of hard page faults.
+
+
+

The current_rss is precise on Windows and MacOSX; other systems estimate this using current_commit. The commit is precise on Windows but estimated on other systems as the amount of read/write accessible memory reserved by mimalloc.

+
diff --git a/docs/group__extended.js b/docs/group__extended.js index 594cadb9..7f298b16 100644 --- a/docs/group__extended.js +++ b/docs/group__extended.js @@ -9,6 +9,7 @@ var group__extended = [ "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_process_info", "group__extended.html#ga9144506d5ffa8cc03547867bd15e1032", 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 ], diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index c4637bad..cbff636b 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -102,11 +102,12 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
mimalloc-doc.h
-
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
83 
87 
91 void mi_free(void* p);
92 
97 void* mi_malloc(size_t size);
98 
103 void* mi_zalloc(size_t size);
104 
114 void* mi_calloc(size_t count, size_t size);
115 
128 void* mi_realloc(void* p, size_t newsize);
129 
140 void* mi_recalloc(void* p, size_t count, size_t size);
141 
155 void* mi_expand(void* p, size_t newsize);
156 
166 void* mi_mallocn(size_t count, size_t size);
167 
177 void* mi_reallocn(void* p, size_t count, size_t size);
178 
195 void* mi_reallocf(void* p, size_t newsize);
196 
197 
206 char* mi_strdup(const char* s);
207 
217 char* mi_strndup(const char* s, size_t n);
218 
231 char* mi_realpath(const char* fname, char* resolved_name);
232 
234 
235 // ------------------------------------------------------
236 // Extended functionality
237 // ------------------------------------------------------
238 
242 
245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
246 
254 void* mi_malloc_small(size_t size);
255 
263 void* mi_zalloc_small(size_t size);
264 
279 size_t mi_usable_size(void* p);
280 
290 size_t mi_good_size(size_t size);
291 
299 void mi_collect(bool force);
300 
305 void mi_stats_print(void* out);
306 
312 void mi_stats_print_out(mi_output_fun* out, void* arg);
313 
315 void mi_stats_reset(void);
316 
318 void mi_stats_merge(void);
319 
323 void mi_thread_init(void);
324 
329 void mi_thread_done(void);
330 
336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
337 
344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
345 
361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
362 
368 typedef void (mi_output_fun)(const char* msg, void* arg);
369 
376 void mi_register_output(mi_output_fun* out, void* arg);
377 
383 typedef void (mi_error_fun)(int err, void* arg);
384 
400 void mi_register_error(mi_error_fun* errfun, void* arg);
401 
406 bool mi_is_in_heap_region(const void* p);
407 
408 
421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
422 
435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
436 
437 
442 bool mi_is_redirected();
443 
444 
446 
447 // ------------------------------------------------------
448 // Aligned allocation
449 // ------------------------------------------------------
450 
456 
469 void* mi_malloc_aligned(size_t size, size_t alignment);
470 void* mi_zalloc_aligned(size_t size, size_t alignment);
471 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
472 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
473 
484 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
485 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
486 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
487 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
488 
490 
496 
501 struct mi_heap_s;
502 
507 typedef struct mi_heap_s mi_heap_t;
508 
511 
519 void mi_heap_delete(mi_heap_t* heap);
520 
528 void mi_heap_destroy(mi_heap_t* heap);
529 
534 
538 
545 
547 void mi_heap_collect(mi_heap_t* heap, bool force);
548 
551 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
552 
556 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
557 
560 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
561 
564 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
565 
568 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
569 
572 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
573 
576 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
577 
580 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
581 
582 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
583 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
584 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
585 
586 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
587 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
588 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
589 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
590 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
591 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
592 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
593 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
594 
596 
597 
606 
607 void* mi_rezalloc(void* p, size_t newsize);
608 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
609 
610 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
611 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
612 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
613 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
614 
615 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
616 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
617 
618 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
619 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
620 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
621 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
622 
624 
633 
645 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
646 
648 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
649 
651 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
652 
654 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
655 
657 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
658 
660 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
661 
663 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
664 
666 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
667 
669 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
670 
672 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
673 
675 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
676 
678 
684 
691 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
692 
701 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
702 
710 bool mi_check_owned(const void* p);
711 
714 typedef struct mi_heap_area_s {
715  void* blocks;
716  size_t reserved;
717  size_t committed;
718  size_t used;
719  size_t block_size;
721 
729 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
730 
742 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
743 
745 
751 
753 typedef enum mi_option_e {
754  // stable options
758  // the following options are experimental
772 } mi_option_t;
773 
774 
775 bool mi_option_is_enabled(mi_option_t option);
776 void mi_option_enable(mi_option_t option);
777 void mi_option_disable(mi_option_t option);
778 void mi_option_set_enabled(mi_option_t option, bool enable);
779 void mi_option_set_enabled_default(mi_option_t option, bool enable);
780 
781 long mi_option_get(mi_option_t option);
782 void mi_option_set(mi_option_t option, long value);
783 void mi_option_set_default(mi_option_t option, long value);
784 
785 
787 
794 
795 void* mi_recalloc(void* p, size_t count, size_t size);
796 size_t mi_malloc_size(const void* p);
797 size_t mi_malloc_usable_size(const void *p);
798 
800 void mi_cfree(void* p);
801 
802 int mi_posix_memalign(void** p, size_t alignment, size_t size);
803 int mi__posix_memalign(void** p, size_t alignment, size_t size);
804 void* mi_memalign(size_t alignment, size_t size);
805 void* mi_valloc(size_t size);
806 
807 void* mi_pvalloc(size_t size);
808 void* mi_aligned_alloc(size_t alignment, size_t size);
809 void* mi_reallocarray(void* p, size_t count, size_t size);
810 
811 void mi_free_size(void* p, size_t size);
812 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
813 void mi_free_aligned(void* p, size_t alignment);
814 
816 
829 
831 void* mi_new(std::size_t n) noexcept(false);
832 
834 void* mi_new_n(size_t count, size_t size) noexcept(false);
835 
837 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
838 
840 void* mi_new_nothrow(size_t n);
841 
843 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
844 
846 void* mi_new_realloc(void* p, size_t newsize);
847 
849 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
850 
858 template<class T> struct mi_stl_allocator { }
859 
861 
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
+
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
83 
87 
91 void mi_free(void* p);
92 
97 void* mi_malloc(size_t size);
98 
103 void* mi_zalloc(size_t size);
104 
114 void* mi_calloc(size_t count, size_t size);
115 
128 void* mi_realloc(void* p, size_t newsize);
129 
140 void* mi_recalloc(void* p, size_t count, size_t size);
141 
155 void* mi_expand(void* p, size_t newsize);
156 
166 void* mi_mallocn(size_t count, size_t size);
167 
177 void* mi_reallocn(void* p, size_t count, size_t size);
178 
195 void* mi_reallocf(void* p, size_t newsize);
196 
197 
206 char* mi_strdup(const char* s);
207 
217 char* mi_strndup(const char* s, size_t n);
218 
231 char* mi_realpath(const char* fname, char* resolved_name);
232 
234 
235 // ------------------------------------------------------
236 // Extended functionality
237 // ------------------------------------------------------
238 
242 
245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
246 
254 void* mi_malloc_small(size_t size);
255 
263 void* mi_zalloc_small(size_t size);
264 
279 size_t mi_usable_size(void* p);
280 
290 size_t mi_good_size(size_t size);
291 
299 void mi_collect(bool force);
300 
305 void mi_stats_print(void* out);
306 
312 void mi_stats_print_out(mi_output_fun* out, void* arg);
313 
315 void mi_stats_reset(void);
316 
318 void mi_stats_merge(void);
319 
323 void mi_thread_init(void);
324 
329 void mi_thread_done(void);
330 
336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
337 
344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
345 
361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
362 
368 typedef void (mi_output_fun)(const char* msg, void* arg);
369 
376 void mi_register_output(mi_output_fun* out, void* arg);
377 
383 typedef void (mi_error_fun)(int err, void* arg);
384 
400 void mi_register_error(mi_error_fun* errfun, void* arg);
401 
406 bool mi_is_in_heap_region(const void* p);
407 
408 
421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
422 
435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
436 
437 
442 bool mi_is_redirected();
443 
456 void mi_process_info(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);
457 
459 
460 // ------------------------------------------------------
461 // Aligned allocation
462 // ------------------------------------------------------
463 
469 
482 void* mi_malloc_aligned(size_t size, size_t alignment);
483 void* mi_zalloc_aligned(size_t size, size_t alignment);
484 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
485 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
486 
497 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
498 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
499 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
500 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
501 
503 
509 
514 struct mi_heap_s;
515 
520 typedef struct mi_heap_s mi_heap_t;
521 
524 
532 void mi_heap_delete(mi_heap_t* heap);
533 
541 void mi_heap_destroy(mi_heap_t* heap);
542 
547 
551 
558 
560 void mi_heap_collect(mi_heap_t* heap, bool force);
561 
564 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
565 
569 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
570 
573 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
574 
577 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
578 
581 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
582 
585 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
586 
589 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
590 
593 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
594 
595 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
596 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
597 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
598 
599 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
600 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
601 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
602 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
603 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
604 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
605 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
606 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
607 
609 
610 
619 
620 void* mi_rezalloc(void* p, size_t newsize);
621 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
622 
623 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
624 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
625 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
626 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
627 
628 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
629 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
630 
631 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
632 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
633 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
634 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
635 
637 
646 
658 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
659 
661 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
662 
664 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
665 
667 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
668 
670 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
671 
673 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
674 
676 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
677 
679 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
680 
682 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
683 
685 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
686 
688 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
689 
691 
697 
704 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
705 
714 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
715 
723 bool mi_check_owned(const void* p);
724 
727 typedef struct mi_heap_area_s {
728  void* blocks;
729  size_t reserved;
730  size_t committed;
731  size_t used;
732  size_t block_size;
734 
742 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);
743 
755 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
756 
758 
764 
766 typedef enum mi_option_e {
767  // stable options
771  // the following options are experimental
785 } mi_option_t;
786 
787 
788 bool mi_option_is_enabled(mi_option_t option);
789 void mi_option_enable(mi_option_t option);
790 void mi_option_disable(mi_option_t option);
791 void mi_option_set_enabled(mi_option_t option, bool enable);
792 void mi_option_set_enabled_default(mi_option_t option, bool enable);
793 
794 long mi_option_get(mi_option_t option);
795 void mi_option_set(mi_option_t option, long value);
796 void mi_option_set_default(mi_option_t option, long value);
797 
798 
800 
807 
808 void* mi_recalloc(void* p, size_t count, size_t size);
809 size_t mi_malloc_size(const void* p);
810 size_t mi_malloc_usable_size(const void *p);
811 
813 void mi_cfree(void* p);
814 
815 int mi_posix_memalign(void** p, size_t alignment, size_t size);
816 int mi__posix_memalign(void** p, size_t alignment, size_t size);
817 void* mi_memalign(size_t alignment, size_t size);
818 void* mi_valloc(size_t size);
819 
820 void* mi_pvalloc(size_t size);
821 void* mi_aligned_alloc(size_t alignment, size_t size);
822 void* mi_reallocarray(void* p, size_t count, size_t size);
823 
824 void mi_free_size(void* p, size_t size);
825 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
826 void mi_free_aligned(void* p, size_t alignment);
827 
829 
842 
844 void* mi_new(std::size_t n) noexcept(false);
845 
847 void* mi_new_n(size_t count, size_t size) noexcept(false);
848 
850 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
851 
853 void* mi_new_nothrow(size_t n);
854 
856 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
857 
859 void* mi_new_realloc(void* p, size_t newsize);
860 
862 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
863 
871 template<class T> struct mi_stl_allocator { }
872 
874 
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
void * mi_new_nothrow(size_t n)
like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
void * mi_reallocn(void *p, size_t count, size_t size)
Re-allocate memory to count elements of size bytes.
void * mi_malloc_aligned(size_t size, size_t alignment)
Allocate size bytes aligned by alignment.
void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
+
void mi_process_info(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_stats_reset(void)
Reset statistics.
void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
bool mi_option_is_enabled(mi_option_t option)
@@ -122,15 +123,15 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void mi_stats_print_out(mi_output_fun *out, void *arg)
Print the main statistics.
void() mi_error_fun(int err, void *arg)
Type of error callback functions.
Definition: mimalloc-doc.h:383
void * mi_rezalloc(void *p, size_t newsize)
-
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:759
+
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:772
void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
Allocate zero-initialized in a specific heap.
void mi_option_set(mi_option_t option, long value)
-
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:760
+
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:773
void mi_cfree(void *p)
Just as free but also checks if the pointer p belongs to our heap.
void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
-
Definition: mimalloc-doc.h:771
+
Definition: mimalloc-doc.h:784
void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:715
+
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:728
void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
void mi_option_enable(mi_option_t option)
int mi__posix_memalign(void **p, size_t alignment, size_t size)
@@ -148,35 +149,35 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
void * mi_zalloc(size_t size)
Allocate zero-initialized size bytes.
void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
-
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:763
+
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:776
void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
Allocate count zero-initialized elements in a specific heap.
void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
bool mi_is_redirected()
Is the C runtime malloc API redirected?
-
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:719
+
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:732
void * mi_reallocarray(void *p, size_t count, size_t size)
int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most t...
void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
Type of deferred free functions.
Definition: mimalloc-doc.h:344
bool mi_is_in_heap_region(const void *p)
Is a pointer part of our heap?
void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc e...
void * mi_realloc(void *p, size_t newsize)
Re-allocate memory to newsize bytes.
-
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:762
+
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:775
void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
void mi_free_size_aligned(void *p, size_t size, size_t alignment)
void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:764
+
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:777
void mi_thread_done(void)
Uninitialize mimalloc on a thread.
bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
Visit all areas and blocks in a heap.
-
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:767
+
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:780
void * mi_malloc(size_t size)
Allocate size bytes.
void mi_register_error(mi_error_fun *errfun, void *arg)
Register an error callback function.
-
Experimental.
Definition: mimalloc-doc.h:768
+
Experimental.
Definition: mimalloc-doc.h:781
char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
Duplicate a string of at most length n in a specific heap.
-
bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
Visitor function passed to mi_heap_visit_blocks()
Definition: mimalloc-doc.h:729
+
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:742
void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
char * mi_realpath(const char *fname, char *resolved_name)
Resolve a file path name.
-
Print error messages to stderr.
Definition: mimalloc-doc.h:755
-
Experimental.
Definition: mimalloc-doc.h:765
+
Print error messages to stderr.
Definition: mimalloc-doc.h:768
+
Experimental.
Definition: mimalloc-doc.h:778
void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
void * mi_new_aligned_nothrow(size_t n, size_t alignment)
like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
void * mi_memalign(size_t alignment, size_t size)
@@ -184,11 +185,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
Does a heap contain a pointer to a previously allocated block?
void mi_heap_collect(mi_heap_t *heap, bool force)
Release outstanding resources in a specific heap.
void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
-
Print verbose messages to stderr.
Definition: mimalloc-doc.h:757
+
Print verbose messages to stderr.
Definition: mimalloc-doc.h:770
void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
Allocate size bytes aligned by alignment at a specified offset.
void mi_heap_delete(mi_heap_t *heap)
Delete a previously allocated heap.
-
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:770
+
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:783
mi_heap_t * mi_heap_get_default()
Get the default heap that is used for mi_malloc() et al.
int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs ...
void mi_option_disable(mi_option_t option)
@@ -197,26 +198,26 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void mi_thread_init(void)
Initialize mimalloc on a thread.
size_t mi_good_size(size_t size)
Return the used allocation size.
void mi_stats_print(void *out)
Deprecated.
-
Experimental.
Definition: mimalloc-doc.h:769
+
Experimental.
Definition: mimalloc-doc.h:782
void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
Allocate count elements in a specific heap.
-
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:714
+
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:727
void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
Print out heap statistics for this thread.
-
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:756
+
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:769
void * mi_zalloc_aligned(size_t size, size_t alignment)
-
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:716
-
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:507
-
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:718
+
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:729
+
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:520
+
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:731
void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
Register a deferred free function.
void mi_free_size(void *p, size_t size)
void mi_collect(bool force)
Eagerly free memory.
void * mi_new_reallocn(void *p, size_t newcount, size_t size)
like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc excepti...
void mi_heap_destroy(mi_heap_t *heap)
Destroy a heap, freeing all its still allocated blocks.
void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
-
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:761
+
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:774
void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
void mi_register_output(mi_output_fun *out, void *arg)
Register an output function.
-
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:858
+
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:871
void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
Allocate a small object in a specific heap.
void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
size_t mi_malloc_usable_size(const void *p)
@@ -233,11 +234,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
mi_heap_t * mi_heap_get_backing()
Get the backing heap.
void mi_free_aligned(void *p, size_t alignment)
void * mi_new(std::size_t n) noexcept(false)
like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception...
-
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:766
+
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:779
mi_heap_t * mi_heap_new()
Create a new heap that can be used for allocation.
void * mi_heap_malloc(mi_heap_t *heap, size_t size)
Allocate in a specific heap.
-
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:717
-
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:753
+
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:730
+
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:766
bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
Check safely if any pointer is part of a heap.
mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
Set the default heap to use for mi_malloc() et al.
diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js index 51be8fb7..92f8d8c9 100644 --- a/docs/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -38,29 +38,30 @@ var NAVTREEINDEX0 = "group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3":[5,9,2], "group__cpp.html#structmi__stl__allocator":[5,9,0], "group__extended.html":[5,1], -"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,21], -"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,18], +"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,22], +"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,19], "group__extended.html#ga1ea64283508718d9d645c38efc2f4305":[5,1,0], -"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,22], +"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,23], "group__extended.html#ga251d369cda3f1c2a955c555486ed90e5":[5,1,2], "group__extended.html#ga299dae78d25ce112e384a98b7309c5be":[5,1,1], -"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,15], -"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,13], -"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,9], -"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,17], +"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,16], +"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,14], +"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,10], +"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,18], "group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,4], -"group__extended.html#ga537f13b299ddf801e49a5a94fde02c79":[5,1,16], +"group__extended.html#ga537f13b299ddf801e49a5a94fde02c79":[5,1,17], "group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,6], "group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,8], -"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,12], -"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,14], -"group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,10], +"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,13], +"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,15], +"group__extended.html#ga9144506d5ffa8cc03547867bd15e1032":[5,1,9], +"group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,11], "group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,7], -"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,20], +"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,21], "group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,5], "group__extended.html#gad823d23444a4b77a40f66bf075a98a0c":[5,1,3], -"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,11], -"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,19], +"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,12], +"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,20], "group__heap.html":[5,3], "group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0":[5,3,20], "group__heap.html#ga08ca6419a5c057a4d965868998eef487":[5,3,3], diff --git a/docs/search/all_6.js b/docs/search/all_6.js index 5c2aa01e..4e4c8a3f 100644 --- a/docs/search/all_6.js +++ b/docs/search/all_6.js @@ -106,6 +106,7 @@ var searchData= ['mi_5foption_5fverbose',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], ['mi_5foutput_5ffun',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',1,'mimalloc-doc.h']]], ['mi_5fposix_5fmemalign',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo',['mi_process_info',['../group__extended.html#ga9144506d5ffa8cc03547867bd15e1032',1,'mimalloc-doc.h']]], ['mi_5fpvalloc',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], ['mi_5frealloc',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], ['mi_5frealloc_5faligned',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js index f2b65c2d..fc333d5f 100644 --- a/docs/search/functions_0.js +++ b/docs/search/functions_0.js @@ -75,6 +75,7 @@ var searchData= ['mi_5foption_5fset_5fenabled',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], ['mi_5foption_5fset_5fenabled_5fdefault',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], ['mi_5fposix_5fmemalign',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo',['mi_process_info',['../group__extended.html#ga9144506d5ffa8cc03547867bd15e1032',1,'mimalloc-doc.h']]], ['mi_5fpvalloc',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], ['mi_5frealloc',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], ['mi_5frealloc_5faligned',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], From c7272afa9a477576369a89ad74cbba4375dafd05 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 7 Sep 2020 21:34:34 -0700 Subject: [PATCH 103/172] add mi_reserve_os_memory/mi_manage_os_memory; allow arena allocations to cross multiple bitmap fields --- ide/vs2019/mimalloc-test-stress.vcxproj | 4 +- include/mimalloc.h | 4 + src/arena.c | 109 +++++----- src/bitmap.inc.c | 252 +++++++++++++++++++++++- src/os.c | 4 +- test/main-override-static.c | 22 ++- test/test-stress.c | 3 +- 7 files changed, 340 insertions(+), 58 deletions(-) diff --git a/ide/vs2019/mimalloc-test-stress.vcxproj b/ide/vs2019/mimalloc-test-stress.vcxproj index afbb6666..ef7ab357 100644 --- a/ide/vs2019/mimalloc-test-stress.vcxproj +++ b/ide/vs2019/mimalloc-test-stress.vcxproj @@ -149,8 +149,8 @@ - - {abb5eae7-b3e6-432e-b636-333449892ea7} + + {abb5eae7-b3e6-432e-b636-333449892ea6} diff --git a/include/mimalloc.h b/include/mimalloc.h index 5b3d13ed..2bcbf10e 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -262,6 +262,10 @@ mi_decl_nodiscard mi_decl_export bool mi_is_redirected(void) mi_attr_noexcept; mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept; mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept; +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; + + // 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/src/arena.c b/src/arena.c index 73a7e704..20a89445 100644 --- a/src/arena.c +++ b/src/arena.c @@ -30,12 +30,13 @@ of 256MiB in practice. #include "mimalloc-atomic.h" #include // memset +#include // ENOMEM #include "bitmap.inc.c" // atomic bitmap // os.c -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld); +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_stats_t* stats); void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats); void _mi_os_free(void* p, size_t size, mi_stats_t* stats); @@ -49,8 +50,7 @@ bool _mi_os_commit(void* p, size_t size, bool* is_zero, mi_stats_t* stats); ----------------------------------------------------------- */ #define MI_SEGMENT_ALIGN MI_SEGMENT_SIZE -#define MI_ARENA_BLOCK_SIZE (8*MI_SEGMENT_ALIGN) // 32MiB -#define MI_ARENA_MAX_OBJ_SIZE (MI_BITMAP_FIELD_BITS * MI_ARENA_BLOCK_SIZE) // 2GiB +#define MI_ARENA_BLOCK_SIZE (4*MI_SEGMENT_ALIGN) // 32MiB #define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_BLOCK_SIZE/2) // 16MiB #define MI_MAX_ARENAS (64) // not more than 256 (since we use 8 bits in the memid) @@ -104,16 +104,11 @@ static size_t mi_block_count_of_size(size_t size) { ----------------------------------------------------------- */ static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx) { - const size_t fcount = arena->field_count; size_t idx = mi_atomic_load_acquire(&arena->search_idx); // start from last search - for (size_t visited = 0; visited < fcount; visited++, idx++) { - if (idx >= fcount) idx = 0; // wrap around - // try to atomically claim a range of bits - if (mi_bitmap_try_find_claim_field(arena->blocks_inuse, idx, blocks, bitmap_idx)) { - mi_atomic_store_release(&arena->search_idx, idx); // start search from here next time - return true; - } - } + if (mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) { + mi_atomic_store_release(&arena->search_idx, idx); // start search from here next time + return true; + }; return false; } @@ -131,7 +126,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n // claimed it! set the dirty bits (todo: no need for an atomic op here?) void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE); *memid = mi_arena_id_create(arena_index, bitmap_index); - *is_zero = mi_bitmap_claim(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL); + *is_zero = mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL); *large = arena->is_large; if (arena->is_committed) { // always committed @@ -140,7 +135,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n else if (*commit) { // arena not committed as a whole, but commit requested: ensure commit now bool any_uncommitted; - mi_bitmap_claim(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted); + mi_bitmap_claim_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted); if (any_uncommitted) { bool commit_zero; _mi_os_commit(p, needed_bcount * MI_ARENA_BLOCK_SIZE, &commit_zero, tld->stats); @@ -149,7 +144,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n } else { // no need to commit, but check if already fully committed - *commit = mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index); + *commit = mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index); } return p; } @@ -166,7 +161,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, // try to allocate in an arena if the alignment is small enough // and the object is not too large or too small. if (alignment <= MI_SEGMENT_ALIGN && - size <= MI_ARENA_MAX_OBJ_SIZE && + // size <= MI_ARENA_MAX_OBJ_SIZE && size >= MI_ARENA_MIN_OBJ_SIZE) { const size_t bcount = mi_block_count_of_size(size); @@ -202,7 +197,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, // finally, fall back to the OS *is_zero = true; *memid = MI_MEMID_OS; - return _mi_os_alloc_aligned(size, alignment, *commit, large, tld); + return _mi_os_alloc_aligned(size, alignment, *commit, large, tld->stats); } void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld) @@ -240,7 +235,7 @@ void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_s return; } const size_t blocks = mi_block_count_of_size(size); - bool ones = mi_bitmap_unclaim(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx); + bool ones = mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx); if (!ones) { _mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size); return; @@ -266,12 +261,59 @@ static bool mi_arena_add(mi_arena_t* arena) { return true; } +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 +{ + const size_t bcount = mi_block_count_of_size(size); + const size_t fields = _mi_divide_up(bcount, MI_BITMAP_FIELD_BITS); + const size_t bitmaps = (is_committed ? 3 : 2); + const size_t asize = sizeof(mi_arena_t) + (bitmaps*fields*sizeof(mi_bitmap_field_t)); + mi_arena_t* arena = (mi_arena_t*)_mi_os_alloc(asize, &_mi_stats_main); // TODO: can we avoid allocating from the OS? + if (arena == NULL) return false; + + arena->block_count = bcount; + arena->field_count = fields; + arena->start = (uint8_t*)start; + arena->numa_node = numa_node; // TODO: or get the current numa node if -1? (now it allows anyone to allocate on -1) + arena->is_large = is_large; + arena->is_zero_init = is_zero; + arena->is_committed = is_committed; + arena->search_idx = 0; + arena->blocks_dirty = &arena->blocks_inuse[fields]; // just after inuse bitmap + arena->blocks_committed = (is_committed ? NULL : &arena->blocks_inuse[2*fields]); // just after dirty bitmap + // the bitmaps are already zero initialized due to os_alloc + // just claim leftover blocks if needed + ptrdiff_t post = (fields * MI_BITMAP_FIELD_BITS) - bcount; + mi_assert_internal(post >= 0); + if (post > 0) { + // don't use leftover bits at the end + mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post); + mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL); + } + + mi_arena_add(arena); + return true; +} + +// Reserve a range of regular OS memory +int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept +{ + size = _mi_os_good_alloc_size(size); + bool large = allow_large; + void* start = _mi_os_alloc_aligned(size, MI_SEGMENT_ALIGN, commit, &large, &_mi_stats_main); + if (start==NULL) return ENOMEM; + if (!mi_manage_os_memory(start, size, commit, large, true, -1)) { + _mi_os_free_ex(start, size, commit, &_mi_stats_main); + _mi_verbose_message("failed to reserve %zu k memory\n", _mi_divide_up(size,1024)); + return ENOMEM; + } + _mi_verbose_message("reserved %zu kb memory\n", _mi_divide_up(size,1024)); + return 0; +} + /* ----------------------------------------------------------- Reserve a huge page arena. ----------------------------------------------------------- */ -#include // ENOMEM - // reserve at a specific numa node int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept { if (pages==0) return 0; @@ -286,35 +328,10 @@ int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msec } _mi_verbose_message("numa node %i: reserved %zu gb huge pages (of the %zu gb requested)\n", numa_node, pages_reserved, pages); - size_t bcount = mi_block_count_of_size(hsize); - size_t fields = _mi_divide_up(bcount, MI_BITMAP_FIELD_BITS); - size_t asize = sizeof(mi_arena_t) + (2*fields*sizeof(mi_bitmap_field_t)); - mi_arena_t* arena = (mi_arena_t*)_mi_os_alloc(asize, &_mi_stats_main); // TODO: can we avoid allocating from the OS? - if (arena == NULL) { + if (!mi_manage_os_memory(p, hsize, true, true, true, numa_node)) { _mi_os_free_huge_pages(p, hsize, &_mi_stats_main); return ENOMEM; } - arena->block_count = bcount; - arena->field_count = fields; - arena->start = (uint8_t*)p; - arena->numa_node = numa_node; // TODO: or get the current numa node if -1? (now it allows anyone to allocate on -1) - arena->is_large = true; - arena->is_zero_init = true; - arena->is_committed = true; - arena->search_idx = 0; - arena->blocks_dirty = &arena->blocks_inuse[fields]; // just after inuse bitmap - arena->blocks_committed = NULL; - // the bitmaps are already zero initialized due to os_alloc - // just claim leftover blocks if needed - ptrdiff_t post = (fields * MI_BITMAP_FIELD_BITS) - bcount; - mi_assert_internal(post >= 0); - if (post > 0) { - // don't use leftover bits at the end - mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post); - mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL); - } - - mi_arena_add(arena); return 0; } diff --git a/src/bitmap.inc.c b/src/bitmap.inc.c index 2d6df46e..739ab2b6 100644 --- a/src/bitmap.inc.c +++ b/src/bitmap.inc.c @@ -61,7 +61,9 @@ static inline size_t mi_bitmap_index_bit(mi_bitmap_index_t bitmap_idx) { // The bit mask for a given number of blocks at a specified bit index. static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) { mi_assert_internal(count + bitidx <= MI_BITMAP_FIELD_BITS); - if (count == MI_BITMAP_FIELD_BITS) return MI_BITMAP_FIELD_FULL; + mi_assert_internal(count > 0); + if (count >= MI_BITMAP_FIELD_BITS) return MI_BITMAP_FIELD_FULL; + if (count == 0) return 0; return ((((uintptr_t)1 << count) - 1) << bitidx); } @@ -137,6 +139,7 @@ static inline bool mi_bitmap_try_claim_field(mi_bitmap_t bitmap, size_t bitmap_f static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx) { mi_assert_internal(bitmap_idx != NULL); + mi_assert_internal(count <= MI_BITMAP_FIELD_BITS); _Atomic(uintptr_t)* field = &bitmap[idx]; uintptr_t map = mi_atomic_load_relaxed(field); if (map==MI_BITMAP_FIELD_FULL) return false; // short cut @@ -185,10 +188,12 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx } -// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success. -// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never span fields. -static inline bool mi_bitmap_try_find_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t* bitmap_idx) { - for (size_t idx = 0; idx < bitmap_fields; idx++) { +// Starts at idx, and wraps around to search in all `bitmap_fields` fields. +// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields. +static inline bool mi_bitmap_try_find_from_claim(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) { + size_t idx = start_field_idx; + for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) { + if (idx >= bitmap_fields) idx = 0; // wrap if (mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { return true; } @@ -196,6 +201,13 @@ static inline bool mi_bitmap_try_find_claim(mi_bitmap_t bitmap, size_t bitmap_fi return false; } +// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success. +// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never span fields. +static inline bool mi_bitmap_try_find_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t count, mi_bitmap_index_t* bitmap_idx) { + return mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, 0, count, bitmap_idx); +} + + // Set `count` bits at `bitmap_idx` to 0 atomically // Returns `true` if all `count` bits were 1 previously. static inline bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { @@ -244,4 +256,234 @@ static inline bool mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fi } +//-------------------------------------------------------------------------- +// the `_across` functions work on bitmaps where sequences can cross over +// between the fields. This is used in arena allocation +//-------------------------------------------------------------------------- + +// 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. +static inline 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); + + // check initial trailing zeros + _Atomic(uintptr_t)* field = &bitmap[idx]; + uintptr_t map = mi_atomic_load_relaxed(field); + const uintptr_t bitidx = (map==0 ? 0 : mi_bsr(map) + 1); + const size_t initial = MI_BITMAP_FIELD_BITS - bitidx; // count of initial zeros starting at idx + if (initial == 0) return false; + if (initial >= count) return mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields + if (_mi_divide_up(count - initial, MI_BITMAP_FIELD_BITS) >= (bitmap_fields - idx)) return false; // not enough entries + + // scan ahead + size_t found = initial; + uintptr_t mask = 0; // mask bits for the final field + while(found < count) { + field++; + map = mi_atomic_load_relaxed(field); + const uintptr_t mask_bits = (found + MI_BITMAP_FIELD_BITS <= count ? MI_BITMAP_FIELD_BITS : (count - found)); + mask = mi_bitmap_mask_(mask_bits, 0); + if ((map & mask) != 0) return false; + found += mask_bits; + } + mi_assert_internal(field < &bitmap[bitmap_fields]); + + // found range of zeros up to the final field; mask contains mask in the final field + // now claim it atomically + _Atomic(uintptr_t)* const final_field = field; + const uintptr_t final_mask = mask; + _Atomic(uintptr_t)* const initial_field = &bitmap[idx]; + const uintptr_t initial_mask = mi_bitmap_mask_(initial, MI_BITMAP_FIELD_BITS - initial); + + // initial field + uintptr_t newmap; + field = initial_field; + map = mi_atomic_load_relaxed(field); + do { + newmap = map | initial_mask; + if ((map & initial_mask) != 0) { goto rollback; }; + } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); + + // intermediate fields + while (++field < final_field) { + newmap = mi_bitmap_mask_(MI_BITMAP_FIELD_BITS, 0); + map = 0; + if (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)) { goto rollback; } + } + + // final field + mi_assert_internal(field == final_field); + map = mi_atomic_load_relaxed(field); + do { + newmap = map | final_mask; + if ((map & final_mask) != 0) { goto rollback; } + } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); + + // claimed! + *bitmap_idx = mi_bitmap_index_create(idx, bitidx); + return true; + +rollback: + // roll back intermediate fields + while (--field > initial_field) { + newmap = 0; + map = mi_bitmap_mask_(MI_BITMAP_FIELD_BITS, 0); + mi_assert_internal(mi_atomic_load_relaxed(field) == map); + mi_atomic_store_release(field, newmap); + } + if (field == initial_field) { + map = mi_atomic_load_relaxed(field); + do { + mi_assert_internal((map & initial_mask) == initial_mask); + newmap = map & ~initial_mask; + } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); + } + // retry? (we make a recursive call instead of goto to be able to use const declarations) + if (retries < 4) { + return mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, retries+1, bitmap_idx); + } + else { + return false; + } +} + + +// 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. +static inline 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==1) return mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, start_field_idx, count, bitmap_idx); + size_t idx = start_field_idx; + for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) { + if (idx >= bitmap_fields) idx = 0; // wrap + // try to claim inside the field + if (count <= MI_BITMAP_FIELD_BITS) { + if (mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { + return true; + } + } + // try to claim across fields + if (mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, 0, bitmap_idx)) { + return true; + } + } + return false; +} + +// Helper for masks across fields; returns the mid count, post_mask may be 0 +static inline size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t bitmap_fields, size_t count, uintptr_t* pre_mask, uintptr_t* mid_mask, uintptr_t* post_mask) { + UNUSED_RELEASE(bitmap_fields); + const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); + if (mi_likely(bitidx + count <= MI_BITMAP_FIELD_BITS)) { + *pre_mask = mi_bitmap_mask_(count, bitidx); + *mid_mask = 0; + *post_mask = 0; + mi_assert_internal(mi_bitmap_index_field(bitmap_idx) < bitmap_fields); + return 0; + } + else { + const size_t pre_bits = MI_BITMAP_FIELD_BITS - bitidx; + mi_assert_internal(pre_bits < count); + *pre_mask = mi_bitmap_mask_(pre_bits, bitidx); + count -= pre_bits; + const size_t mid_count = (count / MI_BITMAP_FIELD_BITS); + *mid_mask = MI_BITMAP_FIELD_FULL; + count %= MI_BITMAP_FIELD_BITS; + *post_mask = (count==0 ? 0 : mi_bitmap_mask_(count, 0)); + mi_assert_internal(mi_bitmap_index_field(bitmap_idx) + mid_count + (count==0 ? 0 : 1) < bitmap_fields); + return mid_count; + } +} + +// Set `count` bits at `bitmap_idx` to 0 atomically +// Returns `true` if all `count` bits were 1 previously. +static inline bool mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { + size_t idx = mi_bitmap_index_field(bitmap_idx); + uintptr_t pre_mask; + uintptr_t mid_mask; + uintptr_t post_mask; + size_t mid_count = mi_bitmap_mask_across(bitmap_idx, bitmap_fields, count, &pre_mask, &mid_mask, &post_mask); + bool all_one = true; + _Atomic(uintptr_t)*field = &bitmap[idx]; + uintptr_t prev = mi_atomic_and_acq_rel(field++, ~pre_mask); + if ((prev & pre_mask) != pre_mask) all_one = false; + while(mid_count-- > 0) { + prev = mi_atomic_and_acq_rel(field++, ~mid_mask); + if ((prev & mid_mask) != mid_mask) all_one = false; + } + if (post_mask!=0) { + prev = mi_atomic_and_acq_rel(field, ~post_mask); + if ((prev & post_mask) != post_mask) all_one = false; + } + return all_one; +} + +// Set `count` bits at `bitmap_idx` to 1 atomically +// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. +static inline bool mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero) { + size_t idx = mi_bitmap_index_field(bitmap_idx); + uintptr_t pre_mask; + uintptr_t mid_mask; + uintptr_t post_mask; + size_t mid_count = mi_bitmap_mask_across(bitmap_idx, bitmap_fields, count, &pre_mask, &mid_mask, &post_mask); + bool all_zero = true; + bool any_zero = false; + _Atomic(uintptr_t)*field = &bitmap[idx]; + uintptr_t prev = mi_atomic_or_acq_rel(field++, pre_mask); + if ((prev & pre_mask) != 0) all_zero = false; + if ((prev & pre_mask) != pre_mask) any_zero = true; + while (mid_count-- > 0) { + prev = mi_atomic_or_acq_rel(field++, mid_mask); + if ((prev & mid_mask) != 0) all_zero = false; + if ((prev & mid_mask) != mid_mask) any_zero = true; + } + if (post_mask!=0) { + prev = mi_atomic_or_acq_rel(field, post_mask); + if ((prev & post_mask) != 0) all_zero = false; + if ((prev & post_mask) != post_mask) any_zero = true; + } + if (pany_zero != NULL) *pany_zero = any_zero; + return all_zero; +} + + +// Returns `true` if all `count` bits were 1. +// `any_ones` is `true` if there was at least one bit set to one. +static inline bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_ones) { + size_t idx = mi_bitmap_index_field(bitmap_idx); + uintptr_t pre_mask; + uintptr_t mid_mask; + uintptr_t post_mask; + size_t mid_count = mi_bitmap_mask_across(bitmap_idx, bitmap_fields, count, &pre_mask, &mid_mask, &post_mask); + bool all_ones = true; + bool any_ones = false; + _Atomic(uintptr_t)* field = &bitmap[idx]; + uintptr_t prev = mi_atomic_load_relaxed(field++); + if ((prev & pre_mask) != pre_mask) all_ones = false; + if ((prev & pre_mask) != 0) any_ones = true; + while (mid_count-- > 0) { + prev = mi_atomic_load_relaxed(field++); + if ((prev & pre_mask) != pre_mask) all_ones = false; + if ((prev & pre_mask) != 0) any_ones = true; + } + if (post_mask!=0) { + prev = mi_atomic_load_relaxed(field); + if ((prev & pre_mask) != pre_mask) all_ones = false; + if ((prev & pre_mask) != 0) any_ones = true; + } + if (pany_ones != NULL) *pany_ones = any_ones; + return all_ones; +} + +static inline bool mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { + return mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, NULL); +} + +static inline bool mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { + bool any_ones; + mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, &any_ones); + return any_ones; +} + #endif diff --git a/src/os.c b/src/os.c index 6985587c..437b8f1a 100644 --- a/src/os.c +++ b/src/os.c @@ -623,9 +623,9 @@ void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { _mi_os_free_ex(p, size, true, stats); } -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld) +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_stats_t* tld_stats) { - UNUSED(tld); + UNUSED(tld_stats); if (size == 0) return NULL; size = _mi_os_good_alloc_size(size); alignment = _mi_align_up(alignment, _mi_os_page_size()); diff --git a/test/main-override-static.c b/test/main-override-static.c index 0b73bb61..6e4572f7 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -14,6 +14,7 @@ static void block_overflow1(); static void invalid_free(); static void test_aslr(void); static void test_process_info(void); +static void test_reserved(void); int main() { mi_version(); @@ -24,7 +25,8 @@ int main() { // corrupt_free(); // block_overflow1(); // test_aslr(); - invalid_free(); + // invalid_free(); + // test_reserved(); void* p1 = malloc(78); void* p2 = malloc(24); @@ -147,4 +149,20 @@ static void test_process_info(void) { } mi_process_info(&user_msecs, &system_msecs, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); printf("\n\n*** process info: user: %3zd.%03zd s, rss: %zd b, commit: %zd b\n\n", user_msecs/1000, user_msecs%1000, peak_rss, peak_commit); -} \ No newline at end of file +} + +static void test_reserved(void) { +#define KiB 1024ULL +#define MiB (KiB*KiB) +#define GiB (MiB*KiB) + mi_reserve_os_memory(4*GiB, false, true); + void* p1 = malloc(100); + void* p2 = malloc(100000); + void* p3 = malloc(2*GiB); + void* p4 = malloc(1*GiB + 100000); + free(p1); + free(p2); + free(p3); + p3 = malloc(1*GiB); + free(p4); +} diff --git a/test/test-stress.c b/test/test-stress.c index 05dbd4b4..68faef90 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -217,7 +217,7 @@ static void test_leak(void) { } #endif -int main(int argc, char** argv) { +int main(int argc, char** argv) { // > mimalloc-test-stress [THREADS] [SCALE] [ITER] if (argc >= 2) { char* end; @@ -235,6 +235,7 @@ int main(int argc, char** argv) { if (n > 0) ITER = n; } printf("Using %d threads with a %d%% load-per-thread and %d iterations\n", THREADS, SCALE, ITER); + //mi_reserve_os_memory(512*1024*1024ULL, true, true); //int res = mi_reserve_huge_os_pages(4,1); //printf("(reserve huge: %i\n)", res); From 30b993ecf3c668097562391e8ee7e70598c30ac0 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 8 Sep 2020 09:27:57 -0700 Subject: [PATCH 104/172] consolidate bit scan operations --- include/mimalloc-internal.h | 103 +++++++++++++++++++++++++++++++++++- src/bitmap.inc.c | 58 ++++---------------- src/os.c | 2 +- src/page-queue.c | 46 +--------------- 4 files changed, 113 insertions(+), 96 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 145f6f92..29f3749c 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -107,7 +107,6 @@ void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page); // callback fro size_t _mi_bin_size(uint8_t bin); // for stats uint8_t _mi_bin(size_t size); // for stats -uint8_t _mi_bsr(uintptr_t x); // bit-scan-right, used on BSD in "os.c" // "heap.c" void _mi_heap_destroy_pages(mi_heap_t* heap); @@ -744,5 +743,107 @@ static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept { } #endif +// ----------------------------------------------------------------------- +// Count bits: trailing or leading zeros (with MI_INTPTR_BITS on all zero) +// ----------------------------------------------------------------------- + +#if defined(__GNUC__) + +#include // LONG_MAX +#define MI_HAVE_FAST_BITSCAN +static inline size_t mi_clz(uintptr_t x) { + if (x==0) return MI_INTPTR_BITS; +#if (INTPTR_MAX == LONG_MAX) + return __builtin_clzl(x); +#else + return __builtin_clzll(x); +#endif +} +static inline size_t mi_ctz(uintptr_t x) { + if (x==0) return MI_INTPTR_BITS; +#if (INTPTR_MAX == LONG_MAX) + return __builtin_ctzl(x); +#else + return __builtin_ctzll(x); +#endif +} + +#elif defined(_MSC_VER) + +#define MI_HAVE_FAST_BITSCAN +static inline size_t mi_clz(uintptr_t x) { + if (x==0) return MI_INTPTR_BITS; + unsigned long idx; +#if (INTPTR_MAX == LONG_MAX) + _BitScanReverse(&idx, x); +#else + _BitScanReverse64(&idx, x); +#endif + return ((MI_INTPTR_BITS - 1) - idx); +} +static inline size_t mi_ctz(uintptr_t x) { + if (x==0) return MI_INTPTR_BITS; + unsigned long idx; +#if (INTPTR_MAX == LONG_MAX) + _BitScanForward(&idx, x); +#else + _BitScanForward64(&idx, x); +#endif + return idx; +} + +#else +static inline size_t mi_ctz32(uint32_t x) { + // de Bruijn multiplication, see + static const unsigned char 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]; +} +static inline size_t mi_clz32(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, + 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 + }; + if (x==0) return 32; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return debruijn[(uint32_t)(x * 0x07C4ACDDUL) >> 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(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 +} + +#endif + +// "bit scan reverse": Return index of the highest bit (or MI_INTPTR_BITS if `x` is zero) +static inline size_t mi_bsr(uintptr_t x) { + return (x==0 ? MI_INTPTR_BITS : MI_INTPTR_BITS - 1 - mi_clz(x)); +} + #endif diff --git a/src/bitmap.inc.c b/src/bitmap.inc.c index 739ab2b6..9d7184e7 100644 --- a/src/bitmap.inc.c +++ b/src/bitmap.inc.c @@ -68,47 +68,6 @@ static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) { } -/* ----------------------------------------------------------- - Use bit scan forward/reverse to quickly find the first zero bit if it is available ------------------------------------------------------------ */ -#if defined(_MSC_VER) -#define MI_HAVE_BITSCAN -#include -#ifndef MI_64 -#if MI_INTPTR_SIZE==8 -#define MI_64(f) f##64 -#else -#define MI_64(f) f -#endif -#endif - -static inline size_t mi_bsf(uintptr_t x) { - if (x==0) return 8*MI_INTPTR_SIZE; - DWORD idx; - MI_64(_BitScanForward)(&idx, x); - return idx; -} -static inline size_t mi_bsr(uintptr_t x) { - if (x==0) return 8*MI_INTPTR_SIZE; - DWORD idx; - MI_64(_BitScanReverse)(&idx, x); - return idx; -} -#elif defined(__GNUC__) || defined(__clang__) -#include // LONG_MAX -#define MI_HAVE_BITSCAN -#if (INTPTR_MAX == LONG_MAX) -# define MI_L(x) x##l -#else -# define MI_L(x) x##ll -#endif -static inline size_t mi_bsf(uintptr_t x) { - return (x==0 ? 8*MI_INTPTR_SIZE : MI_L(__builtin_ctz)(x)); -} -static inline size_t mi_bsr(uintptr_t x) { - return (x==0 ? 8*MI_INTPTR_SIZE : (8*MI_INTPTR_SIZE - 1) - MI_L(__builtin_clz)(x)); -} -#endif /* ----------------------------------------------------------- Claim a bit sequence atomically @@ -148,8 +107,8 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx const uintptr_t mask = mi_bitmap_mask_(count, 0); const size_t bitidx_max = MI_BITMAP_FIELD_BITS - count; -#ifdef MI_HAVE_BITSCAN - size_t bitidx = mi_bsf(~map); // quickly find the first zero bit if possible +#ifdef MI_HAVE_FAST_BITSCAN + size_t bitidx = mi_ctz(~map); // quickly find the first zero bit if possible #else size_t bitidx = 0; // otherwise start at 0 #endif @@ -157,7 +116,8 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx // scan linearly for a free range of zero bits while (bitidx <= bitidx_max) { - if ((map & m) == 0) { // are the mask bits free at bitidx? + const uintptr_t mapm = map & m; + if (mapm == 0) { // are the mask bits free at bitidx? mi_assert_internal((m >> bitidx) == mask); // no overflow? const uintptr_t newmap = map | m; mi_assert_internal((newmap^map) >> bitidx == mask); @@ -173,8 +133,8 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx } else { // on to the next bit range -#ifdef MI_HAVE_BITSCAN - const size_t shift = (count == 1 ? 1 : mi_bsr(map & m) - bitidx + 1); +#ifdef MI_HAVE_FAST_BITSCAN + const size_t shift = (count == 1 ? 1 : mi_bsr(mapm) - bitidx + 1); mi_assert_internal(shift > 0 && shift <= count); #else const size_t shift = 1; @@ -270,8 +230,8 @@ static inline bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, siz // check initial trailing zeros _Atomic(uintptr_t)* field = &bitmap[idx]; uintptr_t map = mi_atomic_load_relaxed(field); - const uintptr_t bitidx = (map==0 ? 0 : mi_bsr(map) + 1); - const size_t initial = MI_BITMAP_FIELD_BITS - bitidx; // count of initial zeros starting at idx + const size_t initial = mi_clz(map); // count of initial zeros starting at idx + mi_assert_internal(initial >= 0 && initial <= MI_BITMAP_FIELD_BITS); if (initial == 0) return false; if (initial >= count) return mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields if (_mi_divide_up(count - initial, MI_BITMAP_FIELD_BITS) >= (bitmap_fields - idx)) return false; // not enough entries @@ -321,7 +281,7 @@ static inline bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, siz } while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap)); // claimed! - *bitmap_idx = mi_bitmap_index_create(idx, bitidx); + *bitmap_idx = mi_bitmap_index_create(idx, MI_BITMAP_FIELD_BITS - initial); return true; rollback: diff --git a/src/os.c b/src/os.c index 437b8f1a..e8d6b74a 100644 --- a/src/os.c +++ b/src/os.c @@ -358,7 +358,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro int fd = -1; #if defined(MAP_ALIGNED) // BSD if (try_alignment > 0) { - size_t n = _mi_bsr(try_alignment); + size_t n = mi_bsr(try_alignment); if (((size_t)1 << n) == try_alignment && n >= 12 && n <= 30) { // alignment is a power of 2 and 4096 <= alignment <= 1GiB flags |= MAP_ALIGNED(n); } diff --git a/src/page-queue.c b/src/page-queue.c index 37719e02..57e3d6a5 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -49,50 +49,6 @@ static inline bool mi_page_queue_is_special(const mi_page_queue_t* pq) { Bins ----------------------------------------------------------- */ -// Bit scan reverse: return the index of the highest bit. -static inline uint8_t mi_bsr32(uint32_t x); - -#if defined(_MSC_VER) -#include -static inline uint8_t mi_bsr32(uint32_t x) { - uint32_t idx; - _BitScanReverse((DWORD*)&idx, x); - return (uint8_t)idx; -} -#elif defined(__GNUC__) || defined(__clang__) -static inline uint8_t mi_bsr32(uint32_t x) { - return (31 - __builtin_clz(x)); -} -#else -static inline uint8_t mi_bsr32(uint32_t x) { - // de Bruijn multiplication, see - static const uint8_t debruijn[32] = { - 31, 0, 22, 1, 28, 23, 18, 2, 29, 26, 24, 10, 19, 7, 3, 12, - 30, 21, 27, 17, 25, 9, 6, 11, 20, 16, 8, 5, 15, 4, 14, 13, - }; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x++; - return debruijn[(x*0x076be629) >> 27]; -} -#endif - -// Bit scan reverse: return the index of the highest bit. -uint8_t _mi_bsr(uintptr_t x) { - if (x == 0) return 0; -#if MI_INTPTR_SIZE==8 - uint32_t hi = (x >> 32); - return (hi == 0 ? mi_bsr32((uint32_t)x) : 32 + mi_bsr32(hi)); -#elif MI_INTPTR_SIZE==4 - return mi_bsr32(x); -#else -# error "define bsr for non-32 or 64-bit platforms" -#endif -} - // Return the bin for a given field size. // Returns MI_BIN_HUGE if the size is too large. // We use `wsize` for the size in "machine word sizes", @@ -125,7 +81,7 @@ extern inline uint8_t _mi_bin(size_t size) { #endif wsize--; // find the highest bit - uint8_t b = mi_bsr32((uint32_t)wsize); + uint8_t b = (uint8_t)mi_bsr(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 From c86459afef12f7830f3c5eda5d803a74fcf3134e Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 8 Sep 2020 10:14:13 -0700 Subject: [PATCH 105/172] split bitmap code into separate header and source file --- CMakeLists.txt | 1 + ide/vs2017/mimalloc-override.vcxproj | 4 +- ide/vs2017/mimalloc-override.vcxproj.filters | 8 +- ide/vs2017/mimalloc.vcxproj | 2 + ide/vs2017/mimalloc.vcxproj.filters | 8 +- ide/vs2019/mimalloc-override.vcxproj | 5 +- ide/vs2019/mimalloc-override.vcxproj.filters | 9 +- ide/vs2019/mimalloc.vcxproj | 5 +- ide/vs2019/mimalloc.vcxproj.filters | 9 +- include/mimalloc-internal.h | 1 + src/arena.c | 14 +-- src/{bitmap.inc.c => bitmap.c} | 120 ++++++------------- src/bitmap.h | 101 ++++++++++++++++ src/region.c | 26 ++-- src/static.c | 1 + 15 files changed, 194 insertions(+), 120 deletions(-) rename src/{bitmap.inc.c => bitmap.c} (72%) create mode 100644 src/bitmap.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 35460e85..b7996f36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ set(mi_sources src/stats.c src/random.c src/os.c + src/bitmap.c src/arena.c src/region.c src/segment.c diff --git a/ide/vs2017/mimalloc-override.vcxproj b/ide/vs2017/mimalloc-override.vcxproj index 990d6ca9..a1266dc9 100644 --- a/ide/vs2017/mimalloc-override.vcxproj +++ b/ide/vs2017/mimalloc-override.vcxproj @@ -215,6 +215,7 @@ + @@ -232,6 +233,7 @@ + @@ -251,4 +253,4 @@ - + \ No newline at end of file diff --git a/ide/vs2017/mimalloc-override.vcxproj.filters b/ide/vs2017/mimalloc-override.vcxproj.filters index 02652658..e045ed8c 100644 --- a/ide/vs2017/mimalloc-override.vcxproj.filters +++ b/ide/vs2017/mimalloc-override.vcxproj.filters @@ -29,6 +29,9 @@ Header Files + + Header Files + @@ -76,5 +79,8 @@ Source Files + + Source Files + - + \ No newline at end of file diff --git a/ide/vs2017/mimalloc.vcxproj b/ide/vs2017/mimalloc.vcxproj index 1ff1af9c..8102b9fe 100644 --- a/ide/vs2017/mimalloc.vcxproj +++ b/ide/vs2017/mimalloc.vcxproj @@ -230,6 +230,7 @@ + @@ -253,6 +254,7 @@ + diff --git a/ide/vs2017/mimalloc.vcxproj.filters b/ide/vs2017/mimalloc.vcxproj.filters index 43660519..500292c5 100644 --- a/ide/vs2017/mimalloc.vcxproj.filters +++ b/ide/vs2017/mimalloc.vcxproj.filters @@ -59,6 +59,9 @@ Source Files + + Source Files + @@ -79,5 +82,8 @@ Header Files + + Header Files + - + \ No newline at end of file diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj index a0e79fb0..182ddab1 100644 --- a/ide/vs2019/mimalloc-override.vcxproj +++ b/ide/vs2019/mimalloc-override.vcxproj @@ -215,6 +215,7 @@ + @@ -232,9 +233,7 @@ - - true - + diff --git a/ide/vs2019/mimalloc-override.vcxproj.filters b/ide/vs2019/mimalloc-override.vcxproj.filters index 8e36f50e..c06fd1de 100644 --- a/ide/vs2019/mimalloc-override.vcxproj.filters +++ b/ide/vs2019/mimalloc-override.vcxproj.filters @@ -40,15 +40,15 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + @@ -69,6 +69,9 @@ Header Files + + Source Files + diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index e18db0c5..6c7e276c 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -220,8 +220,8 @@ - - true + + false @@ -246,6 +246,7 @@ + diff --git a/ide/vs2019/mimalloc.vcxproj.filters b/ide/vs2019/mimalloc.vcxproj.filters index 4704fb2e..4cd0eb2e 100644 --- a/ide/vs2019/mimalloc.vcxproj.filters +++ b/ide/vs2019/mimalloc.vcxproj.filters @@ -46,10 +46,10 @@ Source Files - + Source Files - + Source Files @@ -72,6 +72,9 @@ Header Files + + Source Files + @@ -81,4 +84,4 @@ {852a14ae-6dde-4e95-8077-ca705e97e5af} - + \ No newline at end of file diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 29f3749c..1f4aacef 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -770,6 +770,7 @@ static inline size_t mi_ctz(uintptr_t x) { #elif defined(_MSC_VER) +#include // LONG_MAX #define MI_HAVE_FAST_BITSCAN static inline size_t mi_clz(uintptr_t x) { if (x==0) return MI_INTPTR_BITS; diff --git a/src/arena.c b/src/arena.c index 20a89445..cbc5ba6d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -32,7 +32,7 @@ of 256MiB in practice. #include // memset #include // ENOMEM -#include "bitmap.inc.c" // atomic bitmap +#include "bitmap.h" // atomic bitmap // os.c @@ -105,7 +105,7 @@ static size_t mi_block_count_of_size(size_t size) { static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx) { size_t idx = mi_atomic_load_acquire(&arena->search_idx); // start from last search - if (mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) { + if (_mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) { mi_atomic_store_release(&arena->search_idx, idx); // start search from here next time return true; }; @@ -126,7 +126,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n // claimed it! set the dirty bits (todo: no need for an atomic op here?) void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE); *memid = mi_arena_id_create(arena_index, bitmap_index); - *is_zero = mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL); + *is_zero = _mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL); *large = arena->is_large; if (arena->is_committed) { // always committed @@ -135,7 +135,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n else if (*commit) { // arena not committed as a whole, but commit requested: ensure commit now bool any_uncommitted; - mi_bitmap_claim_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted); + _mi_bitmap_claim_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted); if (any_uncommitted) { bool commit_zero; _mi_os_commit(p, needed_bcount * MI_ARENA_BLOCK_SIZE, &commit_zero, tld->stats); @@ -144,7 +144,7 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n } else { // no need to commit, but check if already fully committed - *commit = mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index); + *commit = _mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index); } return p; } @@ -235,7 +235,7 @@ void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_s return; } const size_t blocks = mi_block_count_of_size(size); - bool ones = mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx); + bool ones = _mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx); if (!ones) { _mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size); return; @@ -287,7 +287,7 @@ bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_la if (post > 0) { // don't use leftover bits at the end mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post); - mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL); + _mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL); } mi_arena_add(arena); diff --git a/src/bitmap.inc.c b/src/bitmap.c similarity index 72% rename from src/bitmap.inc.c rename to src/bitmap.c index 9d7184e7..cc710963 100644 --- a/src/bitmap.inc.c +++ b/src/bitmap.c @@ -1,63 +1,30 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019, Microsoft Research, Daan Leijen +Copyright (c) 2019,2020 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. -----------------------------------------------------------------------------*/ /* ---------------------------------------------------------------------------- -This file is meant to be included in other files for efficiency. -It implements a bitmap that can set/reset sequences of bits atomically -and is used to concurrently claim memory ranges. +Concurrent bitmap that can set/reset sequences of bits atomically, +represeted as an array of fields where each field is a machine word (`uintptr_t`) -A bitmap is an array of fields where each field is a machine word (`uintptr_t`) +There are two api's; the standard one cannot have sequences that cross +between the bitmap fields (and a sequence must be <= MI_BITMAP_FIELD_BITS). +(this is used in region allocation) -A current limitation is that the bit sequences cannot cross fields -and that the sequence must be smaller or equal to the bits in a field. +The `_across` postfixed functions do allow sequences that can cross over +between the fields. (This is used in arena allocation) ---------------------------------------------------------------------------- */ -#pragma once -#ifndef MI_BITMAP_C -#define MI_BITMAP_C #include "mimalloc.h" #include "mimalloc-internal.h" +#include "bitmap.h" /* ----------------------------------------------------------- Bitmap definition ----------------------------------------------------------- */ -#define MI_BITMAP_FIELD_BITS (8*MI_INTPTR_SIZE) -#define MI_BITMAP_FIELD_FULL (~((uintptr_t)0)) // all bits set - -// An atomic bitmap of `uintptr_t` fields -typedef _Atomic(uintptr_t) mi_bitmap_field_t; -typedef mi_bitmap_field_t* mi_bitmap_t; - -// A bitmap index is the index of the bit in a bitmap. -typedef size_t mi_bitmap_index_t; - -// Create a bit index. -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; -} - -// Get the field index from a bit index. -static inline size_t mi_bitmap_index_field(mi_bitmap_index_t bitmap_idx) { - return (bitmap_idx / MI_BITMAP_FIELD_BITS); -} - -// Get the bit index in a bitmap field -static inline size_t mi_bitmap_index_bit_in_field(mi_bitmap_index_t bitmap_idx) { - return (bitmap_idx % MI_BITMAP_FIELD_BITS); -} - -// Get the full bit index -static inline size_t mi_bitmap_index_bit(mi_bitmap_index_t bitmap_idx) { - return bitmap_idx; -} - - // The bit mask for a given number of blocks at a specified bit index. static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) { mi_assert_internal(count + bitidx <= MI_BITMAP_FIELD_BITS); @@ -73,29 +40,9 @@ static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) { Claim a bit sequence atomically ----------------------------------------------------------- */ -// Try to atomically claim a sequence of `count` bits at in `idx` -// in the bitmap field. Returns `true` on success. -static inline bool mi_bitmap_try_claim_field(mi_bitmap_t bitmap, size_t bitmap_fields, const size_t count, mi_bitmap_index_t bitmap_idx) { - const size_t idx = mi_bitmap_index_field(bitmap_idx); - const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); - const uintptr_t mask = mi_bitmap_mask_(count, bitidx); - mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields); - mi_assert_internal(bitidx + count <= MI_BITMAP_FIELD_BITS); - - uintptr_t field = mi_atomic_load_relaxed(&bitmap[idx]); - if ((field & mask) == 0) { // free? - if (mi_atomic_cas_strong_acq_rel(&bitmap[idx], &field, (field|mask))) { - // claimed! - return true; - } - } - return false; -} - - // Try to atomically claim a sequence of `count` bits in a single // field at `idx` in `bitmap`. Returns `true` on success. -static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx) +bool _mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx) { mi_assert_internal(bitmap_idx != NULL); mi_assert_internal(count <= MI_BITMAP_FIELD_BITS); @@ -150,27 +97,28 @@ static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx // Starts at idx, and wraps around to search in all `bitmap_fields` fields. // For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields. -static inline bool mi_bitmap_try_find_from_claim(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) { +bool _mi_bitmap_try_find_from_claim(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) { size_t idx = start_field_idx; for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) { if (idx >= bitmap_fields) idx = 0; // wrap - if (mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { + if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { return true; } } return false; } +/* // Find `count` bits of 0 and set them to 1 atomically; returns `true` on success. // For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never span fields. -static inline bool mi_bitmap_try_find_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t count, mi_bitmap_index_t* bitmap_idx) { - return mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, 0, count, bitmap_idx); +bool _mi_bitmap_try_find_claim(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t count, mi_bitmap_index_t* bitmap_idx) { + return _mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, 0, count, bitmap_idx); } - +*/ // Set `count` bits at `bitmap_idx` to 0 atomically // Returns `true` if all `count` bits were 1 previously. -static inline bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { +bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { const size_t idx = mi_bitmap_index_field(bitmap_idx); const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); const uintptr_t mask = mi_bitmap_mask_(count, bitidx); @@ -183,7 +131,7 @@ static inline bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, s // Set `count` bits at `bitmap_idx` to 1 atomically // Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. -static inline bool mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero) { +bool _mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero) { const size_t idx = mi_bitmap_index_field(bitmap_idx); const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); const uintptr_t mask = mi_bitmap_mask_(count, bitidx); @@ -195,7 +143,7 @@ static inline bool mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, siz } // Returns `true` if all `count` bits were 1. `any_ones` is `true` if there was at least one bit set to one. -static inline bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_ones) { +static bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_ones) { const size_t idx = mi_bitmap_index_field(bitmap_idx); const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); const uintptr_t mask = mi_bitmap_mask_(count, bitidx); @@ -205,11 +153,11 @@ static inline bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_field return ((field & mask) == mask); } -static inline bool mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { +bool _mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { return mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, NULL); } -static inline bool mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { +bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { bool any_ones; mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, &any_ones); return any_ones; @@ -223,7 +171,7 @@ static inline bool mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fi // 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. -static inline 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) +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); @@ -233,7 +181,7 @@ static inline bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, siz const size_t initial = mi_clz(map); // count of initial zeros starting at idx mi_assert_internal(initial >= 0 && initial <= MI_BITMAP_FIELD_BITS); if (initial == 0) return false; - if (initial >= count) return mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields + if (initial >= count) return _mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields if (_mi_divide_up(count - initial, MI_BITMAP_FIELD_BITS) >= (bitmap_fields - idx)) return false; // not enough entries // scan ahead @@ -311,15 +259,15 @@ 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. -static inline 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) { +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==1) return mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, start_field_idx, count, bitmap_idx); + if (count==1) return _mi_bitmap_try_find_from_claim(bitmap, bitmap_fields, start_field_idx, count, bitmap_idx); size_t idx = start_field_idx; for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) { if (idx >= bitmap_fields) idx = 0; // wrap // try to claim inside the field if (count <= MI_BITMAP_FIELD_BITS) { - if (mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { + if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) { return true; } } @@ -332,7 +280,7 @@ static inline bool mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, cons } // Helper for masks across fields; returns the mid count, post_mask may be 0 -static inline size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t bitmap_fields, size_t count, uintptr_t* pre_mask, uintptr_t* mid_mask, uintptr_t* post_mask) { +static size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t bitmap_fields, size_t count, uintptr_t* pre_mask, uintptr_t* mid_mask, uintptr_t* post_mask) { UNUSED_RELEASE(bitmap_fields); const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx); if (mi_likely(bitidx + count <= MI_BITMAP_FIELD_BITS)) { @@ -358,7 +306,7 @@ static inline size_t mi_bitmap_mask_across(mi_bitmap_index_t bitmap_idx, size_t // Set `count` bits at `bitmap_idx` to 0 atomically // Returns `true` if all `count` bits were 1 previously. -static inline bool mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { +bool _mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { size_t idx = mi_bitmap_index_field(bitmap_idx); uintptr_t pre_mask; uintptr_t mid_mask; @@ -381,7 +329,7 @@ static inline bool mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fi // Set `count` bits at `bitmap_idx` to 1 atomically // Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. -static inline bool mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero) { +bool _mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero) { size_t idx = mi_bitmap_index_field(bitmap_idx); uintptr_t pre_mask; uintptr_t mid_mask; @@ -410,7 +358,7 @@ static inline bool mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fiel // Returns `true` if all `count` bits were 1. // `any_ones` is `true` if there was at least one bit set to one. -static inline bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_ones) { +static bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_ones) { size_t idx = mi_bitmap_index_field(bitmap_idx); uintptr_t pre_mask; uintptr_t mid_mask; @@ -436,14 +384,14 @@ static inline bool mi_bitmap_is_claimedx_across(mi_bitmap_t bitmap, size_t bitma return all_ones; } -static inline bool mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { +bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { return mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, NULL); } -static inline bool mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { +/* +bool _mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { bool any_ones; mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, &any_ones); return any_ones; } - -#endif +*/ diff --git a/src/bitmap.h b/src/bitmap.h new file mode 100644 index 00000000..95f0d615 --- /dev/null +++ b/src/bitmap.h @@ -0,0 +1,101 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2019,2020 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. +-----------------------------------------------------------------------------*/ + +/* ---------------------------------------------------------------------------- +Concurrent bitmap that can set/reset sequences of bits atomically, +represeted as an array of fields where each field is a machine word (`uintptr_t`) + +There are two api's; the standard one cannot have sequences that cross +between the bitmap fields (and a sequence must be <= MI_BITMAP_FIELD_BITS). +(this is used in region allocation) + +The `_across` postfixed functions do allow sequences that can cross over +between the fields. (This is used in arena allocation) +---------------------------------------------------------------------------- */ +#pragma once +#ifndef MI_BITMAP_H +#define MI_BITMAP_H + +/* ----------------------------------------------------------- + Bitmap definition +----------------------------------------------------------- */ + +#define MI_BITMAP_FIELD_BITS (8*MI_INTPTR_SIZE) +#define MI_BITMAP_FIELD_FULL (~((uintptr_t)0)) // all bits set + +// An atomic bitmap of `uintptr_t` fields +typedef _Atomic(uintptr_t) mi_bitmap_field_t; +typedef mi_bitmap_field_t* mi_bitmap_t; + +// A bitmap index is the index of the bit in a bitmap. +typedef size_t mi_bitmap_index_t; + +// Create a bit index. +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; +} + +// Get the field index from a bit index. +static inline size_t mi_bitmap_index_field(mi_bitmap_index_t bitmap_idx) { + return (bitmap_idx / MI_BITMAP_FIELD_BITS); +} + +// Get the bit index in a bitmap field +static inline size_t mi_bitmap_index_bit_in_field(mi_bitmap_index_t bitmap_idx) { + return (bitmap_idx % MI_BITMAP_FIELD_BITS); +} + +// Get the full bit index +static inline size_t mi_bitmap_index_bit(mi_bitmap_index_t bitmap_idx) { + return bitmap_idx; +} + +/* ----------------------------------------------------------- + Claim a bit sequence atomically +----------------------------------------------------------- */ + +// Try to atomically claim a sequence of `count` bits in a single +// field at `idx` in `bitmap`. Returns `true` on success. +bool _mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx); + +// Starts at idx, and wraps around to search in all `bitmap_fields` fields. +// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never cross fields. +bool _mi_bitmap_try_find_from_claim(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. +bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); + +// Set `count` bits at `bitmap_idx` to 1 atomically +// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. +bool _mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero); + +bool _mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); +bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); + + +//-------------------------------------------------------------------------- +// the `_across` functions work on bitmaps where sequences can cross over +// between the fields. This is used in arena allocation +//-------------------------------------------------------------------------- + +// 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); + +// Set `count` bits at `bitmap_idx` to 0 atomically +// Returns `true` if all `count` bits were 1 previously. +bool _mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); + +// Set `count` bits at `bitmap_idx` to 1 atomically +// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit. +bool _mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero); + +bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); + +#endif diff --git a/src/region.c b/src/region.c index bebc29fd..a70853d4 100644 --- a/src/region.c +++ b/src/region.c @@ -37,7 +37,7 @@ Possible issues: #include // memset -#include "bitmap.inc.c" +#include "bitmap.h" // Internal raw OS interface size_t _mi_os_large_page_size(); @@ -200,7 +200,7 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, mi_atomic_store_release(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0)); mi_atomic_store_release(&r->reset, (uintptr_t)0); *bit_idx = 0; - mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL); + _mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL); mi_atomic_store_ptr_release(void,&r->start, start); // and share it @@ -248,7 +248,7 @@ static bool mi_region_try_claim(int numa_node, size_t blocks, bool allow_large, // if this region suits our demand (numa node matches, large OS page matches) if (mi_region_is_suitable(r, numa_node, allow_large)) { // then try to atomically claim a segment(s) in this region - if (mi_bitmap_try_find_claim_field(&r->in_use, 0, blocks, bit_idx)) { + if (_mi_bitmap_try_find_claim_field(&r->in_use, 0, blocks, bit_idx)) { tld->region_idx = idx; // remember the last found position *region = r; return true; @@ -277,7 +277,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo // ------------------------------------------------ // found a region and claimed `blocks` at `bit_idx`, initialize them now mi_assert_internal(region != NULL); - mi_assert_internal(mi_bitmap_is_claimed(®ion->in_use, 1, blocks, bit_idx)); + mi_assert_internal(_mi_bitmap_is_claimed(®ion->in_use, 1, blocks, bit_idx)); mi_region_info_t info; info.value = mi_atomic_load_acquire(®ion->info); @@ -285,7 +285,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo mi_assert_internal(!(info.x.is_large && !*is_large)); mi_assert_internal(start != NULL); - *is_zero = mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL); + *is_zero = _mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL); *is_large = info.x.is_large; *memid = mi_memid_create(region, bit_idx); void* p = start + (mi_bitmap_index_bit_in_field(bit_idx) * MI_SEGMENT_SIZE); @@ -294,7 +294,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo if (*commit) { // ensure commit bool any_uncommitted; - mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted); + _mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted); if (any_uncommitted) { mi_assert_internal(!info.x.is_large); bool commit_zero; @@ -304,12 +304,12 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo } else { // no need to commit, but check if already fully committed - *commit = mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx); + *commit = _mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx); } - mi_assert_internal(!*commit || mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx)); + mi_assert_internal(!*commit || _mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx)); // unreset reset blocks - if (mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)) { + if (_mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)) { // some blocks are still reset mi_assert_internal(!info.x.is_large); mi_assert_internal(!mi_option_is_enabled(mi_option_eager_commit) || *commit || mi_option_get(mi_option_eager_commit_delay) > 0); @@ -320,7 +320,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo if (reset_zero) *is_zero = true; } } - mi_assert_internal(!mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)); + mi_assert_internal(!_mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)); #if (MI_DEBUG>=2) if (*commit) { ((uint8_t*)p)[0] = 0; } @@ -409,12 +409,12 @@ void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_re // committed? if (full_commit && (size % MI_SEGMENT_SIZE) == 0) { - mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, NULL); + _mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, NULL); } if (any_reset) { // set the is_reset bits if any pages were reset - mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, NULL); + _mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, NULL); } // reset the blocks to reduce the working set. @@ -423,7 +423,7 @@ void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_re mi_option_is_enabled(mi_option_reset_decommits))) // cannot reset halfway committed segments, use only `option_page_reset` instead { bool any_unreset; - mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, &any_unreset); + _mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, &any_unreset); if (any_unreset) { _mi_abandoned_await_readers(); // ensure no more pending write (in case reset = decommit) _mi_mem_reset(p, blocks * MI_SEGMENT_SIZE, tld); diff --git a/src/static.c b/src/static.c index d024b01a..346aced1 100644 --- a/src/static.c +++ b/src/static.c @@ -23,6 +23,7 @@ terms of the MIT license. A copy of the license can be found in the file #include "stats.c" #include "random.c" #include "os.c" +#include "bitmap.c" #include "arena.c" #include "region.c" #include "segment.c" From 14b8d27386d904b6ea3016f253c2dbb676510805 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 8 Sep 2020 16:46:03 -0700 Subject: [PATCH 106/172] track pinned memory separately from large os pages --- include/mimalloc-internal.h | 2 +- include/mimalloc-types.h | 2 +- src/arena.c | 66 ++++++++++++++++++++++++------------- src/bitmap.c | 2 -- src/bitmap.h | 1 + src/init.c | 2 +- src/region.c | 39 ++++++++++++---------- src/segment.c | 26 ++++++++------- 8 files changed, 83 insertions(+), 57 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 1f4aacef..3c0210b3 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -64,7 +64,7 @@ void _mi_os_free(void* p, size_t size, mi_stats_t* stats); // to free th size_t _mi_os_good_alloc_size(size_t size); // memory.c -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, size_t* id, mi_os_tld_t* tld); +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* id, mi_os_tld_t* tld); void _mi_mem_free(void* p, size_t size, size_t id, bool fully_committed, bool any_reset, mi_os_tld_t* tld); bool _mi_mem_reset(void* p, size_t size, mi_os_tld_t* tld); diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index d9bd14eb..8ffcd2fc 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -261,7 +261,7 @@ typedef enum mi_page_kind_e { typedef struct mi_segment_s { // memory fields size_t memid; // id for the os-level memory manager - bool mem_is_fixed; // `true` if we cannot decommit/reset/protect in this memory (i.e. when allocated using large OS pages) + bool mem_is_pinned; // `true` if we cannot decommit/reset/protect in this memory (i.e. when allocated using large OS pages) bool mem_is_committed; // `true` if the whole segment is eagerly committed // segment fields diff --git a/src/arena.c b/src/arena.c index cbc5ba6d..91cac309 100644 --- a/src/arena.c +++ b/src/arena.c @@ -44,6 +44,7 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_sec void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* 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); /* ----------------------------------------------------------- Arena allocation @@ -61,12 +62,12 @@ typedef struct mi_arena_s { size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`) int numa_node; // associated NUMA node bool is_zero_init; // is the arena zero initialized? - bool is_committed; // is the memory committed - bool is_large; // large OS page allocated - _Atomic(uintptr_t) search_idx; // optimization to start the search for free blocks + bool is_committed; // is the memory fully committed? (if so, block_committed == NULL) + bool is_large; // large- or huge OS pages (always committed) + _Atomic(uintptr_t) search_idx; // optimization to start the search for free blocks mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero? mi_bitmap_field_t* blocks_committed; // if `!is_committed`, are the blocks committed? - mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) + mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`) } mi_arena_t; @@ -118,16 +119,17 @@ static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* ----------------------------------------------------------- */ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t needed_bcount, - bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld) + bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld) { mi_bitmap_index_t bitmap_index; if (!mi_arena_alloc(arena, needed_bcount, &bitmap_index)) return NULL; // claimed it! set the dirty bits (todo: no need for an atomic op here?) - void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE); - *memid = mi_arena_id_create(arena_index, bitmap_index); - *is_zero = _mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL); - *large = arena->is_large; + void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE); + *memid = mi_arena_id_create(arena_index, bitmap_index); + *is_zero = _mi_bitmap_claim_across(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL); + *large = arena->is_large; + *is_pinned = (arena->is_large || arena->is_committed); if (arena->is_committed) { // always committed *commit = true; @@ -149,14 +151,14 @@ static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t n return p; } -void* _mi_arena_alloc_aligned(size_t size, size_t alignment, - bool* commit, bool* large, bool* is_zero, +void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld) { - mi_assert_internal(commit != NULL && large != NULL && is_zero != NULL && memid != NULL && tld != NULL); + mi_assert_internal(commit != NULL && is_pinned != NULL && is_zero != NULL && memid != NULL && tld != NULL); mi_assert_internal(size > 0); *memid = MI_MEMID_OS; *is_zero = false; + *is_pinned = false; // try to allocate in an arena if the alignment is small enough // and the object is not too large or too small. @@ -175,7 +177,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, if ((arena->numa_node<0 || arena->numa_node==numa_node) && // numa local? (*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages { - void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_zero, memid, tld); + void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_pinned, is_zero, memid, tld); mi_assert_internal((uintptr_t)p % alignment == 0); if (p != NULL) return p; } @@ -187,7 +189,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, if ((arena->numa_node>=0 && arena->numa_node!=numa_node) && // not numa local! (*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages { - void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_zero, memid, tld); + void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_pinned, is_zero, memid, tld); mi_assert_internal((uintptr_t)p % alignment == 0); if (p != NULL) return p; } @@ -196,13 +198,15 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, // finally, fall back to the OS *is_zero = true; - *memid = MI_MEMID_OS; - return _mi_os_alloc_aligned(size, alignment, *commit, large, tld->stats); + *memid = MI_MEMID_OS; + void* p = _mi_os_alloc_aligned(size, alignment, *commit, large, tld->stats); + if (p != NULL) *is_pinned = *large; + return p; } -void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld) +void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld) { - return _mi_arena_alloc_aligned(size, MI_ARENA_BLOCK_SIZE, commit, large, is_zero, memid, tld); + return _mi_arena_alloc_aligned(size, MI_ARENA_BLOCK_SIZE, commit, large, is_pinned, is_zero, memid, tld); } /* ----------------------------------------------------------- @@ -225,6 +229,8 @@ void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_s mi_assert_internal(arena_idx < MI_MAX_ARENAS); mi_arena_t* arena = mi_atomic_load_ptr_relaxed(mi_arena_t,&mi_arenas[arena_idx]); mi_assert_internal(arena != NULL); + const size_t blocks = mi_block_count_of_size(size); + // checks if (arena == NULL) { _mi_error_message(EINVAL, "trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid); return; @@ -234,9 +240,18 @@ void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_s _mi_error_message(EINVAL, "trying to free from non-existent arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid); return; } - const size_t blocks = mi_block_count_of_size(size); - bool ones = _mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx); - if (!ones) { + // potentially decommit + if (arena->is_committed) { + mi_assert_internal(all_committed); + } + else { + mi_assert_internal(arena->blocks_committed != NULL); + _mi_os_decommit(p, blocks * MI_ARENA_BLOCK_SIZE, stats); // ok if this fails + _mi_bitmap_unclaim_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx); + } + // and make it available to others again + bool all_inuse = _mi_bitmap_unclaim_across(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx); + if (!all_inuse) { _mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size); return; }; @@ -263,9 +278,14 @@ static bool mi_arena_add(mi_arena_t* arena) { 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 { + if (is_large) { + mi_assert_internal(is_committed); + is_committed = true; + } + const size_t bcount = mi_block_count_of_size(size); const size_t fields = _mi_divide_up(bcount, MI_BITMAP_FIELD_BITS); - const size_t bitmaps = (is_committed ? 3 : 2); + const size_t bitmaps = (is_committed ? 2 : 3); const size_t asize = sizeof(mi_arena_t) + (bitmaps*fields*sizeof(mi_bitmap_field_t)); mi_arena_t* arena = (mi_arena_t*)_mi_os_alloc(asize, &_mi_stats_main); // TODO: can we avoid allocating from the OS? if (arena == NULL) return false; @@ -301,7 +321,7 @@ int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noe bool large = allow_large; void* start = _mi_os_alloc_aligned(size, MI_SEGMENT_ALIGN, commit, &large, &_mi_stats_main); if (start==NULL) return ENOMEM; - if (!mi_manage_os_memory(start, size, commit, large, true, -1)) { + if (!mi_manage_os_memory(start, size, (large || commit), large, true, -1)) { _mi_os_free_ex(start, size, commit, &_mi_stats_main); _mi_verbose_message("failed to reserve %zu k memory\n", _mi_divide_up(size,1024)); return ENOMEM; diff --git a/src/bitmap.c b/src/bitmap.c index cc710963..a94e15cf 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -388,10 +388,8 @@ bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size return mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, NULL); } -/* bool _mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) { bool any_ones; mi_bitmap_is_claimedx_across(bitmap, bitmap_fields, count, bitmap_idx, &any_ones); return any_ones; } -*/ diff --git a/src/bitmap.h b/src/bitmap.h index 95f0d615..f7819803 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -97,5 +97,6 @@ bool _mi_bitmap_unclaim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t bool _mi_bitmap_claim_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* pany_zero); bool _mi_bitmap_is_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); +bool _mi_bitmap_is_any_claimed_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx); #endif diff --git a/src/init.c b/src/init.c index 07a34f57..48601637 100644 --- a/src/init.c +++ b/src/init.c @@ -478,7 +478,7 @@ void mi_process_init(void) mi_attr_noexcept { if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { size_t pages = mi_option_get(mi_option_reserve_huge_os_pages); mi_reserve_huge_os_pages_interleave(pages, 0, pages*500); - } + } } // Called when the process is done (through `at_exit`) diff --git a/src/region.c b/src/region.c index a70853d4..e1283a76 100644 --- a/src/region.c +++ b/src/region.c @@ -50,8 +50,8 @@ bool _mi_os_unreset(void* p, size_t size, bool* is_zero, mi_stats_t* stats); // arena.c void _mi_arena_free(void* p, size_t size, size_t memid, bool all_committed, mi_stats_t* stats); -void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld); -void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld); +void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld); +void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld); @@ -77,7 +77,8 @@ typedef union mi_region_info_u { uintptr_t value; struct { bool valid; // initialized? - bool is_large; // allocated in fixed large/huge OS pages + bool is_large:1; // allocated in fixed large/huge OS pages + bool is_pinned:1; // pinned memory cannot be decommitted short numa_node; // the associated NUMA node (where -1 means no associated node) } x; } mi_region_info_t; @@ -177,8 +178,9 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, bool region_commit = (commit && mi_option_is_enabled(mi_option_eager_region_commit)); bool region_large = (commit && allow_large); bool is_zero = false; + bool is_pinned = false; size_t arena_memid = 0; - void* const start = _mi_arena_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, ®ion_commit, ®ion_large, &is_zero, &arena_memid, tld); + void* const start = _mi_arena_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, ®ion_commit, ®ion_large, &is_pinned, &is_zero, &arena_memid, tld); if (start == NULL) return false; mi_assert_internal(!(region_large && !allow_large)); mi_assert_internal(!region_large || region_commit); @@ -208,6 +210,7 @@ static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, info.value = 0; // initialize the full union to zero info.x.valid = true; info.x.is_large = region_large; + info.x.is_pinned = is_pinned; info.x.numa_node = (short)_mi_os_numa_node(tld); mi_atomic_store_release(&r->info, info.value); // now make it available to others *region = r; @@ -259,16 +262,16 @@ static bool mi_region_try_claim(int numa_node, size_t blocks, bool allow_large, } -static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bool* is_zero, size_t* memid, mi_os_tld_t* tld) +static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld) { mi_assert_internal(blocks <= MI_BITMAP_FIELD_BITS); mem_region_t* region; mi_bitmap_index_t bit_idx; const int numa_node = (_mi_os_numa_node_count() <= 1 ? -1 : _mi_os_numa_node(tld)); // try to claim in existing regions - if (!mi_region_try_claim(numa_node, blocks, *is_large, ®ion, &bit_idx, tld)) { + if (!mi_region_try_claim(numa_node, blocks, *large, ®ion, &bit_idx, tld)) { // otherwise try to allocate a fresh region and claim in there - if (!mi_region_try_alloc_os(blocks, *commit, *is_large, ®ion, &bit_idx, tld)) { + if (!mi_region_try_alloc_os(blocks, *commit, *large, ®ion, &bit_idx, tld)) { // out of regions or memory return NULL; } @@ -282,12 +285,13 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo mi_region_info_t info; info.value = mi_atomic_load_acquire(®ion->info); uint8_t* start = (uint8_t*)mi_atomic_load_ptr_acquire(uint8_t,®ion->start); - mi_assert_internal(!(info.x.is_large && !*is_large)); + mi_assert_internal(!(info.x.is_large && !*large)); mi_assert_internal(start != NULL); - *is_zero = _mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL); - *is_large = info.x.is_large; - *memid = mi_memid_create(region, bit_idx); + *is_zero = _mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL); + *large = info.x.is_large; + *is_pinned = info.x.is_pinned; + *memid = mi_memid_create(region, bit_idx); void* p = start + (mi_bitmap_index_bit_in_field(bit_idx) * MI_SEGMENT_SIZE); // commit @@ -296,7 +300,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo bool any_uncommitted; _mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted); if (any_uncommitted) { - mi_assert_internal(!info.x.is_large); + mi_assert_internal(!info.x.is_large && !info.x.is_pinned); bool commit_zero; _mi_mem_commit(p, blocks * MI_SEGMENT_SIZE, &commit_zero, tld); if (commit_zero) *is_zero = true; @@ -311,7 +315,7 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo // unreset reset blocks if (_mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)) { // some blocks are still reset - mi_assert_internal(!info.x.is_large); + mi_assert_internal(!info.x.is_large && !info.x.is_pinned); mi_assert_internal(!mi_option_is_enabled(mi_option_eager_commit) || *commit || mi_option_get(mi_option_eager_commit_delay) > 0); mi_bitmap_unclaim(®ion->reset, 1, blocks, bit_idx); if (*commit || !mi_option_is_enabled(mi_option_reset_decommits)) { // only if needed @@ -338,12 +342,13 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo // Allocate `size` memory aligned at `alignment`. Return non NULL on success, with a given memory `id`. // (`id` is abstract, but `id = idx*MI_REGION_MAP_BITS + bitidx`) -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld) +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_pinned, bool* is_zero, size_t* memid, mi_os_tld_t* tld) { mi_assert_internal(memid != NULL && tld != NULL); mi_assert_internal(size > 0); *memid = 0; *is_zero = false; + *is_pinned = false; bool default_large = false; if (large==NULL) large = &default_large; // ensure `large != NULL` if (size == 0) return NULL; @@ -354,14 +359,14 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* l size_t arena_memid; const size_t blocks = mi_region_block_count(size); if (blocks <= MI_REGION_MAX_OBJ_BLOCKS && alignment <= MI_SEGMENT_ALIGN) { - p = mi_region_try_alloc(blocks, commit, large, is_zero, memid, tld); + p = mi_region_try_alloc(blocks, commit, large, is_pinned, is_zero, memid, tld); if (p == NULL) { _mi_warning_message("unable to allocate from region: size %zu\n", size); } } if (p == NULL) { // and otherwise fall back to the OS - p = _mi_arena_alloc_aligned(size, alignment, commit, large, is_zero, &arena_memid, tld); + p = _mi_arena_alloc_aligned(size, alignment, commit, large, is_pinned, is_zero, &arena_memid, tld); *memid = mi_memid_create_from_arena(arena_memid); } @@ -418,7 +423,7 @@ void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_re } // reset the blocks to reduce the working set. - if (!info.x.is_large && mi_option_is_enabled(mi_option_segment_reset) + if (!info.x.is_large && !info.x.is_pinned && mi_option_is_enabled(mi_option_segment_reset) && (mi_option_is_enabled(mi_option_eager_commit) || mi_option_is_enabled(mi_option_reset_decommits))) // cannot reset halfway committed segments, use only `option_page_reset` instead { diff --git a/src/segment.c b/src/segment.c index a5077711..ef8a166f 100644 --- a/src/segment.c +++ b/src/segment.c @@ -231,7 +231,7 @@ static void mi_segment_protect(mi_segment_t* segment, bool protect, mi_os_tld_t* static void mi_page_reset(mi_segment_t* segment, mi_page_t* page, size_t size, mi_segments_tld_t* tld) { mi_assert_internal(page->is_committed); if (!mi_option_is_enabled(mi_option_page_reset)) return; - if (segment->mem_is_fixed || page->segment_in_use || !page->is_committed || page->is_reset) return; + if (segment->mem_is_pinned || page->segment_in_use || !page->is_committed || page->is_reset) return; size_t psize; void* start = mi_segment_raw_page_start(segment, page, &psize); page->is_reset = true; @@ -244,8 +244,8 @@ static bool mi_page_unreset(mi_segment_t* segment, mi_page_t* page, size_t size, { mi_assert_internal(page->is_reset); mi_assert_internal(page->is_committed); - mi_assert_internal(!segment->mem_is_fixed); - if (segment->mem_is_fixed || !page->is_committed || !page->is_reset) return true; + mi_assert_internal(!segment->mem_is_pinned); + if (segment->mem_is_pinned || !page->is_committed || !page->is_reset) return true; page->is_reset = false; size_t psize; uint8_t* start = mi_segment_raw_page_start(segment, page, &psize); @@ -284,7 +284,7 @@ static void mi_pages_reset_add(mi_segment_t* segment, mi_page_t* page, mi_segmen mi_assert_expensive(!mi_pages_reset_contains(page, tld)); mi_assert_internal(_mi_page_segment(page)==segment); if (!mi_option_is_enabled(mi_option_page_reset)) return; - if (segment->mem_is_fixed || page->segment_in_use || !page->is_committed || page->is_reset) return; + if (segment->mem_is_pinned || page->segment_in_use || !page->is_committed || page->is_reset) return; if (mi_option_get(mi_option_reset_delay) == 0) { // reset immediately? @@ -324,7 +324,7 @@ static void mi_pages_reset_remove(mi_page_t* page, mi_segments_tld_t* tld) { } static void mi_pages_reset_remove_all_in_segment(mi_segment_t* segment, bool force_reset, mi_segments_tld_t* tld) { - if (segment->mem_is_fixed) return; // never reset in huge OS pages + if (segment->mem_is_pinned) return; // never reset in huge OS pages for (size_t i = 0; i < segment->capacity; i++) { mi_page_t* page = &segment->pages[i]; if (!page->segment_in_use && page->is_committed && !page->is_reset) { @@ -458,7 +458,7 @@ static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_se segment->thread_id = 0; mi_segments_track_size(-((long)segment_size),tld); if (MI_SECURE != 0) { - mi_assert_internal(!segment->mem_is_fixed); + mi_assert_internal(!segment->mem_is_pinned); mi_segment_protect(segment, false, tld->os); // ensure no more guard pages are set } @@ -587,7 +587,7 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ else { if (MI_SECURE!=0) { - mi_assert_internal(!segment->mem_is_fixed); + mi_assert_internal(!segment->mem_is_pinned); mi_segment_protect(segment, false, tld->os); // reset protection if the page kind differs } // different page kinds; unreset any reset pages, and unprotect @@ -615,10 +615,12 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ // Allocate the segment from the OS size_t memid; bool mem_large = (!eager_delayed && (MI_SECURE==0)); // only allow large OS pages once we are no longer lazy - segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &is_zero, &memid, os_tld); + bool is_pinned = false; + segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &is_pinned, &is_zero, &memid, os_tld); if (segment == NULL) return NULL; // failed to allocate if (!commit) { // ensure the initial info is committed + mi_assert_internal(!mem_large && !is_pinned); bool commit_zero = false; bool ok = _mi_mem_commit(segment, pre_size, &commit_zero, tld->os); if (commit_zero) is_zero = true; @@ -629,12 +631,12 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ } } segment->memid = memid; - segment->mem_is_fixed = mem_large; + segment->mem_is_pinned = (mem_large || is_pinned); segment->mem_is_committed = commit; mi_segments_track_size((long)segment_size, tld); } mi_assert_internal(segment != NULL && (uintptr_t)segment % MI_SEGMENT_SIZE == 0); - mi_assert_internal(segment->mem_is_fixed ? segment->mem_is_committed : true); + mi_assert_internal(segment->mem_is_pinned ? segment->mem_is_committed : true); mi_atomic_store_ptr_release(mi_segment_t, &segment->abandoned_next, NULL); // tsan if (!pages_still_good) { // zero the segment info (but not the `mem` fields) @@ -719,7 +721,7 @@ static bool mi_segment_page_claim(mi_segment_t* segment, mi_page_t* page, mi_seg mi_pages_reset_remove(page, tld); // check commit if (!page->is_committed) { - mi_assert_internal(!segment->mem_is_fixed); + mi_assert_internal(!segment->mem_is_pinned); mi_assert_internal(!page->is_reset); size_t psize; uint8_t* start = mi_segment_raw_page_start(segment, page, &psize); @@ -736,7 +738,7 @@ static bool mi_segment_page_claim(mi_segment_t* segment, mi_page_t* page, mi_seg segment->used++; // check reset if (page->is_reset) { - mi_assert_internal(!segment->mem_is_fixed); + mi_assert_internal(!segment->mem_is_pinned); bool ok = mi_page_unreset(segment, page, 0, tld); if (!ok) { page->segment_in_use = false; From 364674185ebfec6c0176f11dd1842c58acb09c66 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 8 Sep 2020 16:56:51 -0700 Subject: [PATCH 107/172] add option to limit OS allocation and only allow allocation from arenas --- include/mimalloc.h | 1 + src/arena.c | 3 ++- src/options.c | 1 + test/test-stress.c | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 2bcbf10e..ea79a522 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -311,6 +311,7 @@ typedef enum mi_option_e { mi_option_eager_commit_delay, mi_option_reset_delay, mi_option_use_numa_nodes, + mi_option_limit_os_alloc, mi_option_os_tag, mi_option_max_errors, _mi_option_last diff --git a/src/arena.c b/src/arena.c index 91cac309..a6ea4125 100644 --- a/src/arena.c +++ b/src/arena.c @@ -197,6 +197,7 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* } // finally, fall back to the OS + if (mi_option_is_enabled(mi_option_limit_os_alloc)) return NULL; *is_zero = true; *memid = MI_MEMID_OS; void* p = _mi_os_alloc_aligned(size, alignment, *commit, large, tld->stats); @@ -326,7 +327,7 @@ int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noe _mi_verbose_message("failed to reserve %zu k memory\n", _mi_divide_up(size,1024)); return ENOMEM; } - _mi_verbose_message("reserved %zu kb memory\n", _mi_divide_up(size,1024)); + _mi_verbose_message("reserved %zu kb memory%s\n", _mi_divide_up(size,1024), large ? " (in large os pages)" : ""); return 0; } diff --git a/src/options.c b/src/options.c index 9da3a9bd..7e565ea4 100644 --- a/src/options.c +++ b/src/options.c @@ -86,6 +86,7 @@ static mi_option_desc_t options[_mi_option_last] = #endif { 100, UNINIT, MI_OPTION(reset_delay) }, // reset delay in milli-seconds { 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes. + { 0, UNINIT, MI_OPTION(limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas) { 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose { 16, UNINIT, MI_OPTION(max_errors) } // maximum errors that are output }; diff --git a/test/test-stress.c b/test/test-stress.c index 68faef90..d969284e 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -235,7 +235,7 @@ int main(int argc, char** argv) { if (n > 0) ITER = n; } printf("Using %d threads with a %d%% load-per-thread and %d iterations\n", THREADS, SCALE, ITER); - //mi_reserve_os_memory(512*1024*1024ULL, true, true); + //mi_reserve_os_memory(1024*1024*1024ULL, false, true); //int res = mi_reserve_huge_os_pages(4,1); //printf("(reserve huge: %i\n)", res); From 8607ff617c175dc4a7e436349bf6284758d5e4ea Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 8 Sep 2020 17:16:31 -0700 Subject: [PATCH 108/172] add environment option mi_reserve_os_memory --- include/mimalloc.h | 1 + src/init.c | 6 +++++- src/options.c | 11 ++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index ea79a522..b980037c 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -304,6 +304,7 @@ typedef enum mi_option_e { mi_option_reset_decommits, mi_option_large_os_pages, // implies eager commit mi_option_reserve_huge_os_pages, + mi_option_reserve_os_memory, mi_option_segment_cache, mi_option_page_reset, mi_option_abandoned_page_reset, diff --git a/src/init.c b/src/init.c index 48601637..bc17791b 100644 --- a/src/init.c +++ b/src/init.c @@ -478,7 +478,11 @@ void mi_process_init(void) mi_attr_noexcept { if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { size_t pages = mi_option_get(mi_option_reserve_huge_os_pages); mi_reserve_huge_os_pages_interleave(pages, 0, pages*500); - } + } + if (mi_option_is_enabled(mi_option_reserve_os_memory)) { + long ksize = mi_option_get(mi_option_reserve_os_memory); + if (ksize > 0) mi_reserve_os_memory((size_t)ksize*KiB, true, true); + } } // Called when the process is done (through `at_exit`) diff --git a/src/options.c b/src/options.c index 7e565ea4..2dbc8b03 100644 --- a/src/options.c +++ b/src/options.c @@ -74,7 +74,8 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(reset_decommits) }, // reset uses MADV_FREE/MADV_DONTNEED #endif { 0, UNINIT, MI_OPTION(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) }, + { 0, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages + { 0, UNINIT, MI_OPTION(reserve_os_memory) }, { 0, UNINIT, MI_OPTION(segment_cache) }, // cache N segments per thread { 1, UNINIT, MI_OPTION(page_reset) }, // reset page memory on free { 0, UNINIT, MI_OPTION(abandoned_page_reset) },// reset free page memory when a thread terminates @@ -504,6 +505,14 @@ static void mi_option_init(mi_option_desc_t* desc) { else { char* end = buf; long value = strtol(buf, &end, 10); + if (desc->option == mi_option_reserve_os_memory) { + // this option is interpreted in KiB to prevent overflow of `long` + if (*end == 'K') { end++; } + else if (*end == 'M') { value *= KiB; end++; } + else if (*end == 'G') { value *= MiB; end++; } + else { value = (value + KiB - 1) / KiB; } + if (*end == 'B') { end++; } + } if (*end == 0) { desc->value = value; desc->init = INITIALIZED; From 568d6e532b65c6441e5ea8ee873e68055a2f5841 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 10 Sep 2020 18:49:19 +0000 Subject: [PATCH 109/172] Haiku build fix. Haiku does not provide page faults statistics only system wide. --- src/stats.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/stats.c b/src/stats.c index 842e2009..099dea7f 100644 --- a/src/stats.c +++ b/src/stats.c @@ -497,7 +497,9 @@ static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* c getrusage(RUSAGE_SELF, &rusage); *utime = timeval_secs(&rusage.ru_utime); *stime = timeval_secs(&rusage.ru_stime); +#if !defined(__HAIKU__) *page_faults = rusage.ru_majflt; +#endif // estimate commit using our stats *peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.peak)); *current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.current)); From bf9c3bd08847e7dc1972db52b419b21171bc6c6e Mon Sep 17 00:00:00 2001 From: Igor Kostenko Date: Mon, 14 Sep 2020 10:50:22 +0100 Subject: [PATCH 110/172] Fix rare access violation on out of memory --- src/region.c | 8 ++++++-- src/segment.c | 9 ++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/region.c b/src/region.c index bebc29fd..fa51c298 100644 --- a/src/region.c +++ b/src/region.c @@ -297,9 +297,13 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted); if (any_uncommitted) { mi_assert_internal(!info.x.is_large); - bool commit_zero; - _mi_mem_commit(p, blocks * MI_SEGMENT_SIZE, &commit_zero, tld); + bool commit_zero = false; + bool ok = _mi_mem_commit(p, blocks * MI_SEGMENT_SIZE, &commit_zero, tld); if (commit_zero) *is_zero = true; + if (!ok) + { + return NULL; + } } } else { diff --git a/src/segment.c b/src/segment.c index a5077711..35fc3ba7 100644 --- a/src/segment.c +++ b/src/segment.c @@ -208,7 +208,11 @@ static void mi_segment_protect(mi_segment_t* segment, bool protect, mi_os_tld_t* uint8_t* start = (uint8_t*)segment + segment->segment_size - os_psize; if (protect && !segment->mem_is_committed) { // ensure secure page is committed +#if (MI_DEBUG>1) + bool ok = +#endif _mi_mem_commit(start, os_psize, NULL, tld); + mi_assert_internal(ok); } mi_segment_protect_range(start, os_psize, protect); } @@ -606,8 +610,11 @@ static mi_segment_t* mi_segment_init(mi_segment_t* segment, size_t required, mi_ // ensure the initial info is committed if (segment->capacity < capacity) { bool commit_zero = false; - _mi_mem_commit(segment, pre_size, &commit_zero, tld->os); + bool ok = _mi_mem_commit(segment, pre_size, &commit_zero, tld->os); if (commit_zero) is_zero = true; + if (!ok) { + return NULL; + } } } } From f5e3cca74ebf74b0894dfc5ff472098f9d31d144 Mon Sep 17 00:00:00 2001 From: Igor Kostenko Date: Mon, 14 Sep 2020 11:13:03 +0100 Subject: [PATCH 111/172] Do not require to specify version for cmake find_package --- cmake/mimalloc-config-version.cmake | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cmake/mimalloc-config-version.cmake b/cmake/mimalloc-config-version.cmake index 6454d91f..edffeea1 100644 --- a/cmake/mimalloc-config-version.cmake +++ b/cmake/mimalloc-config-version.cmake @@ -3,14 +3,16 @@ set(mi_version_minor 6) set(mi_version ${mi_version_major}.${mi_version_minor}) set(PACKAGE_VERSION ${mi_version}) -if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "${mi_version_major}") - if ("${PACKAGE_FIND_VERSION_MINOR}" EQUAL "${mi_version_minor}") - set(PACKAGE_VERSION_EXACT TRUE) - elseif("${PACKAGE_FIND_VERSION_MINOR}" LESS "${mi_version_minor}") - set(PACKAGE_VERSION_COMPATIBLE TRUE) +if(PACKAGE_FIND_VERSION_MAJOR) + if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "${mi_version_major}") + if ("${PACKAGE_FIND_VERSION_MINOR}" EQUAL "${mi_version_minor}") + set(PACKAGE_VERSION_EXACT TRUE) + elseif("${PACKAGE_FIND_VERSION_MINOR}" LESS "${mi_version_minor}") + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_UNSUITABLE TRUE) + endif() else() set(PACKAGE_VERSION_UNSUITABLE TRUE) endif() -else() - set(PACKAGE_VERSION_UNSUITABLE TRUE) endif() From d6ca70c9cce75d382bfe9be3409f58dd688edb61 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 14 Sep 2020 08:30:49 -0700 Subject: [PATCH 112/172] Update readme.md Clarify the distinctive idea of mimalloc as free-list multi-sharding --- readme.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index daf57f39..96565fde 100644 --- a/readme.md +++ b/readme.md @@ -18,19 +18,27 @@ without code changes, for example, on dynamically linked ELF-based systems (Linu ``` > LD_PRELOAD=/usr/bin/libmimalloc.so myprogram ``` -It also has an easy way to override the allocator in [Windows](#override_on_windows). Notable aspects of the design include: +It also has an easy way to override the default allocator in [Windows](#override_on_windows). Notable aspects of the design include: -- __small and consistent__: the library is about 6k LOC using simple and +- __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). -- __free list sharding__: the big idea: instead of one big free list (per size class) we have - many smaller lists per memory "page" which both reduces fragmentation - and increases locality -- +- __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 memory "page" in _mimalloc_ contains blocks of one size class and is - usually 64KiB on a 64-bit system). + (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` operatinons, and another separate one for concurrent `free` + operations. Free-ing from another thread can now be a single CAS without needing + a sophisticated data structure to coordinate 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 From 0df0c17f5abf555bddbf2842ec700395667bd8b6 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 14 Sep 2020 08:31:20 -0700 Subject: [PATCH 113/172] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 96565fde..ca94e7f0 100644 --- a/readme.md +++ b/readme.md @@ -36,7 +36,7 @@ It also has an easy way to override the default allocator in [Windows](#override operations. Free-ing from another thread can now be a single CAS without needing a sophisticated data structure to coordinate 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 + 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 From 840eba28742b324d45b09e44e351767de29a8ced Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 14 Sep 2020 09:02:06 -0700 Subject: [PATCH 114/172] improve handling of out-of-memory situations --- src/region.c | 8 ++++---- src/segment.c | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/region.c b/src/region.c index fa51c298..aa4f95b5 100644 --- a/src/region.c +++ b/src/region.c @@ -298,12 +298,12 @@ static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bo if (any_uncommitted) { mi_assert_internal(!info.x.is_large); bool commit_zero = false; - bool ok = _mi_mem_commit(p, blocks * MI_SEGMENT_SIZE, &commit_zero, tld); - if (commit_zero) *is_zero = true; - if (!ok) - { + if (!_mi_mem_commit(p, blocks * MI_SEGMENT_SIZE, &commit_zero, tld)) { + // failed to commit! unclaim and return + mi_bitmap_unclaim(®ion->in_use, 1, blocks, bit_idx); return NULL; } + if (commit_zero) *is_zero = true; } } else { diff --git a/src/segment.c b/src/segment.c index 35fc3ba7..0daf8ddb 100644 --- a/src/segment.c +++ b/src/segment.c @@ -207,14 +207,16 @@ static void mi_segment_protect(mi_segment_t* segment, bool protect, mi_os_tld_t* mi_assert_internal(MI_SECURE <= 1 || segment->page_kind >= MI_PAGE_LARGE); uint8_t* start = (uint8_t*)segment + segment->segment_size - os_psize; if (protect && !segment->mem_is_committed) { - // ensure secure page is committed -#if (MI_DEBUG>1) - bool ok = -#endif - _mi_mem_commit(start, os_psize, NULL, tld); - mi_assert_internal(ok); + if (protect) { + // ensure secure page is committed + if (_mi_mem_commit(start, os_psize, NULL, tld)) { // if this fails that is ok (as it is an unaccessible page) + mi_segment_protect_range(start, os_psize, protect); + } + } + } + else { + mi_segment_protect_range(start, os_psize, protect); } - mi_segment_protect_range(start, os_psize, protect); } else { // or protect every page From 64a3d24dcdf702aa7c1fc36c03e6cc8e8d4a49c2 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 23 Sep 2020 20:00:23 -0700 Subject: [PATCH 115/172] bump version to 1.6.5 --- include/mimalloc.h | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 5b3d13ed..e09f7d36 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 166 // major + 2 digits minor +#define MI_MALLOC_VERSION 165 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes diff --git a/readme.md b/readme.md index daf57f39..d8c94119 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent [performance](#performance) characteristics. Initially developed by Daan Leijen for the run-time systems of the [Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages. -Latest release:`v1.6.4` (2020-08-06). +Latest release:`v1.6.5` (2020-09-24). It is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: From 1adec58c835ac7deedb3ee74818af1a46329da28 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 23 Sep 2020 20:02:24 -0700 Subject: [PATCH 116/172] fix spelling --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 3ce29538..a1a4b759 100644 --- a/readme.md +++ b/readme.md @@ -32,9 +32,9 @@ It also has an easy way to override the default allocator in [Windows](#override (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` operatinons, and another separate one for concurrent `free` + 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 - a sophisticated data structure to coordinate between threads. Since there will be + 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 From 4d3ddcfc51e04ca0583a9aaa895ba529a603f27b Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 23 Sep 2020 20:37:17 -0700 Subject: [PATCH 117/172] update readme for upcoming release; add acknowledgements --- readme.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a1a4b759..5e9407ad 100644 --- a/readme.md +++ b/readme.md @@ -63,8 +63,18 @@ You can read more on the design of _mimalloc_ in the [technical report](https:// Enjoy! +### Branches + +* `master`: latest stable release. +* `dev`: latest development branch. +* `dev-slice`: experimental branch with a different way of managing mimalloc pages that tends + to use less memory than plain mimalloc with similar performance. Give it a try and please + report any significant performance improvement or degradation. + ### Releases +* 2020-09-24, `v1.6.5`: stable release 1.6: using standard C atomics, passing tsan testing, improved + handling of out-of-memory and failed commits, add `mi_process_info` api call. * 2020-08-06, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, support for IllumOS and Haiku, NUMA support for Vista/XP, improved NUMA detection for AMD Ryzen, ubsan support. * 2020-05-05, `v1.6.3`: stable release 1.6: improved behavior in out-of-memory situations, improved malloc zones on macOS, @@ -92,9 +102,16 @@ free list encoding](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af Special thanks to: -* Jason Gibson (@jasongibson) for exhaustive testing on large workloads and server environments and finding complex bugs in (early versions of) `mimalloc`. +* Mary Feofanova (@mary3000), Evgeniy Moiseenko, and Manuel Pöter (@mpoeter) for making mimalloc TSAN checkable, and finding + memory model bugs using the [genMC] model checker. +* Weipeng Liu (@pongba), Zhuowei Li, Junhua Wang, and Jakub Szymanski, for their early support of mimalloc and deployment + at large scale services, leading to many improvements in the mimalloc algorithms for large workloads. +* Jason Gibson (@jasongibson) for exhaustive testing on large scale workloads and server environments, and finding complex bugs + in (early versions of) `mimalloc`. * Manuel Pöter (@mpoeter) and Sam Gross (@colesbury) for finding an ABA concurrency issue in abandoned segment reclamation. +[genMC]: https://plv.mpi-sws.org/genmc/ + # Building ## Windows From 41683071c1395340b4243fb6b4f1133966c13f71 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 09:05:01 -0700 Subject: [PATCH 118/172] update readme --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 5e9407ad..3dcefb53 100644 --- a/readme.md +++ b/readme.md @@ -68,13 +68,13 @@ Enjoy! * `master`: latest stable release. * `dev`: latest development branch. * `dev-slice`: experimental branch with a different way of managing mimalloc pages that tends - to use less memory than plain mimalloc with similar performance. Give it a try and please + to use less memory than regular mimalloc with similar performance. Give it a try and please report any significant performance improvement or degradation. ### Releases * 2020-09-24, `v1.6.5`: stable release 1.6: using standard C atomics, passing tsan testing, improved - handling of out-of-memory and failed commits, add `mi_process_info` api call. + handling of failing to commit on Windows, add `mi_process_info` api call. * 2020-08-06, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, support for IllumOS and Haiku, NUMA support for Vista/XP, improved NUMA detection for AMD Ryzen, ubsan support. * 2020-05-05, `v1.6.3`: stable release 1.6: improved behavior in out-of-memory situations, improved malloc zones on macOS, From d0d36341436eb948359aead82b74b00ea70f7795 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 09:29:37 -0700 Subject: [PATCH 119/172] bump version for further development --- include/mimalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index a0f537bf..b980037c 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 165 // major + 2 digits minor +#define MI_MALLOC_VERSION 166 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes From f88b4b4c27529da0f6c4f705915d8d295a0b94a2 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 10:13:25 -0700 Subject: [PATCH 120/172] extend mi_process_info to include elapsed time --- include/mimalloc.h | 4 +++- src/stats.c | 42 ++++++++++++++++++++----------------- test/main-override-static.c | 24 ++++++++++++++++++--- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index e09f7d36..a06a5f26 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -153,7 +153,9 @@ mi_decl_export void mi_thread_init(void) mi_attr_noexcept; mi_decl_export void mi_thread_done(void) mi_attr_noexcept; mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; -mi_decl_export void mi_process_info(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) mi_attr_noexcept; +mi_decl_export 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) mi_attr_noexcept; // ------------------------------------------------------------------------------------- // Aligned allocation diff --git a/src/stats.c b/src/stats.c index 099dea7f..b04822cc 100644 --- a/src/stats.c +++ b/src/stats.c @@ -276,9 +276,9 @@ static void mi_buffered_out(const char* msg, void* arg) { // Print statistics //------------------------------------------------------------ -static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults); +static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults); -static void _mi_stats_print(mi_stats_t* stats, mi_msecs_t elapsed, mi_output_fun* out0, void* arg0) mi_attr_noexcept { +static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_attr_noexcept { // wrap the output function to be line buffered char buf[256]; buffered_t buffer = { out0, arg0, NULL, 0, 255 }; @@ -319,8 +319,8 @@ static void _mi_stats_print(mi_stats_t* stats, mi_msecs_t elapsed, mi_output_fun mi_stat_print(&stats->threads, "threads", -1, out, arg); mi_stat_counter_print_avg(&stats->searches, "searches", out, arg); _mi_fprintf(out, arg, "%10s: %7i\n", "numa nodes", _mi_os_numa_node_count()); - if (elapsed > 0) _mi_fprintf(out, arg, "%10s: %7ld.%03ld s\n", "elapsed", elapsed/1000, elapsed%1000); - + + mi_msecs_t elapsed; mi_msecs_t user_time; mi_msecs_t sys_time; size_t current_rss; @@ -328,8 +328,9 @@ static void _mi_stats_print(mi_stats_t* stats, mi_msecs_t elapsed, mi_output_fun size_t current_commit; size_t peak_commit; size_t page_faults; - mi_stat_process_info(&user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); - _mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, rss: ", "process", + mi_stat_process_info(&elapsed, &user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); + _mi_fprintf(out, arg, "%10s: %7ld.%03ld s\n", "elapsed", elapsed/1000, elapsed%1000); + _mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, rss: ", "process", user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, (unsigned long)page_faults ); mi_printf_amount((int64_t)peak_rss, 1, out, arg, "%s"); if (peak_commit > 0) { @@ -339,7 +340,7 @@ static void _mi_stats_print(mi_stats_t* stats, mi_msecs_t elapsed, mi_output_fun _mi_fprintf(out, arg, "\n"); } -static mi_msecs_t mi_time_start; // = 0 +static mi_msecs_t mi_process_start; // = 0 static mi_stats_t* mi_stats_get_default(void) { mi_heap_t* heap = mi_heap_get_default(); @@ -357,7 +358,7 @@ void mi_stats_reset(void) mi_attr_noexcept { mi_stats_t* stats = mi_stats_get_default(); if (stats != &_mi_stats_main) { memset(stats, 0, sizeof(mi_stats_t)); } memset(&_mi_stats_main, 0, sizeof(mi_stats_t)); - mi_time_start = _mi_clock_start(); + if (mi_process_start == 0) { mi_process_start = _mi_clock_start(); }; } void mi_stats_merge(void) mi_attr_noexcept { @@ -369,9 +370,8 @@ void _mi_stats_done(mi_stats_t* stats) { // called from `mi_thread_done` } void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept { - mi_msecs_t elapsed = _mi_clock_end(mi_time_start); mi_stats_merge_from(mi_stats_get_default()); - _mi_stats_print(&_mi_stats_main, elapsed, out, arg); + _mi_stats_print(&_mi_stats_main, out, arg); } void mi_stats_print(void* out) mi_attr_noexcept { @@ -380,8 +380,7 @@ void mi_stats_print(void* out) mi_attr_noexcept { } void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept { - mi_msecs_t elapsed = _mi_clock_end(mi_time_start); - _mi_stats_print(mi_stats_get_default(), elapsed, out, arg); + _mi_stats_print(mi_stats_get_default(), out, arg); } @@ -456,8 +455,9 @@ static mi_msecs_t filetime_msecs(const FILETIME* ftime) { return msecs; } -static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) +static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) { + *elapsed = _mi_clock_end(mi_process_start); FILETIME ct; FILETIME ut; FILETIME st; @@ -491,8 +491,9 @@ static mi_msecs_t timeval_secs(const struct timeval* tv) { return ((mi_msecs_t)tv->tv_sec * 1000L) + ((mi_msecs_t)tv->tv_usec / 1000L); } -static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) +static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) { + *elapsed = _mi_clock_end(mi_process_start); struct rusage rusage; getrusage(RUSAGE_SELF, &rusage); *utime = timeval_secs(&rusage.ru_utime); @@ -532,8 +533,9 @@ static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* c #pragma message("define a way to get process info") #endif -static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) +static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msecs_t* stime, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) { + *elapsed = _mi_clock_end(mi_process_start); *peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.peak)); *current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.current)); *peak_rss = *peak_commit; @@ -545,8 +547,9 @@ static void mi_stat_process_info(mi_msecs_t* utime, mi_msecs_t* stime, size_t* c #endif -mi_decl_export void mi_process_info(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) mi_attr_noexcept +mi_decl_export 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) mi_attr_noexcept { + mi_msecs_t elapsed = 0; mi_msecs_t utime = 0; mi_msecs_t stime = 0; size_t current_rss0 = 0; @@ -554,9 +557,10 @@ mi_decl_export void mi_process_info(size_t* user_msecs, size_t* system_msecs, si size_t current_commit0 = 0; size_t peak_commit0 = 0; size_t page_faults0 = 0; - mi_stat_process_info(&utime, &stime, ¤t_rss0, &peak_rss0, ¤t_commit0, &peak_commit0, &page_faults0); - if (user_msecs!=NULL) *user_msecs = (utime < 0 ? 0 : (utime < (mi_msecs_t)SIZE_MAX ? (size_t)utime : SIZE_MAX)); - if (system_msecs!=NULL) *system_msecs = (stime < 0 ? 0 : (stime < (mi_msecs_t)SIZE_MAX ? (size_t)stime : SIZE_MAX)); + mi_stat_process_info(&elapsed,&utime, &stime, ¤t_rss0, &peak_rss0, ¤t_commit0, &peak_commit0, &page_faults0); + if (elapsed_msecs!=NULL) *elapsed_msecs = (elapsed < 0 ? 0 : (elapsed < (mi_msecs_t)PTRDIFF_MAX ? (size_t)elapsed : PTRDIFF_MAX)); + if (user_msecs!=NULL) *user_msecs = (utime < 0 ? 0 : (utime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)utime : PTRDIFF_MAX)); + if (system_msecs!=NULL) *system_msecs = (stime < 0 ? 0 : (stime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)stime : PTRDIFF_MAX)); if (current_rss!=NULL) *current_rss = current_rss0; if (peak_rss!=NULL) *peak_rss = peak_rss0; if (current_commit!=NULL) *current_commit = current_commit0; diff --git a/test/main-override-static.c b/test/main-override-static.c index 0b73bb61..1efc01d3 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -134,6 +134,7 @@ static void test_aslr(void) { } static void test_process_info(void) { + size_t elapsed = 0; size_t user_msecs = 0; size_t system_msecs = 0; size_t current_rss = 0; @@ -145,6 +146,23 @@ static void test_process_info(void) { void* p = calloc(100,10); free(p); } - mi_process_info(&user_msecs, &system_msecs, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); - printf("\n\n*** process info: user: %3zd.%03zd s, rss: %zd b, commit: %zd b\n\n", user_msecs/1000, user_msecs%1000, peak_rss, peak_commit); -} \ No newline at end of file + mi_process_info(&elapsed, &user_msecs, &system_msecs, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults); + printf("\n\n*** process info: elapsed %3zd.%03zd s, user: %3zd.%03zd s, rss: %zd b, commit: %zd b\n\n", elapsed/1000, elapsed%1000, user_msecs/1000, user_msecs%1000, peak_rss, peak_commit); +} + +static void test_reserved(void) { +#define KiB 1024ULL +#define MiB (KiB*KiB) +#define GiB (MiB*KiB) + mi_reserve_os_memory(4*GiB, false, true); + void* p1 = malloc(100); + void* p2 = malloc(100000); + void* p3 = malloc(2*GiB); + void* p4 = malloc(1*GiB + 100000); + free(p1); + free(p2); + free(p3); + p3 = malloc(1*GiB); + free(p4); +} + From 6adb919085d9177cca7491cbb5ecec9dcb69c0a2 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 10:14:10 -0700 Subject: [PATCH 121/172] bump version to 1.6.6 --- include/mimalloc.h | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index a06a5f26..05cf92e4 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 165 // major + 2 digits minor +#define MI_MALLOC_VERSION 166 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes diff --git a/readme.md b/readme.md index 3dcefb53..accd09cb 100644 --- a/readme.md +++ b/readme.md @@ -73,7 +73,7 @@ Enjoy! ### Releases -* 2020-09-24, `v1.6.5`: stable release 1.6: using standard C atomics, passing tsan testing, improved +* 2020-09-24, `v1.6.6`: stable release 1.6: using standard C atomics, passing tsan testing, improved handling of failing to commit on Windows, add `mi_process_info` api call. * 2020-08-06, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, support for IllumOS and Haiku, NUMA support for Vista/XP, improved NUMA detection for AMD Ryzen, ubsan support. From eb1e4817ef974f5629c4f32bf25f4464ba01e127 Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 24 Sep 2020 10:18:00 -0700 Subject: [PATCH 122/172] Update readme.md Fix version --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index accd09cb..2821802e 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent [performance](#performance) characteristics. Initially developed by Daan Leijen for the run-time systems of the [Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages. -Latest release:`v1.6.5` (2020-09-24). +Latest release:`v1.6.6` (2020-09-24). It is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: From 229fbac770d2c8dde28199b4362e19464b17a988 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 10:26:08 -0700 Subject: [PATCH 123/172] update documentation --- doc/mimalloc-doc.h | 5 +-- docs/group__extended.html | 19 +++++++---- docs/group__extended.js | 2 +- docs/mimalloc-doc_8h_source.html | 56 ++++++++++++++++---------------- docs/navtreeindex0.js | 2 +- docs/search/all_6.js | 2 +- docs/search/functions_0.js | 2 +- 7 files changed, 48 insertions(+), 40 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index c9cb580d..1566ba24 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -442,7 +442,8 @@ int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msec bool mi_is_redirected(); /// Return process information (time and memory usage). -/// @param user_msecs Optional. User time in milli-seconds. +/// @param elapsed_msecs Optional. Elapsed wall-clock time of the process in milli-seconds. +/// @param user_msecs Optional. User time in milli-seconds (as the sum over all threads). /// @param system_msecs Optional. System time in milli-seconds. /// @param current_rss Optional. Current working set size (touched pages). /// @param peak_rss Optional. Peak working set size (touched pages). @@ -453,7 +454,7 @@ bool mi_is_redirected(); /// The \a current_rss is precise on Windows and MacOSX; other systems estimate /// this using \a current_commit. The \a commit is precise on Windows but estimated /// on other systems as the amount of read/write accessible memory reserved by mimalloc. -void mi_process_info(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); +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); /// \} diff --git a/docs/group__extended.html b/docs/group__extended.html index c9145660..12e51cbb 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -187,9 +187,9 @@ Functions bool mi_is_redirected ()  Is the C runtime malloc API redirected? More...
  -void mi_process_info (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). More...

Detailed Description

Extended functionality.

@@ -416,8 +416,8 @@ Functions
- -

◆ mi_process_info()

+ +

◆ mi_process_info()

@@ -426,6 +426,12 @@ Functions void mi_process_info ( size_t *  + elapsed_msecs, + + + + + size_t *  user_msecs, @@ -475,7 +481,8 @@ Functions

Return process information (time and memory usage).

Parameters
- + + diff --git a/docs/group__extended.js b/docs/group__extended.js index 7f298b16..ed4a8b46 100644 --- a/docs/group__extended.js +++ b/docs/group__extended.js @@ -9,7 +9,7 @@ var group__extended = [ "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_process_info", "group__extended.html#ga9144506d5ffa8cc03547867bd15e1032", 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 ], diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index cbff636b..915b2d59 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -102,12 +102,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
mimalloc-doc.h
-
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
83 
87 
91 void mi_free(void* p);
92 
97 void* mi_malloc(size_t size);
98 
103 void* mi_zalloc(size_t size);
104 
114 void* mi_calloc(size_t count, size_t size);
115 
128 void* mi_realloc(void* p, size_t newsize);
129 
140 void* mi_recalloc(void* p, size_t count, size_t size);
141 
155 void* mi_expand(void* p, size_t newsize);
156 
166 void* mi_mallocn(size_t count, size_t size);
167 
177 void* mi_reallocn(void* p, size_t count, size_t size);
178 
195 void* mi_reallocf(void* p, size_t newsize);
196 
197 
206 char* mi_strdup(const char* s);
207 
217 char* mi_strndup(const char* s, size_t n);
218 
231 char* mi_realpath(const char* fname, char* resolved_name);
232 
234 
235 // ------------------------------------------------------
236 // Extended functionality
237 // ------------------------------------------------------
238 
242 
245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
246 
254 void* mi_malloc_small(size_t size);
255 
263 void* mi_zalloc_small(size_t size);
264 
279 size_t mi_usable_size(void* p);
280 
290 size_t mi_good_size(size_t size);
291 
299 void mi_collect(bool force);
300 
305 void mi_stats_print(void* out);
306 
312 void mi_stats_print_out(mi_output_fun* out, void* arg);
313 
315 void mi_stats_reset(void);
316 
318 void mi_stats_merge(void);
319 
323 void mi_thread_init(void);
324 
329 void mi_thread_done(void);
330 
336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
337 
344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
345 
361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
362 
368 typedef void (mi_output_fun)(const char* msg, void* arg);
369 
376 void mi_register_output(mi_output_fun* out, void* arg);
377 
383 typedef void (mi_error_fun)(int err, void* arg);
384 
400 void mi_register_error(mi_error_fun* errfun, void* arg);
401 
406 bool mi_is_in_heap_region(const void* p);
407 
408 
421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
422 
435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
436 
437 
442 bool mi_is_redirected();
443 
456 void mi_process_info(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);
457 
459 
460 // ------------------------------------------------------
461 // Aligned allocation
462 // ------------------------------------------------------
463 
469 
482 void* mi_malloc_aligned(size_t size, size_t alignment);
483 void* mi_zalloc_aligned(size_t size, size_t alignment);
484 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
485 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
486 
497 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
498 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
499 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
500 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
501 
503 
509 
514 struct mi_heap_s;
515 
520 typedef struct mi_heap_s mi_heap_t;
521 
524 
532 void mi_heap_delete(mi_heap_t* heap);
533 
541 void mi_heap_destroy(mi_heap_t* heap);
542 
547 
551 
558 
560 void mi_heap_collect(mi_heap_t* heap, bool force);
561 
564 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
565 
569 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
570 
573 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
574 
577 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
578 
581 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
582 
585 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
586 
589 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
590 
593 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
594 
595 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
596 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
597 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
598 
599 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
600 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
601 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
602 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
603 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
604 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
605 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
606 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
607 
609 
610 
619 
620 void* mi_rezalloc(void* p, size_t newsize);
621 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
622 
623 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
624 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
625 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
626 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
627 
628 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
629 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
630 
631 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
632 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
633 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
634 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
635 
637 
646 
658 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
659 
661 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
662 
664 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
665 
667 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
668 
670 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
671 
673 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
674 
676 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
677 
679 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
680 
682 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
683 
685 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
686 
688 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
689 
691 
697 
704 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
705 
714 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
715 
723 bool mi_check_owned(const void* p);
724 
727 typedef struct mi_heap_area_s {
728  void* blocks;
729  size_t reserved;
730  size_t committed;
731  size_t used;
732  size_t block_size;
734 
742 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);
743 
755 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
756 
758 
764 
766 typedef enum mi_option_e {
767  // stable options
771  // the following options are experimental
785 } mi_option_t;
786 
787 
788 bool mi_option_is_enabled(mi_option_t option);
789 void mi_option_enable(mi_option_t option);
790 void mi_option_disable(mi_option_t option);
791 void mi_option_set_enabled(mi_option_t option, bool enable);
792 void mi_option_set_enabled_default(mi_option_t option, bool enable);
793 
794 long mi_option_get(mi_option_t option);
795 void mi_option_set(mi_option_t option, long value);
796 void mi_option_set_default(mi_option_t option, long value);
797 
798 
800 
807 
808 void* mi_recalloc(void* p, size_t count, size_t size);
809 size_t mi_malloc_size(const void* p);
810 size_t mi_malloc_usable_size(const void *p);
811 
813 void mi_cfree(void* p);
814 
815 int mi_posix_memalign(void** p, size_t alignment, size_t size);
816 int mi__posix_memalign(void** p, size_t alignment, size_t size);
817 void* mi_memalign(size_t alignment, size_t size);
818 void* mi_valloc(size_t size);
819 
820 void* mi_pvalloc(size_t size);
821 void* mi_aligned_alloc(size_t alignment, size_t size);
822 void* mi_reallocarray(void* p, size_t count, size_t size);
823 
824 void mi_free_size(void* p, size_t size);
825 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
826 void mi_free_aligned(void* p, size_t alignment);
827 
829 
842 
844 void* mi_new(std::size_t n) noexcept(false);
845 
847 void* mi_new_n(size_t count, size_t size) noexcept(false);
848 
850 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
851 
853 void* mi_new_nothrow(size_t n);
854 
856 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
857 
859 void* mi_new_realloc(void* p, size_t newsize);
860 
862 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
863 
871 template<class T> struct mi_stl_allocator { }
872 
874 
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
+
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
83 
87 
91 void mi_free(void* p);
92 
97 void* mi_malloc(size_t size);
98 
103 void* mi_zalloc(size_t size);
104 
114 void* mi_calloc(size_t count, size_t size);
115 
128 void* mi_realloc(void* p, size_t newsize);
129 
140 void* mi_recalloc(void* p, size_t count, size_t size);
141 
155 void* mi_expand(void* p, size_t newsize);
156 
166 void* mi_mallocn(size_t count, size_t size);
167 
177 void* mi_reallocn(void* p, size_t count, size_t size);
178 
195 void* mi_reallocf(void* p, size_t newsize);
196 
197 
206 char* mi_strdup(const char* s);
207 
217 char* mi_strndup(const char* s, size_t n);
218 
231 char* mi_realpath(const char* fname, char* resolved_name);
232 
234 
235 // ------------------------------------------------------
236 // Extended functionality
237 // ------------------------------------------------------
238 
242 
245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
246 
254 void* mi_malloc_small(size_t size);
255 
263 void* mi_zalloc_small(size_t size);
264 
279 size_t mi_usable_size(void* p);
280 
290 size_t mi_good_size(size_t size);
291 
299 void mi_collect(bool force);
300 
305 void mi_stats_print(void* out);
306 
312 void mi_stats_print_out(mi_output_fun* out, void* arg);
313 
315 void mi_stats_reset(void);
316 
318 void mi_stats_merge(void);
319 
323 void mi_thread_init(void);
324 
329 void mi_thread_done(void);
330 
336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
337 
344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
345 
361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
362 
368 typedef void (mi_output_fun)(const char* msg, void* arg);
369 
376 void mi_register_output(mi_output_fun* out, void* arg);
377 
383 typedef void (mi_error_fun)(int err, void* arg);
384 
400 void mi_register_error(mi_error_fun* errfun, void* arg);
401 
406 bool mi_is_in_heap_region(const void* p);
407 
408 
421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
422 
435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
436 
437 
442 bool mi_is_redirected();
443 
457 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);
458 
460 
461 // ------------------------------------------------------
462 // Aligned allocation
463 // ------------------------------------------------------
464 
470 
483 void* mi_malloc_aligned(size_t size, size_t alignment);
484 void* mi_zalloc_aligned(size_t size, size_t alignment);
485 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
486 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
487 
498 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
499 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
500 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
501 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
502 
504 
510 
515 struct mi_heap_s;
516 
521 typedef struct mi_heap_s mi_heap_t;
522 
525 
533 void mi_heap_delete(mi_heap_t* heap);
534 
542 void mi_heap_destroy(mi_heap_t* heap);
543 
548 
552 
559 
561 void mi_heap_collect(mi_heap_t* heap, bool force);
562 
565 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
566 
570 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
571 
574 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
575 
578 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
579 
582 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
583 
586 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
587 
590 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
591 
594 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
595 
596 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
597 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
598 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
599 
600 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
601 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
602 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
603 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
604 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
605 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
606 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
607 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
608 
610 
611 
620 
621 void* mi_rezalloc(void* p, size_t newsize);
622 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
623 
624 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
625 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
626 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
627 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
628 
629 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
630 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
631 
632 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
633 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
634 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
635 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
636 
638 
647 
659 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
660 
662 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
663 
665 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
666 
668 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
669 
671 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
672 
674 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
675 
677 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
678 
680 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
681 
683 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
684 
686 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
687 
689 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
690 
692 
698 
705 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
706 
715 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
716 
724 bool mi_check_owned(const void* p);
725 
728 typedef struct mi_heap_area_s {
729  void* blocks;
730  size_t reserved;
731  size_t committed;
732  size_t used;
733  size_t block_size;
735 
743 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);
744 
756 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
757 
759 
765 
767 typedef enum mi_option_e {
768  // stable options
772  // the following options are experimental
786 } mi_option_t;
787 
788 
789 bool mi_option_is_enabled(mi_option_t option);
790 void mi_option_enable(mi_option_t option);
791 void mi_option_disable(mi_option_t option);
792 void mi_option_set_enabled(mi_option_t option, bool enable);
793 void mi_option_set_enabled_default(mi_option_t option, bool enable);
794 
795 long mi_option_get(mi_option_t option);
796 void mi_option_set(mi_option_t option, long value);
797 void mi_option_set_default(mi_option_t option, long value);
798 
799 
801 
808 
809 void* mi_recalloc(void* p, size_t count, size_t size);
810 size_t mi_malloc_size(const void* p);
811 size_t mi_malloc_usable_size(const void *p);
812 
814 void mi_cfree(void* p);
815 
816 int mi_posix_memalign(void** p, size_t alignment, size_t size);
817 int mi__posix_memalign(void** p, size_t alignment, size_t size);
818 void* mi_memalign(size_t alignment, size_t size);
819 void* mi_valloc(size_t size);
820 
821 void* mi_pvalloc(size_t size);
822 void* mi_aligned_alloc(size_t alignment, size_t size);
823 void* mi_reallocarray(void* p, size_t count, size_t size);
824 
825 void mi_free_size(void* p, size_t size);
826 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
827 void mi_free_aligned(void* p, size_t alignment);
828 
830 
843 
845 void* mi_new(std::size_t n) noexcept(false);
846 
848 void* mi_new_n(size_t count, size_t size) noexcept(false);
849 
851 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
852 
854 void* mi_new_nothrow(size_t n);
855 
857 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
858 
860 void* mi_new_realloc(void* p, size_t newsize);
861 
863 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
864 
872 template<class T> struct mi_stl_allocator { }
873 
875 
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
void * mi_new_nothrow(size_t n)
like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
void * mi_reallocn(void *p, size_t count, size_t size)
Re-allocate memory to count elements of size bytes.
void * mi_malloc_aligned(size_t size, size_t alignment)
Allocate size bytes aligned by alignment.
void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
-
void mi_process_info(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_stats_reset(void)
Reset statistics.
void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
bool mi_option_is_enabled(mi_option_t option)
@@ -123,15 +122,15 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void mi_stats_print_out(mi_output_fun *out, void *arg)
Print the main statistics.
void() mi_error_fun(int err, void *arg)
Type of error callback functions.
Definition: mimalloc-doc.h:383
void * mi_rezalloc(void *p, size_t newsize)
-
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:772
+
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:773
void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
Allocate zero-initialized in a specific heap.
void mi_option_set(mi_option_t option, long value)
-
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:773
+
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:774
void mi_cfree(void *p)
Just as free but also checks if the pointer p belongs to our heap.
void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
-
Definition: mimalloc-doc.h:784
+
Definition: mimalloc-doc.h:785
void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:728
+
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:729
void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
void mi_option_enable(mi_option_t option)
int mi__posix_memalign(void **p, size_t alignment, size_t size)
@@ -139,6 +138,7 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
char * mi_heap_strdup(mi_heap_t *heap, const char *s)
Duplicate a string 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_calloc_aligned_at(mi_heap_t *heap, size_t count, size_t size, size_t alignment, size_t offset)
+
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_calloc_aligned(size_t count, size_t size, size_t alignment)
void * mi_heap_zalloc_aligned(mi_heap_t *heap, size_t size, size_t alignment)
void * mi_zalloc_small(size_t size)
Allocate a zero initialized small object.
@@ -149,35 +149,35 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
void * mi_zalloc(size_t size)
Allocate zero-initialized size bytes.
void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
-
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:776
+
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:777
void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
Allocate count zero-initialized elements in a specific heap.
void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
bool mi_is_redirected()
Is the C runtime malloc API redirected?
-
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:732
+
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:733
void * mi_reallocarray(void *p, size_t count, size_t size)
int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most t...
void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
Type of deferred free functions.
Definition: mimalloc-doc.h:344
bool mi_is_in_heap_region(const void *p)
Is a pointer part of our heap?
void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc e...
void * mi_realloc(void *p, size_t newsize)
Re-allocate memory to newsize bytes.
-
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:775
+
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:776
void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
void mi_free_size_aligned(void *p, size_t size, size_t alignment)
void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:777
+
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:778
void mi_thread_done(void)
Uninitialize mimalloc on a thread.
bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
Visit all areas and blocks in a heap.
-
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:780
+
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:781
void * mi_malloc(size_t size)
Allocate size bytes.
void mi_register_error(mi_error_fun *errfun, void *arg)
Register an error callback function.
-
Experimental.
Definition: mimalloc-doc.h:781
+
Experimental.
Definition: mimalloc-doc.h:782
char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
Duplicate a string of at most length n in a specific heap.
-
bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
Visitor function passed to mi_heap_visit_blocks()
Definition: mimalloc-doc.h:742
+
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:743
void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
char * mi_realpath(const char *fname, char *resolved_name)
Resolve a file path name.
-
Print error messages to stderr.
Definition: mimalloc-doc.h:768
-
Experimental.
Definition: mimalloc-doc.h:778
+
Print error messages to stderr.
Definition: mimalloc-doc.h:769
+
Experimental.
Definition: mimalloc-doc.h:779
void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
void * mi_new_aligned_nothrow(size_t n, size_t alignment)
like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
void * mi_memalign(size_t alignment, size_t size)
@@ -185,11 +185,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
Does a heap contain a pointer to a previously allocated block?
void mi_heap_collect(mi_heap_t *heap, bool force)
Release outstanding resources in a specific heap.
void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
-
Print verbose messages to stderr.
Definition: mimalloc-doc.h:770
+
Print verbose messages to stderr.
Definition: mimalloc-doc.h:771
void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
Allocate size bytes aligned by alignment at a specified offset.
void mi_heap_delete(mi_heap_t *heap)
Delete a previously allocated heap.
-
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:783
+
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:784
mi_heap_t * mi_heap_get_default()
Get the default heap that is used for mi_malloc() et al.
int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs ...
void mi_option_disable(mi_option_t option)
@@ -198,26 +198,26 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void mi_thread_init(void)
Initialize mimalloc on a thread.
size_t mi_good_size(size_t size)
Return the used allocation size.
void mi_stats_print(void *out)
Deprecated.
-
Experimental.
Definition: mimalloc-doc.h:782
+
Experimental.
Definition: mimalloc-doc.h:783
void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
Allocate count elements in a specific heap.
-
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:727
+
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:728
void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
Print out heap statistics for this thread.
-
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:769
+
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:770
void * mi_zalloc_aligned(size_t size, size_t alignment)
-
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:729
-
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:520
-
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:731
+
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:730
+
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:521
+
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:732
void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
Register a deferred free function.
void mi_free_size(void *p, size_t size)
void mi_collect(bool force)
Eagerly free memory.
void * mi_new_reallocn(void *p, size_t newcount, size_t size)
like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc excepti...
void mi_heap_destroy(mi_heap_t *heap)
Destroy a heap, freeing all its still allocated blocks.
void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
-
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:774
+
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:775
void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
void mi_register_output(mi_output_fun *out, void *arg)
Register an output function.
-
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:871
+
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:872
void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
Allocate a small object in a specific heap.
void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
size_t mi_malloc_usable_size(const void *p)
@@ -234,11 +234,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
mi_heap_t * mi_heap_get_backing()
Get the backing heap.
void mi_free_aligned(void *p, size_t alignment)
void * mi_new(std::size_t n) noexcept(false)
like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception...
-
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:779
+
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:780
mi_heap_t * mi_heap_new()
Create a new heap that can be used for allocation.
void * mi_heap_malloc(mi_heap_t *heap, size_t size)
Allocate in a specific heap.
-
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:730
-
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:766
+
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:731
+
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:767
bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
Check safely if any pointer is part of a heap.
mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
Set the default heap to use for mi_malloc() et al.
diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js index 92f8d8c9..4a1e93fa 100644 --- a/docs/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -53,8 +53,8 @@ var NAVTREEINDEX0 = "group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,6], "group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,8], "group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,13], +"group__extended.html#ga7d862c2affd5790381da14eb102a364d":[5,1,9], "group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,15], -"group__extended.html#ga9144506d5ffa8cc03547867bd15e1032":[5,1,9], "group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,11], "group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,7], "group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,21], diff --git a/docs/search/all_6.js b/docs/search/all_6.js index 4e4c8a3f..491883f4 100644 --- a/docs/search/all_6.js +++ b/docs/search/all_6.js @@ -106,7 +106,7 @@ var searchData= ['mi_5foption_5fverbose',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], ['mi_5foutput_5ffun',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',1,'mimalloc-doc.h']]], ['mi_5fposix_5fmemalign',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo',['mi_process_info',['../group__extended.html#ga9144506d5ffa8cc03547867bd15e1032',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], ['mi_5fpvalloc',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], ['mi_5frealloc',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], ['mi_5frealloc_5faligned',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js index fc333d5f..b188b270 100644 --- a/docs/search/functions_0.js +++ b/docs/search/functions_0.js @@ -75,7 +75,7 @@ var searchData= ['mi_5foption_5fset_5fenabled',['mi_option_set_enabled',['../group__options.html#ga9a13d05fcb77489cb06d4d017ebd8bed',1,'mimalloc-doc.h']]], ['mi_5foption_5fset_5fenabled_5fdefault',['mi_option_set_enabled_default',['../group__options.html#ga65518b69ec5d32336b50e07f74b3f629',1,'mimalloc-doc.h']]], ['mi_5fposix_5fmemalign',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], - ['mi_5fprocess_5finfo',['mi_process_info',['../group__extended.html#ga9144506d5ffa8cc03547867bd15e1032',1,'mimalloc-doc.h']]], + ['mi_5fprocess_5finfo',['mi_process_info',['../group__extended.html#ga7d862c2affd5790381da14eb102a364d',1,'mimalloc-doc.h']]], ['mi_5fpvalloc',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], ['mi_5frealloc',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], ['mi_5frealloc_5faligned',['mi_realloc_aligned',['../group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae',1,'mimalloc-doc.h']]], From b5196e5971fb64061116ce78886fdf03adaa5bec Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 10:33:33 -0700 Subject: [PATCH 124/172] further updates to documentation --- doc/mimalloc-doc.h | 22 ++++++++---- docs/index.html | 7 ++-- docs/mimalloc-doc_8h_source.html | 60 ++++++++++++++++---------------- 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 1566ba24..7c238d29 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -26,17 +26,25 @@ without code changes, for example, on Unix you can use it as: Notable aspects of the design include: -- __small and consistent__: the library is less than 6k LOC using simple and +- __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). -- __free list sharding__: the big idea: instead of one big free list (per size class) we have - many smaller lists per memory "page" which both reduces fragmentation - and increases locality -- +- __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 memory "page" in _mimalloc_ contains blocks of one size class and is - usually 64KiB on a 64-bit system). + (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 @@ -51,7 +59,7 @@ Notable aspects of the design include: 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](#performance)), - _mimalloc_ always outperforms all other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), + _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. diff --git a/docs/index.html b/docs/index.html index ce9c983d..01af9bec 100644 --- a/docs/index.html +++ b/docs/index.html @@ -105,13 +105,14 @@ $(document).ready(function(){initNavTree('index.html','');});

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 less than 6k 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).
  • -
  • free list sharding: the big idea: instead of one big free list (per size class) we have many smaller lists per memory "page" which both reduces fragmentation and increases locality – things that are allocated close in time get allocated close in memory. (A memory "page" in mimalloc contains blocks of one size class and is usually 64KiB on a 64-bit system).
  • +
  • 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).
  • +
  • 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 3% 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 always 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.
  • +
  • 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.

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

Further information:

diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index 915b2d59..6d2e86ff 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -102,7 +102,7 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
mimalloc-doc.h
-
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
83 
87 
91 void mi_free(void* p);
92 
97 void* mi_malloc(size_t size);
98 
103 void* mi_zalloc(size_t size);
104 
114 void* mi_calloc(size_t count, size_t size);
115 
128 void* mi_realloc(void* p, size_t newsize);
129 
140 void* mi_recalloc(void* p, size_t count, size_t size);
141 
155 void* mi_expand(void* p, size_t newsize);
156 
166 void* mi_mallocn(size_t count, size_t size);
167 
177 void* mi_reallocn(void* p, size_t count, size_t size);
178 
195 void* mi_reallocf(void* p, size_t newsize);
196 
197 
206 char* mi_strdup(const char* s);
207 
217 char* mi_strndup(const char* s, size_t n);
218 
231 char* mi_realpath(const char* fname, char* resolved_name);
232 
234 
235 // ------------------------------------------------------
236 // Extended functionality
237 // ------------------------------------------------------
238 
242 
245 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
246 
254 void* mi_malloc_small(size_t size);
255 
263 void* mi_zalloc_small(size_t size);
264 
279 size_t mi_usable_size(void* p);
280 
290 size_t mi_good_size(size_t size);
291 
299 void mi_collect(bool force);
300 
305 void mi_stats_print(void* out);
306 
312 void mi_stats_print_out(mi_output_fun* out, void* arg);
313 
315 void mi_stats_reset(void);
316 
318 void mi_stats_merge(void);
319 
323 void mi_thread_init(void);
324 
329 void mi_thread_done(void);
330 
336 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
337 
344 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
345 
361 void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
362 
368 typedef void (mi_output_fun)(const char* msg, void* arg);
369 
376 void mi_register_output(mi_output_fun* out, void* arg);
377 
383 typedef void (mi_error_fun)(int err, void* arg);
384 
400 void mi_register_error(mi_error_fun* errfun, void* arg);
401 
406 bool mi_is_in_heap_region(const void* p);
407 
408 
421 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
422 
435 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
436 
437 
442 bool mi_is_redirected();
443 
457 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);
458 
460 
461 // ------------------------------------------------------
462 // Aligned allocation
463 // ------------------------------------------------------
464 
470 
483 void* mi_malloc_aligned(size_t size, size_t alignment);
484 void* mi_zalloc_aligned(size_t size, size_t alignment);
485 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
486 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
487 
498 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
499 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
500 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
501 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
502 
504 
510 
515 struct mi_heap_s;
516 
521 typedef struct mi_heap_s mi_heap_t;
522 
525 
533 void mi_heap_delete(mi_heap_t* heap);
534 
542 void mi_heap_destroy(mi_heap_t* heap);
543 
548 
552 
559 
561 void mi_heap_collect(mi_heap_t* heap, bool force);
562 
565 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
566 
570 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
571 
574 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
575 
578 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
579 
582 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
583 
586 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
587 
590 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
591 
594 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
595 
596 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
597 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
598 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
599 
600 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
601 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
602 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
603 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
604 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
605 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
606 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
607 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
608 
610 
611 
620 
621 void* mi_rezalloc(void* p, size_t newsize);
622 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
623 
624 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
625 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
626 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
627 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
628 
629 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
630 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
631 
632 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
633 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
634 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
635 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
636 
638 
647 
659 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
660 
662 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
663 
665 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
666 
668 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
669 
671 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
672 
674 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
675 
677 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
678 
680 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
681 
683 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
684 
686 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
687 
689 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
690 
692 
698 
705 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
706 
715 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
716 
724 bool mi_check_owned(const void* p);
725 
728 typedef struct mi_heap_area_s {
729  void* blocks;
730  size_t reserved;
731  size_t committed;
732  size_t used;
733  size_t block_size;
735 
743 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);
744 
756 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
757 
759 
765 
767 typedef enum mi_option_e {
768  // stable options
772  // the following options are experimental
786 } mi_option_t;
787 
788 
789 bool mi_option_is_enabled(mi_option_t option);
790 void mi_option_enable(mi_option_t option);
791 void mi_option_disable(mi_option_t option);
792 void mi_option_set_enabled(mi_option_t option, bool enable);
793 void mi_option_set_enabled_default(mi_option_t option, bool enable);
794 
795 long mi_option_get(mi_option_t option);
796 void mi_option_set(mi_option_t option, long value);
797 void mi_option_set_default(mi_option_t option, long value);
798 
799 
801 
808 
809 void* mi_recalloc(void* p, size_t count, size_t size);
810 size_t mi_malloc_size(const void* p);
811 size_t mi_malloc_usable_size(const void *p);
812 
814 void mi_cfree(void* p);
815 
816 int mi_posix_memalign(void** p, size_t alignment, size_t size);
817 int mi__posix_memalign(void** p, size_t alignment, size_t size);
818 void* mi_memalign(size_t alignment, size_t size);
819 void* mi_valloc(size_t size);
820 
821 void* mi_pvalloc(size_t size);
822 void* mi_aligned_alloc(size_t alignment, size_t size);
823 void* mi_reallocarray(void* p, size_t count, size_t size);
824 
825 void mi_free_size(void* p, size_t size);
826 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
827 void mi_free_aligned(void* p, size_t alignment);
828 
830 
843 
845 void* mi_new(std::size_t n) noexcept(false);
846 
848 void* mi_new_n(size_t count, size_t size) noexcept(false);
849 
851 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
852 
854 void* mi_new_nothrow(size_t n);
855 
857 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
858 
860 void* mi_new_realloc(void* p, size_t newsize);
861 
863 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
864 
872 template<class T> struct mi_stl_allocator { }
873 
875 
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
+
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 #error "documentation file only!"
9 
10 
91 
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 
344 void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
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 
416 
429 int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
430 
443 int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs);
444 
445 
450 bool mi_is_redirected();
451 
465 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);
466 
468 
469 // ------------------------------------------------------
470 // Aligned allocation
471 // ------------------------------------------------------
472 
478 
491 void* mi_malloc_aligned(size_t size, size_t alignment);
492 void* mi_zalloc_aligned(size_t size, size_t alignment);
493 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
494 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
495 
506 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
507 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
508 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
509 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
510 
512 
518 
523 struct mi_heap_s;
524 
529 typedef struct mi_heap_s mi_heap_t;
530 
533 
541 void mi_heap_delete(mi_heap_t* heap);
542 
550 void mi_heap_destroy(mi_heap_t* heap);
551 
556 
560 
567 
569 void mi_heap_collect(mi_heap_t* heap, bool force);
570 
573 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
574 
578 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
579 
582 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
583 
586 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
587 
590 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
591 
594 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
595 
598 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
599 
602 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
603 
604 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
605 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
606 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
607 
608 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
609 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
610 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
611 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
612 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
613 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
614 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
615 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
616 
618 
619 
628 
629 void* mi_rezalloc(void* p, size_t newsize);
630 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
631 
632 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
633 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
634 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
635 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
636 
637 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
638 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
639 
640 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
641 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
642 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
643 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
644 
646 
655 
667 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
668 
670 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
671 
673 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
674 
676 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
677 
679 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
680 
682 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
683 
685 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
686 
688 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
689 
691 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
692 
694 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
695 
697 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
698 
700 
706 
713 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
714 
723 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
724 
732 bool mi_check_owned(const void* p);
733 
736 typedef struct mi_heap_area_s {
737  void* blocks;
738  size_t reserved;
739  size_t committed;
740  size_t used;
741  size_t block_size;
743 
751 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);
752 
764 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
765 
767 
773 
775 typedef enum mi_option_e {
776  // stable options
780  // the following options are experimental
794 } mi_option_t;
795 
796 
797 bool mi_option_is_enabled(mi_option_t option);
798 void mi_option_enable(mi_option_t option);
799 void mi_option_disable(mi_option_t option);
800 void mi_option_set_enabled(mi_option_t option, bool enable);
801 void mi_option_set_enabled_default(mi_option_t option, bool enable);
802 
803 long mi_option_get(mi_option_t option);
804 void mi_option_set(mi_option_t option, long value);
805 void mi_option_set_default(mi_option_t option, long value);
806 
807 
809 
816 
817 void* mi_recalloc(void* p, size_t count, size_t size);
818 size_t mi_malloc_size(const void* p);
819 size_t mi_malloc_usable_size(const void *p);
820 
822 void mi_cfree(void* p);
823 
824 int mi_posix_memalign(void** p, size_t alignment, size_t size);
825 int mi__posix_memalign(void** p, size_t alignment, size_t size);
826 void* mi_memalign(size_t alignment, size_t size);
827 void* mi_valloc(size_t size);
828 
829 void* mi_pvalloc(size_t size);
830 void* mi_aligned_alloc(size_t alignment, size_t size);
831 void* mi_reallocarray(void* p, size_t count, size_t size);
832 
833 void mi_free_size(void* p, size_t size);
834 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
835 void mi_free_aligned(void* p, size_t alignment);
836 
838 
851 
853 void* mi_new(std::size_t n) noexcept(false);
854 
856 void* mi_new_n(size_t count, size_t size) noexcept(false);
857 
859 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
860 
862 void* mi_new_nothrow(size_t n);
863 
865 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
866 
868 void* mi_new_realloc(void* p, size_t newsize);
869 
871 void* mi_new_reallocn(void* p, size_t newcount, size_t size);
872 
880 template<class T> struct mi_stl_allocator { }
881 
883 
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
void * mi_new_nothrow(size_t n)
like mi_malloc, but when out of memory, use std::get_new_handler but return NULL on failure.
void * mi_reallocn(void *p, size_t count, size_t size)
Re-allocate memory to count elements of size bytes.
void * mi_malloc_aligned(size_t size, size_t alignment)
Allocate size bytes aligned by alignment.
@@ -120,17 +120,17 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void * mi_new_n(size_t count, size_t size) noexcept(false)
like mi_mallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exceptio...
void mi_option_set_default(mi_option_t option, long value)
void mi_stats_print_out(mi_output_fun *out, void *arg)
Print the main statistics.
-
void() mi_error_fun(int err, void *arg)
Type of error callback functions.
Definition: mimalloc-doc.h:383
+
void() mi_error_fun(int err, void *arg)
Type of error callback functions.
Definition: mimalloc-doc.h:391
void * mi_rezalloc(void *p, size_t newsize)
-
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:773
+
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:781
void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
Allocate zero-initialized in a specific heap.
void mi_option_set(mi_option_t option, long value)
-
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:774
+
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:782
void mi_cfree(void *p)
Just as free but also checks if the pointer p belongs to our heap.
void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
-
Definition: mimalloc-doc.h:785
+
Definition: mimalloc-doc.h:793
void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:729
+
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:737
void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
void mi_option_enable(mi_option_t option)
int mi__posix_memalign(void **p, size_t alignment, size_t size)
@@ -149,35 +149,35 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
void * mi_zalloc(size_t size)
Allocate zero-initialized size bytes.
void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
-
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:777
+
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:785
void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
Allocate count zero-initialized elements in a specific heap.
void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
bool mi_is_redirected()
Is the C runtime malloc API redirected?
-
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:733
+
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:741
void * mi_reallocarray(void *p, size_t count, size_t size)
int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most t...
-
void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
Type of deferred free functions.
Definition: mimalloc-doc.h:344
+
void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
Type of deferred free functions.
Definition: mimalloc-doc.h:352
bool mi_is_in_heap_region(const void *p)
Is a pointer part of our heap?
void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
like mi_malloc_aligned(), but when out of memory, use std::get_new_handler and raise std::bad_alloc e...
void * mi_realloc(void *p, size_t newsize)
Re-allocate memory to newsize bytes.
-
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:776
+
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:784
void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
void mi_free_size_aligned(void *p, size_t size, size_t alignment)
void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:778
+
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:786
void mi_thread_done(void)
Uninitialize mimalloc on a thread.
bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
Visit all areas and blocks in a heap.
-
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:781
+
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:789
void * mi_malloc(size_t size)
Allocate size bytes.
void mi_register_error(mi_error_fun *errfun, void *arg)
Register an error callback function.
-
Experimental.
Definition: mimalloc-doc.h:782
+
Experimental.
Definition: mimalloc-doc.h:790
char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
Duplicate a string of at most length n in a specific heap.
-
bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
Visitor function passed to mi_heap_visit_blocks()
Definition: mimalloc-doc.h:743
+
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:751
void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
char * mi_realpath(const char *fname, char *resolved_name)
Resolve a file path name.
-
Print error messages to stderr.
Definition: mimalloc-doc.h:769
-
Experimental.
Definition: mimalloc-doc.h:779
+
Print error messages to stderr.
Definition: mimalloc-doc.h:777
+
Experimental.
Definition: mimalloc-doc.h:787
void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
void * mi_new_aligned_nothrow(size_t n, size_t alignment)
like mi_malloc_aligned, but when out of memory, use std::get_new_handler but return NULL on failure.
void * mi_memalign(size_t alignment, size_t size)
@@ -185,11 +185,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
Does a heap contain a pointer to a previously allocated block?
void mi_heap_collect(mi_heap_t *heap, bool force)
Release outstanding resources in a specific heap.
void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
-
Print verbose messages to stderr.
Definition: mimalloc-doc.h:771
+
Print verbose messages to stderr.
Definition: mimalloc-doc.h:779
void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
Allocate size bytes aligned by alignment at a specified offset.
void mi_heap_delete(mi_heap_t *heap)
Delete a previously allocated heap.
-
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:784
+
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:792
mi_heap_t * mi_heap_get_default()
Get the default heap that is used for mi_malloc() et al.
int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs ...
void mi_option_disable(mi_option_t option)
@@ -198,30 +198,30 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void mi_thread_init(void)
Initialize mimalloc on a thread.
size_t mi_good_size(size_t size)
Return the used allocation size.
void mi_stats_print(void *out)
Deprecated.
-
Experimental.
Definition: mimalloc-doc.h:783
+
Experimental.
Definition: mimalloc-doc.h:791
void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
Allocate count elements in a specific heap.
-
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:728
+
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:736
void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
Print out heap statistics for this thread.
-
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:770
+
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:778
void * mi_zalloc_aligned(size_t size, size_t alignment)
-
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:730
-
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:521
-
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:732
+
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:738
+
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:529
+
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:740
void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
Register a deferred free function.
void mi_free_size(void *p, size_t size)
void mi_collect(bool force)
Eagerly free memory.
void * mi_new_reallocn(void *p, size_t newcount, size_t size)
like mi_reallocn(), but when out of memory, use std::get_new_handler and raise std::bad_alloc excepti...
void mi_heap_destroy(mi_heap_t *heap)
Destroy a heap, freeing all its still allocated blocks.
void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
-
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:775
+
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:783
void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
void mi_register_output(mi_output_fun *out, void *arg)
Register an output function.
-
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:872
+
std::allocator implementation for mimalloc for use in STL containers.
Definition: mimalloc-doc.h:880
void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
Allocate a small object in a specific heap.
void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
size_t mi_malloc_usable_size(const void *p)
-
void() mi_output_fun(const char *msg, void *arg)
Type of output functions.
Definition: mimalloc-doc.h:368
+
void() mi_output_fun(const char *msg, void *arg)
Type of output functions.
Definition: mimalloc-doc.h:376
char * mi_strdup(const char *s)
Allocate and duplicate a string.
void * mi_heap_realloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
void * mi_reallocf(void *p, size_t newsize)
Re-allocate memory to newsize bytes,.
@@ -234,11 +234,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
mi_heap_t * mi_heap_get_backing()
Get the backing heap.
void mi_free_aligned(void *p, size_t alignment)
void * mi_new(std::size_t n) noexcept(false)
like mi_malloc(), but when out of memory, use std::get_new_handler and raise std::bad_alloc exception...
-
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:780
+
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:788
mi_heap_t * mi_heap_new()
Create a new heap that can be used for allocation.
void * mi_heap_malloc(mi_heap_t *heap, size_t size)
Allocate in a specific heap.
-
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:731
-
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:767
+
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:739
+
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:775
bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
Check safely if any pointer is part of a heap.
mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
Set the default heap to use for mi_malloc() et al.
From abcaa4a4f2e48dadb24b64b8984243c3cd777ce3 Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 24 Sep 2020 10:38:18 -0700 Subject: [PATCH 125/172] Update readme.md link to mi_process_info --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2821802e..bf879d49 100644 --- a/readme.md +++ b/readme.md @@ -74,7 +74,7 @@ Enjoy! ### Releases * 2020-09-24, `v1.6.6`: stable release 1.6: using standard C atomics, passing tsan testing, improved - handling of failing to commit on Windows, add `mi_process_info` api call. + handling of failing to commit on Windows, add [`mi_process_info`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc.h#L156) api call. * 2020-08-06, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, support for IllumOS and Haiku, NUMA support for Vista/XP, improved NUMA detection for AMD Ryzen, ubsan support. * 2020-05-05, `v1.6.3`: stable release 1.6: improved behavior in out-of-memory situations, improved malloc zones on macOS, From 44d030ba9d63b2a4f1dcb78d8592928b228b1735 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 16:28:25 -0700 Subject: [PATCH 126/172] fuse used decrement with test for slightly better codegen --- src/alloc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 2cef8bcd..8e863a67 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -448,8 +448,7 @@ void mi_free(void* p) mi_attr_noexcept #endif mi_block_set_next(page, block, page->local_free); page->local_free = block; - page->used--; - if (mi_unlikely(mi_page_all_free(page))) { + if (mi_unlikely(--page->used == 0)) { // using this expression generates better code than: page->used--; if (mi_page_all_free(page)) _mi_page_retire(page); } } From 1233de73884732f8be6dc26354848bd948848405 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 16:29:41 -0700 Subject: [PATCH 127/172] use relaxed load for region count as that is monotonic --- src/region.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/region.c b/src/region.c index aa4f95b5..b6d0da31 100644 --- a/src/region.c +++ b/src/region.c @@ -240,7 +240,7 @@ static bool mi_region_is_suitable(const mem_region_t* region, int numa_node, boo static bool mi_region_try_claim(int numa_node, size_t blocks, bool allow_large, mem_region_t** region, mi_bitmap_index_t* bit_idx, mi_os_tld_t* tld) { // try all regions for a free slot - const size_t count = mi_atomic_load_acquire(®ions_count); + const size_t count = mi_atomic_load_relaxed(®ions_count); // monotonic, so ok to be relaxed size_t idx = tld->region_idx; // Or start at 0 to reuse low addresses? Starting at 0 seems to increase latency though for (size_t visited = 0; visited < count; visited++, idx++) { if (idx >= count) idx = 0; // wrap around From 13a4030619edada133e1a3c06c6287ad5a9c74c1 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 24 Sep 2020 16:30:40 -0700 Subject: [PATCH 128/172] bump version to 1.6.7 --- include/mimalloc.h | 2 +- readme.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 05cf92e4..254a7d9c 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 166 // major + 2 digits minor +#define MI_MALLOC_VERSION 167 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes diff --git a/readme.md b/readme.md index bf879d49..9419a658 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent [performance](#performance) characteristics. Initially developed by Daan Leijen for the run-time systems of the [Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages. -Latest release:`v1.6.6` (2020-09-24). +Latest release:`v1.6.7` (2020-09-24). It is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: @@ -73,7 +73,7 @@ Enjoy! ### Releases -* 2020-09-24, `v1.6.6`: stable release 1.6: using standard C atomics, passing tsan testing, improved +* 2020-09-24, `v1.6.7`: stable release 1.6: using standard C atomics, passing tsan testing, improved handling of failing to commit on Windows, add [`mi_process_info`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc.h#L156) api call. * 2020-08-06, `v1.6.4`: stable release 1.6: improved error recovery in low-memory situations, support for IllumOS and Haiku, NUMA support for Vista/XP, improved NUMA detection for AMD Ryzen, ubsan support. From ead1f349305d59b81c3b11076e97f760c3c72a02 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 11 Oct 2020 10:50:09 -0700 Subject: [PATCH 129/172] add extra NULL checks for heap parameters in the heap API (issue #311) --- src/heap.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/heap.c b/src/heap.c index b1079e14..4a91786b 100644 --- a/src/heap.c +++ b/src/heap.c @@ -114,7 +114,7 @@ static bool mi_heap_page_never_delayed_free(mi_heap_t* heap, mi_page_queue_t* pq static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) { - if (!mi_heap_is_initialized(heap)) return; + if (heap==NULL || !mi_heap_is_initialized(heap)) return; _mi_deferred_free(heap, collect >= MI_FORCE); // note: never reclaim on collect but leave it to threads that need storage to reclaim @@ -213,6 +213,7 @@ uintptr_t _mi_heap_random_next(mi_heap_t* heap) { // zero out the page queues static void mi_heap_reset_pages(mi_heap_t* heap) { + mi_assert_internal(heap != NULL); mi_assert_internal(mi_heap_is_initialized(heap)); // TODO: copy full empty heap instead? memset(&heap->pages_free_direct, 0, sizeof(heap->pages_free_direct)); @@ -228,6 +229,7 @@ static void mi_heap_reset_pages(mi_heap_t* heap) { static void mi_heap_free(mi_heap_t* heap) { mi_assert(heap != NULL); mi_assert_internal(mi_heap_is_initialized(heap)); + if (heap==NULL || !mi_heap_is_initialized(heap)) return; if (mi_heap_is_backing(heap)) return; // dont free the backing heap // reset default @@ -310,7 +312,7 @@ void mi_heap_destroy(mi_heap_t* heap) { mi_assert(mi_heap_is_initialized(heap)); mi_assert(heap->no_reclaim); mi_assert_expensive(mi_heap_is_valid(heap)); - if (!mi_heap_is_initialized(heap)) return; + if (heap==NULL || !mi_heap_is_initialized(heap)) return; if (!heap->no_reclaim) { // don't free in case it may contain reclaimed pages mi_heap_delete(heap); @@ -366,7 +368,7 @@ void mi_heap_delete(mi_heap_t* heap) mi_assert(heap != NULL); mi_assert(mi_heap_is_initialized(heap)); mi_assert_expensive(mi_heap_is_valid(heap)); - if (!mi_heap_is_initialized(heap)) return; + if (heap==NULL || !mi_heap_is_initialized(heap)) return; if (!mi_heap_is_backing(heap)) { // tranfer still used pages to the backing heap @@ -381,8 +383,9 @@ void mi_heap_delete(mi_heap_t* heap) } mi_heap_t* mi_heap_set_default(mi_heap_t* heap) { + mi_assert(heap != NULL); mi_assert(mi_heap_is_initialized(heap)); - if (!mi_heap_is_initialized(heap)) return NULL; + if (heap==NULL || !mi_heap_is_initialized(heap)) return NULL; mi_assert_expensive(mi_heap_is_valid(heap)); mi_heap_t* old = mi_get_default_heap(); _mi_heap_set_default_direct(heap); @@ -408,7 +411,7 @@ static mi_heap_t* mi_heap_of_block(const void* p) { bool mi_heap_contains_block(mi_heap_t* heap, const void* p) { mi_assert(heap != NULL); - if (!mi_heap_is_initialized(heap)) return false; + if (heap==NULL || !mi_heap_is_initialized(heap)) return false; return (heap == mi_heap_of_block(p)); } @@ -426,7 +429,7 @@ static bool mi_heap_page_check_owned(mi_heap_t* heap, mi_page_queue_t* pq, mi_pa bool mi_heap_check_owned(mi_heap_t* heap, const void* p) { mi_assert(heap != NULL); - if (!mi_heap_is_initialized(heap)) return false; + if (heap==NULL || !mi_heap_is_initialized(heap)) return false; if (((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0) return false; // only aligned pointers bool found = false; mi_heap_visit_pages(heap, &mi_heap_page_check_owned, (void*)p, &found); From 5d2b925f3e2f4927a909efb4b97d35e9cad2a440 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 11 Oct 2020 10:56:57 -0700 Subject: [PATCH 130/172] wrap MI_SECURE conditional in #ifdef to avoid warnings (issue #311) --- src/page.c | 9 ++++++--- src/segment.c | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/page.c b/src/page.c index cd96bb90..4b7e9ffb 100644 --- a/src/page.c +++ b/src/page.c @@ -705,14 +705,17 @@ 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_t* page = pq->first; if (page != NULL) { - if ((MI_SECURE >= 3) && page->capacity < page->reserved && ((_mi_heap_random_next(heap) & 1) == 1)) { - // in secure mode, we extend half the time to increase randomness + #if (MI_SECURE>=3) // in secure mode, we extend half the time to increase randomness + if (page->capacity < page->reserved && ((_mi_heap_random_next(heap) & 1) == 1)) { mi_page_extend_free(heap, page, heap->tld); mi_assert_internal(mi_page_immediate_available(page)); } - else { + else + #endif + { _mi_page_free_collect(page,false); } + if (mi_page_immediate_available(page)) { page->retire_expire = 0; return page; // fast path diff --git a/src/segment.c b/src/segment.c index fb47fb0f..4dc7dbf6 100644 --- a/src/segment.c +++ b/src/segment.c @@ -385,11 +385,13 @@ static uint8_t* mi_segment_raw_page_start(const mi_segment_t* segment, const mi_ psize -= segment->segment_info_size; } - if (MI_SECURE > 1 || (MI_SECURE == 1 && page->segment_idx == segment->capacity - 1)) { - // secure == 1: the last page has an os guard page at the end - // secure > 1: every page has an os guard page +#if (MI_SECURE > 1) // every page has an os guard page + psize -= _mi_os_page_size(); +#elif (MI_SECURE==1) // the last page has an os guard page at the end + if (page->segment_idx == segment->capacity - 1) { psize -= _mi_os_page_size(); } +#endif if (page_size != NULL) *page_size = psize; mi_assert_internal(page->xblock_size == 0 || _mi_ptr_page(p) == page); From 7114d5424acbe38411fd4c7938878ddcb2763479 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 11 Oct 2020 13:14:43 -0700 Subject: [PATCH 131/172] fix statistics to include padding correctly (issue #301) --- src/alloc.c | 42 ++++++++++++++++++++++++++++--------- src/segment.c | 7 ------- test/main-override-static.c | 27 +++++++++++++++++------- test/test-stress.c | 2 +- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 8e863a67..cceb35c7 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -282,6 +282,35 @@ static void mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, co } #endif +// only maintain stats for smaller objects if requested +#if (MI_STAT>1) +static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { + mi_heap_t* const heap = mi_heap_get_default(); + const size_t usize = mi_page_usable_size_of(page, block); + const size_t bsize = mi_page_usable_block_size(page); + mi_heap_stat_decrease(heap, malloc, usize); + if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { + mi_heap_stat_decrease(heap, normal[_mi_bin(bsize)], 1); + } +} +#else +static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { + UNUSED(page); UNUSED(block); +} +#endif + +// always maintain stats for huge objects +static void mi_stat_huge_free(const mi_page_t* page) { + mi_heap_t* const heap = mi_heap_get_default(); + const size_t bsize = mi_page_block_size(page); // to match stats in `page.c:mi_page_huge_alloc` + if (bsize <= MI_HUGE_OBJ_SIZE_MAX) { + mi_heap_stat_decrease(heap, huge, bsize); + } + else { + mi_heap_stat_decrease(heap, giant, bsize); + } +} + // ------------------------------------------------------ // Free // ------------------------------------------------------ @@ -300,6 +329,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc // huge page segments are always abandoned and can be freed immediately mi_segment_t* const segment = _mi_page_segment(page); if (segment->page_kind==MI_PAGE_HUGE) { + mi_stat_huge_free(page); _mi_segment_huge_page_free(segment, page, block); return; } @@ -343,7 +373,6 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc } } - // regular free static inline void _mi_free_block(mi_page_t* page, bool local, mi_block_t* block) { @@ -383,6 +412,7 @@ mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* p static void mi_decl_noinline mi_free_generic(const mi_segment_t* segment, bool local, void* p) { mi_page_t* const page = _mi_segment_page_of(segment, p); mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(segment, page, p) : (mi_block_t*)p); + mi_stat_free(page, block); _mi_free_block(page, local, block); } @@ -430,19 +460,11 @@ void mi_free(void* p) mi_attr_noexcept mi_page_t* const page = _mi_segment_page_of(segment, p); mi_block_t* const block = (mi_block_t*)p; -#if (MI_STAT>1) - mi_heap_t* const heap = mi_heap_get_default(); - const size_t bsize = mi_page_usable_block_size(page); - mi_heap_stat_decrease(heap, malloc, bsize); - if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { // huge page stats are accounted for in `_mi_page_retire` - mi_heap_stat_decrease(heap, normal[_mi_bin(bsize)], 1); - } -#endif - if (mi_likely(tid == segment->thread_id && page->flags.full_aligned == 0)) { // the thread id matches and it is not a full page, nor has aligned blocks // local, and not full or aligned if (mi_unlikely(mi_check_is_double_free(page,block))) return; mi_check_padding(page, block); + mi_stat_free(page, block); #if (MI_DEBUG!=0) memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); #endif diff --git a/src/segment.c b/src/segment.c index 4dc7dbf6..fb8e0fe1 100644 --- a/src/segment.c +++ b/src/segment.c @@ -1334,13 +1334,6 @@ void _mi_segment_huge_page_free(mi_segment_t* segment, mi_page_t* page, mi_block page->is_zero = false; mi_assert(page->used == 0); mi_tld_t* tld = heap->tld; - const size_t bsize = mi_page_usable_block_size(page); - if (bsize > MI_HUGE_OBJ_SIZE_MAX) { - _mi_stat_decrease(&tld->stats.giant, bsize); - } - else { - _mi_stat_decrease(&tld->stats.huge, bsize); - } mi_segments_track_size((long)segment->segment_size, &tld->segments); _mi_segment_page_free(page, true, &tld->segments); } diff --git a/test/main-override-static.c b/test/main-override-static.c index 8eb2249c..221db7e8 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -15,10 +15,11 @@ static void invalid_free(); static void test_aslr(void); static void test_process_info(void); static void test_reserved(void); +static void negative_stat(void); int main() { mi_version(); - + mi_stats_reset(); // detect double frees and heap corruption // double_free1(); // double_free2(); @@ -27,27 +28,29 @@ int main() { // test_aslr(); // invalid_free(); // test_reserved(); - + // negative_stat(); + void* p1 = malloc(78); void* p2 = malloc(24); free(p1); p1 = mi_malloc(8); - //char* s = strdup("hello\n"); + char* s = strdup("hello\n"); free(p2); + p2 = malloc(16); p1 = realloc(p1, 32); free(p1); free(p2); - //free(s); - //mi_collect(true); - + free(s); + /* now test if override worked by allocating/freeing across the api's*/ //p1 = mi_malloc(32); //free(p1); //p2 = malloc(32); //mi_free(p2); + mi_collect(true); mi_stats_print(NULL); - test_process_info(); + // test_process_info(); return 0; } @@ -167,3 +170,13 @@ static void test_reserved(void) { p3 = malloc(1*GiB); free(p4); } + + + +static void negative_stat(void) { + int* p = mi_malloc(60000); + mi_stats_print_out(NULL, NULL); + *p = 100; + mi_free(p); + mi_stats_print_out(NULL, NULL); +} \ No newline at end of file diff --git a/test/test-stress.c b/test/test-stress.c index d969284e..cba56310 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -123,7 +123,7 @@ static void free_items(void* p) { static void stress(intptr_t tid) { //bench_start_thread(); - uintptr_t r = (tid * 43); // rand(); + uintptr_t r = ((tid + 1) * 43); // rand(); const size_t max_item_shift = 5; // 128 const size_t max_item_retained_shift = max_item_shift + 2; size_t allocs = 100 * ((size_t)SCALE) * (tid % 8 + 1); // some threads do more From 6279835976c4f122a3ccd26bef68976971434bcd Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 11 Oct 2020 13:22:14 -0700 Subject: [PATCH 132/172] fix unused parameter warning --- src/alloc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/alloc.c b/src/alloc.c index cceb35c7..595cb86f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -299,7 +299,8 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { } #endif -// always maintain stats for huge objects +#if (MI_STAT>0) +// maintain stats for huge objects static void mi_stat_huge_free(const mi_page_t* page) { mi_heap_t* const heap = mi_heap_get_default(); const size_t bsize = mi_page_block_size(page); // to match stats in `page.c:mi_page_huge_alloc` @@ -310,6 +311,11 @@ static void mi_stat_huge_free(const mi_page_t* page) { mi_heap_stat_decrease(heap, giant, bsize); } } +#else +static void mi_stat_huge_free(const mi_page_t* page) { + UNUSED(page); +} +#endif // ------------------------------------------------------ // Free From 69f935944f7af435a12668b1770f47a7b93bc83e Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 15 Oct 2020 19:46:19 -0700 Subject: [PATCH 133/172] add test to avoid searching arenas when possible --- src/arena.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arena.c b/src/arena.c index a6ea4125..6e1526ac 100644 --- a/src/arena.c +++ b/src/arena.c @@ -163,8 +163,8 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* // try to allocate in an arena if the alignment is small enough // and the object is not too large or too small. if (alignment <= MI_SEGMENT_ALIGN && - // size <= MI_ARENA_MAX_OBJ_SIZE && - size >= MI_ARENA_MIN_OBJ_SIZE) + size >= MI_ARENA_MIN_OBJ_SIZE && + mi_atomic_load_relaxed(&mi_arena_count) > 0) { const size_t bcount = mi_block_count_of_size(size); const int numa_node = _mi_os_numa_node(tld); // current numa node From ca13e9cd59aea912f1eae6b6c5dee5e79dd11b2e Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 15 Oct 2020 19:46:33 -0700 Subject: [PATCH 134/172] better instruction scheduling for alloc --- src/alloc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 595cb86f..6bb9e30a 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -23,20 +23,22 @@ terms of the MIT license. A copy of the license can be found in the file // Fall back to generic allocation only if the list is empty. extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept { mi_assert_internal(page->xblock_size==0||mi_page_block_size(page) >= size); - mi_block_t* block = page->free; + mi_block_t* const block = page->free; if (mi_unlikely(block == NULL)) { return _mi_malloc_generic(heap, size); } mi_assert_internal(block != NULL && _mi_ptr_page(block) == page); // pop from the free list - page->free = mi_block_next(page, block); page->used++; + page->free = mi_block_next(page, block); mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); + #if (MI_DEBUG>0) if (!page->is_zero) { memset(block, MI_DEBUG_UNINIT, size); } #elif (MI_SECURE!=0) block->next = 0; // don't leak internal data #endif + #if (MI_STAT>1) const size_t bsize = mi_page_usable_block_size(page); if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { @@ -44,6 +46,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz mi_heap_stat_increase(heap, normal[bin], 1); } #endif + #if (MI_PADDING > 0) && defined(MI_ENCODE_FREELIST) mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + mi_page_usable_block_size(page)); ptrdiff_t delta = ((uint8_t*)padding - (uint8_t*)block - (size - MI_PADDING_SIZE)); @@ -54,6 +57,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); // set at most N initial padding bytes for (size_t i = 0; i < maxpad; i++) { fill[i] = MI_DEBUG_PADDING; } #endif + return block; } From cb45e3c6b198ed60a86428350d69b7a3e781fb77 Mon Sep 17 00:00:00 2001 From: Vasya B Date: Mon, 19 Oct 2020 21:00:16 +0000 Subject: [PATCH 135/172] fix for x32 builds --- include/mimalloc-internal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 145f6f92..c0fa1d66 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -699,6 +699,8 @@ static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept { __asm__("movl %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // 32-bit always uses GS #elif defined(__MACH__) && defined(__x86_64__) __asm__("movq %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 macOSX uses GS +#elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) + __asm__("movl %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x32 ABI #elif defined(__x86_64__) __asm__("movq %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 Linux, BSD uses FS #elif defined(__arm__) @@ -720,6 +722,8 @@ static inline void mi_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { __asm__("movl %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // 32-bit always uses GS #elif defined(__MACH__) && defined(__x86_64__) __asm__("movq %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 macOSX uses GS +#elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) + __asm__("movl %1,%%fs:%1" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x32 ABI #elif defined(__x86_64__) __asm__("movq %1,%%fs:%1" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 Linux, BSD uses FS #elif defined(__arm__) From e6c2fd44fcd892a6109e4a80d2bbb1a475c9cef9 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 22 Oct 2020 11:15:37 +0100 Subject: [PATCH 136/172] DragonFly support fix (for 5.8.x and forward). The pthread slot approach is somewhat buggy (pretty visible with the stress unit test which segfault more or less randomly, but the stats never show up). Using the default approach instead, the test passes eventough it s relatively slow (e.g 1.5 sec on FreeBSD vs 4.5 on DragonFly with same machine). --- include/mimalloc-internal.h | 6 +++--- test/test-stress.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 3c0210b3..b5517e4b 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -286,7 +286,7 @@ We try to circumvent this in an efficient way: - macOSX : we use an unused TLS slot from the OS allocated slots (MI_TLS_SLOT). On OSX, the loader itself calls `malloc` even before the modules are initialized. - OpenBSD: we use an unused slot from the pthread block (MI_TLS_PTHREAD_SLOT_OFS). -- DragonFly: not yet working. +- DragonFly: the uniqueid use is buggy but kept for reference. ------------------------------------------------------------------------------------------- */ extern const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value of the thread local default heap @@ -304,7 +304,7 @@ mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing hea #define MI_TLS_PTHREAD_SLOT_OFS (6*sizeof(int) + 4*sizeof(void*) + 24) #elif defined(__DragonFly__) #warning "mimalloc is not working correctly on DragonFly yet." -#define MI_TLS_PTHREAD_SLOT_OFS (4 + 1*sizeof(void*)) // offset `uniqueid` (also used by gdb?) +//#define MI_TLS_PTHREAD_SLOT_OFS (4 + 1*sizeof(void*)) // offset `uniqueid` (also used by gdb?) #endif #endif @@ -316,7 +316,7 @@ static inline mi_heap_t** mi_tls_pthread_heap_slot(void) { pthread_t self = pthread_self(); #if defined(__DragonFly__) if (self==NULL) { - static mi_heap_t* pheap_main = _mi_heap_main_get(); + mi_heap_t* pheap_main = _mi_heap_main_get(); return &pheap_main; } #endif diff --git a/test/test-stress.c b/test/test-stress.c index cba56310..ead88e37 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -306,7 +306,7 @@ static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { pthread_t* threads = (pthread_t*)custom_calloc(nthreads,sizeof(pthread_t)); memset(threads, 0, sizeof(pthread_t) * nthreads); //pthread_setconcurrency(nthreads); - for (uintptr_t i = 0; i < nthreads; i++) { + for (size_t i = 0; i < nthreads; i++) { pthread_create(&threads[i], NULL, &thread_entry, (void*)i); } for (size_t i = 0; i < nthreads; i++) { From 1deea03bf18119bab2b010ac5fdc2d303ac5403d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 31 Oct 2020 22:22:04 +0000 Subject: [PATCH 137/172] On Darwin, using MADV_FREE_REUSABLE/MADV_FREE_REUSE. The former to notify the pages are available for other processes, the latter is needed for proper counting in case those pages where tagged as reusable previously otherwise is a no-op, all for better RSS reporting for task_info apps. --- src/os.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index e8d6b74a..dfe654f5 100644 --- a/src/os.c +++ b/src/os.c @@ -435,7 +435,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro // though since properly aligned allocations will already use large pages if available // in that case -- in particular for our large regions (in `memory.c`). // However, some systems only allow THP if called with explicit `madvise`, so - // when large OS pages are enabled for mimalloc, we call `madvice` anyways. + // when large OS pages are enabled for mimalloc, we call `madvise` anyways. if (allow_large && use_large_os_page(size, try_alignment)) { if (madvise(p, size, MADV_HUGEPAGE) == 0) { *is_large = true; // possibly @@ -721,6 +721,9 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ // for commit, just change the protection err = mprotect(start, csize, (PROT_READ | PROT_WRITE)); if (err != 0) { err = errno; } + #if defined(MADV_FREE_REUSE) + while ((err = madvise(start, csize, MADV_FREE_REUSE)) != 0 && errno == EAGAIN) {} + #endif } #else err = mprotect(start, csize, (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE)); @@ -782,9 +785,17 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) if (p != start) return false; #else #if defined(MADV_FREE) + #if defined(MADV_FREE_REUSABLE) + static _Atomic(uintptr_t) advice = ATOMIC_VAR_INIT(MADV_FREE_REUSABLE); + int oadvice = (int)mi_atomic_load_relaxed(&advice); + int err; + while ((err = madvise(start, csize, oadvice)) != 0 && errno == EAGAIN) {} + if (err != 0 && errno == EINVAL && advice == MADV_FREE_REUSABLE) { + #else static _Atomic(uintptr_t) advice = ATOMIC_VAR_INIT(MADV_FREE); int err = madvise(start, csize, (int)mi_atomic_load_relaxed(&advice)); if (err != 0 && errno == EINVAL && advice == MADV_FREE) { + #endif // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on mi_atomic_store_release(&advice, (uintptr_t)MADV_DONTNEED); err = madvise(start, csize, MADV_DONTNEED); From 9c45221243b48ae5a1eea0027a88759cfe020dda Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 1 Nov 2020 23:57:42 +0300 Subject: [PATCH 138/172] Do not use the same counter for warnings and errors. Warnings happen normally and could be safely ignored in the most cases, however errors, if enabled, should not be ignored. Currently since warnings and errors share the same counter we effectively stop showing errors after 16 warnings (which happen all the time). Use different counters for errors and warnings. --- include/mimalloc.h | 1 + src/options.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index d4fbeec5..03535f0c 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -317,6 +317,7 @@ typedef enum mi_option_e { mi_option_limit_os_alloc, mi_option_os_tag, mi_option_max_errors, + mi_option_max_warnings, _mi_option_last } mi_option_t; diff --git a/src/options.c b/src/options.c index 2dbc8b03..f3e8f30b 100644 --- a/src/options.c +++ b/src/options.c @@ -19,7 +19,8 @@ terms of the MIT license. A copy of the license can be found in the file #endif -static uintptr_t mi_max_error_count = 16; // stop outputting errors after this +static uintptr_t mi_max_error_count = -1ULL; // stop outputting errors after this +static uintptr_t mi_max_warning_count = 16; // stop outputting warnings after this static void mi_add_stderr_output(); @@ -89,7 +90,8 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes. { 0, UNINIT, MI_OPTION(limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas) { 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose - { 16, UNINIT, MI_OPTION(max_errors) } // maximum errors that are output + { 16, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output + { -1ULL, UNINIT, MI_OPTION(max_errors) } // maximum errors that are output }; static void mi_option_init(mi_option_desc_t* desc); @@ -107,6 +109,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); } long mi_option_get(mi_option_t option) { @@ -325,7 +328,7 @@ static void mi_show_error_message(const char* fmt, va_list args) { void _mi_warning_message(const char* fmt, ...) { if (!mi_option_is_enabled(mi_option_show_errors) && !mi_option_is_enabled(mi_option_verbose)) return; - if (mi_atomic_increment_acq_rel(&error_count) > mi_max_error_count) return; + if (mi_atomic_increment_acq_rel(&error_count) > mi_max_warning_count) return; va_list args; va_start(args,fmt); mi_vfprintf(NULL, NULL, "mimalloc: warning: ", fmt, args); From 39bcf8a6b0af0c07379aea9c1a2330db49d3d5a0 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Mon, 2 Nov 2020 00:14:02 +0300 Subject: [PATCH 139/172] Honour MI_STAT in couple more places. --- include/mimalloc-types.h | 1 + src/heap.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 8ffcd2fc..b94bbf6f 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -447,6 +447,7 @@ void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); #define mi_stat_counter_increase(stat,amount) (void)0 #endif +#define mi_heap_stat_counter_increase(heap,stat,amount) mi_stat_counter_increase( (heap)->tld->stats.stat, amount) #define mi_heap_stat_increase(heap,stat,amount) mi_stat_increase( (heap)->tld->stats.stat, amount) #define mi_heap_stat_decrease(heap,stat,amount) mi_stat_decrease( (heap)->tld->stats.stat, amount) diff --git a/src/heap.c b/src/heap.c index 4a91786b..1dd6343f 100644 --- a/src/heap.c +++ b/src/heap.c @@ -274,10 +274,10 @@ static bool _mi_heap_page_destroy(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_ const size_t bsize = mi_page_block_size(page); if (bsize > MI_LARGE_OBJ_SIZE_MAX) { if (bsize > MI_HUGE_OBJ_SIZE_MAX) { - _mi_stat_decrease(&heap->tld->stats.giant, bsize); + mi_heap_stat_decrease(heap, giant, bsize); } else { - _mi_stat_decrease(&heap->tld->stats.huge, bsize); + mi_heap_stat_decrease(heap, huge, bsize); } } #if (MI_STAT>1) From d9a062452979a34cd8d5f882c9b5acca5478cc13 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Mon, 2 Nov 2020 00:24:24 +0300 Subject: [PATCH 140/172] Print current values of stat counters as well. For some reasons unknown to me the current values of stat counters are never printed. This makes is quite hard to use printing during the debugging in the middle of program run. --- src/stats.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/stats.c b/src/stats.c index b04822cc..b083b26a 100644 --- a/src/stats.c +++ b/src/stats.c @@ -167,6 +167,7 @@ static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out, void* ar static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg ) { _mi_fprintf(out, arg,"%10s:", msg); if (unit>0) { + mi_print_amount(stat->current, unit, out, arg); mi_print_amount(stat->peak, unit, out, arg); mi_print_amount(stat->allocated, unit, out, arg); mi_print_amount(stat->freed, unit, out, arg); @@ -178,6 +179,7 @@ static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t _mi_fprintf(out, arg, " ok\n"); } else if (unit<0) { + mi_print_amount(stat->current, -1, out, arg); mi_print_amount(stat->peak, -1, out, arg); mi_print_amount(stat->allocated, -1, out, arg); mi_print_amount(stat->freed, -1, out, arg); @@ -194,6 +196,7 @@ static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t _mi_fprintf(out, arg, " ok\n"); } else { + mi_print_amount(stat->current, 1, out, arg); mi_print_amount(stat->peak, 1, out, arg); mi_print_amount(stat->allocated, 1, out, arg); _mi_fprintf(out, arg, "\n"); @@ -215,7 +218,7 @@ static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* static void mi_print_header(mi_output_fun* out, void* arg ) { - _mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "unit ", "count "); + _mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s %10s\n", "heap stats", "current ", "peak ", "total ", "freed ", "unit ", "count "); } #if MI_STAT>1 From 00fb89f7715770d253bcb32f2fcf536a462b5ce7 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Wed, 11 Nov 2020 10:57:48 +0300 Subject: [PATCH 141/172] Rename the field --- include/mimalloc-types.h | 2 +- src/alloc.c | 4 ++-- src/heap.c | 2 +- src/stats.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 8ffcd2fc..f89553ec 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -428,7 +428,7 @@ typedef struct mi_stats_s { mi_stat_counter_t huge_count; mi_stat_counter_t giant_count; #if MI_STAT>1 - mi_stat_count_t normal[MI_BIN_HUGE+1]; + mi_stat_count_t normal_bins[MI_BIN_HUGE+1]; #endif } mi_stats_t; diff --git a/src/alloc.c b/src/alloc.c index 6bb9e30a..f6805bce 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -43,7 +43,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz const size_t bsize = mi_page_usable_block_size(page); if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { const size_t bin = _mi_bin(bsize); - mi_heap_stat_increase(heap, normal[bin], 1); + mi_heap_stat_increase(heap, normal_bins[bin], 1); } #endif @@ -294,7 +294,7 @@ static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { const size_t bsize = mi_page_usable_block_size(page); mi_heap_stat_decrease(heap, malloc, usize); if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { - mi_heap_stat_decrease(heap, normal[_mi_bin(bsize)], 1); + mi_heap_stat_decrease(heap, normal_bins[_mi_bin(bsize)], 1); } } #else diff --git a/src/heap.c b/src/heap.c index 4a91786b..7b560ade 100644 --- a/src/heap.c +++ b/src/heap.c @@ -284,7 +284,7 @@ static bool _mi_heap_page_destroy(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_ _mi_page_free_collect(page, false); // update used count const size_t inuse = page->used; if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { - mi_heap_stat_decrease(heap, normal[_mi_bin(bsize)], inuse); + mi_heap_stat_decrease(heap, normal_bins[_mi_bin(bsize)], inuse); } mi_heap_stat_decrease(heap, malloc, bsize * inuse); // todo: off for aligned blocks... #endif diff --git a/src/stats.c b/src/stats.c index b04822cc..1fb41d62 100644 --- a/src/stats.c +++ b/src/stats.c @@ -116,8 +116,8 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) { mi_stat_counter_add(&stats->giant_count, &src->giant_count, 1); #if MI_STAT>1 for (size_t i = 0; i <= MI_BIN_HUGE; i++) { - if (src->normal[i].allocated > 0 || src->normal[i].freed > 0) { - mi_stat_add(&stats->normal[i], &src->normal[i], 1); + if (src->normal_bins[i].allocated > 0 || src->normal_bins[i].freed > 0) { + mi_stat_add(&stats->normal_bins[i], &src->normal_bins[i], 1); } } #endif @@ -290,7 +290,7 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_print_header(out,arg); #if MI_STAT>1 mi_stat_count_t normal = { 0,0,0,0 }; - mi_stats_print_bins(&normal, stats->normal, MI_BIN_HUGE, "normal",out,arg); + mi_stats_print_bins(&normal, stats->normal_bins, MI_BIN_HUGE, "normal",out,arg); mi_stat_print(&normal, "normal", 1, out, arg); mi_stat_print(&stats->huge, "huge", (stats->huge_count.count == 0 ? 1 : -(stats->huge.allocated / stats->huge_count.count)), out, arg); mi_stat_print(&stats->giant, "giant", (stats->giant_count.count == 0 ? 1 : -(stats->giant.allocated / stats->giant_count.count)), out, arg); From 765fc9c0cae0e127d091ab405a71df7933d26634 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Wed, 11 Nov 2020 11:34:40 +0300 Subject: [PATCH 142/172] Unify statistic collection: - For MI_STAT == 0 no allocation stats are collected - For MI_STAT == 1 only aggregated values (across normal, large and huge heaps) are collected - For MI_STAT == 1 separate per-bin collection for normal heap is done as well --- include/mimalloc-types.h | 3 +++ src/alloc.c | 18 +++++++++++++++--- src/heap.c | 5 ++++- src/init.c | 4 ++-- src/stats.c | 20 ++++++++++++-------- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index f89553ec..99024679 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -416,6 +416,7 @@ typedef struct mi_stats_s { mi_stat_count_t segments_abandoned; mi_stat_count_t pages_abandoned; mi_stat_count_t threads; + mi_stat_count_t normal; mi_stat_count_t huge; mi_stat_count_t giant; mi_stat_count_t malloc; @@ -425,6 +426,7 @@ typedef struct mi_stats_s { mi_stat_counter_t commit_calls; mi_stat_counter_t page_no_retire; mi_stat_counter_t searches; + mi_stat_counter_t normal_count; mi_stat_counter_t huge_count; mi_stat_counter_t giant_count; #if MI_STAT>1 @@ -447,6 +449,7 @@ void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount); #define mi_stat_counter_increase(stat,amount) (void)0 #endif +#define mi_heap_stat_counter_increase(heap,stat,amount) mi_stat_counter_increase( (heap)->tld->stats.stat, amount) #define mi_heap_stat_increase(heap,stat,amount) mi_stat_increase( (heap)->tld->stats.stat, amount) #define mi_heap_stat_decrease(heap,stat,amount) mi_stat_decrease( (heap)->tld->stats.stat, amount) diff --git a/src/alloc.c b/src/alloc.c index f6805bce..11831e22 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -39,11 +39,15 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz block->next = 0; // don't leak internal data #endif -#if (MI_STAT>1) +#if (MI_STAT>0) const size_t bsize = mi_page_usable_block_size(page); if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { + mi_heap_stat_increase(heap, normal, bsize); + mi_heap_stat_counter_increase(heap, normal_count, 1); +#if (MI_STAT>1) const size_t bin = _mi_bin(bsize); mi_heap_stat_increase(heap, normal_bins[bin], 1); +#endif } #endif @@ -287,14 +291,22 @@ static void mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, co #endif // only maintain stats for smaller objects if requested -#if (MI_STAT>1) +#if (MI_STAT>0) static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) { +#if (MI_STAT < 2) + UNUSED(block); +#endif mi_heap_t* const heap = mi_heap_get_default(); + const size_t bsize = mi_page_usable_block_size(page); +#if (MI_STAT>1) const size_t usize = mi_page_usable_size_of(page, block); - const size_t bsize = mi_page_usable_block_size(page); mi_heap_stat_decrease(heap, malloc, usize); +#endif if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { + mi_heap_stat_decrease(heap, normal, bsize); +#if (MI_STAT > 1) mi_heap_stat_decrease(heap, normal_bins[_mi_bin(bsize)], 1); +#endif } } #else diff --git a/src/heap.c b/src/heap.c index 7b560ade..cd57e5f4 100644 --- a/src/heap.c +++ b/src/heap.c @@ -280,11 +280,14 @@ static bool _mi_heap_page_destroy(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_ _mi_stat_decrease(&heap->tld->stats.huge, bsize); } } -#if (MI_STAT>1) +#if (MI_STAT) _mi_page_free_collect(page, false); // update used count const size_t inuse = page->used; if (bsize <= MI_LARGE_OBJ_SIZE_MAX) { + mi_heap_stat_decrease(heap, normal, bsize * inuse); +#if (MI_STAT>1) mi_heap_stat_decrease(heap, normal_bins[_mi_bin(bsize)], inuse); +#endif } mi_heap_stat_decrease(heap, malloc, bsize * inuse); // todo: off for aligned blocks... #endif diff --git a/src/init.c b/src/init.c index bc17791b..6948039f 100644 --- a/src/init.c +++ b/src/init.c @@ -73,8 +73,8 @@ const mi_page_t _mi_page_empty = { MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ - MI_STAT_COUNT_NULL(), \ - { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } \ MI_STAT_COUNT_END_NULL() diff --git a/src/stats.c b/src/stats.c index 1fb41d62..ad698920 100644 --- a/src/stats.c +++ b/src/stats.c @@ -103,6 +103,7 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) { mi_stat_add(&stats->malloc, &src->malloc, 1); mi_stat_add(&stats->segments_cache, &src->segments_cache, 1); + mi_stat_add(&stats->normal, &src->normal, 1); mi_stat_add(&stats->huge, &src->huge, 1); mi_stat_add(&stats->giant, &src->giant, 1); @@ -112,6 +113,7 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) { mi_stat_counter_add(&stats->page_no_retire, &src->page_no_retire, 1); 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->giant_count, &src->giant_count, 1); #if MI_STAT>1 @@ -219,7 +221,7 @@ static void mi_print_header(mi_output_fun* out, void* arg ) { } #if MI_STAT>1 -static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bins, size_t max, const char* fmt, mi_output_fun* out, void* arg) { +static void mi_stats_print_bins(const mi_stat_count_t* bins, size_t max, const char* fmt, mi_output_fun* out, void* arg) { bool found = false; char buf[64]; for (size_t i = 0; i <= max; i++) { @@ -227,12 +229,9 @@ static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bin found = true; int64_t unit = _mi_bin_size((uint8_t)i); snprintf(buf, 64, "%s %3lu", fmt, (long)i); - mi_stat_add(all, &bins[i], unit); mi_stat_print(&bins[i], buf, unit, out, arg); } } - //snprintf(buf, 64, "%s all", fmt); - //mi_stat_print(all, buf, 1); if (found) { _mi_fprintf(out, arg, "\n"); mi_print_header(out, arg); @@ -289,16 +288,21 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) // and print using that mi_print_header(out,arg); #if MI_STAT>1 - mi_stat_count_t normal = { 0,0,0,0 }; - mi_stats_print_bins(&normal, stats->normal_bins, MI_BIN_HUGE, "normal",out,arg); - mi_stat_print(&normal, "normal", 1, out, arg); + mi_stats_print_bins(stats->normal_bins, MI_BIN_HUGE, "normal",out,arg); + #endif + #if MI_STAT + mi_stat_print(&stats->normal, "normal", (stats->normal_count.count == 0 ? 1 : -(stats->normal.allocated / stats->normal_count.count)), out, arg); mi_stat_print(&stats->huge, "huge", (stats->huge_count.count == 0 ? 1 : -(stats->huge.allocated / stats->huge_count.count)), out, arg); mi_stat_print(&stats->giant, "giant", (stats->giant_count.count == 0 ? 1 : -(stats->giant.allocated / stats->giant_count.count)), out, arg); mi_stat_count_t total = { 0,0,0,0 }; - mi_stat_add(&total, &normal, 1); + mi_stat_add(&total, &stats->normal, 1); mi_stat_add(&total, &stats->huge, 1); mi_stat_add(&total, &stats->giant, 1); mi_stat_print(&total, "total", 1, out, arg); + #endif + #if MI_STAT>1 + mi_stat_print(&stats->malloc, "malloc total", 1, out, arg); + _mi_fprintf(out, arg, "malloc requested: "); mi_print_amount(stats->malloc.allocated, 1, out, arg); _mi_fprintf(out, arg, "\n\n"); From bbdf470715d2f8c0adae4f21e79e73386d1b3da5 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 18 Nov 2020 17:21:51 +0000 Subject: [PATCH 143/172] mi_bitmap_try_find_claim_field_across number of leading zeros is unsigned. --- src/bitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmap.c b/src/bitmap.c index a94e15cf..68ae3b2e 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -179,7 +179,7 @@ static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bit _Atomic(uintptr_t)* field = &bitmap[idx]; uintptr_t map = mi_atomic_load_relaxed(field); const size_t initial = mi_clz(map); // count of initial zeros starting at idx - mi_assert_internal(initial >= 0 && initial <= MI_BITMAP_FIELD_BITS); + mi_assert_internal(initial <= MI_BITMAP_FIELD_BITS); if (initial == 0) return false; if (initial >= count) return _mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx); // no need to cross fields if (_mi_divide_up(count - initial, MI_BITMAP_FIELD_BITS) >= (bitmap_fields - idx)) return false; // not enough entries From cbc14a9287847599e2b4fb1e2b1f7a5287f5a401 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Dec 2020 10:28:54 -0800 Subject: [PATCH 144/172] count warnings and errors separately --- src/options.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/options.c b/src/options.c index f3e8f30b..56ba6bdd 100644 --- a/src/options.c +++ b/src/options.c @@ -19,8 +19,8 @@ terms of the MIT license. A copy of the license can be found in the file #endif -static uintptr_t mi_max_error_count = -1ULL; // stop outputting errors after this -static uintptr_t mi_max_warning_count = 16; // stop outputting warnings after this +static uintptr_t mi_max_error_count = 64; // stop outputting errors after this +static uintptr_t mi_max_warning_count = 16; // stop outputting warnings after this static void mi_add_stderr_output(); @@ -90,8 +90,9 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes. { 0, UNINIT, MI_OPTION(limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas) { 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose - { 16, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output - { -1ULL, UNINIT, MI_OPTION(max_errors) } // maximum errors that are output + { 64, UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output + { 16, UNINIT, MI_OPTION(max_warnings) } // maximum warnings that are output + }; static void mi_option_init(mi_option_desc_t* desc); @@ -250,7 +251,8 @@ static void mi_add_stderr_output() { // -------------------------------------------------------- // Messages, all end up calling `_mi_fputs`. // -------------------------------------------------------- -static _Atomic(uintptr_t) error_count; // = 0; // when MAX_ERROR_COUNT stop emitting errors and warnings +static _Atomic(uintptr_t) error_count; // = 0; // when >= max_error_count stop emitting errors +static _Atomic(uintptr_t) warning_count; // = 0; // when >= max_warning_count stop emitting warnings // When overriding malloc, we may recurse into mi_vfprintf if an allocation // inside the C runtime causes another message. @@ -328,7 +330,7 @@ static void mi_show_error_message(const char* fmt, va_list args) { void _mi_warning_message(const char* fmt, ...) { if (!mi_option_is_enabled(mi_option_show_errors) && !mi_option_is_enabled(mi_option_verbose)) return; - if (mi_atomic_increment_acq_rel(&error_count) > mi_max_warning_count) return; + if (mi_atomic_increment_acq_rel(&warning_count) > mi_max_warning_count) return; va_list args; va_start(args,fmt); mi_vfprintf(NULL, NULL, "mimalloc: warning: ", fmt, args); From f37a3db37c43509dbe9f76ec49cdd2a1b5dbadaa Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Dec 2020 11:51:58 -0800 Subject: [PATCH 145/172] cleanup madv_resuable --- src/options.c | 4 ++-- src/os.c | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/options.c b/src/options.c index 56ba6bdd..d4f3f29a 100644 --- a/src/options.c +++ b/src/options.c @@ -19,7 +19,7 @@ terms of the MIT license. A copy of the license can be found in the file #endif -static uintptr_t mi_max_error_count = 64; // stop outputting errors after this +static uintptr_t mi_max_error_count = 16; // stop outputting errors after this static uintptr_t mi_max_warning_count = 16; // stop outputting warnings after this static void mi_add_stderr_output(); @@ -90,7 +90,7 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes. { 0, UNINIT, MI_OPTION(limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas) { 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose - { 64, UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output + { 16, UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output { 16, UNINIT, MI_OPTION(max_warnings) } // maximum warnings that are output }; diff --git a/src/os.c b/src/os.c index dfe654f5..22e736f7 100644 --- a/src/os.c +++ b/src/os.c @@ -721,9 +721,9 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ // for commit, just change the protection err = mprotect(start, csize, (PROT_READ | PROT_WRITE)); if (err != 0) { err = errno; } - #if defined(MADV_FREE_REUSE) - while ((err = madvise(start, csize, MADV_FREE_REUSE)) != 0 && errno == EAGAIN) {} - #endif + #if defined(MADV_FREE_REUSE) + while ((err = madvise(start, csize, MADV_FREE_REUSE)) != 0 && errno == EAGAIN) { errno = 0; } + #endif } #else err = mprotect(start, csize, (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE)); @@ -786,17 +786,16 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) #else #if defined(MADV_FREE) #if defined(MADV_FREE_REUSABLE) - static _Atomic(uintptr_t) advice = ATOMIC_VAR_INIT(MADV_FREE_REUSABLE); + #define KK_MADV_FREE_INITIAL MADV_FREE_REUSABLE + #else + #define KK_MADV_FREE_INITIAL MADV_FREE + #endif + static _Atomic(uintptr_t) advice = ATOMIC_VAR_INIT(KK_MADV_FREE_INITIAL); int oadvice = (int)mi_atomic_load_relaxed(&advice); int err; - while ((err = madvise(start, csize, oadvice)) != 0 && errno == EAGAIN) {} - if (err != 0 && errno == EINVAL && advice == MADV_FREE_REUSABLE) { - #else - static _Atomic(uintptr_t) advice = ATOMIC_VAR_INIT(MADV_FREE); - int err = madvise(start, csize, (int)mi_atomic_load_relaxed(&advice)); - if (err != 0 && errno == EINVAL && advice == MADV_FREE) { - #endif - // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on + while ((err = madvise(start, csize, oadvice)) != 0 && errno == EAGAIN) { errno = 0; }; + if (err != 0 && errno == EINVAL && oadvice == KK_MADV_FREE_INITIAL) { + // if MADV_FREE/MADV_FREE_REUSABLE is not supported, fall back to MADV_DONTNEED from now on mi_atomic_store_release(&advice, (uintptr_t)MADV_DONTNEED); err = madvise(start, csize, MADV_DONTNEED); } From d1d06b67eb4b67dfba8fccfb4f90e4c1fd37d752 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Dec 2020 12:13:06 -0800 Subject: [PATCH 146/172] fix type warning (issue #337) --- src/os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index 22e736f7..e2c93d72 100644 --- a/src/os.c +++ b/src/os.c @@ -421,7 +421,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro #endif if (large_only) return p; if (p == NULL) { - mi_atomic_store_release(&large_page_try_ok, 10UL); // on error, don't try again for the next N allocations + mi_atomic_store_release(&large_page_try_ok, (uintptr_t)10); // on error, don't try again for the next N allocations } } } From 745cf1e2f57f2f9207a9c45beda3ec1b20fd04ba Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Dec 2020 12:33:35 -0800 Subject: [PATCH 147/172] fix build on ghc4.8 (issue #330) --- src/alloc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/alloc.c b/src/alloc.c index 6bb9e30a..3aa97158 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -778,7 +778,12 @@ but we call `exit` instead (i.e. not returning). #ifdef __cplusplus #include static bool mi_try_new_handler(bool nothrow) { - std::new_handler h = std::get_new_handler(); + #if defined(_MSC_VER) || (__cplusplus >= 201103L) + std::new_handler h = std::get_new_handler(); + #else + std::new_handler h = std::set_new_handler(); + std::set_new_handler(h); + #endif if (h==NULL) { if (!nothrow) throw std::bad_alloc(); return false; From 33a10b48605f8bb419487a03125815ad6ee00a70 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 12 Dec 2020 12:06:24 +0000 Subject: [PATCH 148/172] Restricts cpu yield instructions a little. adding clobber for ARM and preventing older 32 bits chips not supporting this instruction. --- include/mimalloc-atomic.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index b6506075..9f464593 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -282,16 +282,22 @@ static inline void mi_atomic_yield(void) { YieldProcessor(); } #elif (defined(__GNUC__) || defined(__clang__)) && \ - (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)) + (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__)) #if defined(__x86_64__) || defined(__i386__) static inline void mi_atomic_yield(void) { __asm__ volatile ("pause" ::: "memory"); } -#elif defined(__arm__) || defined(__aarch64__) +#elif (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__) static inline void mi_atomic_yield(void) { - __asm__ volatile("yield"); + __asm__ volatile("yield" ::: "memory"); } #endif +#elif defined(__sun) +// Fallback for other archs +#include +static inline void mi_atomic_yield(void) { + smt_pause(); +} #elif defined(__wasi__) #include static inline void mi_atomic_yield(void) { @@ -305,4 +311,4 @@ static inline void mi_atomic_yield(void) { #endif -#endif // __MIMALLOC_ATOMIC_H \ No newline at end of file +#endif // __MIMALLOC_ATOMIC_H From 30fc86cca9751d1fc5e8a75ab3fa88470a61a9b3 Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Sun, 13 Dec 2020 01:50:31 -0500 Subject: [PATCH 149/172] Fix strndup override --- include/mimalloc-override.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-override.h b/include/mimalloc-override.h index 201fb8b4..2362bfbc 100644 --- a/include/mimalloc-override.h +++ b/include/mimalloc-override.h @@ -24,7 +24,7 @@ not accidentally mix pointers from different allocators). #define free(p) mi_free(p) #define strdup(s) mi_strdup(s) -#define strndup(s) mi_strndup(s) +#define strndup(s,n) mi_strndup(s,n) #define realpath(f,n) mi_realpath(f,n) // Microsoft extensions @@ -33,7 +33,7 @@ not accidentally mix pointers from different allocators). #define _recalloc(p,n,c) mi_recalloc(p,n,c) #define _strdup(s) mi_strdup(s) -#define _strndup(s) mi_strndup(s) +#define _strndup(s,n) mi_strndup(s,n) #define _wcsdup(s) (wchar_t*)mi_wcsdup((const unsigned short*)(s)) #define _mbsdup(s) mi_mbsdup(s) #define _dupenv_s(b,n,v) mi_dupenv_s(b,n,v) From d7f3d7679ad0e3115edba1679c5347402d4939c5 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Tue, 15 Dec 2020 10:20:58 +0100 Subject: [PATCH 150/172] Don't set march=native on Apple Silicon --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7996f36..c2deae13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM endif() # Architecture flags -if(${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "arm") +if(${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT APPLE) list(APPEND mi_cflags -march=native) endif() From 62b6ccb03e8381b094eb3a92c6840fe4d2daf18f Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Tue, 15 Dec 2020 11:03:20 +0100 Subject: [PATCH 151/172] Check for march=native before using it --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2deae13..ca7a6faa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,7 +187,10 @@ endif() # Architecture flags if(${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT APPLE) - list(APPEND mi_cflags -march=native) + check_cxx_compiler_flag(-march=native CXX_SUPPORTS_MARCH_NATIVE) + if (CXX_SUPPORTS_MARCH_NATIVE) + list(APPEND mi_cflags -march=native) + endif() endif() # extra needed libraries From bb386025b5d6cbcccdeb77e213ba0076c410e1bb Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Tue, 15 Dec 2020 16:03:54 -0800 Subject: [PATCH 152/172] update override on macOS with interpose of malloc_default_zone (issues #313) --- include/mimalloc-internal.h | 1 - src/alloc-override-osx.c | 105 +++++++++++++++++++++--------------- src/alloc-override.c | 7 +++ src/options.c | 4 +- test/test-stress.c | 4 +- 5 files changed, 75 insertions(+), 46 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 459a0867..e3e78e40 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -32,7 +32,6 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_decl_cache_align #endif - // "options.c" void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message); void _mi_fprintf(mi_output_fun* out, void* arg, const char* fmt, ...); diff --git a/src/alloc-override-osx.c b/src/alloc-override-osx.c index c1c880ca..4b77f631 100644 --- a/src/alloc-override-osx.c +++ b/src/alloc-override-osx.c @@ -35,7 +35,6 @@ terms of the MIT license. A copy of the license can be found in the file extern malloc_zone_t* malloc_default_purgeable_zone(void) __attribute__((weak_import)); #endif - /* ------------------------------------------------------ malloc zone members ------------------------------------------------------ */ @@ -44,7 +43,7 @@ static size_t zone_size(malloc_zone_t* zone, const void* p) { UNUSED(zone); if (!mi_is_in_heap_region(p)) return 0; // not our pointer, bail out - + return mi_usable_size(p); } @@ -190,63 +189,85 @@ static malloc_zone_t* mi_get_default_zone() } } -static void __attribute__((constructor)) _mi_macos_override_malloc() -{ - static malloc_introspection_t intro; - memset(&intro, 0, sizeof(intro)); +static malloc_introspection_t mi_introspect = { + .enumerator = &intro_enumerator, + .good_size = &intro_good_size, + .check = &intro_check, + .print = &intro_print, + .log = &intro_log, + .force_lock = &intro_force_lock, + .force_unlock = &intro_force_unlock, +#if defined(MAC_OS_X_VERSION_10_6) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + .zone_locked = &intro_zone_locked, + .statistics = &intro_statistics, +#endif +}; - intro.enumerator = &intro_enumerator; - intro.good_size = &intro_good_size; - intro.check = &intro_check; - intro.print = &intro_print; - intro.log = &intro_log; - intro.force_lock = &intro_force_lock; - intro.force_unlock = &intro_force_unlock; +static malloc_zone_t mi_malloc_zone = { + .size = &zone_size, + .zone_name = "mimalloc", + .introspect = &mi_introspect, + .malloc = &zone_malloc, + .calloc = &zone_calloc, + .valloc = &zone_valloc, + .free = &zone_free, + .realloc = &zone_realloc, + .destroy = &zone_destroy, + .batch_malloc = &zone_batch_malloc, + .batch_free = &zone_batch_free, +#if defined(MAC_OS_X_VERSION_10_6) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + // switch to version 9 on OSX 10.6 to support memalign. + .version = 9, + .memalign = &zone_memalign, + .free_definite_size = &zone_free_definite_size, + .pressure_relief = &zone_pressure_relief, +#else + .version = 4, +#endif +}; - static malloc_zone_t zone; - memset(&zone, 0, sizeof(zone)); - zone.version = 4; - zone.zone_name = "mimalloc"; - zone.size = &zone_size; - zone.introspect = &intro; - zone.malloc = &zone_malloc; - zone.calloc = &zone_calloc; - zone.valloc = &zone_valloc; - zone.free = &zone_free; - zone.realloc = &zone_realloc; - zone.destroy = &zone_destroy; - zone.batch_malloc = &zone_batch_malloc; - zone.batch_free = &zone_batch_free; +#if defined(MI_SHARED_LIB_EXPORT) && defined(MI_INTERPOSE) +static malloc_zone_t *mi_malloc_default_zone(void) { + return &mi_malloc_zone; +} +// TODO: should use the macros in alloc-override but they aren't available here. +__attribute__((used)) static struct { + const void *replacement; + const void *target; +} replace_malloc_default_zone[] __attribute__((section("__DATA, __interpose"))) = { + { (const void*)mi_malloc_default_zone, (const void*)malloc_default_zone }, +}; +#endif + +static void __attribute__((constructor(0))) _mi_macos_override_malloc() { malloc_zone_t* purgeable_zone = NULL; #if defined(MAC_OS_X_VERSION_10_6) && \ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - // switch to version 9 on OSX 10.6 to support memalign. - zone.version = 9; - zone.memalign = &zone_memalign; - zone.free_definite_size = &zone_free_definite_size; - zone.pressure_relief = &zone_pressure_relief; - intro.zone_locked = &intro_zone_locked; - intro.statistics = &intro_statistics; - // force the purgeable zone to exist to avoid strange bugs if (malloc_default_purgeable_zone) { purgeable_zone = malloc_default_purgeable_zone(); } #endif - // Register our zone - malloc_zone_register(&zone); - + // Register our zone. + // thomcc: I think this is still needed to put us in the zone list. + malloc_zone_register(&mi_malloc_zone); // Unregister the default zone, this makes our zone the new default // as that was the last registered. malloc_zone_t *default_zone = mi_get_default_zone(); - malloc_zone_unregister(default_zone); + // thomcc: Unsure if the next test is *always* false or just false in the + // cases I've tried. I'm also unsure if the code inside is needed. at all + if (default_zone != &mi_malloc_zone) { + malloc_zone_unregister(default_zone); - // Reregister the default zone so free and realloc in that zone keep working. - malloc_zone_register(default_zone); + // Reregister the default zone so free and realloc in that zone keep working. + malloc_zone_register(default_zone); + } // Unregister, and re-register the purgeable_zone to avoid bugs if it occurs // earlier than the default zone. @@ -257,4 +278,4 @@ static void __attribute__((constructor)) _mi_macos_override_malloc() } -#endif // MI_MALLOC_OVERRIDE +#endif // MI_MALLOC_OVERRIDE \ No newline at end of file diff --git a/src/alloc-override.c b/src/alloc-override.c index ae7ad7dd..5906bd20 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -60,6 +60,13 @@ terms of the MIT license. A copy of the license can be found in the file MI_INTERPOSE_MI(posix_memalign), MI_INTERPOSE_MI(reallocf), MI_INTERPOSE_MI(valloc), + #ifndef MI_OSX_ZONE + // some code allocates from default zone but deallocates using plain free :-( (like NxHashResizeToCapacity ) + MI_INTERPOSE_FUN(free,mi_cfree), // use safe free that checks if pointers are from us + #else + // We interpose malloc_default_zone in alloc-override-osx.c + MI_INTERPOSE_MI(free), + #endif // some code allocates from a zone but deallocates using plain free :-( (like NxHashResizeToCapacity ) MI_INTERPOSE_FUN(free,mi_cfree), // use safe free that checks if pointers are from us }; diff --git a/src/options.c b/src/options.c index d4f3f29a..c489c65e 100644 --- a/src/options.c +++ b/src/options.c @@ -259,7 +259,7 @@ static _Atomic(uintptr_t) warning_count; // = 0; // when >= max_warning_count s static mi_decl_thread bool recurse = false; static bool mi_recurse_enter(void) { - #ifdef MI_TLS_RECURSE_GUARD + #if defined(__MACH__) || defined(MI_TLS_RECURSE_GUARD) if (_mi_preloading()) return true; #endif if (recurse) return false; @@ -268,7 +268,7 @@ static bool mi_recurse_enter(void) { } static void mi_recurse_exit(void) { - #ifdef MI_TLS_RECURSE_GUARD + #if defined(__MACH__) || defined(MI_TLS_RECURSE_GUARD) if (_mi_preloading()) return; #endif recurse = false; diff --git a/test/test-stress.c b/test/test-stress.c index ead88e37..c4247abe 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -20,7 +20,6 @@ terms of the MIT license. #include #include #include -#include // > mimalloc-test-stress [THREADS] [SCALE] [ITER] // @@ -43,6 +42,7 @@ static size_t use_one_size = 0; // use single object size of `N * s #define custom_realloc(p,s) realloc(p,s) #define custom_free(p) free(p) #else +#include #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) @@ -251,7 +251,9 @@ int main(int argc, char** argv) { #endif // mi_collect(true); +#ifndef USE_STD_MALLOC mi_stats_print(NULL); +#endif //bench_end_program(); return 0; } From 9cdab141bc0588c76a8de0e4a3b0d61809adcf6f Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 17 Dec 2020 13:05:15 -0800 Subject: [PATCH 153/172] add ds logo --- doc/ds-logo.jpg | Bin 0 -> 168069 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/ds-logo.jpg diff --git a/doc/ds-logo.jpg b/doc/ds-logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8610c91660d790794cb75760d25544c72b785218 GIT binary patch literal 168069 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

7eJ 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 Date: Thu, 17 Dec 2020 13:06:43 -0800 Subject: [PATCH 154/172] remove ds logo --- doc/ds-logo.jpg | Bin 168069 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 doc/ds-logo.jpg diff --git a/doc/ds-logo.jpg b/doc/ds-logo.jpg deleted file mode 100644 index 8610c91660d790794cb75760d25544c72b785218..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168069 zcmeFYcT`i|_BOf`dMJtnrT3D6fI#RV%}_#5C=#(yO+Y$=;EObCL~1|{EkF`#6g5b( z7wjm6q9UTAf`DKFL_y$N!S|f=yZ5hq?j7SBN~_vQc_Z!rGY_A zqJD5#Y)H6%Xl%5>f#5g;L;WoVkhSfBxZu#J@FbOx@V(?18|^PwZfL8J!)&wzOgy%D z#5snO$S!FK;e<3#-_W$EP>V2a+pP%e1C|G(jPg?~6&aJYb`?c5zFv&->ay zZL4)cScD~ho73NCfFm2Vzq^u>lA@nttRI`O*TB%i!opySk%5ts9ymiUF*PPB_<&wa zqWa$#*cP4`nm~?ABFDz4@Gck}61zXiMs5Foa+qaAaD+)nSeS`kNU(93o}pn_uwHPO zv7ug=v2mE0iJ`esgkgx<-_3`G{=4Mo2o9!cS<>5qY1D?Ua!Ji#)*{ui>5fN*H|JmT$Isaq8 zf1eEQ8`%5zUEYdN`QPyRr;-24$p4t@A9MXz7Wl7D{%3amW3K@skf4B|u#k{2LQ)h!421N$^42%tQjI?!hb$Azn2?+}$L=Z?(QKXK7jDpU8{aU>VNec5{ z5q9E(sX=f_7@s6;^)93gbTR>ujpHTc{(iyWeEb4}Lc$^lQE)=*dI%2Vc5%fKeEs|bwg(bJ!@?u>lE{&XN&Ayi4y2~#96oaN*zpsTqGD=E z>FG0PX*IPBCabQ#q4DA+PV42i_KwcmckXuGyZ_+fBW_>+z~J*2FNfZZzW?xXZ2Z&2 zkXqBJE2i9*KSRuH;hX`(FD@ z)9YCNN*BUqBp+(s-O{vSR(5gV(Ctj5f)5Rcf+aeUQ8p;}K*#d$t#7&a`&XgoxahXu ze>qk;dfCq^FMNWFJdM#JGG^fZx>4_1{f&@IcTIU|6?%RvNg84X3Z#{$#*YjZ)9 z1t80!(t;kC3sw&ai$ENW(J;X%bF0gigXy6tx{qCUZZ8%>o@FvHkQ5$0T4SP?L>F9z z1hjFxPPp0$lI=W7;mqti*=NYILlS#xGJCUH8++I5Ya34fzPPXVp zAD1^t%izX7d{VFqb?WRmKVP`4qnkg!cI3u8Lcz~2-Jf#B9s0&#!TZqtLyibz7ZOXA zg!D$iZlA_vQ=lNO&z}p^Ae1&TqM(ulX_e6kz;wK!YUz`-F;s6AFimB^M3A_}vlazM z#6gaBQ*PL;nL-qt|A%iL+KLAjxvcuMThE!$gx!h3-%r^c7WwYDB^5Ov9W_~Qb|P3bn5+f8ZuW2l5k-dxM=*pVdX+b@F4eN03y)+2-$5)xOExxl8Rk<5IUoV8aWH4+?JpUU5 z4LQ1DAx*1RO(ZOGID_Fl*ATi2ZGZEn-#glS_A%s*-|S@-i7eP31@E#MQmY4E5GNh4fSPjk)0$fKnN zeY|Hi6R*VK9L?N70nY$v@n0MNpL=0Xhv)SJ&wW9_(QNS%O`>+fyL;tgRxZ!YgXagr z%Mnp97Q>Tz$IFun9h>n@Wriek5s`=_Cm{j+nw3bFROkQ-{=`sojk-56Hu+8@FUk+z~jfx2&e*AD(vII z1h@Rp73e|+jvlsYl{b?5_p(8NnlQGb3)#L#KJvFFkYIDi*s=`Jh+t8{pNXZ1RHB}x z3ov3k4^cC@Rp1>KG5)1%ac+_H`h`;*)FW_?J){Je>n_<9~NA}bdQ3=2+X+nY&v^b=PJd&MT zim;h79S^#kqbmPoYyV8?+jBoKKZ+8B-g|ea@Qa>hiss|S&b7X3xOib@!mGM@yzoQp z$ky4(C^HQ4SYl1bHzX-}i1mIlO6|ShmCn#H*Q`%EB{I#!Wf&h9d_r3BJfnu^OTo(?-L_$N}#zPbo{J^;xm8GI8R+Ph=yHfY!&4+EG)F|g74s-YJh-%sq zlqpuWuDa=F&O+RsrQ7Z9i2>95txn=iuNY+{Rq9Ze3f{e#YKT0N$Bs>=Z$!)=2>Wj7 ze>B#fL|>ly zprto|YAuMqE*;=K;*2QG0UY)X0$j)KBXw_4q&bin|9L{}L1=~pkU=&E@W2=goFg7M zA_3VNieO;o_pK#jU_9b(LLR!$6{(NSiQ78Rv3DpG4M-o$uC)4uFThdf<1UjfA`WzObo=K z))ZqPyp(-Sroyp>6Z3UJ8RufzhPH!D%eO1Pu5*NQztMK}56`;2=m9B6Y(N zsBT$0RPHUVO5e|db0bb;hU{F9>5z}Hx7v1scSsZJb+PQ>D`T3LzeaOz2K53w%)3=E zvVE5pi7ud3jKSlfZnTA95d~^X$VgqcRKw`7#q6Gu%Nt(~Q^ut~8#%dr$4**gtQe!j zq22_2p%~f;gTYcEJea1?+9hG6zXO4>E3iAy&#(FVh|;1=UX+BB*ST}YZ$wt7HogkX z;e5%kBPH86y|`AcKlU!&BVr_~;8l2tQs~^<_tHlWHVwZn5{>q}>8E9LUwiOU!e>(T zaBE8a@XqUD37dNSJdaTXq|5eknuRJkNi{hx!EO`*_!&VI&%vN16;S}icyn&X44L+q zVdY6Jl1J*I8{oYZC_h?0(hhx~=5~jSQh$4cfWEQkP3*Pwt}2PY&;(F!IKM1vn3I7Q8^q$V7BaJfe?(nnE%ygfku9_k)>DYXtpfgeV~3C!Ijf8tyzo3c2cA)pp2)q3PJBV|IKg;2G&Cd65EqTHxj9XEKiE#v55HVs zt?!-hIp0HG{E+xg-%!44R6B==-koSBzi(e98ZDipZ_lqZ*U_Yc{@Z!cym+X|o!`0_ z1Rp+R2$(PH;Kdj=7X&D~nk+jBqP5={gOQI!|mTUro3O%m2%T^Pb%;1zTQ;8cWFkM}zq8gMK zdf=^&P5G+>=VjJEaKLsDJKtmozN^eMe)cAoja0t=X3b|gkYFTMjwcV?0cWzF3b3SL zQI0E35YRJkH$+?bO6&EShT?$D7A4nfGA%`8e=e7;bWm>gXT1M9INi|w@%~ax%YLbq za+196`859}7L8Ssj}#8qL{jexQXI%eiIN+7Anmnh3?}1@8W$6xFd;|p& zH?44`@SYX~1k7MV<`Lj}#xtbYrGGi9D&7tybg9oyj8(~*#POS!=D6}aoU0oJ5^0dC zuAi7B!PpBrmIsxK&X6ExH-<}C|Jf(khvxH)2;t)B6!#v!Q}D84oH%4j#RCEqdZq6Q z!Pu>s!mm#T%uE0{t;2n=iIrCLbK9x>!CHsE`T-5}`rmg^ zJb~YXky&6Wn(AeIK+IF3B3`UQcWJnL({^_OKs*jm;ooSGhtA!)AWgv>S9f?R@D`-(3@QwHyL_8Rx9xy=v^PvpKAUI z)tYmr;bXB6XR|nIA786#zD>h+i`?aA)I;h0)f!4VQZebM3%G6a-EhZ|%HTc2Np;Qq zd049;{p0ROi=UVn@2J8ZDQHU2NtPpdjAdzKs)&2P#d8@oaq~KEe#SU?B%|ggO`T{JMB{|66N8>`()ksH;^nB#aD4n;XwJ6j6te$zyU&pRN_H9En z`-TU*?iD|N@RTfkE^(x&`AilI19~hgu39(!qf6@%6pg$ht|~L-nkg+)|DeH;MkWdx zBe{n7BvvI^%pHzyHsoe|D5mxBk>lL}6BENwM=cm&Mj_k5JUM+HhePo>-0`RNW&ibH zX}mQl`SgXI^aI=XDm0uktwLVBJ?gTXtW<(?KaG6);rh%A%-Lp9ul15gI)hfB)*V}h zyW*;A;?kRZ`;6jAr3GB6oM*_hHj{_ZKyU!zje-NDa>5-m%RNJes0c&s76tTe8i3~a z>zgE(@A$b+_=nnFvBg10u79g3s5;Z@B9e&J)U$8-R{#W`!r);LyMrt_#a}vl13J!!)ppvbr3j&Z#7itQi2t}_p+w0OBBi%CQZ)YlN zzqTdjm{?cEEl1v9LVD(M(Tbm7uSs-#4}VWa^T{dy+EMakv+`8P;sA9O+8J*rJN^Z5 zezSSj7(h6V-N5SzOgK$C0MSJo_zx_66DFd78<82(>q;}WJEuH`(iLlkC<*)g*@ApKT~e^w_lGO1{kv7$TQ&k=52qj#4`E9eVK=-CvdA!@|mLm z^~I2n6I=maRqUjY>bzmDG;yRDpr||$ixhU}O3{E2gzR9{fM5pB1`-S<+T0sn$%)8u z0no;^5;y_TEecx}eG@a-n4gEfE)ujrpGYt&AfY{QJdgGBevPCh(1IsCi4b{-+UL1~ zAk!V>a0FL(Aw(RD5=V#TSbh1pXq8P!dPo+R0>!cVj+kaq#4XPP{Kh%UWc8>3ZO6x5 zNP7|ZyP1r^Djrm;8>~uP;VhHjMu|8}!a-h8aqo2nEqar9U>ZZkuL+8D@q>w{HsbC* zd!!q(?ibu9bX_OFxaY9HHZ2`n>`$@Tvq+d(*S%@!Xr_)5Fd#tWe;bvD_5O5qO=ARKQvpfQCj*Dyt%?D9 zBas(@wMfq}epbt#Rx-zxF^o9$u3J&XuXlFsl_i%c#0e3C2CJJNC%ec0Rk$cIkDr`z z>kxg^b*U%K7vUr!5cV&ZEhkhTHjXhdMVAVxQ}_^xooajb*Qdm=?w*8Mm`{88P5WTY@xs3@ z&(|&2U)d;1Vd%ML@A<*h^>EgEDAN!?iw-I)m>y?Z8_23L1+co70=H%&iTpDdC)5GM z-zE_@l*t{1JC4($??y`aUGTh}K>E1y?E5&fNf_QKoAe^Nm~Zck0l~}Bw`7xN2TvVl zCK}erJk@C~3}5uWTDr1hy;meF^l`uOwnrNRXFgdpUff|RQPQIUqt%wa%!%*zLf08v zeA(RFCPaH)bl0GJqzNMv<6lR$pa>~8w2w7gAKd=dH(X=_zx{p8U)P3x74mc(o-HJh zk9d+Z`zpuE+Vkdq$kcbMD2|zhdIr9T^Kf=f(-$bI(!RDm@S?f2ed18FddZZB@Wq`w ze#U#eunI+sTZ!Xv%(h-N=evVZ^^aIx6 z9}O3dHsFnXY5tEf^S;wwsZOP=k)?#q@h zNDT5kAdr@`Qz`#|_VI0RQn6&&q=Wmy3Rc!RGrb%|O$IzcH+#y*bcpC&dNS=*bIlcrJLnfv1H~OdwtI*Iv^HNrr(@(9w?%lFr48KsvNW*c@_{i4nVRUbO8(=uq%kCyFg$rLz)0;b{s0% zsIwzu{;{1z@r*Lt{twb*@f`tZRS^xzMVt3|0YP4QzA!!VCh)e2bB!$*-fS9d&RKd~ z#e}?VlL+L*5`db#c_bAdQ5@e52hyB#nm8PRHg=`)IzXqbJ%n4<4?JEs&tCbuvfq86 z+jcoBjP zw=4i=k%aYY4wu10U0Z4>B3+Q4o-rl{1HE?}I!j9-@`K3IB}?az;SBjRSbV3KL(<8! z0FD19pImr8<=Jjt{EaTyHbN()Y#_e`1eYh46607A<>DaFo2-Q6}c@LpgxFg59Ftg+eY<1u)a`!kcJTeHSQpA^@V}1oZEC`h|K3OWRL* zhVd2J<<2+2m6mn-lcbVW5v~ojnUx+ELfu?;W6{-+@;#1)L8q?bbMV$;9y)jV#0P?! z%c_4&678b=&9@l)*1%GwnK5D~xvjbGb!u0-a?1VONbaYLKqsaVYm z+rNkJRn3C-OBMzD9ct97h^G;-vEq_VtSTyWDMg zU`_B3sgrg+mv^AXH3O*JPvnho;@M+S3CUt8+db2Sot?UNjF37Yx=dg2MJqF<&BhtOKYkW z=TO*cnTLq2k&U0F7elg7YTZ&YELRvze6?H@*LBG0ZENIfF9pfQy2$zk$p^TOUtW>? z=k^ZoxcTdQpT(CczwnEqvLWqVyS5xYlNwtxP4L?Ib0y+^kMG67W7gl!N$6}m`El&> zDURLmYmw}(D*ikjqRxWh>-a7c_2HXRnO?hbm82iE6J>k%<;`nuSk9U)KDO&#)iUkH z)5!}YH@e~6oJne^e5y>-g|Y~<0ub50f7NwxvA5MX_KOfef5yC0?XpO)^gZ~iL8VxH z7LWeyUTbZlfAcD(SZDlWbvf#TAITny@j`y3-272L5C@*imDG+oLRozu=O2$>5}aw}ewgBZ=kO3jQ4yZtME?)O_yIC}Co7Kp%U z*~I~HfDfruqJC~2^0qmH4~_oG zDg@;6G*F5Wr6P>BGp>@il-XD}J4Mfmdd=^dhXS2_0w^UKlC;s9v+v@*m2a_$s_xq# z-nl&7-MYLqc;R#++PM+)sS7n{EoZsENyQy6-EGB2Lc`uz%N%#XkWwnw8?MwEVK5&( z*Z3i+$uOfSmI?U-IhGkbD~E>ZA$`2}X{W`p7U~ddk!B6fg5b1)!b=sRf#(BRQTxHt zOoR^ri$K?)K*?k>hXcKH^FVTdy20nc1Tc@xgI@qd0`yh-W;v~2joG#eg14~H%K57hlWd@kd)^vT9m=z)V5Q?(?N8QNuH$!$vu zkq5rd$6WxpO_0wA`T-Bv3IXaX$BzUEQ~V3SeS=hQc<j5PAsGcJUBm0}kP1$5JKV>{~~SV*vS+63vIC;m}yP^r6LNa!khHAxzE}gTd1A zFMV*!pl_~jLzx=@03XRzu&6^s_SHi`a3QY)8i@#<>n+IHyQ1MS-<-7&6=?f`|4?hu zHIR@3|4=1?er==xFipZBcoAt0%40Ge!9C|Iu4dS#l~;%xcJ{!zIUYdA8nY&lcQ8%Q zAW&@BYMrC|wgy6pDh z+dmTnY$kmRlv>@M)QQA{jG$`R>`u11f%@i z{)To0r$V<`wauinT)2dc!d$a_m&ZLqZe`77gj-U!AAimeJ>A^Q z2o0ycf8wk8xFd6CMclf_^NmlBT%z<2=y6}HeEJp`^1e0xv2#SS{p+0@?yQ&Dtn)8q8+u&Pw8@(8@C()^j?5(R=%g!Ncne1eoG-1WOM+j*>I z!ed>@hwo(FjolkI-;eWiib`?sa6Xl}Z;L_z#+cSdj_Y+Xd_$?fB8B?2KYryGyyfAz ziT`$YZP9LL@dr?1cI1cNE87(1)un6uAL`+>Jg(XbGF;8t9u76Rl$FO=STs}@hB`rs zg!b3R$11KqO@-Hn+*T#Q!Rr80dslFR7DxcX)yL{SZiqoIqU=}Uyt8`%NyphMzSGnN&uU>g19P;~h@Je!%{AlYV zr@tOrwK08T^hC;=$sJGEF(aNO>}bnh zbnd1p{}QLq2$z@#jlGf{*fEZriht8DtFSIoVOiLZhHPX1@U~$~yuFfe)1waaAB`W? z&)lT-SAX!s8xD4&-|d<|n@aweI~Xm8mVI)SD?M6i^GPF=lKtQ^EyAL~1H*RR7KRTg zCxgT(FENS2J6qhEM^e27XU;Zf^P2@#cJBzzk`+=PY|l(c+cU^I+k_GS7^K+yV`~W` zytfeb!*Xjsf$x}~&Z{g1$)R#_Qkb3~2sD4B(%jMJZCjldefikiPtKUA=(hYig=B-8 z251sTB<2JQ=mDB0pa)8+K%x>q2B=!58BPKP^TI`=EkMBVaiw`Df^?>j zolqLl9p3}=sx1nHOLn66H9&p&BVGZu6KaSC#RKmSl}NkBWN$nZ`E``#684pfr!8Ni~^#t~fGk zJ?Ah!hRFh%jtW;7eg+dmfEa6(uBkI+@%;*@S+Ha|ODB4bhOX@kMh|5?z)gM9mGT4J zAh!xP#IgNm)VYZ08UWl$n_D0)#nw$>cyibySzXKo>|HkXWL>wsF_@fd* zmJ}fzU@k~J$f5z)%Rib4Xd1}0k!nGH5P>tc#{jZ-eQOEw#?&cSkze<@wWpWKbU{!J z(ZMS2hESLYUTxLd*?eBae6|Y*dh?Ef*_#Upi~!L0LJ;0$6oc=Q6Pe>}=mlB^H3PgH z9+GehBbP!1B9j|P2Z`8ExKSL;>99lJm&vosi+hx>`goQ9o`XpnM7qzqRif5YD?W82 z#o|Ep?V!VRfZzo3dG0;xff>A*Rj^LFv2I1f_EZ>6@QUHIf z3W!r{!hb}j!ZmUA{mfnVtTw=av7nFzwurFDy%qrB6#>+&UY<6{n+zbcpb2y{v)35v zu^BFW;Mqvd1U@MJ6EA|*wl58?Lb&w%BgZpZcoB>@KY0Cu$l`*X}s+5G<5qDk7NAhXk(Bp37M zOLA%6wgxz#E?y98(dj>_%+`wU7Ia8&fZk?$d+Ml-701`S3vuYrYBcVKXI|L)&iO3m zSjsj2Z+6?MkH~CwrFrFjTm<|<^6W_V%UY!5giDAIP5=qr}^2kS?B>0{uX>x^o zlU57{n{sp9`Y8foL2eTP*Kh_Wt40*kb&ii^-c>*_wX~7le7fd0_p6Uot28BP5BsIx z=@YDTeek6!@~`K^c{}!P&zl?*llc()lr6q1Mg6J#^{WHEG&A|Y#x z;`FpOvQ1JUeR6C@Pf2PvPB+MNdR7G1m>)mhk+=J4O%1-ETQRyfF%Nx9_P%r~=b=o5 zRH2V>L|gH`LfZX8c6Y~V2Y7Q%31(#7Dzxi7hIv|Ehf~6W8D1`7fgG9ZVC+1>P2o?-u>6FX_Oz&7?{+7^NF0~vlOrLM(&%|F zA$xB?e9Q&0>8A%NPb-Z@MG}(7`Tf}Hc&Wy&1m|7z>_nEx`>n(o2i@r2?n40)VGb9J zvf1SW_1j|+0d+Ts4VuNo^_fXu@OE#mp9*_4+if@#C2wFc7zRNW(iI71AL1GcEQ@zs zZY*|J&;4C@olGk!x>I^=g@4k)453(9qCl|uHH#}4Jd5*k* zE7mEBbB+uz&v_UYQX9BHS%D$ld*Q8u9Z;H>NCW|sK*(J(CV`w*r$ z#P(_$pRYz&Yy9TMqV-00Z24}bgIK{)BgvKbS+^QXzutZl9OsW!W+$f!HjO!8Uhnje z`YTwmlNsdxvHC%(`?1)D25Y9XplhyBwwD@?fGn68m68RdwkNd*?BC zv*ZtEdU?9mO?*4#6c_KuZG1alUxYTMU1^CzyOfweWA4S#EetDl2hYu2aeI;DLa|qn zdwbQsnw{H4-&Z|Nd3blgxRN=k6TEMFA+=5zF<*ZP)8T#|QyrP&F1Huws1{!TjM(B7 zspaXRqRy-ZDfAHTdh>ZENTb4PS&<(5R@`sIEtvFX%fcKBqE1c?UQXKS$bSpuiIZqt zqfdKL^JW5Q#?vicX~xBKY_ac~9>js;C@O}y6KJd!tJS3N@h^+=A zzdE9+3fJ>ogY5OGhEzl7T1)mmjI{_~N$a%|)<4F9eBbB*ggk zlP5ZoSE1C53cQWZOvMUk6}o!kX;ztO)%Oh`n%*1m`t2UJhpt4O4CGP5$dtuCTDB8Uz~vRx#PlQf0K&Z1PBtKi&>W*n56P?j6NgN5LCr7h<~MuH zkN`--`tZtZRe=M}0VFZ-*q3~!v*Gf)2DQnpCH!xuKvB}41a$!~X^uRaxv}z^j%8t* zHy@BYk-|7oj2R4An95pNq8!ojPn@cYC|K(UxS~E8l>5?!*3F;vtoqU?G_splC%7MS zb{nEu60Uf|fh_FJSI?LR1eI5T&BFsuG{AU;Rs;f_TAhDqIxh_r|6fa`L3=!%^Isca zfFN)tEcdzFkf1s~cP3zfpU~(XGZg!^-tZ#lzcMVYqcrq_K)>^=BApmEZhsQ84^cX4If3N;;c5dM&IuSm!)IK&#DZ9&Xc%PH_UI%D zJ_e5EFG9&gD{-!n;l=*ZHU6=*EVGd7eG{&fmm9PF?uOK?bW_dwLz+s8pXTX0$n;4-x!LM(okU~%VQUxGW57}oN-8z!LeEx@UDY|CuH2CG5O6f>qPGBuWnOCYK~ z5}Ap0jF0%;0#!!3ZW#3Yg%~t%)d-6?v#n?DsqU`iHmAQ%e153^R`SN91C4i;ZkO-X zTj=C2znj>8#bwA+a<3vevCBmz;se1wrmoN@f*c3DhX96iq(dVC6Wt*pe6H5vdHKa# z7B}yweYn--6&?TKDSIM7Ht_6Igv(4Tioa3A4)ErU*g~e*eWmLIZPmN)XNc~2+@DV! z+{GB>hA>jt6?vqcR+}(UtI(xL;Zr#qQ$vS3ui?8iFOk`Zi;|^XaiyPeUqru;x9;!M zd#`tcDxc7DOYkt7^fV!i6s9iIEWT%>$(tyDEB3a+x+fBzx_SLIBUdFzMLlt)tPMjK z?~hggI_5|$h;oQB6o0q;Jt=hLqEf2*=3`kyHAnvXHL(4yF{}#r@S(xsk>@}2&S^%K znI_OPby4n(Z%|63t^4|ihRzHuprwl&>_6Q5jvixACz?+_+7z(OSoo(_!+47I%sgh} zFujtM6=;@tP}G0lXX1?4O#S2t_3~i#^@s`l&Yi-c>vxnZd?@rSdR_3bcasTBhj@Hn zyUzk;6_O6t8TC4&Fiv~f7i$(`AtH1^x;d#SYJ!?-&$L18XFWHq!GG*MD{sy4Jq~T( zi@CrlU4_gGA1%CZVDEIpR`$LPyaXMR%umD*-E4_DIxUs4kpC@Rr`g#k%5k^X*OBw} zBy?lotK}N_p$Jdh;I`6dW1lmw9`qkSIzR1o$MW#e?iV{Oe}Ap&9FVxAk@C$oBX$$D z`eMk!eBF`irN0 z#1?{;uu`aB+m%|w&kI}%!K;N$UHRE0=d~_!{p0V7OI~jTi}aKOD$1K<^{r@?dtWGo zEYhB*L^TXmsRdC#8T-x6ckbVsw#D0AgRt)}v%iW`Pcv>>QbyKajjw-wLs3F^`&5%r zu}`mTwpd$t7gj?+UOn4t@Nl;MZxhj@B9EkeH69#g*E>|>L$kO=;{@6-_|79+e>ToA zFFGsq8$q?3qfAN1?uS&LIFU4q|FZn%JZMWa4W=6@#xx+oGC+W)5_T-Y(?x8(a>x#W6lkP@JbYgDXTi!1_S|7K^dEqh1VjMtpBr|B=k%f=6N3xsq5 zDEISRE#}OMZ%9@?0~1k{JAUcZDvhT}vN;LE%3{PKT&_GxweoM6j5VHJ`>Z>`A;C#^zkOHXRQ?b8Zv zT!=cTIRFgt?_yI>2$6_ehZH7oK@}*K$}5B5rM-9`yc&+fTyGB^xy%KK#}(vJQU4*A z8!4djlLB2@7t6FaSiD2Ho%qWyb=?;aNDBoDP{scaG&oI{6??LWrHvcKYHjT;RhYOT<|#X_;ZS$8A^6T-p%O()gNG zI}tduucYA2T-^~&V`Zy~I(@9*u=n~z`-sF=m{z%;{ja?A#%acnuh?rhU%yNzAJ0}a zN{!pT-iF*4*eqrFN8&-L3I*D)FSOYQhru}taZ-ujm^TgOiGvCQXKvI*v+WmgybdQ6n|)f9hO zufyy*9B=S=){ixQ9eqmWHJ%%;)tj$oZkq@%iLQ9AP2rYBaW^Y#3vC^!QvIvTW!lEW zrRn2xFQtUa#$Fk$D3X4)*)i!`PCoIkw(pkjZ6Z(JP}Xy9pMQq?>$Xov=+orTQtfXn zu*F(Q z2mj1|_;@sTcMDP8a+hAb;O=+T3xi1re~O9?@@gf2-Q|>!adM>n=c`zC_Wl*+3WKDD*0RZtX`=H^ zu?TAVd!tvoc5Kfz(vnDf?)q-pe<=0#l}wp=o2JtPbLX{O*YQgg29}=A4>#Zcsg9}e zRR76o;qIMEkCPS4iFcW~Crg6+q#s8Ph1$uqLyL%*6Qiuu;80YMg5vLQJ5Ad%YA3xP z=zS11$}O?!j% za&vz4vi?3%wYCyY@zcoL_bw2R_u9w&tigO~|48rj%!J z2j{jomdCbK>wh#qQ`?}}bp7ko+Ss^_>!p>K2F6oSY44?z2Y*cmxr$1wUCM2K)F2U- z7IXE`b7pJPk)rLtoMv=4IdHCAi9YR9;2pekYGdEsi&isdug4OHTEFR(BIGHbg4iSD z>baxrkk>QR;LG~?9VHjviAOvT-L^;mMEp%b_TzK+J1Ek>j>_!K@w#}8v+?_b!t-aY zb#L{(%hYH^ljRf!X@{NWze%o$&7Z5;x$)i1jot@&f(lt97vC1@zbi^DlQ{JqLD`w` z-6H#oh0i@SqrePpMZeM}>HhWfP}8S0T5?&+a;1!QcuC`7eCl_X*@sK_ETm(ej*Ly3 z8s;JA)Jjha(t1yC9c;rJ^R-lF_7`?_x?lL^dK0NtrPq1lBf?&0f_wVlz1r?qed>x+ zZf7{>tK}VKI}P(`Ow&)H2Y%?s4>pM8SDd*RwsinixKMGw*n0sJV0d0_2RZq|>tb51 z<$e8RG5`J_WpCog2b;Rd-)FXUxtW}Fw$TyzMZyl%nM95bl)6`z_@@lDOBb7BomD($ zlNyNXErk!%np|F8qP2yM*@aqv>%tAZ=>2rgmvsD-j!nCb?#}67H)TNz22n{hZ^5J9 z+ccUH+e6f8N5BIwhc>DX!uvik_L1yX18bVBkZ0(@Q(pq+uDrSQL_P7lS!A^xSm@$i zad@Ej#aHh=-}>?Xy9(3CojO;-w>5RzRk-;@;GHpDOh_GQc8i`@q~IH1@poib*6uaC*tyU z!8u?F*%wbBM)Z;UAp}~Sj}7T?!o`rihFO$7mOS%<)zNs~f?pt75Im4~c|rxqPlLKikWIm%APmBD?pi(U z@xtjTFED}~KIeh7;2OVB4>x$nT#<7eI{g!{Yd8fB5XT?>pAD83xQicHh1OEbxe~M$YKn4r!=gfy;wp5YbZF{n#eB?p;fx$q2Nslp z#pb*&d3&Ou`mqWXr&9cu+N^CCn+;_(%=uaq<&M%95(?^s*WpUJXzXRvmE|v5uZyHw z8rw&6rnyBIJJ`*9mDG3l4Ewp~6*N6IFm_vCT|~fIzL)F2@9E!`_}!QLq%Xb~Ypk;= zx7fwy`1lQC>Clkd2~#Jd^mLt%rDqmSU74ww*S@wpB2RkD_H#R~AQ&eSE+5a-NH$E3 zKLt`el8wf)%n#__P4w)$I)cS#WkOAQJ}n~SwO^g5nvv-DN4B=s={@=NIpRR#9TCOO zH)bzUjw)1bp=h_*m`_t2& zP@YR!+=R0=3QLA7UWWWwJ~yLu@MVhGu4@7z-Ho?3P>0)ElYS_RwN4YlhNum}qTkKT zBKymnzoukw+9V~8UywyuK)p}=iiY1=KTHnqr7Af&=~(DHjGc?5752}3C|r+~)o9E} zO7pj_YneptBL@+zjQ5YS2p#E>%~2iqz7RW^lJPXD_LqDLauKt%(!li}BwBqIl*)aF zN#$*dk(VCM#*vro^Gh3l?i|K<5s$aL_3ysMs!%Eo-+XU8SvLNjPHXeG+sqx*w7xztmD);A zZ4ruzCt`JF9y$3|g>NubfAz)tgy5Igw25<9RSy&%Jq2=b3WMTLPsfwvmj*=Vs_)&B z)pEGm>hQHFa*(@DT598K{J^7aPS4}I{ENgpq-!_6Q_+YxFOMm73l&0k#F*$RjGw-b z^QauCJ-DGxa{h~-zs=Oc3GZG;Sb(l8rKCpX>jB0+v|OT?c%C6n;@~JXmlmpz-mdR* zQQF3X=uosLCtK&J3sXqB%eUh2`$W$`F^ciCNVZ038cq-~43gqpFTG z?ndov83U@IiZ85SzW()JtN_orM8{LD4zXtgE7-ruDbel8yP|ThwSE6!ey+^5f7|iu zZ>>iMyYYk3myOrgMk!M%+<1I|v$g!;=BKGUYgMZ6*@(wXbW+^$7PqX9nn?`gY>wFA zD8aeh*LpQG4;#EGA_-^xU_#5|ZRXN|m#j1~TFvT=?C87xuzvMGZ#uHeOOT-{W1o4z zPTrY#P~l-k*4^6Jqiq`!`oFuXVG+}V&bF+gsTv%YDy(d$R#I}g1sol`{~ z8r+&o?XUXaCF=e+?cCCJoG)%$h5TK2(Un@$xB__w=8{(foOLaRxyIaqt2c!kVmP-$ z9;5jbyLN2gQ`Jnk`}<0ofB&@6(0zpog~Gz(tOpGwi^}n{Zzen$7ZHzNX>27=A7N;Z~`!>&}}3d7WA$^%^42h_&B9JL1Td)w%q zCXJZts_5oyZ#SQbmTh2*l)9SbT$ykB@w`Z{-8*i_d6SBASRVP-g>7Lyt~=%43>BZ; z@A30R>ism1!S9#ScgEv}M*bI9ZynZj`~LqA5RgzrLK>AEB{8}|I!CvG#71|CfGFss zo6*uSlm-b=BxN)MDV3B~LPX;JUgN$$@8fs;{s5;EsRiEKfE4=eY7aHPJ|xY-oKEt}rkJ0BjN{meBQN-F zv!iXbFu$EOgypn_juNNSw6nC3iZW8C!{&PiZQ7hI%Rb_h{?JP|ZQxFR?TV9DDGyIU z)e24EP%oE&R7~zc-y`8Z27k<}SrN7^meo4Sn`|!hRqjP-iR;QR54iM<3515 zAR9Ce3i^niPNJI26)i2m6z<-|wu;fEKS9B&A6rZS0WK{aP#?dDY=bzLh#Dif(Kj0V zS3v+`yaLr>C43?w3}Xd(oXsDKq&z5J2EdQWFm1AjV>CLN!6P?GK-pE;nb6{V;~z-7 z)%AZMy{&o3;rN|9CzAzt=rKFIyq`%|Xj@9wRzS{LbzcjY1$^viqt#5%r6pZWK)VTn zs)-KT9UQZGHy)p2Dg zvT{93Aanq;qu}f6QhU<8_Nn;I(II^D@*o z7lG$}SsOpr5YvX^?Q!U)h7|1YkGM3*chTK|5Imnl%K#U^s5C!1%=cDh-Bmphx8k(5a z_dlDT=s(kf5V$mGh^eCJ8B%M=?)AO4_f|<^@0F;Nb#kw8-LVHE1ecKWH6~EOAqKM& z-V(t=T)Kv$zN%Ur){&lu&;AI@u@8HGlRiR?FauN?fk>2;4(d`ZMcfIaO2jhwbUDa= zIEG(OVbUgsXtqN;>Q?~R1$`g1MzOrGaI+uKlvO!$H(-eUe~2y@LkWk`m^j1=3{+`& ziDV5(B)b3o=HFQcVsuf3p+H-K?;eC_EK}e!i^KAFvzL|+?}-mVsy&P+&^szGJR=Xw zy=&mHJsUEw7Nkw3lxNCDb9s08c`C)V`xGL@Vf1@8QrF5o?jgrUAItkx+B`6KRo#`Y z9-7svAJ2EjB!}2jPH&nr%w_6vpwjh2OyEp6{LlD8LJ3z*_jwo&Y!0g{WR>aHbqG63 z8&qj`LwyAf`p}F1uI@w;<^zfG^&a-*R96jP?>o+Bf`f4}3hZ@tu|>_U5#!uVe*BES zF%;{G#T4nLuFtDwjV6maGSqI&@esb^ypfWznbp{mzJ=3iAXp=OW2MYmULki)3Tl4{UeS+V(y+hBl!8Av4S;DL%e!Xz7TI00#nVLL3zlSvPLmhvWnt9TtkV6O#ku<6)_Yh+3$YP*7~x4 zuJ=z?^6`Z3*9GLul`SZ3VcBYG6MM!uMXq#-dy$}#ZS-+84n1TL`~WtFAbusH9SJ!s zMyM}=a26?Pv2-5HMnHS;ifXoRNg8Y%oz|1E=M78`bupc6a&y*~rX6;OHX5uj8!z?- z-7Bx!n@44i_p$Ia>B38Bw|q?zEgit#L2A=yzd<=6bw@~^Hx0EKs9KpFQMvH+c@jTR z6MHjXPPtdp|B!Fug;&dT*CJGNW=wbqS8h8rb*DX}X~{wuyZ_`@EaC%S-+O3f`(TRz zxk(c&%Qyg*eAl$Ys+1GUZkLk#oXh){pK2;>$=m-YGDUFBegQ*aL<*jJLXX~hPRnX} zy_(H0t4iw2B6?}pG&$P2qcStTUH)t8O@Il)=+C)rPneS3hZ>H0B^o1!X^SNVE#hv^ zm%m}=@Rk{?3E-=}?*m^#<8*wJ6ocQ0r+q}gdWsBLOkUk$4K{+QL7zR0MU5s$lcYX! z7=Aoyvsi3a>g{UV&@P%`18elaBI+%=d_M6X3o*OB=G zz15MLDd4S+ExnS8gUv-?Bv90j6l>s{ z0&#}NG6XuV`9JJ?>DKIc-MD)^=4Z?2fAHt}rv2C`wbT2O8_e*Cz{siWcD?(y+v>b{ zImK6xVyA!)a;UW==gn6}>Z_3}1Y+x>W6WRw zxqc?ZLqGObDNydPIzzUS#V_3ip^y8OvX{3E60xu5)rq)QwkM_vH#?Z4#%^X-^ru@d`8> z2E@b|W~^Kfx~`Bo@LH^odQmsx|9=Y~sk2aoEF}PlM*@HJ)Te{;N6sj2so$J9-{PUMG|_ zYtK192@^8TX(Jy@#11tXAq0 zmMB#uZSdCSA4iK*zKk@kp%}}skQ7gzm@e7u)|kO)zrRCg6LZx?w8x0aA9}f*fm}&g zL}w-iD#y{c%V`F1M3w(CWmkDYI(7lCf@uOp9``JCqilA zW{#GCbYLWY_29c+@iveWBqEe3^l6`7bOZ3>!D}Ft08s|2c9VT38Ai@aFcF1P#fL53 zfY6chuU>FDc+4mlaF)o4K_ZV7L{F6E3<<$RR84oSboL*}8`{fB2JfCUTwXU;1O%zb z215FT!y<5I4}k;;UcPDh2SSJer^M348Nav!5PO2_L5DUz>|;b`Xju`f9#9xS%N}2y z5(dHs=n4RX1I#F3M#4klz-#dUU62t23cX?F-+QNz6~8NCLlloM&xH~{+z8vdp1z@& z>S}>62Y^Y4+2p@TsQgN*@&|TfgD0s>ho?x5llp!Rd=ikh{=((KLs= zLd0WGK+hG-N}#i)=}a(zhqizx1OgELg?N;MVQ81>*Ijfj`=MiH9`I-Y@FoR94#tve z^-(BdqH7bcKs|eNEaLLS2Lt4NJZjSpNUP!(%LJgt~fKk4OCnbfu7YP!=+?143!1ADt#t7nTXPY{Dpx~`0 zfdWmy8Srl)7U*e&E4`<0L7`Uxuhzujl^f_3J5X_`4oiq-p!J}&C|yM`b*A;X0Zcex1`Yl#mEl$O`w(dFO?xgkVliud&(lYL^ut0c^j$)l!>$B-OgK2an;I=kutP{@#GZvL(Q4G62gnK&M?v5uiT6|A~IJnO1Pvpr2 z;C8?Fc<0tuNQ11lJid0}5?=^VVy{!WsgNq1n!*0IW9q2hB7Q}ltrOTAyRZ1jCmIdw zCs|UanZ@%FVF%}Uk1%B7I`SM>lY|OFVo1&zHgBKUw6z{{r$f&s7`h+n2+wzow?{jE zPXGJ7`>;zdi2Im1`>!cU%D3&Zl^l&Wic^Nwpng zLbl#b649(aGVz;A$BC$5qdVe`OS-L3jj~LC%`?N^uAA?Le)jjkXql^dw;5l#*F4&w z`9M_1?KV$E49@5JRfcP!Jy604;3*=YloUQ%@6u4J5X8qUmGNum2lG zD3sI+;&T(;t)hQLPw#d(ON@vSl%#-#+%z50Ss+XB=*{O&tbvQdha)7zPFCSn=w4s- z` zyGRoApBc_#GV#b{!PT1}0;^)2tjDLJ&#M<{F6h=*)=!@UH>+c@HD@h;ISdB*W&!HMJ_vIXOHAqZ*TZ=01uVP7jUW%pGBHR}3NX<}a;JrJp`VK2&HxR}j$obF1m= zOJg2fHI_+QW#o)fU-%YHn&)M)z|j!5^f^d>>YzHBVwLc6wXvP(S<%iVjNaX(3E#Z; z1&Q*gS>1RKiDjNd-3h_AM$0JSB^I-V#8S(9)n7_3pQYqB*qeKWw}#Aa^cqJjG}dGEZDscOQ&eWH*VwoI;%G-3+FCUit7i0aulRH~w=(y0#}~Ny zSw4R7?ThQBXT#Tz6NJxit^YA67wDMik)CpW)fKtH7v1&sIxCNvrp5WL)bih{!oXH_ zdgE@4<(*6qsZUwz{%hG&cde{gjN?kL&8XE&GQV`VK4XQmILd>z_t+SU@gqr*@C z__TMzREsg7Ntz_CVBEM^&xl^H5*L4Gc(rEBEw<+?$7(O!y8Fpz^6+A%h=k0tG)xtLNF0L5m-#>?xWUgUlOG(!1pUJ zwdK^g%7vl}$t1aAa2qwRB_^cq3r;@W2m0IiF55$JsF4z>BZvhr)C@qmLIBqZPw@c! zGao&ykQziLVN@BoDkxEK=w-tbHT58j`Djq6!y_-0h#`x3uE{D&Sx1RvBkAjzXIX`{ z&&hYC>!1jWt6VMd7Jkw|in(-1IjTlW3uci^@v3`Nz-zKUkGK4F_Tl`{F8h3$3Q54& zavTdlZg>VS`XS}mxHr_B7lH+?iu<(B@La?TK}Fk2S&3Yq?{}Jy>?D!-!JEUeP+lUt zUf?+?M(aH23Z}21k`#s&ua(on~EZ@Ol^Up;55mNl(7iVgEd_@y73g9bXF3MNA zC@%tU1%d!P6JWjJrz9}JfJ*@E7C=J-*ijG;qIE(+WethT40f>QJZs1rva>H0y}Jz% zfS3c*j))TMks$&2LGFBw4Y3KIKsggs0kT6@F_>~zWAI%{?1iTV5PuLMXMD?|1yn@; z{W}n-)dptI2DG01k~AoVAa&y3!^@BHz7xkFEu;&VUIXeULV++yN=p$Ibo%k-Oz=*4 z#3>1$7bbxT8U>2gBOEUVgn%yP9qBzpDG7onhUe+w(FBfZ$+RuB5a0(Dfyo63EFjnP z%}4F#5(a#GxuFEBIf;6#&V*`;(2{`CJM*wHpqr^9GJzFk6j+44GKL3^JOfx05ah*Q zlZzqmVyMd>)eJT!oLl23D79hFy%=Kjj&6d-3+l4Z6mbc(b?Z9K!~%gt)z05dYJSMz zu2z<(bMrE<409T}cg0xKm`)5b;HO+0{+8*V`DSj7Zney` zf-qEKxs!c3aWGYs97~PrZ;WaTCA#7JJ#vi)m)klZQp-DA{2E3bAq{(O6Ge$P<@HRJ|g`&OFszhtf2O;sX{(GlXR&gs$ z&>5-iT~qfvx8rxU#m+{tM!<=OdZJK@D6`JfcjGN`m@Qj__BaxGJ)@3^*AX2-wEmlx zH_#1@OKZ0ETfqWE$oNm+aL7$IRYwYoS7E`rP5Wg&nq#o9#&#}Cd^>T{7Qrw2NPl%3 zrLC@~hbKgAEY__}dbs;^cvpTgUSTgb^T^xX3yllQaok|y^A~JeQGfhBcSUy6N9J(( z4B2ACmQhMqzUtaaC29HNX`z@z;9@cY_MJ?=!q353EQIaZx$igY7R4OR#xb_(($LJQ z@=^r(kLpir@7FZRSjkQ|0-kLTAr*Q5jyl3d2J?)M$BvVz-fbx|kyC4${57h(LKL#b zHGBRS_T7uurYMQ(4`YdMfxV+=OD7MS9LCZ7PNL<;bvpT1G$voUYJ(J7FgF@qoMYU^ z*`bG3xNqZ+_{l(qxhNkX7ePi0z`?I|^qg4{Vpq#BfgMwqo6 zrH(wCjO1H$GuE`0=hHLRO_Kg7$$`oY&u|cdU$$nIIw=1}j_KR9G`39m z2Xg23yQmnMUwRUdg3i@sa~3E27_?w4{MgdYrQqGTmi=?AsRWk>zoj?2JR|DXI$ZSI zFKa<(ea{9f9o62?MvI6c$K~?!!Yq#kNZg@7T2)(WxB9JNWj$wk#+!S2`6V*p%h29- zb$k9Jgyc2#4ReMaT3TVTTv~0O znv2nSXz|OpX7bNnk^qwTQ<<{Lq!IT+!^`GLdO54eh@HAayj0%?e?zuPnisOsNMJ;g zDsq5bMP|wkTH5l#EbG;X%k(e}QG#)Uw5NA_H*&`ILm*00XwI+1PWh6qXD7{AYm)6% zX|1inCS_ed%}y4RF`set%X?*{Xd|er_>lyJGX#~mZQoqyxtU2DP~s}!Y0Y++7f{wu zQ5)UsfpOqYTTOhGJhCQEh)Y+wd+Zt5Z6}k_TCd^$$gV+U)ilk2Uz)AKNV;QKlBLqW znn&`6U(G_nU~0dIyV;8O=lb$()53?CM6-F0X4R%hT!pJ!w-?rDI3!EM2o?Y#6G3cfbK=(wtEs`a+ExYAEmHu7*u-7V$rSk7zT%{^$ z#mM@pT*;V|nVpW=@+igoHj$Wg-_x^Alc6Afkx>Wx%Nm3Q zxuRoNMfr9*A;Ywn=H{X9+G48>Z~|~Q|J>frvT>|GIo@jBo%;7rsR|N~_^g8b!Yp+E z(A|lmURm{w4m?!bvTrKeEYDrxwtC}tse^0OpXBua7)$)#WvTlXCp2!p_ zD(BZsp%lL%7EUB69EWr~D9i9M`m92rq5m|!0b-K+fK*!~x4sCDg6Ow9180MB^G8u} zbuzV@paeMDzMzbq{MjXga>OTZm&UTdTf)^yKn3&S zz8=^__+rGr4hyh}J{DrNNbx{O_vlS{@Wh*uGb8~n!o~_%5X2urX`fo)-bU}qq<>hm zLaMrAv*JSK5$lb!aizhp+R!W9h!-|vG-|Y;@LI@4#*-M7bAW3DUT)(1_LFCK&K|wr zK^K_Ue?3eB>>X#u8o=egMG>EWu2Lg@=a@|Akgo22*y01P1NJ^Mp+fL?P(X_0zq4?v zrwMRqg{&PVxnKS9?Nd;QOc=#yR=}AH5*xtCx%h(eiD~O+{D2t(rilN&03ifHHUAnN zYXd-WV+9}|KjiuK_|CcF|-5l9P3 zJWv;~s|^X`QrJ?6G!1Aw@uJj)q=IK)5&+siJh$QEH9pk>;x>3BPYHmBtud-> zPWKTV%s?|=7C1XLo_w%0`?l7b7lp&Ei<6EME4*Fr2o2pE&_NC{u{@|yp z=fHYq#d*5iKC+4$5;Z0#RSC}f*pj31No;|oKx)ed7YBd&G^WUJ3cZ4~bVCzeC zhU)RCT5%P~Yti2SWn3U`!GsnwzizjZGhL#2OxweQ%gnQCO}_8AL_4DrRFYQKVsy-+d7(L3)0>ZA#{N&S%p)*ZoY0 za{u{x!%Ky`(PI_rUZXWBnXl91wUfFqLNf-%vT}wuSxmyqe;`Hll}O=A(TgZ$gKh{f zBkfp`@nntukTW$?HXE|*tw=Z@4aiT25Jyo*l|Dp4Y2^*%m|98J3qLHDRnW_s^mFu% zq5ZiEkrZ-wIAB!~<_J3MVbz-!Pc^4u z3iV?m)Y#tppnaB!Rt{;({4=C>OA>?YYM~?RyUF#cDXw=^+GP)Ir&*mHxHIMJ3kyxQ zzADhJ){SbqH@IID%O2r=X~hz!2D2(KPBc0$3kP|pg^D@kh;=n}K&x+|is?ePOC?v7 zgimKxya?JxJ-=E8msTz&{<^J+P;~y`E~-D|jqs)LAm>6xRy|ec8QzHBpO}YbGY*Iv zjGc%(;1T*c5h?p=hh@=&ozVV+Zq>PY=V!sss;wiEt*$tiMU*~%QSn6ic+9!z zw)*DKVyc4!Lr+i{>#M7JFwgoFw1ZShEO9bc!MIujqhI1ex#b@?=l$%L<HaMZ=5&AhuzJI7?@Kn_?d0~@hm?vHUHvZ zd1>vwjP6F8#0+2Y$m+`8X!ck)#-rL#6_S2Kd{HelIs{uvRXn>K!B4gl2kPkW``~gL z7u#1_2O@vnNy>Bj88d_s^S>~ z{h7(suo=!t`ZZ0+l{Uc&@u;%=8uCw%oG>Acbw#R6_lVCLXAy0Ux^Icn7T?h(#||-e ze+*`Wf2VJ*pCGz3$8*WNv?#Hbq;J``n!W3{bVlW(gmKip;LV3*;Wc~a)h>^!;(`YD zTJ8@M^6Xl(j3?F&x?Yy&7dodA_AI<~Rm5h_YGonS*UWY>d@0%VHTRTk(z7+vO^c@F zZ7vN{aly29w=jm;+l5VVy^dF26b$_yi*(oDK|LHF+HG999us$vaF2}R=C|ar3YSqV z$!OE<*W-(#DRPlt=`t&{yR*t@H96y(SKl_MA*8zf0z6$IZ*+Yu&@uO$r63_j4j;1p zx@%qub~1HKQpTg0E)nkVl9l1C*8<)ua8h{iEm zZ9I61KpEIO5SEKis5>?W*6(NlhAWnqpa~haXePgJG3dn+>hf^*T=~@>oEYdLd0>bL z5iPG#5An@cASXHE2dIBv2zaq1U|a)vT!?0Aq%N#-Ap!98FXARrV}`+S%}d>^pi%@f z)3o)S7oUuwJ`)e6j^4@k4k5Qv@ozL>TWf$Q!kewFX;a@n^OV=~nxe_doKfdY{%d;X zVkns;p!r0z`7h2FE;o4lrH(AieewbQ)loBc4;R77kE)QlL9YnAwvsQA6>oGyFpqU!6BN66Pnb1${psS7KRs$PhD)N$dz zY&r@S%`#G(^gyOso;h!iuk z?a^*`1=0E`0r@zGX%!#kB6;T`%L)gIBDJB*i)FGeNrIU`cveB2H49xiB%+r&9e@k*~R%IQ_zFb1Gg_tuW>MTu#O~THO7oXl`0b!}A1SrqS+PYCMjTk}wxyj|2TO6>T zQkA3DvX5KCw3A$JJeL&i#Z}DE3|2ejLPhzsys0>Dzy5|!>Mo|hLfEzauMp7^&6H{~ zKEE47S7|kwnBD-Z*3EfQwZwPEuSHljU@5AYs?2EWE@D=g=ryc8YRS+)heK1<&uA>4 z{hEj{9!MW9##9d9j0mD$Lk%{y2Rg7>JB0F=)pj(zYx<%y87D@n>SS4=sSA^d9{M#_8J?Jwi_BT|=Y%IjKQqZ?u=2@Ag-6dSb1ObANN z?(M_7MfRmjy#)&%m$R-{cu#LCC-aK*1CW~Y-ttj?7Jbo+L&Az-pB3Rt%ae895`-=s z#%IeBW6^IHtGD`B+OCi-J8ilWN~SRgVcb43|-np$(#K5W}q)wU&MuAcVWeh!l4WrJNw!W@C$ zxL*1JuH@Dx<%1#{a~0Zp4nZ+jyXC{zI(?)5mOZ4EO~G#jN*w1ou7`|kr@`X@2Wvhy zDCC6$f^!}!xUNccRM%gU;A6m2Ejv-WMIIV5mN=6+vTqb;F27DdFPm(nac4jovi81M z{AY-<3>#k~Z7Q}>FxW-bQjq6t8*Fkg3i&N=Gw`dKe#h2gjbYtXbDqsSiEju!Ti1;H znNqavgNDP+HQ*(RIrjTh8Kyw+_9S8<7@5rB;rChzBU`PWv+5E$lxzM$955jGfrU?7 z%+Vy^&hLyb2CDs-OpMVg%Q8!xi|E39VYVA1WIxf?)vL` za_c?$>Ahv``hDaG#2IEnLy-nG8ZO*FIHpS@ z;+~ls&FwGOb2UZ|W%f&-^0OO`U3Y1WQ`;OzeQEOGUW#IHKa?nRXLtR4l;T?{I=#QS zdv)GYI&E0ar?dQEml}&Sqd4r*7j>yua*X%Og#cq4-;AxWP=RT#g@;O zHC%dwUAJXO6%xknFlw%&dvH%oxeDzM=qStDeWi6i-#PH^JgAa?Zhh0N{>XhcRekga zvMi?2o1flaebYNd*Ut9M*LH;stk+)5$%JvC`bjj#rZG(BHgh$vSup)cA=x5tuV)#f zXCNk|)ln|aMf}%rgFTnMMQcLh9@>%5FG@=)mV#!S5YzqIPFJj+=j3B*7T>BP*}7J< z6XWVT-p8VC%$Zv9A91N2i4IirFGP+?x8@^rSWs5jn*-{fLV2rK;2aF5rtI2$?U`(& znJI8JXA!U+DlMDndh5R{h{!6vYPh}`Q!SxR$ z1OQQ}$7kEs^MZ4GF%S*#h2n(<;MLqW0!dUDP;r1Z!2nXJgg~76x8MRc7Ks2w2d@w~ zCV?H1O5ms#gpG{^8xm*y1DTu*QaCfX@weis!Fzl|7LYdpQ3_IT?2TU;Ns=0D#Fnyr zQV({C8B@Xac~-!-4G<(w=8m{p1OQ|pi+bUw08dKw;&XI@u>rhy{Zl+XB?_$G_^-la z0mWB`i$L7eN+E@S@npikWHlW`Zbkvk7e99Z*@gCD0;CvBK{Ei^neZqq*1rF|<-7qy z@DJoAGOXQFG^{%8D3*v>4eb5^QL)-L~Kz3c>R zhEoG#7!go#$3QqF9K@mT)8d61{I$5aD&$uII7imJ?V5@qORJZ;V~Q%7lN3>cOWM0; zN#pwHpLC-BYHGHLd};R~Tv-i%!Fp9pg70VVNVIpwC(84aV9y5@e1z`(F(@d-`fv?q zt$1S%W4V@{=Qn9=20epuA%x3m%d3fj%ll@xn}Ra@>8$D`ADLe^AQ#i(q@WD4Pph1w zVl7hR_>hdNElz0ZmxgKg(M^9m{#`;}OcY?Hk|9n~fOb%1pq)`7#H(3FF~$(AVyczu zwLEl5g#V7h>x{(Z<$Ys<2vq$`*ZZ{1$K_u75L5DRuXEI3jeNOJ=UhzGbM=HLQUEeE z9hNG3=_UhGT~QngTR0>xfFiuKl<(#`?KB3DUsYE~$=TN@dY6AY=@T8 z9eYEIs23v08Bhr#W!|As<$Sjrf;*QC_9;>0Pyc?IV}G}B7{#0m-RP1V*Y9yB%XxIe zGxNqyUa_okqQk4@#TLJW$OO$(1U6JrZyD7QN_m#sL~q9T2R1p|igr%5S?PscFD5Dh0>MQb>>so9V9bBo+wlm7g>Bhc&iwVGTbgy_{ zp?_<)Qt(tBYA-mFd+_PjY+TBI*W-pqO!Pk__K=>sPAjgaE{^NDeBN5;ER%&iA?a!# z9zmKIDs(?A^Z0w|a;pujMVd0HYux;akf2sCg0xw#qioxjv&|k$c3%do=XR?13LkV6 z4D2AlO@uJ>bHPu%&Hjq1_C=T}o|$?Ki*74dKWwC^N;fX4gh2dKjiat#rGI0Q&9y;} z_=POLP=o^q9b968wB4mR#yX((X4CkkB!>?8S8-MNQ-&kV+d1WB^y8^9{eqQ;75XZ1 z!u%3zhNc4rSSRi(1Tpsj37PH7#11R_GNa<4ZrwV$wySyC882Ql^ek;!th?lB@2cEd zougD2hOERZn|5hXcN!0(gbXa89rEw4GDYw)h9!14^g|+#V7vj!Lo5R5Lged;^b1@7=ItoFXfaqL` z)LjdJ5pW3JgvSMsH#sT>d)PS>{4NUmVDnw8TTei}=jXT67^w{2VKU`u1h%j6#pTj$hX;&?e2nQsO68+R|cjE$+R{1 z*Jv}V1P2DRw{KOJj#T>|lO{jO6OB*t7axKNUe`!Il^cJM)o+uwYnv21nc3_ATgKLC zfpM4m^(P07n@nqd6k&~Gt_-sixrctLa|=qB!gm>u^)=ZJ%Y8~e&_)P+))d*NXWgXD zGGiBgWl+Ahw_c|zVMzg9-!{!{VFE+X>+^PjX1|kOEYgP^^|QkicKf{ z`6{Zn?!dkf5%n!*daS;BPA;`;H8ztTk!eB{$B!P|aO1dYp<8B7m!4E@+I;&RLr?z` z_rNn34wJ?&lIZNXKUHftT+k}ozh&-G21YGTrpbS?`8)O6a&F$mY^X-3jtKROSvt1; zqbAvmf%b33%NzcA4^^L=bF^TfI+-lfFL*a%U-5E9DGGV(5aAjH-RT`fG^KmQbREqN z4Ii;#rcK}xEMLB|-`h2t$<}4mtLhOu^4Xi{B#Kn~5Ea-ZR};yuD_qrbxGmAoylswb z)sVWcCm8Mc`wrHF<%gNcC8kwBgUiJqoEl`AtBG&iqduUpOOlITw>Zk9uQFtRJKfI_ z+@xx_#`7E!BhB-D{O8akt==^nL%s#eAlct&CKC5+5{6^4#^to+J&XJN-=gw6M`T z3!d_I7Rg_+oDWqrjl9D7D(VLRsO6f;Cu)`ZT~`Z{w(D6&XHzF#qZc=_wK6|>*|hMQ zNxx)PH`rm6bn=SpOd!Rlsf6RVh+5)a<{tjEz&UyGAncvYiMOU-zX)3`23@sM;jJDw z_yd1qHydBCelx+_J9yN_Xy_-kzaRYlZ-0*3lhHxPv@HEM&ifz1Pj+H(h=Q{a4UTMt z4^Uo&0NNTX0J|uv0>y<3j};|?fkz;u@xR-2aOeXcg-h^OK9M-r`@hSlNInn&@qPmP zBppY4rl-1T^nPB^814_d%nM|k@oO8}cxpx_)j$||gLl~2Yxb?lyC;}KI`_46h3~*i zNuZT^0vbZWc^EE`Sq1qFnNje3pn&18jXzpJ_?0Au2}EeY#~B;BMWx+Znuor3giNeV zV-LpbE_J1O2b*}~=ItR7pq`K!oZK60JOC36z;fV67#c$mkX;X3$iGa3k#5F{$efFF z9OU2i#rqMC7dyAK|8s2cSL0%a!zVw%MwNeC$mF_UE#b8b9fqhJDh9SzfxQ)zN^5K7 zz!ow!)H*8r*G3_qm?6V&c!>f63T=Zt)n`;(5!hj)D0mCT-m2*gA{bx*y10;_-OGi) zq|k6U3W|Uj8I4|Sk+}rJmxDV`KOdG0QSEAgD;4ylfvflLcc8bFhZuof0bm3&1l{Az z{81$eEuH^9=6%;LKs=fL2eMF=X|S7jwqymU-+dB_N0n^$CrAH40!Ku|)L=}0gfu{G z0V2}>e}N1=iWuZ|lfYjk8Vn$wX6N~iYXn1}op`)BR1T~bD1jd6SVqlV;NQOv@Dvj$M}o&NTADUS4|CLrm=_|t*}Ij& z{~*5DiGi?rS|aLrhLSv_k6#HI;+SN;WfWDp?TS-`AVp_bV^G zRdl&>#HgM;VMiW8a8*61)V){RITp1{F1%DRdY{MAAUNS{i#h=q>7B zxXOP1x)9SVbBFu}G%|i~3UZ zl)2{|bKT{-dvDjywQkRRxt#{hSTV3_ty3_uqp3?GSnrk=bZDOY+|P<^zz7_grXy%n}N0J%u8h2r9T~IYeTqcI)pe6g(8{T!Ur0pi6 z=LZ#^UAINJH17qEXx{bW?Nz8>g~!C;u9r`5Jm+^;c~SPBcQxY&qbJf+!ODFOr#JV7 zvyrzp#l7u!S@q3*^FihPJMc|&#}~qDKg*OIM$o6eq^UlRz4Z8tm5(>LNwN1z+~E72D(7kYESVd6!(E;)nG&VkD}Q2a zv=YFr{g?USo!SLA>An8Gqw0^$gnvyWKUFGt=KFPfdFgt%p8K5iJ@;Q=YO$WDRrj`1 znB0ITd8iIlqg9Hctj!$1AKBAg^7q#7%xgveaCIFStlE$e{-MT{-0g(?NK9~I?lWnd zZ8Ni%9~C0Y?`INgX1BY5{`Ih4ZJ2Oqy36i*zCX zr+wd=6ZvueJ>{DZ>$j@(=AK^vCL(uBZX%a!5~kLUsGltm6Y1~lqqLG=kKCQ_ z$uIHGP-E2G7Q9l>)qMj^+bDegn@d(-%NW;!czs>0M3^~W{7qTlU+ZO&hT6m!GtR%+ zq}Ojhp3Gj;!!Q=h_?dr-3F2^m#5;E_usXTRD#IYjsI&ar8fvY&8ogn=V8Kv!By)!2 z&uy-z<6^XBt!DXEC;R?d;LfSKfPf9>eeX?N3sg?E+`ldB{BH$lGnAg!s z&Qdhr%jAh_h&asAH&nf+3vLBnCp`{cS_=v!Nrb(8S?TgyYIrb!Da5Ym-bMjiPkJSP zs$e3eS)JCTaM%o8u%I|9UL=J|twgngKG8IMwSmYT1bpBz7CEC<@-oEVs<-}*3uRkU zuP8A-Ne$A(N`;>aWAE|Z%^ckjS-V9`GfM|EFVXtgJVT{x^2Xld)*P)<3!OecUGC=R zI;Z^`i3xglOH%Ag5(}ioop);{0>iqPre5qYpNNtq(Xop?qI}{vX8D+TYWFaL?%*W? zStu|YXRu=SgwDo=o~f!3A+ZNxq$1k1dtbIev0Pm5dj7bLm$djX2_nb-?Voh*WSci{ zJj8yKM#f4q@Cy1(`E4!-xflGT&J}D#qxO{DzVx%Fx*@(2KbB}Lew3?K3LznQ$8;bW z@`_c=r##n0m&Kfst&}^SV_r`Pmyrer%b!bVM~e)p6Y~<>2G)5bjRS4ifWuiQfBD1l zQAW4C__GsB?c2Vu$yPprK1w6@k`nKHxjuZSQ&z-yzk2gUD@dWBY(C$Qotqh5==F<3 z<9rOI<*uVH6EpI2dS-0FXt!g{R+pm`Hn&~UE_52Nj&OT4c8Yt-Yg7HLm_(yNr+ChW z!rSpXDVit;%yUZ<&l8qIw8Z_Cpc%n4{TEtqVyAFAGuNZ6Yvtfs%|N zkVKMU^_2RD?w@yc4l154R()Y}_-jbAns*V7Invmpiw3)#4;os)%mr50&x3Fb>pzgw zFde09RBh1hBSd6_e8+b%T>VRp)4T%O*!6|Q_#smrbf;-A{x~;fh75Q-f?)AfwlCn) z>&-dOITL6V!afE8XxtM7zEuRS7`PZB&f99-f%z1k*<5D!`{>*|he2g556XbTl?(&R zuP!+5;30%5_@Kn(l@i%0zn(|Cb|BGAR`wz2XM++mehI2$#PbVuoeEkN^wz`c>u0Q# zF1{`Jb`*FX_yd?jY~Owtj&%rU2xo2^O7G!RkA$ zRMqiTCJ50mdxrfxXx%#;KL3TudXOXSGmGv?&Sc&|P&!;_Zs0jWUdMn9(?STce=jut zVuzEse@aq@5zKOuLTd>p_U~~Tkz~g6bnS)Iw0;x;rk8LS)Ha>k; zBNOhF@Jq&@{i^<`TXPquq{Byh^hK;B64XVHNL^i?A`*&R_BCe>$sgnmCxbOCW-`!S zz1!9;$kiY7x`bZj@u`ZKyL*=ldD`Voi2GP3DbmkYuULU}>~ji)Oi=n5Jh3W# z5NXlq+Q@-)&{RicltIa_65j$F$0+gDeqjUc7B_b(#|=IP3n3q)teC5OsV`DL$9$(D z%-@$qzgbJhWsD{1L-)z{~kO`|S6bS1adke>2wpTO$usWtb2`Y$17I z)3>={UHUv|Hyr^h#HPA)IYSCu9jQ%#OBsV_kATHv1o`&S+Du@XEyyn2fZ1QsE?ohE zqz4NZ+t$I3>I5`I@dbHp_3fBM-0N7awS_d@`UtZKsz$w`M@aLtvz`w}YBK87pQvSW z>t9fMg})DNM^NS}SU^N?6k7&P~q6G0oj5i<$b5>9GjjGTV(o#nir;rx6y)5@I*_PUZ>K6<@W6N@G|T79Ec zG@v;7Hq6yj`X-v>Q(}TMg{ZUp%8Sz~#c#HJbLM@gZK`u`=+ax|l2L)j(ek{l>h8Q7 z+wNO!4bCN>uNIt`mV0~)xc*cWga>J#*maKM%zj)YEw;)`E}j5XgeJSO6(NBv*D~+Y zkx5o-<1C}R?HftEkIkeKVwmhDGyd4*Jy6Y<6!)}G6C7cRlUndd6BqEYGJAJ7U6;vY zzIWQJjecaddfI#=)J2k?x#vpC7Ht1g$m);*vZb+jO)klK)>2x+g@L!0uztQlR*-uE zK^cx=7Up|cKgKssqvn6lD$1g6AarNa6(d}%Unn*-mX-3rfReAOhQfZ61`MIjZ{@mK z0_X?~H<$Yq%uX=t+a|fMz21ox83;C>OP9noIBHtn>q~ghJ1jL+Vqtx~6Ph8AFtSN8y^39quGNLt}=k2;f#W@ z4LP$g?OAg7M?5DT6C^@U?7L-T5sw}=L*kKWeiilcqm6rB#i1`IQ$xnBOzfZ2IU|Nn zR5&z0?a`W^gi+dkzDYkKm&AVTSeXpxONj60j9rSVl-=uYWw7p)^HP2|FJ|lWhsH9> z;?q0RPD>K+KJ_cU=ztH~e&280xK{Bg2ttK!;dhkM=G!leEsUtz_IvcV?lVrBxdaJ! zlOp18k|&dQS%BSpy0}PqB<9A^I5S%N$F#uGR`Qh7CtpoE{yOo}LR;o9HgdsYOe?E_ z5d78IqMNT)o2BPiU~ZDo@D9$5Vv7HsDw2sR{Gj}G_I%e$T+I%tpC|}H zoL@d6>Mfo=PU8Le!k&n`)<)T=!mj684)%LGyv-p<>hKF22jaWSmx#S8t={>*>PU@0 zVT-nwsSoSP3vuseW5Y~Zx_iXg*ItJ2ox#Wt`>8x+wnx(Yva7%3p2jgPQmU z;-{x}{EC{T@(Q!hf?d-oDvh12fo%7A`$FI4l|1oLyT|Nx<4YPR58Ty%CmgVDJfBmz z)sdhVR8^rVtpMbK&B>4qq0$&G940`D)#N>0tn?&&CtB_+vA)(gay}(&5d7Es zPWn@hDah$v%r^Vu_u@MGQ*A`~?oD4 z%(*e1XZYOr{kcD3s8B5x&@Ci1cXng(M}GI^m2>{;Jz}|T&+)G{D?jV3YtXE_03AzgKs?ymO@$;S``l^II12D6Tkj0qV|VJ+8)V;;<*5{R(e#yCUIA zjrNru-cYLAS2r8mps-PvDesB4;OJeH;^x zm=(=eTrCR_8#b_PsxPjFFqQy5ECi0Td z@V|i$*zSh50;Z1~VN;e7p3GOq-i(MfPIWR0HkywHaF_sh z1&E_pK>ja4aQ=2-PXH2U2TlngNR5@3_=Eg=B*pIuc|Z*Q0EoeaE!72MEd#J7qy=um z1kg^aw20sj!^P~RP$Bz=-~6AR3C{R!4D8}A5C}zo)=dQOekufS2^4}-bUMbT68gsO z-5awX-j z|1C3|tZs_FEZ7^J-tWd6DY+(+oKU?3L#1%dA4X|F;>krfci=rmVni}ZI_d&cc8C$- zLmV^p2^x3_)c-q!T>`0o2s0*Nyn?h61`dzAU7fyc{Wb z^r`Hg)I227ON*~7*-SvUbVh#&SG{RcGU^1+ygv6WpgP>p%5EUxj;?Nu_MU@MSou@d z#AVw6qGpfB_2*p&m%3RQINq;pRq?cOA(L|Zx2!W-eI*BIrKGo!KXENo#EB~U-D*y} z*F{o-etzRyB=zlWxQck|1#=Zk1I|#y&biAANf**r(#q)h3=pcTsC(uDdIDxBlVCm@ zb?@da?ZztlUe1D)jd^;GWtGig&deCpmwVI+2WA1PjtLG9IS!seFZ zb2#|rP?F4Xc>_ya;*LQR?_Z>Ku@88k>m_d7&nMkvj=gf_7G;~{JBy(PemAtY);wd- zI6^}%XGCr5Xgtz!x0$O$V(r+xOUTVMDf5CxC0;6M&HXXuoXrQ0Hoqpw*BAvi95(kJ zpPWwN=mAxKzfON|$uQGyc7m9Kx;}l*OUWyeN>RaskLbt63p$YPW{u!thIzqAUp0UJ zJ9loWM?yeW=jICPOa3K0@t@iQXBs1&+zZP>?2eC)$fNw^vo9%z;O@Tq?ok`;wLEPx zD9RpepNjg)cw+uVpI_-^FVdwY#{Edc`*Hp0&4nk{w%YX1qqZ5@Ti2P`^PwH}d(7C^ zicB50G(Q+^=y?@vcP5GlJHFbw=}Toa4qtt^M?U-5uafSa^)pTjjNhfyK@#+iUkBqR z*uDQ)#%Ow2+{>~ir5kE)>5VCC8${|tc#2RPg}QR@yYKLmSmYGb=2Td=-EWX^f6RB#2~yfZafWI^Q|QfP@KH%^|0J}r-!QkNel0Z*i;oeY*KiIr(9L^q_SjOp7m?9 z9qEj&VE%l1=EU%|5B$A{nXz~4df`f4<@~<)CSE6d>f;sJTp9Fu&@$}uUdd)RPeQ+j zNN#SSHPDB!AWf#b>n7Xv3X*Jg^>K8EJ|~;GZ*D*F-&GAi9T7EWyI9P}H&M;^P+Guc z3d=+3Irk4FMV7{Jk?M~1<5kU+xyGe)iJ^VwB8vRKiq<~}Exn_==FTp)SB2Bz5Dbpt zsGDzDzkX2<1ISISi|=GSSP|!sH=GP5YQfbz{dMipY|38m8BeTH)@4|_NTAIG?}TPl=Jr6zK_i~uRN00mgYD{%(Q5q#OFcMWdB%Ns-;Sq=AQ z_*8=n4*8)Z_DitoGT93{55AWLy8~$J@C+M%=#I&!0J+4V7C|}3>Bl?O<}IApkCeG1 zZX2~f=x@*_VVQJXQ}5XBkp1*qX_`S;nGOGG3u+x7A&&aExLvfT`t$%3E$R~3aJDGy zW3}+1wD_g^K%V;DA37G+Ya*Gcmt9Elw*m$oy@JZs@2w{UR?uBJxWwbpQ26kiB%dfu zjkPGtfzc7DFZ!$X$6wz1v2t-3$rW>ygMQ^lk{0jpux(9hyYL!_D3+_xn}i$WevxRVHpF39i+?=s4Ot&Fjt~EEH4hUH^yjH zFHrHdTjNGJTnl{EMVjG01~|zq4g!0b3Q(52HPI<_2b=o^=d8ESxGVD-ysO+KD+^(soKBtI! z$hR?O4_APGfMWXx0XeU$1)vT&kY)$?)#B5jnK-|>U+K?!$<9}rf<3_>3P3J|L-nh&_m7=t7T0)q4RwSV5$L%k>C^S0TI z`^Age9!gK?W9XpKvMF(6&Y4lb-)@?y8}jFG|8Fe7zllqP6F_`hiLdfv>CtaQ||NV~Gj`tpQxsLuHW#ft%-FfUQ?7+U9+@=q!nrlN4b<|=RwgZg5`ivd-? z_Zm*-bA#X`&E_*`H`%P$kSnR-1>W;;bHRsF)w1SYk#|lWOI$bhaMD;)JRlLY>Tb|& z(s?fTa`jgr+dl8-C>CB!Tar3s@0~D{aIz1xfx08RAfz#j!W-9hZE-%U0TU|d=V5V7 z<&*U7Mfai46Lpd6O=`h@skxQb{177w1h|l zyii!~CWk9t!i!rbm>=RKiYB-7f0i$&(mJ}|T>S-4*Op-g*7u>8XK&d{r>mQ#TE0n7 zShr+2O(HYr;>l%w_L1B+>=+%byD1%hQ}&e1>yizQ%SSviuSNU`!*luVlfbfXt+UUK zHcFciVbRa(^;9*>?AGHd-S2Or6vsP-0|N9(J23>sD6@MAbU?^R z(|)7>2E{Rp7542A8LyE6#eA*#=o{+KV$W))B{Y`ErEz}DN^kXL1J6c-Ls>X9DKQt1 zr?Rb;I*r?xgZ(8e-3?uaWo|4VuLUs1EqM$Xs+gr3Hv7%6kPXQ?ppUtGJK1Q*Z(`id zHsFIrs)ee$^H&Lm#0R(-cuVrcls4^Fej`mv%& zS|aQj9_MxObclHv7b)^9KzblpaYrqG>@lUAIm$5|c8%PNV{^;)O4j!q&doiAzLOhr zni2U!EuR!+0#JNe)wl1!S?r>{j?KuiKcwEH)2Fgo_mi4Jg<=XvhuxHdyq@gxn?4wU zY2Or*IJz}y{Z;B|RSm_@+~bh6(DPpn*I^rXSifIMcTOZ7iG=4?e8L6TuA&;^O;STb z1S98`L$B!`58$8%jSyu9tgXWD9XZ^>Jx-6gf% zYfNt|e|}~a+NvsSh%h8UhG`izEWWDn5Mt~JWloTi<_Xhm2x9-3sXcD8F>ki*WPJ;3 zj47&Wx7=`9d|XZT?ntDFj|albV#fXIhueGR$_N%55j^pE+!XBx+X!aLog6d#%SSYP zd>ZJMVL?CV8M8Yv>yAI}v{Ym2Z13s~VEd>w+~|dC9DeWhJqThD$H}f&3!ij}J&nGL zMDI!j>Lt4jdOS|wG%nV;SkIaK&itYk{17u#rqL3;hKb^$V05T=nQjws*I78PH23|> zmxb4r8m*E|cGlZXq|R+=Z4NJPcSq1_?c6Dm;S70$kz%o{^;k;!r| zCnKgXxR`W2Z?1%lA2N%>!3pPLtQNopc|`=glNSn$q1Ql z3oTyDkd_eN;qVY6)94#&aVlw1XMdS^5ayC9Hv!RUv6gl1$~7A& zcRhWzcO%xn{NFC6uBN%rhyB!GdYMz(;1Mt|f82k6+(%w36JjRRG<~CKNQ35nk7MhBz*!3c zHZ~XRfe=kkEu66+U&kH#o~Z4eVo|bF$blty?MNPJdPOq)2m5_pHn7uNrXNU zgh~F7pB)OKpv2tdbO=5nUw}OSs5DdZUOXLDzA77f5<2?_cM{n4EIpoF$pu-GP3+r= zO9E7TXG*2VBVzQMFsV6-OQ##jZ?=e;0IGBi>__y#T5;SJM?y$60xeG(SjPc|lhFU& zAqVLR(#$&G-00tc8i|y-pxn>nLwGMDNp>e5{sXZC}?EKRQ$0lxor42JY zYX)Im90sLhKM9dhWaME`0E`fNYtS$QAnGOEiH_k|oq5Uq&=1#71+ImRDt7_!39R=( zUk#qrUG%?T+8?=~!sA6a-{7IX$iu&(PNcxjCMO7H4=}D`acXcgBA3L>JAGu0GEQrU!wvSl|xh(i*%NZjenSnb5vrKgcFJS<&W^94|@( zIAYX51IbiI)=hkYDk)@CuZ%XW(+H_9!B|G+soosIo6qY{U zOpEXJF)cp2pcAxu=rA7(`N;-zr#OtqA5*oJP4hqgY2Y)yX*AR6Bx8r)4cWXS-BoZ` zN6!^{DX=VDr_%7ekrlHhw1QvxP3I}1){B&VbIC}7jPq#}mflU+J!oE0s8|pg*NWT6 zH4-hSt{-A|>ug!6gM^x zYDO>=x%jY2=PNer9ztNCNH&Ay!gO3!ZOv+y#4^5jCB0AK0kX|QDB4+Rhxu@jJxoXF zq<fMMuXtboe!R}3oU`O*@;p>BokIm-VI0UInXg&Obx3GIfGrGx*+;Xk= z{IFAouQN=a*(KF&HMUO&-y{mS*O4XYBlZ9rhJ2I#gS`vwzMd=IwaR$)0?1&vZ(7M9 zsBljAyPQjgaoPEylKjB~m*-Xi3}&sOWKBupPnWNP{3V9BApsZ0t(u*`%~if>|JCv{ zbJAAewp_82@K;pT=PR#`A9^^r@d_~}FtX*Bcr+KOYb#F z;RZ)x;t*>bqU~rZXRyr5rYY+|o)`Px$V!Q|#pUhy#T$IR*I|?Gmbx8kR!5O5=*i*Z zPi$G(M`qtoCeNI6OJDC2MSW&uthoyR@ed^C=Jla`s+rn*o%hWA-+rVUNQ(GnZotm{ zcI2UPM@^|{4?a@Ht}JtA7#h%I8gI5^Y+*_+%1*B#g%1-FuJ+dTR`xlQ@a>_|Fd}vv zi>DH?dGSPdWZ4g?uypp*G>_v!OG`%Jryvi9-c5ZGjZvZo&EK;VrOM_g&onB(YKQG_ zdS!q#-L5xNd9S0rF4oFZ7d)UB`gX^p?df&=?d3rF(Uzf!@L%5V3QLzy#2fZD-Fp7zlG#zLntkC+F=1H&-u9VuPyu^y>;?L*NvGyM11rm zpQW?_oY=n;yI8K+F!n1Lh7dXLl-h9b-6dO#FN!zrL`;`9IM=;Fsi*Q9Fb0{M%196F zIAmZW|yZcvrpFCnLc{f@)X%S%@xuPsX^QkYn7cSV>K8UhpW_w=Ud^Q z?CTD)3BaB4S>-$Oq`oTdK;i+IoCc3*qqhgPidi4bkLraw^T2%y zgG^vekJj|hN8F3 zU8~AlOy=kCel>Jm)4A(t-on&}_b=PlH{Er4^GU!i@pG?(Z6$mV%Vvf|yu26X(cXPy zBF@X!>(Dy=u-v`m+_ih3n5xeoh)q)@?(j(Xw`8eIanYaGO-vilxL+%w^TSG;C;>y! z&&iqL5$0cYBte?NN#d>$bvI=uo0=^_O0%={N?DLbKIWZ7Zwk?oqyTS$*U|Vz+nMh@00tl z`J7z;PPb{8oR2i_aZ|jQSc+VH)zGrrOO0fR?T=&Fg56CHl1_V175{D; zg|#cM;vc+r6l`pT6}Ygl?P9D>|7;oJFg?%QA>OJ8~t~IBPiXhqdg;D$fLX*&mV> z4CR4%XhfQPc#J<}|8dChyQuPg&?z!F;_NxNA9n5eADHZA{%0i+AOYlDX$1Zg8<58T zAq@SC@c^o{J791LNr|@cvzt0*&1gO1Dw7zhzofuF%9 zuu1$M2-poK{sdI1sG!hsC(x4J_>Es#LsTBF<3>g}(g=ro?GJdRLxBGN-om2@7}np1 zL3=`2#{C!5NuYk|0b~s7UvOUJ2LnBIeo$%b=^g%abi=57pwlI6;{L+(|WpG zKq@{BL;OLvKv$}b)&s2+unu(nvwS1qfq&oE3P3ht1k0wsF`H+v;ZQ(6FB=BCRuW!l zbeeA|cv~2F5$GR50_cAqj$8f_DY}>bh322WtXGHpZzRTFgC#&G19&IsM8LKWZKX`; zZWR>QOX1_&XeZ#Oh~_0h-vgPAD><4#T?VbsEFlhmmXKL$)A8Kno3ui_?g)Dc3~zm< zAZYAOSd-XciZ)L*C$C%7Vw~fMNfb`|!pCz8hB`QAU!LT5_ihqbeX0@rJiCAm?_}-W zw36J6H2pcqJi*jZ@KSN&o!`b|;3Q^1D>q&vOd`|EsMug&DP=OC7N_-ezQ|m#P`i(n zj3jPcA9y2Czr{dOVMM!QS7wH8!9)jQiiPw8Unt(;7yGoSF2)iQ z7`YZDs~YP9FckPoqx?9Y5n6MQMN4qwv>7uJr#QmnqGE0a#mjhs#O^1%Udpsl0fIsB zVsh<=k0C+ue9CZSciJPsA?9Tke8=3=A##*x#gnPd20fXpP*oLPkq53`PH8y4-p7yv z%C7o^&{i1<`}xZcrARIkP0frIMssIHil$DjAZN797|kf7DSWif2`w1+F_MHS@OQGV zoo`}f#eVe`5KGw*$t@OqKv5Qy|4laX#nYFKh$i38@=xB3UJ-G@<^>2v+41@g>Y3@@ zvgfbkF5r@f<;`;w-kTRPwq98A{H|a_MIYE+tKU%9olm|w)mZQ?U@n2!zESYaCEM!8 zQxygrR}|8zH{p?*!ni{H`3pnl@(Y!=Zf|(-PJ6N|SqNrKvwu9bj85>|~f z^r(qx`CIDD-FLOQ-UJFB^a?hKRG=%LH5G|waHC4oq&jY=zj3LxY6^QT@nBQ*iRx@+ z9S!Qq;sSf5?_jEAs(p&?>5@SM;LkZnhQGOCFU#fw@A0SRFK6p2bcD{fRN&Lz*k?$} z4{1waOWenV#LJjmTfM=_74?$Pxtq>D9Yw zo7DdRx{y+ukBzJoOVz(#ed;IF^z60ngKy4LJiPDHXe@Wt1jn+R+t8{(%dPmYh|Y_) z-`^RPeOJGE+pwwfZ!2s`tAL7;0EXVjX|e1UzSF9U08Z@e|pID?NJpbj!A zQYcP^k#%CYyh;kHZjp{qFm4&npls`11;nnkX)vHv!w%^ApyOJC8ePRRI71ZTjw>;7 z^SbfYQ37(*2Cx1=pW}iwW9b(NznRVG@<}~qBz0;8$`y#VeP^pgd|+EMIML_Q&et7E z#P#FO50c6i*+dU-Hw7J=-8^m-)yA{<%uYEyq->6PMkoCxVdBGv|B{G5km0^|q(6p)0rB!_qnmlt16edus(5;rjURrPE5@+-Vq>1`E_F_opC`z0)K7h-C?3c$SC^~R$lpLH9(%ec}Fb}5=eiy+kIep|ZbrQ0%h4mQ4GFja^0 z-)_6t75iK&DWn$b%$br2WR9L=SP*E;_-ON~?R}@CPcnL`G_qK%Pg(v4Y7C>tJ9Nx6 zxtI31x%ym z>c*Trxsu#AqQ?E}gG)+~>7(S`L)LZEx@+Po#8(v_nvplkveVu*BwKo{!m)=pudq}- z^skm!a$mVbyEp&ZT)$QF;WM6lLFSbK4&6%ARCamlw@thFHf>ExO0wQPi)bHhPFxn2 zb3sjyZ_6+7&OQ;vc^xurG(F+eQe0`=57FQ)z1XLzuxCrb*z};GeN*LEZF8A*nC1ti z=$#ssvc;+*q4iA^~Don-Hx8= zl~QK$v+PMncjs}OBWT*npPsavFdJ$vReSh`AwX3c71^wwozPbfv(s_LB(8;)_`JFH zBIM@RiC0qAGr5b6kh2hh%I{U~F5iy_crz(prUk$ZUdj>B{tPL+~Nj1MAW`!3j4y_PtM9UxkxarC@YUxE1=05$R4?ekIRvgQEr5RK}e3<2P~2lAl^JRWHMsID?C zw0^(_lvhH*1h=$*Q4hk_$Y$Y*$DgQbRkXoAGa)xS?b`^Ewk{~d=M0~odXMvc53Mom z$)pY4Kym}v$M8K~vl?vA0Cob1CD&s+CaY{hduQ)%qiPvK|DsUk0EHsD1K7$3rEnnj zw*r5hAOu?^VEF?mLj*qf|K2D-R79;sD7N{Ssu%>K;B6j5iE7J2fz0J}^zV-FTZh%` zUju=&HK4$&Ra*Rcx0-~@u*1M38r`wU2U?!LX`h5XhYuVya8M!@0(jH^z+Hr0sj&*^ zV{~{SJZPd7uuekA854AN46`8Sv#Ro9$UrU6@jE?2$|nS_t>H!BRD-)#K_Sx#7=!3A zW{~JW1p#SgKtG3|0Zb}_fbaho67d&lBl#D5Dt}6dh)_Bn?h219+0tkCg|`6&4!~3p zR{-P@z&yh3qtfmA`*p<*HU3la{nWHJUobaB3{_?8Su_J z`d-|E#YFbT#W@!jT3vuKo5_#Ccy;ugbJZbI?u=zH`*0d@Sh9AL_NJ2s_nU?Gkj+|w6d z)Gy})zZO~r0FHvd&}4iCH4&~QMNe)MjtKmN@;6~%M-G&Rcxjx@=j*|mLFDY4HKNlE z4$5ts$Vvy#-JQn`_K4e}b?kxBko^MlYi&8VGM^VLO+29VOuK~Z8Y}v4dF1?MVor88 zEAFNL7bCH`_?I&pKKQs)Ga>vNM+IPS$mGSiZZ_dxZaiK1GNpO{YP7x_Bd{S2*fc`e z(fh!!35>I+bE1-9!O*8E71r&N3IfL-qw?MiO{)tj$|d=v$_FwrjjeI1Qw5Nu1oDp=eOH`Fl)-uqwE#`R0NQ#I8W z1bDZF0pSI**X{E{XR_)1^+4))>td7mdTBKuPS)yefh(|=1IyB^l|@B{^O_QJn1!Ky z^YL+`vBHUa>>`YQcRH+wo7yrc&FvQIU*9U%xIaDQ6E&#EvJxB~%vGpvGy5Zc1n>I~gnDiBZ34|09n7}*q|R2OmU->r&ntD3oJ|cX zO$r~0LvsV?3m;7>UHpO)c4$hb_)_3cUE=vqwR|8NqfP=UixZ`EheLosh6bW#&3;L_H4Fv4L7y8H!oAT=TGIlETxEA zQQHNt&PL45mmOd#wGvZ~`3Cp_)|sHVNpGDgS-vKr^K|UjUKC}sl~5;RA2$~j%$TSU z0wfcX0EP`r-~LY~1s*dZ{)r)s$qeGopbi)T**amRfd<4^z{nvL0!s`qTm2V_>>M}# zM}h;f@>SY=KAnXoP>RD?{(<1}8YQ51UJ-|o=<0(2MNIkyZ$9KHyPsCdQS4BTcsuBLM~gH_?Benzis;JZm9LsQauO zUCZ+syP(t}LHcy1fP4&C^<`36foRUZugH74T*~b0LVyg?2v)uS;t_iY;m`8` zW7UYTOMsB9+^tqzJarQJ*9>p~l33U+900-!ZXzMd2>htQztcZxW};KY3CT$J0qgiu z=r0-v6rdMnDxHwm{R8O)pVz-F&mXK{5_OA^c;*tV?VKvu0wYZ z8tgK+>4_8PO@o!u8x`dp#kl8T`C{ z(3ofF-7?$&??iJA5=Wa^8e2${|D1hZ!qoVq$K!q9m#htKTmsEwk=RMufW*8s?}TMo zCg!7|PQB6gy1@m}EtE~6cV3t5_+n&}RkP5!O_)&8%^z@Me8vDB`DBkAEKs%HO8icl z#8t-eyoQow*>vLHXK8ON_i+|`7xsPvyf9Y?7w^jI0}*xQ>{g zJ&Nr}?j~xnz15Fw^^|383H-qUOfSAEri;|8bCGajrboZa8r#j$m&CmC?cu-0ME{8R zb5OD0N-Wj#>k-!IR{&2P!q&%7@3Yj18PGO{K=DKl>x(+kOzPt?N zgLFD$>NX8m&=p8^dNPiITkxWBV{b1w|Cm$ZS_6Nnrg)49(sAABlY{D5d0EBrSTf9r zw;#GyCJ!Sqv{?!Nh@g-z5k;jsTjjyg=6n~)I?EhTl->Mseg({oDmXF&ej_4r5eWQR zjL=nbqzX!Mq}wZV=FqjbS{vnN#L)~Li)i3m$nHQp)^iDysc|k*<-Tz$Wx1&LgqX5) zm5034E-$SoF&qtv!c(u7n5Bp|EmtN;meNVkec!K8{fKL;w~lp*sTJz0Q9YJIsfzC1 zB%KQC{2q*2^~=8IDEQiwy&6F=GN38z6ZR29(!2?yKaxDW(^3jDUyzQ9b5B211t{=g z==@Dv;VCt6owtQExw9z-yc;f9wkjYeIp~DU3YWk}^OR^cy`Qls5 z8KEy(y2HCw1j8**h-~Tos-u*VNkp6fVY10_CT1eVdS$LWAmjal7k}jXX8#OyFLYfq~HP*QjCs| znmONhGI;~KUo+C240BB*>qYLZ4G%#Sg3Ln;dR)f+Q*(^<=Pb~h*b?`^CO4NA@^(7C z0Et}IZ`&evZE^4Cad#|bM6@Gpl_DibTDI=!x1G7}hQ@>*Z(0h`-mcny@H|=ZX}RtC zctq=`#<)XzH%-q*w~W(_%d2&YvBUc{sS8))Pm4Gv?-{)k`Q)9u_i;+D;8W|mZ1*N> zDPx@SpDjpxZ;B1%D%w(wz1?6`eBHN}W>9|grFJkk z16KuYXklrlmVH34RZJy4cXpkB&%qZN8Z(#IDPO3Y*wT|&ghkEW!&7z{y%imXC7cZe zeA>T1&MWO-NfM=gooKb7$nk0B&IZT5L2^;1aLL-nNOIKH)*bf+xt`VuDc$&9 znQoqs9PPuhdGpqRk~xbF^y70@ngX;kMX!FkelzvG1$03e4_+|8k$L@LMG6BzA23G$ zCKZBe4r22N_Vk3b!t*+OEyd#f&5PQE+P?93eoP5tRVf|SBTSNiz5NN|Ad^5W2Pn+- zki(q=2@*eS{xM!7JO(I?M>s$-0g6;m7N|M{fd~-G-1=J)sR3iyh;8g2C z9{dKF|7^%{TnGpY03ODczeY&-f`KAx=W78e2zLfjmA^@b#vmG;2vl9(0-A8(I0KTg z9S^I)W;%&rwmhlMkx+z|9mj%`{&#o=ld;<5pS#LX+InNro2k8NqrXR4$!%l(PiZwvdtB=5enDf_R`rG1FQ9!xN9m!{)$qus&I+C1&)S5j zOCkd!f0APq=lBfg#eK;$523#F;{1W!SyzeTjwhm$ow%isX|+q$I0EVE6p&JF_rL0E ztUiiNw1MjdV)?F1&*^UJ-Rh`jvn(G-$80N*A;9#|_~@`iGjTWE)qBdq!d!MEuHYo{;<~25r4+~S^IQB^OYXSE z*aqA;6Yh!o`kXvB71a<-H6{L*CN~~kEBx)C;<1~CH($?syxdbh4g(DSMhL%Yvj(Fb zj)w{BAdrmGNuSI@Ww^$G_OF=!#(k(UsNr4Vy8pI-RB|vXh~KrMJjlhxcF4uTlzVh@ z^xmpQ?yQD737>9j0dY}r@~#y7YdqxgFsqx+!0hd|8SF~s#~Jca(aqc6nKb8Fs2~=% z+Lt|I$4bJzsh|Ezq`#Dy>+p?2!jYz!xG>{sI7~>RffJwh>`ETrlN=h36e2_Dd#oHP zC7Ban!7uW9B9gIOh|Yky#473>4NSv3lsS4|()!Ak(mUzQ@D1`NHojR$5`E}b?Qi08 zgG`LrWWJbN=GS7yYY-#PxCZg_hB&jLhC$~tH&{_pTu+!uuz=~7!IzMV`lNdY1;X(2 z5qfqRm5Jg%Ll>)aY$Vz2)2~(-S?3)A{=`?B9O$8o!pSZ-(Rq@US{)_wNhUbm5Kh(;@o~1wE zf#050>zB~^Icw;#d7`^_bF#KC{5e1JHOc_;`|~@qXLWtZE5DV3ig!YGs$G~jcHEV- zrWm!OjgF<)ZR%r}KP)mb^)6a>XV&u`ec=yENN0KE;>Wtilf;*zwfTbN6SjdZPNw$|@D(O_O__n`XLSkze*Xk>4i9KM%a+ zu8*I>JE%evJSaVZi(Y4@eog~e zaddaf>rp+Fn7vGSRj!suiK~g;>J@`X_BPwqC<(a$PBtGu`qfWID%;4p+`-%L@($kW z_y^_sA$)pzF-UzD+#697yY`fGro~?(rpDrBomyWqZK9&JZ_B+1p0eFeV6%4hH%2N= zPrfnjTaIS`JTmEERd3WDh3(SkTva%#Xmxtmb20oVc*?M3b|$3C7E0QyI`XtRAocKP zs#2iYh~D^X4MAl~ zGFqCvvd*;uUW*}iZ1AMgmcW|%1v7tn^u}urw}_Pnhv0VFER8|Cyy;#9EzQ zebsM+mD|IEw&ZQH+y(zYq)5$$L`~a=jqsxI_;@FEC+gr)Q>Ru@jUrk8dUgS^AL>vu ziU%+w*Mhu46rYbanw&TTK+K|GEG-Hb0gLyR0xQC@@edOW6pHuYq54knuRz1%45}JP zjRT}SBD9r`6cvD&vq}m`yS0fr6R{n? zj$_yO>v>jAklmk89(C_SiAaH#8V#a*L_gq+fipi`TctqdZ**J+fusk13?h&si0LD& z**QVvU)-%l=bN_kgFHK=@f_l|aX@)6~;N z>Otw z-fJZWu!5|GIFu@|7cmYQcw+bl>H2tCjb~mQ^5L&DeG5RvS=G7KnV=vWBq(ISP97|= zjYzaH(92-v2D2~`*sKG}qz^dJVbp(J)qp=5q1J*k1@iyE&Ycivz^f#7iU3DZRZ91| z{^-pqMC70>lt%oZ`uzxa;;1?#zB{Qb^yY!{NotsCbiHG`* zFh*dZi?aWVcKEyEB!N#%DvsL~gCSmd4xP3c5s?SJvVfktkYxzA`Cph-bYz)z$RY4v zXeR4>$E%yc-9I`iE!`4oh6sPIDTj z7LU0L*Axx~X7WGhd!z?`%=}>)Gjmt5sJf~xBc`sN>p@Gg$5LNuqrL*;{obHT+lY@^ zsSimfnmPEZ+QnoKE7mZQ>eia?V^a^x1`BU`$HY{oE7tF3Rvun?r+9A-iM26Gs?ls( z#%b7pp0A1;SSXrlXoh}c5E!IO6Z3wY*0&OFy-KrR`StDB=bYI2nSUV6+=}V6LQu@p znqtyWKN?NNYOc83#EEvMdWH$+`A4SzQQ=QZ-OQxlZYArXM=qw((}-f3 z!q7o2(4SGyEARmlf^{?fn+A*uh|FSg42BP|bt7TC0Q~t^woUl0*4B;CO|*hQ9r38B zmFdu@J0=db^zzD4hYI=-Z2_9sA#cZu8)JsK4fVzyPZwjRN)Vk-uA34kUG6CmreG|g z;0bkF-$tD4lrGaClHSsCtmAf|p0h^h+=Pze6p$Lc^w(J68hl?+>V=4nmQvaVG5aJc zB6`k)6?B;dX9W7ms8}Aqy2OQbLo<2?2^0@8Mx8i|RYzr3)aX-%paxOdz10#;wty}8 zV)&k4)eQf17%RWJ-Z;I%M$;vi23@C*7KKA}5?FT#l>(C2ek%cqSAI%dy6h{ck!?s^ zHch#LuA*9Ei$FWr@GmACEM3l2xznKIn&w|7@r7$yLMOy(n(L+JphE#uX;xnO{aIgP zum)pVLplUQW1Alp9HUAe`o=^iX6H?~KE3AO*Gq4@Oa*|L+CG^z{z}0-b%|;IYE@}_|PI-w7tb~pA;VOx6MiO_*4F@c>F-7AE(aMQ<>Y1 zm|mJ~p3?G)`;Cg)PRoI4PGZIT9xr8EgP^*=F}n6=Wahjr@nqR6oid8}-aOTyg^EfF z845cL?dH3a`Lp^XwaizmZ$#c-)Mb5 ztMC-rH89xYy38)>eeihnzOheBAWRN8m|DEOINJlE*?qB(oZI^h+PvYGFsZEb-mhpD zKLRksRH8r^PFceX6H#Fq|Kt@Ga?2RInxImx7iHHeey|*f@f#qP^DDXArcC*iTIFD& zG>x^4g^fl-L%G)~w?!`x10!zl6};NQf)7}z67xtz$FjDKkWda0t(z^{`Ph#(-DKxl zH#KZRJ_1P8tn?zfyuOKBw>(+<6=XFpeZ+Mt%e^+vjC9RDXSJ9*VjX7nVf2F}dOlwB z9HZ%z9D{z;>q5;SYzW3<_SZsjf;~NJAZLv*=7!zX9FocQyZ*ZK^20$l)iTi}=Ruf} zS&F@=HF`LsLtIm0sExuy099e+ujzg>#HNLMqb|izJo@lDFBenQk#~W8v0iFYU{!mu z6|*d2!&h`j@s8W$nZb-Mt<2M3!@D)yGI#ldNo-k5COP1<)aFji&s$wskwLCttBHbT zt!bSiey$!4(COh@F?KhXuRZAHtcZ&f*}CI)=r}r?J29+M$05WpxS^?HbU$e}ne)40 z(9rjZ!=2~DsfYHhflR`salreZsc4hcS1L9^W-qqb~*OCIz*@ENNsKd2kkk+q5S zUpJUoRUmuFe81Ol^rS2D-lI=7N(N7d@K?C{c^dqgPtzKw<-MN^T%|QD;!c-9u;gJM zA9~AIJ+RoPe}3cBG@aLES@Ow;AE+UphEHCTg^eCXu|I5&o*lLtn=HmvECGfT-d`gZ zY7BFQ!u3h2iCKY{#vgkKP{8?6U%|zO0aUf58p4kEPk94#md-s{l*-t@g^;hT8thq1 z$IH7R*Ve&OvXk#8sLD}d7@)DX;UyXig&VOoi09+++~Ki=P`B{Ev-Tym!w%+GfbGwI zF@(QLDfCCBROpW%3}ayegJ&(+`gNr#3CaK9Vel10FyLwdm^{a(I(fJpENl5d>6w3pZC~(W5=@ zI*+$FHo>~uotHr8`fnBoUx{iNWGx7@u{LA1h0+ppzM7@XnR8MXinsI{=pP7dJc7Rj z;U$F4@jd9baReU`KYQ9((Ado&RaeHZ2GF+vPhT8Mi2wugm88+XqaD*xMahEK*&)4m z<$R%Qzy=M^i_z#s>W~C}R~62zYlEwM*e~mFdVhG(B}`yhOqlp`L6gKw4Rf|+l#hca ztGY(YqdBBh>fuxJr!TJ0fLOQoM_8|3y>XtXMQ;ts3CCoME%}S{)$g^w1W1b5~0`oh+V_OX_>UE8ijX=OB&R z6{FbClV#VI?9m_3O`62PyStc+`BV6bEj5D-)(|%Bd}c$UmRpDM!mDicb0rB#CX6b| zs5FOxo~*hD#thfistgBS{Altge}>?j+!13r#pjhtLcSTz8Y%wN=VC!aE~mm@ZP}nu zin3$jt%gWQ9WpF;%UsRj*wjRtk)BJE0gtasJ!)AfjjuB)?q`ya_Ld!EdZ2A+DMPRO zfvXUwaD4~H%+NGGrebn?e?KExtG#WkB)$TzjZVKiRqjO{Uyr8M_$KU-hX%JxpEasdt1CU*AGiH`7eFBkq!* zMnSUqMbRhxyai^l%@RoZt}i}`R?(eFE!q_AyxC;Wq&v%(W_vyLe&p+*oIf!)icyf4 zE>a$_REEuAqnDCXg1yj~Nqb5y!3VRc=&HTbk`a!N*bT)4tBH$lSGGMrU0$MT8!_|D z%X3)efA76BU8U=@q}i@1)FX@jf5>|4xTfQ`dw8^>h*HuZJ-WLT>24Sy(i~xxdwCH7yUk* zTg-iede130^KA16w(+iOk;91;(|}!Tz_QTPMhm(F81h~Z-g9{v-we# z^@{fj;)Otzbh6mGQFhd)riGdL^44yHIS*55!|3%<@+g}KFlu7Z6=8NP*IEh2ptW7R zFA$|6{q^45!j!vLuAupEU+EIFx+N~{^oeHa{_d)AR@8RCK^SyBa#TuEfU=hb`nH#o z7wNr|>C+vhpa@ZL=_n7i%1 z9wx0=@1LU`{`_j3u~>~ct49f1`ARvqgyW^4)nhuV2YH@k6*GNUUxmSbHfL-Ih+9cW81t z4&`dESyAB)b)O)}6%Jx>>K;=8Su|G5|>ZKlVYL}W|@XOiO#_CMR`CWgIq5FWU z;l)>L&*RR;vgMcQZVW?C7D8H+*#QvI~4u zM3ekr!`whDSwP27jeMZGp;6DPdnaw(@=L2_Eq9X6;=-Hh%JcJ;ntt|#<%Y^JEoLe2 zR%_m1WsjU_y#;9cFV4dEJ;6RDhvVf6nyLPK!)q&PUe8}92^zfWfLU%mz^#zUkv1G_ za@v2wHu=_TLdH*7UuN2IGYgXn@WQ}SyqhtytQqBrvAhy~asn0B?3bb+c>XHC46hvl zFIUx@NdhsB+j;&Lw`(qlY)16>BS${YtOiyl2G;F2M631WytfOR%W;iSD&=D2pOxUY zvoVdu1A=W&z5fpP7ipUV`>C51p|IVoz{22`k;^THgSf0GCbu2vuJ-^eXtG< z?;yuftCAbi0Ld4Osq;bn?yP7D;9mlf!u7cfdgI z19T=H$FVIVsPVgB@P$r}cmbLVtnK^<%N5s8Uz%sP?fo<&fgA83yy1XJ+m81`g4{^~ zHsT+B227`e;OB?9K}^nR4wNojJ8Lu#!q3Y0j@R~5PI?dXmdvi71_q6sXn{{vhjc;4 zk6QZ=WQI02C>*y4a2Y5apYZ-JsPE~QN?pMC0Rul?C16DPg86jf?!vyl*p>GnXLbQ) zH$Kfr5Nw3#>LoWJV58; z0oogX=l}3_y4)P3i<0t&D5JV`?kqI@f1@ixn|B(0s3so8- zbwd18$-+;=Nf`2RAj1Gspako4$+*%G4-` z6BY{Bv}_%mI_Qr1V6`UrR&6Al~F9cCR|l zOw3{ry~#bKXNroZdDh}<{i>CM+9t_1r5EGmn2?iV@;C;X8c|_6;G{6~)URc+fkOAf zqGRpNtO^U9>*Eq%ou#5Ec!@@ci9povA+X=wV%4^7+tVKJJO31!=oxZpd) zS(sadOk-Y7X)0eD)lT+|3y;ZacZ=+@^0p}81mo~7%oX{EdJ19*Q5nPh!Zw>bMmXpt zfwg>7^2G5brET}h?{>Yt!2O#&UHl;9g2f$ws|3aONWKjdqx7-K95_1VIuMg!5a>!g zCCs5TsdWg#^T5`GAWb{>9_DfgIYg};<7oGKuUKm!H^W)2hcJS%l0;Znh9*8b)D$Pt z$i}T0__*;UDqO^idiVYICwiAMaLT6KBK8@4++txX=pdP9GXP47$bg<{Zq7K2>

7eJ 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 Date: Thu, 17 Dec 2020 13:08:35 -0800 Subject: [PATCH 155/172] add ds logo --- .gitattributes | 1 + doc/ds-logo.jpg | Bin 0 -> 168349 bytes 2 files changed, 1 insertion(+) create mode 100644 doc/ds-logo.jpg diff --git a/.gitattributes b/.gitattributes index acdbdbf4..1534e778 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,7 @@ * text eol=lf *.png binary *.pdn binary +*.jpg binary *.sln binary *.suo binary *.vcproj binary diff --git a/doc/ds-logo.jpg b/doc/ds-logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01b94c89963e6e2d8653de5dc21882c1fcd40c65 GIT binary patch literal 168349 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 NulKFVM%}+h{vW#tO(p;U literal 0 HcmV?d00001 From dc3121001917d403e198ea818c5a642a522fd9d1 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 17 Dec 2020 13:10:34 -0800 Subject: [PATCH 156/172] remove ds logo --- doc/ds-logo.jpg | Bin 168349 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 doc/ds-logo.jpg diff --git a/doc/ds-logo.jpg b/doc/ds-logo.jpg deleted file mode 100644 index 01b94c89963e6e2d8653de5dc21882c1fcd40c65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168349 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 NulKFVM%}+h{vW#tO(p;U From de694191dab3b31b627622f75cb25bfcfe740f8f Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 17 Dec 2020 13:11:34 -0800 Subject: [PATCH 157/172] add ds logo --- doc/ds-logo.jpg | Bin 0 -> 168349 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/ds-logo.jpg diff --git a/doc/ds-logo.jpg b/doc/ds-logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..853a727927532e3bf5c2ef17579907c195b6280d GIT binary patch literal 168349 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 NulKFVM%}+h{vTq)O%4D6 literal 0 HcmV?d00001 From 3eeb0f5ce39efeb30b10080942a87a0d7ef01ba6 Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 17 Dec 2020 13:32:41 -0800 Subject: [PATCH 158/172] Add some usage info --- readme.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/readme.md b/readme.md index 9419a658..fd95510b 100644 --- a/readme.md +++ b/readme.md @@ -112,6 +112,14 @@ Special thanks to: [genMC]: https://plv.mpi-sws.org/genmc/ +### Usage + +mimalloc is used in various large scale low-latency services and programs, for example: + + + + + # Building ## Windows From 59032eaf424284c514b28db447b5af8fccfd886b Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 17 Dec 2020 13:44:02 -0800 Subject: [PATCH 159/172] update svg background --- doc/bench-c5-18xlarge-2020-01-20-a.svg | 1 + doc/bench-c5-18xlarge-2020-01-20-rss-a.svg | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/bench-c5-18xlarge-2020-01-20-a.svg b/doc/bench-c5-18xlarge-2020-01-20-a.svg index 0e550935..90050974 100644 --- a/doc/bench-c5-18xlarge-2020-01-20-a.svg +++ b/doc/bench-c5-18xlarge-2020-01-20-a.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-c5-18xlarge-2020-01-20-rss-a.svg b/doc/bench-c5-18xlarge-2020-01-20-rss-a.svg index 6b15ebe5..393bfad9 100644 --- a/doc/bench-c5-18xlarge-2020-01-20-rss-a.svg +++ b/doc/bench-c5-18xlarge-2020-01-20-rss-a.svg @@ -1,6 +1,7 @@ + From 981947a4bef55b67e61b668304092fa4dbe91f95 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 17 Dec 2020 13:49:35 -0800 Subject: [PATCH 160/172] update backgrounds on benchmarks for dark mode --- doc/bench-c5-18xlarge-2020-01-20-b.svg | 1 + doc/bench-c5-18xlarge-2020-01-20-rss-b.svg | 1 + doc/bench-r5a-1.svg | 1 + doc/bench-r5a-12xlarge-2020-01-16-a.svg | 1 + doc/bench-r5a-12xlarge-2020-01-16-b.svg | 1 + doc/bench-r5a-2.svg | 1 + doc/bench-r5a-rss-1.svg | 1 + doc/bench-r5a-rss-2.svg | 1 + 8 files changed, 8 insertions(+) diff --git a/doc/bench-c5-18xlarge-2020-01-20-b.svg b/doc/bench-c5-18xlarge-2020-01-20-b.svg index 22bfa5c2..2d853edc 100644 --- a/doc/bench-c5-18xlarge-2020-01-20-b.svg +++ b/doc/bench-c5-18xlarge-2020-01-20-b.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-c5-18xlarge-2020-01-20-rss-b.svg b/doc/bench-c5-18xlarge-2020-01-20-rss-b.svg index e3eb774c..419dc250 100644 --- a/doc/bench-c5-18xlarge-2020-01-20-rss-b.svg +++ b/doc/bench-c5-18xlarge-2020-01-20-rss-b.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-r5a-1.svg b/doc/bench-r5a-1.svg index 127d6de8..c296a048 100644 --- a/doc/bench-r5a-1.svg +++ b/doc/bench-r5a-1.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-r5a-12xlarge-2020-01-16-a.svg b/doc/bench-r5a-12xlarge-2020-01-16-a.svg index b110ff47..b8a2f20e 100644 --- a/doc/bench-r5a-12xlarge-2020-01-16-a.svg +++ b/doc/bench-r5a-12xlarge-2020-01-16-a.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-r5a-12xlarge-2020-01-16-b.svg b/doc/bench-r5a-12xlarge-2020-01-16-b.svg index f7a3287e..4a7e21e7 100644 --- a/doc/bench-r5a-12xlarge-2020-01-16-b.svg +++ b/doc/bench-r5a-12xlarge-2020-01-16-b.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-r5a-2.svg b/doc/bench-r5a-2.svg index 8b7b2da4..917ea573 100644 --- a/doc/bench-r5a-2.svg +++ b/doc/bench-r5a-2.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-r5a-rss-1.svg b/doc/bench-r5a-rss-1.svg index 1c7f8566..375ebd20 100644 --- a/doc/bench-r5a-rss-1.svg +++ b/doc/bench-r5a-rss-1.svg @@ -1,6 +1,7 @@ + diff --git a/doc/bench-r5a-rss-2.svg b/doc/bench-r5a-rss-2.svg index e819884d..cb2bbc89 100644 --- a/doc/bench-r5a-rss-2.svg +++ b/doc/bench-r5a-rss-2.svg @@ -1,6 +1,7 @@ + From 4cc8bff90d9e081298ca2c1a94024c7ad4a9e478 Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 17 Dec 2020 14:03:10 -0800 Subject: [PATCH 161/172] Add special thanks to David Carlier --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index fd95510b..18d50636 100644 --- a/readme.md +++ b/readme.md @@ -102,6 +102,8 @@ free list encoding](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af Special thanks to: +* [David Carlier](https://devnexen.blogspot.com/) (@devnexen) for his many contributions, and making + mimalloc work better on many less common operating systems, like Haiku, Dragonfly, etc. * Mary Feofanova (@mary3000), Evgeniy Moiseenko, and Manuel Pöter (@mpoeter) for making mimalloc TSAN checkable, and finding memory model bugs using the [genMC] model checker. * Weipeng Liu (@pongba), Zhuowei Li, Junhua Wang, and Jakub Szymanski, for their early support of mimalloc and deployment From ab3dac04c2478a484b0e063b04fd0f19cc0f368d Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Wed, 30 Dec 2020 21:36:41 +0100 Subject: [PATCH 162/172] Use tpidrro_el0 for thread local storage in macOS-arm64 Fixes #343 --- include/mimalloc-internal.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index e3e78e40..df700d39 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -707,7 +707,11 @@ static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept { res = tcb[slot]; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); +#if defined(__MACH__) + __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tcb)); +#else __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); +#endif res = tcb[slot]; #endif return res; @@ -730,7 +734,11 @@ static inline void mi_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { tcb[slot] = value; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); +#if defined(__MACH__) + __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tcb)); +#else __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); +#endif tcb[slot] = value; #endif } From 88330cfc9fdd4ec5aaa7988efdd209a593bb0026 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Fri, 22 Jan 2021 17:06:43 +0100 Subject: [PATCH 163/172] Use __APPLE__ instead of __MACH__ --- 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 df700d39..dca21bb9 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -707,7 +707,7 @@ static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept { res = tcb[slot]; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); -#if defined(__MACH__) +#if defined(__APPLE__) __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tcb)); #else __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); From 335fbd9a43a90164d3a5a264f8e4b7580193440d Mon Sep 17 00:00:00 2001 From: Tarcisio Rodrigues Date: Fri, 22 Jan 2021 19:49:15 -0300 Subject: [PATCH 164/172] Avoid MATCHES operator to check CMake options Instead use simply the option name in conditional contexts. --- CMakeLists.txt | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca7a6faa..73e3d1f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ set(mi_sources # ----------------------------------------------------------------------------- if (NOT CMAKE_BUILD_TYPE) - if ("${CMAKE_BINARY_DIR}" MATCHES ".*(D|d)ebug$" OR MI_DEBUG_FULL MATCHES "ON") + if ("${CMAKE_BINARY_DIR}" MATCHES ".*(D|d)ebug$" OR MI_DEBUG_FULL) message(STATUS "No build type selected, default to: Debug") set(CMAKE_BUILD_TYPE "Debug") else() @@ -68,20 +68,20 @@ if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel") set(MI_USE_CXX "ON") endif() -if(MI_OVERRIDE MATCHES "ON") +if(MI_OVERRIDE) message(STATUS "Override standard malloc (MI_OVERRIDE=ON)") if(APPLE) - if(MI_OSX_ZONE MATCHES "ON") + if(MI_OSX_ZONE) # use zone's on macOS message(STATUS " Use malloc zone to override malloc (MI_OSX_ZONE=ON)") list(APPEND mi_sources src/alloc-override-osx.c) list(APPEND mi_defines MI_OSX_ZONE=1) - if(NOT MI_INTERPOSE MATCHES "ON") + if(NOT MI_INTERPOSE) message(STATUS " (enabling INTERPOSE as well since zone's require this)") set(MI_INTERPOSE "ON") endif() endif() - if(MI_INTERPOSE MATCHES "ON") + if(MI_INTERPOSE) # use interpose on macOS message(STATUS " Use interpose to override malloc (MI_INTERPOSE=ON)") list(APPEND mi_defines MI_INTERPOSE) @@ -89,42 +89,42 @@ if(MI_OVERRIDE MATCHES "ON") endif() endif() -if(MI_SECURE MATCHES "ON") +if(MI_SECURE) message(STATUS "Set full secure build (MI_SECURE=ON)") list(APPEND mi_defines MI_SECURE=4) endif() -if(MI_SEE_ASM MATCHES "ON") +if(MI_SEE_ASM) message(STATUS "Generate assembly listings (MI_SEE_ASM=ON)") list(APPEND mi_cflags -save-temps) endif() -if(MI_CHECK_FULL MATCHES "ON") +if(MI_CHECK_FULL) message(STATUS "The MI_CHECK_FULL option is deprecated, use MI_DEBUG_FULL instead") set(MI_DEBUG_FULL "ON") endif() -if(MI_DEBUG_FULL MATCHES "ON") +if(MI_DEBUG_FULL) message(STATUS "Set debug level to full internal invariant checking (MI_DEBUG_FULL=ON)") list(APPEND mi_defines MI_DEBUG=3) # full invariant checking endif() -if(MI_PADDING MATCHES "OFF") +if(NOT MI_PADDING) message(STATUS "Disable padding of heap blocks in debug mode (MI_PADDING=OFF)") list(APPEND mi_defines MI_PADDING=0) endif() -if(MI_XMALLOC MATCHES "ON") +if(MI_XMALLOC) message(STATUS "Enable abort() calls on memory allocation failure (MI_XMALLOC=ON)") list(APPEND mi_defines MI_XMALLOC=1) endif() -if(MI_SHOW_ERRORS MATCHES "ON") +if(MI_SHOW_ERRORS) message(STATUS "Enable printing of error and warning messages by default (MI_SHOW_ERRORS=ON)") list(APPEND mi_defines MI_SHOW_ERRORS=1) endif() -if(MI_DEBUG_TSAN MATCHES "ON") +if(MI_DEBUG_TSAN) if(CMAKE_C_COMPILER_ID MATCHES "Clang") message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") list(APPEND mi_defines MI_TSAN=1) @@ -135,13 +135,13 @@ if(MI_DEBUG_TSAN MATCHES "ON") endif() endif() -if(MI_DEBUG_UBSAN MATCHES "ON") +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_cflags -fsanitize=undefined -g) list(APPEND CMAKE_EXE_LINKER_FLAGS -fsanitize=undefined) - if (MI_USE_CXX MATCHES "OFF") + if (NOT MI_USE_CXX) message(STATUS "(switch to use C++ due to MI_DEBUG_UBSAN)") set(MI_USE_CXX "ON") endif() @@ -153,7 +153,7 @@ if(MI_DEBUG_UBSAN MATCHES "ON") endif() endif() -if(MI_USE_CXX MATCHES "ON") +if(MI_USE_CXX) message(STATUS "Use the C++ compiler to compile (MI_USE_CXX=ON)") set_source_files_properties(${mi_sources} PROPERTIES LANGUAGE CXX ) set_source_files_properties(src/static.c test/test-api.c test/test-stress PROPERTIES LANGUAGE CXX ) @@ -178,7 +178,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "Intel") endif() if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku") - if(MI_LOCAL_DYNAMIC_TLS MATCHES "ON") + if(MI_LOCAL_DYNAMIC_TLS) list(APPEND mi_cflags -ftls-model=local-dynamic) else() list(APPEND mi_cflags -ftls-model=initial-exec) @@ -211,7 +211,7 @@ endif() # ----------------------------------------------------------------------------- set(mi_install_dir "${CMAKE_INSTALL_PREFIX}/lib/mimalloc-${mi_version}") -if(MI_SECURE MATCHES "ON") +if(MI_SECURE) set(mi_basename "mimalloc-secure") else() set(mi_basename "mimalloc") @@ -235,7 +235,7 @@ endif() message(STATUS "") message(STATUS "Library base name: ${mi_basename}") message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}") -if(MI_USE_CXX MATCHES "ON") +if(MI_USE_CXX) message(STATUS "Compiler : ${CMAKE_CXX_COMPILER}") else() message(STATUS "Compiler : ${CMAKE_C_COMPILER}") @@ -334,7 +334,7 @@ endif() # API surface testing # ----------------------------------------------------------------------------- -if (MI_BUILD_TESTS MATCHES "ON") +if (MI_BUILD_TESTS) add_executable(mimalloc-test-api test/test-api.c) target_compile_definitions(mimalloc-test-api PRIVATE ${mi_defines}) target_compile_options(mimalloc-test-api PRIVATE ${mi_cflags}) @@ -355,7 +355,7 @@ endif() # ----------------------------------------------------------------------------- # Set override properties # ----------------------------------------------------------------------------- -if (MI_OVERRIDE MATCHES "ON") +if (MI_OVERRIDE) if (MI_BUILD_SHARED) target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) endif() From fb66ebea1d018130b4f0b228f0b9f2f651cca7ae Mon Sep 17 00:00:00 2001 From: "Michael R. Crusoe" <1330696+mr-c@users.noreply.github.com> Date: Sat, 23 Jan 2021 16:45:47 +0100 Subject: [PATCH 165/172] add/improve atomic yields for SSE2, ARM*, PowerPC --- include/mimalloc-atomic.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 9f464593..a925a7f1 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -281,16 +281,33 @@ static inline void mi_atomic_yield(void) { static inline void mi_atomic_yield(void) { YieldProcessor(); } +#elif defined(__SSE2__) +#include +static inline void mi_atomic_yield(void) { + _mm_pause(); +} #elif (defined(__GNUC__) || defined(__clang__)) && \ - (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__)) + (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) || defined(__armel__) || defined(__ARMEL__) || defined(__aarch64__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)) #if defined(__x86_64__) || defined(__i386__) static inline void mi_atomic_yield(void) { __asm__ volatile ("pause" ::: "memory"); } -#elif (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__) +#elif defined(__aarch64__) +static inline void mi_atomic_yield(void) { + asm volatile("wfe"); +} +#elif (defined(__arm__) && __ARM_ARCH__ >= 7) static inline void mi_atomic_yield(void) { __asm__ volatile("yield" ::: "memory"); } +#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) +static inline void mi_atomic_yield(void) { + __asm__ __volatile__ ("or 27,27,27" ::: "memory"); +} +#elif defined(__armel__) || defined(__ARMEL__) +static inline void mi_atomic_yield(void) { + asm volatile ("nop" ::: "memory"); +} #endif #elif defined(__sun) // Fallback for other archs From a753084f748d59dcd18fdc4f10c3e36ccfc107f5 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Thu, 28 Jan 2021 11:38:38 +0100 Subject: [PATCH 166/172] Use APPLE instead of MACH --- 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 dca21bb9..e1190c7e 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -734,7 +734,7 @@ static inline void mi_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { tcb[slot] = value; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); -#if defined(__MACH__) +#if defined(__APPLE__) __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tcb)); #else __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); From 8d4444ef00c8aa3c073ea9a744659a74db75980a Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 28 Jan 2021 17:36:35 -0800 Subject: [PATCH 167/172] remove spurious parenthesis (#350) --- include/mimalloc-atomic.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index a925a7f1..2d725a25 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -287,7 +287,8 @@ static inline void mi_atomic_yield(void) { _mm_pause(); } #elif (defined(__GNUC__) || defined(__clang__)) && \ - (defined(__x86_64__) || defined(__i386__) || (defined(__arm__) || defined(__armel__) || defined(__ARMEL__) || defined(__aarch64__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)) + (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__armel__) || defined(__ARMEL__) || \ + defined(__aarch64__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)) #if defined(__x86_64__) || defined(__i386__) static inline void mi_atomic_yield(void) { __asm__ volatile ("pause" ::: "memory"); From 78ce716e2d5b1572e9b459cba12830e88c892989 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 28 Jan 2021 17:36:56 -0800 Subject: [PATCH 168/172] add comment on use of tpidrro_el0 on macOS --- include/mimalloc-internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index e1190c7e..6a239f1a 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -707,7 +707,7 @@ static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept { res = tcb[slot]; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); -#if defined(__APPLE__) +#if defined(__APPLE__) // issue #343 __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tcb)); #else __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); @@ -734,7 +734,7 @@ static inline void mi_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { tcb[slot] = value; #elif defined(__aarch64__) void** tcb; UNUSED(ofs); -#if defined(__APPLE__) +#if defined(__APPLE__) // issue #343 __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tcb)); #else __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tcb)); From eb5613563b288748c6de1d201fa91c805aa34d21 Mon Sep 17 00:00:00 2001 From: Tarcisio Rodrigues Date: Thu, 28 Jan 2021 23:58:41 -0300 Subject: [PATCH 169/172] Add /Zc:__cplusplus to MSVC compiler flags Fix build errors for a clean build on Windows. For details about the CMake teting code see https://stackoverflow.com/a/60890947/1254880 --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 73e3d1f6..3a7406a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,6 +185,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM endif() endif() +if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) + list(APPEND mi_cflags /Zc:__cplusplus) +endif() + # Architecture flags if(${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT APPLE) check_cxx_compiler_flag(-march=native CXX_SUPPORTS_MARCH_NATIVE) From a8b282091f8b4a6f78c8948fe96b6ea1d6a4d6dc Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 29 Jan 2021 13:03:06 -0800 Subject: [PATCH 170/172] update formatting of statistics --- src/stats.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/stats.c b/src/stats.c index ad698920..59c1896d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -301,11 +301,8 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_stat_print(&total, "total", 1, out, arg); #endif #if MI_STAT>1 - mi_stat_print(&stats->malloc, "malloc total", 1, out, arg); - - _mi_fprintf(out, arg, "malloc requested: "); - mi_print_amount(stats->malloc.allocated, 1, out, arg); - _mi_fprintf(out, arg, "\n\n"); + mi_stat_print(&stats->malloc, "malloc req", 1, out, arg); + _mi_fprintf(out, arg, "\n"); #endif mi_stat_print(&stats->reserved, "reserved", 1, out, arg); mi_stat_print(&stats->committed, "committed", 1, out, arg); From f68c1a74da7279f32550fe0b1eeb334079bf2687 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 29 Jan 2021 14:33:49 -0800 Subject: [PATCH 171/172] fix assertion comparison (#353) --- src/heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heap.c b/src/heap.c index db1b773e..54562d10 100644 --- a/src/heap.c +++ b/src/heap.c @@ -359,7 +359,7 @@ static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) { // turns out to be ok as `_mi_heap_delayed_free` only visits the list and calls a // the regular `_mi_free_delayed_block` which is safe. _mi_heap_delayed_free(from); - mi_assert_internal(from->thread_delayed_free == NULL); + mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_block_t,&from->thread_delayed_free) == NULL); // and reset the `from` heap mi_heap_reset_pages(from); From a6fa7b083eaaf9787901105338d1fdafe46c3882 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 29 Jan 2021 14:45:16 -0800 Subject: [PATCH 172/172] make current stat the third column instead of first --- src/stats.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/stats.c b/src/stats.c index fc457d05..091ad173 100644 --- a/src/stats.c +++ b/src/stats.c @@ -151,7 +151,7 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* const int64_t tens = (n / (divider/10)); const long whole = (long)(tens/10); const long frac1 = (long)(tens%10); - snprintf(buf, len, "%ld.%ld %s%s", whole, frac1, magnitude, suffix); + snprintf(buf, len, "%ld.%ld %s%s", whole, (frac1 < 0 ? -frac1 : frac1), magnitude, suffix); } _mi_fprintf(out, arg, (fmt==NULL ? "%11s" : fmt), buf); } @@ -169,10 +169,10 @@ static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out, void* ar static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg ) { _mi_fprintf(out, arg,"%10s:", msg); if (unit>0) { - mi_print_amount(stat->current, unit, out, arg); mi_print_amount(stat->peak, unit, out, arg); mi_print_amount(stat->allocated, unit, out, arg); mi_print_amount(stat->freed, unit, out, arg); + mi_print_amount(stat->current, unit, out, arg); mi_print_amount(unit, 1, out, arg); mi_print_count(stat->allocated, unit, out, arg); if (stat->allocated > stat->freed) @@ -181,10 +181,10 @@ static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t _mi_fprintf(out, arg, " ok\n"); } else if (unit<0) { - mi_print_amount(stat->current, -1, out, arg); mi_print_amount(stat->peak, -1, out, arg); mi_print_amount(stat->allocated, -1, out, arg); mi_print_amount(stat->freed, -1, out, arg); + mi_print_amount(stat->current, -1, out, arg); if (unit==-1) { _mi_fprintf(out, arg, "%22s", ""); } @@ -198,9 +198,10 @@ static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t _mi_fprintf(out, arg, " ok\n"); } else { - mi_print_amount(stat->current, 1, out, arg); mi_print_amount(stat->peak, 1, out, arg); mi_print_amount(stat->allocated, 1, out, arg); + _mi_fprintf(out, arg, "%11s", " "); // no freed + mi_print_amount(stat->current, 1, out, arg); _mi_fprintf(out, arg, "\n"); } } @@ -220,7 +221,7 @@ static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* static void mi_print_header(mi_output_fun* out, void* arg ) { - _mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s %10s\n", "heap stats", "current ", "peak ", "total ", "freed ", "unit ", "count "); + _mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "current ", "unit ", "count "); } #if MI_STAT>1

user_msecsOptional. User time in milli-seconds.
elapsed_msecsOptional. Elapsed wall-clock time of the process in milli-seconds.
user_msecsOptional. User time in milli-seconds (as the sum over all threads).
system_msecsOptional. System time in milli-seconds.
current_rssOptional. Current working set size (touched pages).
peak_rssOptional. Peak working set size (touched pages).