FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Update vendored mimalloc to upstream dev3 plus CPython fixes · python/cpython@2e001e5 · GitHub

Repository navigation

Commit 2e001e5

Browse files
committed
Update vendored mimalloc to upstream dev3 plus CPython fixes
Sync Objects/mimalloc and Include/internal/mimalloc with microsoft/mimalloc dev3 (e34c9d38, "fix qsbr tests") plus the CPython-motivated fixes that are being proposed upstream, replacing the local edits previously made directly to the vendored copy: - Put mi_decl_forceinline before the return type (-Wold-style-declaration) - Fix MI_ARENA_SLICE_SHIFT selection on WASI - Use quoted, relative includes for mimalloc's own headers - Fix debug assertion during process init with MI_WIN_INIT_USE_FLS - Mark memory written by raw syscalls as initialized under MSan - Emscripten: allocate OS memory from the builtin allocator - Allow disabling the aligned-allocation fallback warning (MI_NO_ALIGN_FALLBACK_WARNING) - Allow not defining the weak std::get_new_handler in C builds (MI_NO_CXX_NEW_HANDLER) - Fix build with MI_NO_THP after the MADV_NOHUGEPAGE change - Fix -Wsign-compare warning when reading hpage_pmd_size - Remove trailing whitespace This also picks up the dev3 commits since the previous snapshot (e83c5605), including transparent huge page detection changes, allowing page abandonment for QSBR pages, and relaxed atomics in mi_free_block_mt. Define MI_NO_ALIGN_FALLBACK_WARNING in pycore_mimalloc.h, since the vendored copy no longer has the warning commented out.
1 parent 568dacd commit 2e001e5

16 files changed

Lines changed: 201 additions & 79 deletions

File tree

‎Include/internal/mimalloc/mimalloc.h‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -493,8 +493,8 @@ typedef enum mi_option_e {
493493
mi_option_deprecated_visit_abandoned, // allow visiting theap blocks from abandoned threads (=0)
494494
mi_option_guarded_min, // only used when building with MI_GUARDED: minimal rounded object size for guarded objects (=0)
495495
mi_option_guarded_max, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects (=0)
496-
mi_option_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0)
497-
mi_option_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000)
496+
mi_option_unsafe_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0)
497+
mi_option_guarded_sample_rate, // guard an object in the min/max range about every N requested bytes (=0)
498498
mi_option_guarded_sample_seed, // can be set to allow for a (more) deterministic re-execution when a guard page is triggered (=0)
499499
mi_option_generic_collect, // collect theaps every N (=10000) generic allocation calls
500500
mi_option_page_reclaim_on_free, // heap-creation default for reclaim on free: -1 disallow, 0 originating theap only, 1 allow across theaps
@@ -510,10 +510,10 @@ typedef enum mi_option_e {
510510
mi_option_arena_max_object_size, // set maximal object size that can be allocated in an arena (in KiB) (=2GiB on 64-bit).
511511
mi_option_arena_is_numa_local, // experimental: associate local numa node with an initial arena allocation
512512
mi_option_stats_merge_on_collect, // on each theap collection, the theap stats are merged automatically with the parent heap
513-
mi_option_profile_alloc_interval, // number of allocated bytes between automatic dumps of the `MIMALLOC_PROFILE` heap profiler (internally, this value is in KiB; use `mi_option_get_size`) (=0, disabled)
514-
mi_option_profile_inuse_interval, // number of in-use bytes grown between automatic dumps of the `MIMALLOC_PROFILE` heap profiler (internally, this value is in KiB; use `mi_option_get_size`) (=0, disabled)
515-
mi_option_profile_time_interval, // number of seconds between automatic dumps of the `MIMALLOC_PROFILE` heap profiler (=0, disabled)
516-
mi_option_profile_sample_rate, // sample rate (in bytes) for the `MIMALLOC_PROFILE` heap profiler (internally, this value is in KiB; use `mi_option_get_size`) (=16 KiB)
513+
mi_option_profile_alloc_interval, // number of allocated bytes between automatic snapshots of the heap profiler (internally, this value is in KiB; use `mi_option_get_size`) (=1GiB, disabled)
514+
mi_option_profile_inuse_interval, // number of in-use bytes grown between automatic snapshots of the heap profiler (internally, this value is in KiB; use `mi_option_get_size`) (=0, disabled)
515+
mi_option_profile_time_interval, // number of seconds between automatic snapshots of the heap profiler (=0, disabled)
516+
mi_option_profile_sample_rate, // sample rate (in bytes) for heap profiler (internally, this value is in KiB; use `mi_option_get_size`) (=512 KiB)
517517
mi_option_stats_merge_threshold, // on a page stats update, merge theap stats into the parent heap if N bytes were freed/allocated (=0, disabled)
518518
mi_option_arena_purge_immediate_size, // ranges above this size are purged immediately
519519
_mi_option_last,

‎Include/internal/mimalloc/mimalloc/alloc/page.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mi_decl_nodiscard bool _mi_page_init(mi_theap_t* theap, mi_page_t* page);
2828
void _mi_page_update_stats(mi_page_t* page);
2929

3030
void _mi_theap_collect_retired(mi_theap_t* theap, bool force);
31-
void _mi_theap_page_reclaim(mi_theap_t* theap, mi_page_t* page);
31+
bool _mi_theap_page_reclaim(mi_theap_t* theap, mi_page_t* page); // true if an empty page was freed
3232
#if MI_DEBUG>1
3333
bool _mi_page_is_valid(mi_page_t* page);
3434
#endif

‎Include/internal/mimalloc/mimalloc/decl.h‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,22 @@ terms of the MIT license. A copy of the license can be found in the file
7373
#endif
7474

7575
#if defined(__GNUC__) || defined(__clang__)
76-
#define mi_unlikely(x) (__builtin_expect(!!(x),false))
77-
#define mi_likely(x) (__builtin_expect(!!(x),true))
76+
#define mi_unlikely(x) (__builtin_expect(!!(x),false))
77+
#define mi_likely(x) (__builtin_expect(!!(x),true))
7878
#elif (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
79-
#define mi_unlikely(x) (x) [[unlikely]]
80-
#define mi_likely(x) (x) [[likely]]
79+
#define mi_unlikely(x) (x) [[unlikely]]
80+
#define mi_likely(x) (x) [[likely]]
8181
#else
82-
#define mi_unlikely(x) (x)
83-
#define mi_likely(x) (x)
82+
#define mi_unlikely(x) (x)
83+
#define mi_likely(x) (x)
84+
#endif
85+
86+
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
87+
#define mi_prefetch_write(p) __builtin_prefetch(p, 1, 3)
88+
#define mi_prefetch_read(p) __builtin_prefetch(p, 0, 3)
89+
#else
90+
#define mi_prefetch_write(p)
91+
#define mi_prefetch_read(p)
8492
#endif
8593

8694
#if (defined(__GNUC__) && (__GNUC__ >= 7)) || defined(__clang__)

‎Include/internal/mimalloc/mimalloc/prim/os.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ size_t _mi_os_guard_page_size(void);
2121
size_t _mi_os_good_alloc_size(size_t size);
2222
bool _mi_os_has_overcommit(void);
2323
bool _mi_os_has_virtual_reserve(void);
24-
bool _mi_os_canuse_thp(void);
24+
bool _mi_os_has_thp(void);
2525
size_t _mi_os_virtual_address_bits(void);
2626
size_t _mi_os_minimal_purge_size(void);
2727

‎Include/internal/mimalloc/mimalloc/util/libc.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ char* _mi_strnstr(char* s, size_t max_len, const char* pat);
2525
const char* _mi_strchr(const char* s, char c);
2626
const char* _mi_strrchr(const char* s, char c);
2727
bool _mi_streq(const char* s, const char* t);
28+
bool _mi_strntol(const char* s, size_t max_len, const char** end, long* result); // parses at most max_len bytes; no terminator required
2829
int _mi_getenv(const char* name, char* result, size_t result_size);
2930
void _mi_detect_cpu_features(void);
3031

‎Include/internal/pycore_mimalloc.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
// CPython never uses mimalloc's C++ operator new APIs, so don't define a weak
1818
// std::get_new_handler() (_ZSt15get_new_handlerv) in libpython.
1919
# define MI_NO_CXX_NEW_HANDLER 1
20+
// The aligned OS allocation fallback is benign, but its warning is printed to
21+
// stderr and breaks tests that check output (e.g. test_cmd_line under ASan).
22+
# define MI_NO_ALIGN_FALLBACK_WARNING 1
2023
# ifdef MS_WINDOWS
2124
// Initialize from a CRT initializer and use FLS for thread cleanup instead
2225
// of TLS callbacks, which run during DLL attach before the CRT is set up.

‎Objects/mimalloc/alloc/free.c‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,13 @@ void mi_free_block_mt(mi_page_t* page, mi_block_t* block, bool was_guarded, bool
107107
do {
108108
mi_block_set_next(page, block, mi_tf_block(tf_old));
109109
tf_new = mi_tf_create(block, true);
110-
} while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tf_old, tf_new));
110+
if (mi_tf_is_owned(tf_old)) {
111+
if (mi_atomic_cas_weak_release(&page->xthread_free, &tf_old, tf_new)) break; // release is enough if we don't change ownership
112+
}
113+
else {
114+
if (mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tf_old, tf_new)) break; // otherwise we need acquire-release
115+
}
116+
} while(true);
111117

112118
// and atomically try to collect the page if it was abandoned
113119
const bool is_newly_owned = mi_tf_is_owned(tf_new) && !mi_tf_is_owned(tf_old);
@@ -216,7 +222,7 @@ static mi_decl_forceinline bool mi_ptr_page_is_valid_ex(const void* p, const cha
216222
{
217223
MI_UNUSED_RELEASE(msg); MI_UNUSED(free_small);
218224
#if MI_DEBUG
219-
if mi_unlikely(!mi_is_aligned(p,MI_SIZE_SIZE) && !mi_option_is_enabled(mi_option_guarded_precise)) {
225+
if mi_unlikely(!mi_is_aligned(p,MI_SIZE_SIZE) && !mi_option_is_enabled(mi_option_unsafe_guarded_precise)) {
220226
_mi_error_message(EINVAL, "%s: invalid (unaligned) pointer: %p\n", msg, p);
221227
return false;
222228
}
@@ -466,19 +472,29 @@ bool mi_cfree(void* p) mi_attr_noexcept {
466472
// 3. if it went to < 7/8th used, re-abandon to be mapped (so it can be found by theaps looking for free pages)
467473
// --------------------------------------------------------------------------------------------
468474

469-
// Consume an empty page, either freeing it or leaving it abandoned until its grace period ends.
475+
// Consume an empty page, reclaiming delayed pages if this thread has a theap for their heap.
470476
static bool mi_abandoned_page_collect_empty(mi_page_t* page)
471477
{
472478
if (!mi_page_all_free(page)) return false;
473479
const bool should_delay = _mi_page_qsbr_should_delay(page);
474480
// first remove it from the abandoned pages in the arena (if mapped, this might wait for any readers to finish)
475481
_mi_arenas_page_unabandon(page,NULL);
476-
if (!should_delay) {
482+
if mi_likely(!should_delay) {
477483
_mi_page_qsbr_clear(page);
478484
_mi_arenas_page_free(page,NULL);
479485
}
480486
else {
481-
_mi_arenas_page_abandon(page,NULL);
487+
mi_heap_t* const heap = mi_page_heap(page);
488+
mi_theap_t* const theap = mi_heap_theap(heap);
489+
if (theap != NULL) {
490+
// reclaim such that it gets part of the theap's qsbr list.
491+
_mi_theap_page_reclaim(theap, page);
492+
}
493+
else {
494+
mi_assert_internal(false);
495+
// abandon as empty; it can only be collected by _mi_heap_collect_abandoned at this point
496+
_mi_arenas_page_abandon(page,NULL);
497+
}
482498
}
483499
return true;
484500
}

‎Objects/mimalloc/alloc/page.c‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ mi_block_t* _mi_page_free_collect_partly(mi_page_t* page, mi_block_t* head) {
450450
----------------------------------------------------------- */
451451

452452
// called from `mi_free` on a reclaim, and fresh_alloc if we get an abandoned page
453-
void _mi_theap_page_reclaim(mi_theap_t* theap, mi_page_t* page)
453+
bool _mi_theap_page_reclaim(mi_theap_t* theap, mi_page_t* page)
454454
{
455455
mi_assert_internal(mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
456456
mi_assert_internal(mi_ptr_page(mi_page_start(page))==page);
@@ -463,8 +463,8 @@ void _mi_theap_page_reclaim(mi_theap_t* theap, mi_page_t* page)
463463
mi_page_queue_t* pq = mi_theap_page_queue_of(theap, page);
464464
mi_page_queue_push_at_end(theap, pq, page);
465465
if (!mi_page_all_free(page)) { _mi_page_qsbr_clear(page); }
466-
else if (!_mi_page_qsbr_is_clear(page)) { mi_page_qsbr_enqueue(page, theap); }
467466
mi_assert_expensive(_mi_page_is_valid(page));
467+
return (mi_page_all_free(page) && _mi_page_free(page, pq));
468468
}
469469

470470
void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) {
@@ -488,13 +488,17 @@ mi_page_t* _mi_page_fresh_alloc(mi_theap_t* theap, mi_page_queue_t* pq, size_t b
488488
mi_assert_internal(mi_theap_contains_queue(theap, pq));
489489
mi_assert_internal(page_alignment > 0 || block_size > MI_LARGE_MAX_OBJ_SIZE || block_size == pq->block_size);
490490
#endif
491-
mi_page_t* page = _mi_arenas_page_alloc(theap, block_size, page_alignment);
492-
if (page == NULL) {
493-
// out-of-memory
494-
return NULL;
495-
}
496-
if (mi_page_is_abandoned(page)) {
497-
_mi_theap_page_reclaim(theap, page);
491+
mi_page_t* page;
492+
bool reclaimed;
493+
do {
494+
page = _mi_arenas_page_alloc(theap, block_size, page_alignment);
495+
if (page == NULL) {
496+
// out-of-memory
497+
return NULL;
498+
}
499+
reclaimed = mi_page_is_abandoned(page);
500+
} while (reclaimed && _mi_theap_page_reclaim(theap, page));
501+
if (reclaimed) {
498502
if (!mi_page_immediate_available(page)) {
499503
if (mi_page_is_expandable(page)) {
500504
if (!_mi_page_extend_free(theap, page)) {

‎Objects/mimalloc/alloc/page.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file
88
#ifndef MI_PAGE_H
99
#define MI_PAGE_H
1010

11-
#include <mimalloc.h>
11+
#include "mimalloc.h"
1212
#include "page-queue.h"
1313

1414
bool _mi_page_extend_free(mi_theap_t* theap, mi_page_t* page);

‎Objects/mimalloc/heap/theap.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ mi_theap_t* mi_theap_set_default(mi_theap_t* theap) {
220220

221221
static void mi_theap_options_init(mi_theap_t* theap, mi_heap_t* heap) {
222222
theap->allow_page_reclaim = (mi_heap_reclaim_on_free(heap) >= 0);
223-
theap->allow_page_abandon = (mi_option_get(mi_option_page_full_retain) >= 0 && !mi_heap_qsbr_is_enabled(heap));
223+
theap->allow_page_abandon = (mi_option_get(mi_option_page_full_retain) >= 0); // nowadays qsbr pages can be abandoned: && !mi_heap_qsbr_is_enabled(heap));
224224
theap->page_full_retain = mi_option_get_clamp(mi_option_page_full_retain, -1, 32);
225225
theap->is_detached = (theap->tld->thread_id == MI_THREADID_DETACHED);
226226
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL