@shd101wyy/yo 0.1.24 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +30 -0
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +436 -2
- package/out/cjs/index.cjs +551 -553
- package/out/cjs/yo-cli.cjs +638 -632
- package/out/cjs/yo-lsp.cjs +595 -597
- package/out/esm/index.mjs +487 -489
- package/out/types/src/codegen/utils/index.d.ts +1 -0
- package/out/types/src/expr.d.ts +1 -0
- package/out/types/src/test-runner.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/vendor/mimalloc/.github/workflows/release.yaml +55 -0
- package/vendor/mimalloc/.github/workflows/stale.yaml +27 -0
- package/vendor/mimalloc/.github/workflows/test.yaml +163 -0
- package/vendor/mimalloc/CMakeLists.txt +52 -33
- package/vendor/mimalloc/azure-pipelines.yml +4 -3
- package/vendor/mimalloc/bin/bundle.bat +74 -0
- package/vendor/mimalloc/bin/bundle.sh +232 -0
- package/vendor/mimalloc/cmake/mimalloc-config-version.cmake +2 -2
- package/vendor/mimalloc/contrib/docker/alpine/Dockerfile +1 -1
- package/vendor/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile +2 -2
- package/vendor/mimalloc/contrib/docker/alpine-x86/Dockerfile +1 -1
- package/vendor/mimalloc/contrib/docker/manylinux-x64/Dockerfile +1 -1
- package/vendor/mimalloc/contrib/vcpkg/portfile.cmake +4 -3
- package/vendor/mimalloc/contrib/vcpkg/vcpkg.json +1 -1
- package/vendor/mimalloc/doc/mimalloc-doc.h +42 -4
- package/vendor/mimalloc/doc/release-notes.md +15 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-lib.vcxproj +3 -3
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-static-lib.vcxproj +511 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-static-lib.vcxproj.filters +117 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test-dep.vcxproj +360 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test-override-static.vcxproj +310 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc.sln +92 -35
- package/vendor/mimalloc/include/mimalloc/atomic.h +178 -182
- package/vendor/mimalloc/include/mimalloc/bits.h +8 -10
- package/vendor/mimalloc/include/mimalloc/internal.h +76 -32
- package/vendor/mimalloc/include/mimalloc/prim.h +25 -18
- package/vendor/mimalloc/include/mimalloc/track.h +7 -2
- package/vendor/mimalloc/include/mimalloc/types.h +57 -29
- package/vendor/mimalloc/include/mimalloc-override.h +10 -10
- package/vendor/mimalloc/include/mimalloc-stats.h +18 -6
- package/vendor/mimalloc/include/mimalloc.h +22 -12
- package/vendor/mimalloc/readme.md +42 -17
- package/vendor/mimalloc/src/alloc-aligned.c +13 -11
- package/vendor/mimalloc/src/alloc-override.c +97 -17
- package/vendor/mimalloc/src/alloc-posix.c +44 -27
- package/vendor/mimalloc/src/alloc.c +73 -23
- package/vendor/mimalloc/src/arena-meta.c +3 -3
- package/vendor/mimalloc/src/arena.c +380 -192
- package/vendor/mimalloc/src/bitmap.c +68 -18
- package/vendor/mimalloc/src/bitmap.h +8 -4
- package/vendor/mimalloc/src/free.c +83 -47
- package/vendor/mimalloc/src/heap.c +94 -40
- package/vendor/mimalloc/src/init.c +273 -102
- package/vendor/mimalloc/src/libc.c +53 -8
- package/vendor/mimalloc/src/options.c +43 -40
- package/vendor/mimalloc/src/os.c +110 -45
- package/vendor/mimalloc/src/page-map.c +14 -8
- package/vendor/mimalloc/src/page-queue.c +9 -6
- package/vendor/mimalloc/src/page.c +26 -16
- package/vendor/mimalloc/src/prim/emscripten/prim.c +10 -1
- package/vendor/mimalloc/src/prim/osx/alloc-override-zone.c +35 -16
- package/vendor/mimalloc/src/prim/unix/prim.c +26 -22
- package/vendor/mimalloc/src/prim/wasi/prim.c +7 -4
- package/vendor/mimalloc/src/prim/windows/prim.c +247 -44
- package/vendor/mimalloc/src/random.c +8 -3
- package/vendor/mimalloc/src/stats.c +59 -48
- package/vendor/mimalloc/src/theap.c +85 -44
- package/vendor/mimalloc/src/threadlocal.c +102 -41
- package/vendor/mimalloc/test/main-override-static.c +31 -2
- package/vendor/mimalloc/test/main-override.c +27 -14
- package/vendor/mimalloc/test/main-static-dep.cpp +46 -0
- package/vendor/mimalloc/test/main-static-dep.h +11 -0
- package/vendor/mimalloc/test/test-api-fill.c +2 -2
- package/vendor/mimalloc/test/test-stress.c +3 -3
- package/vendor/mimalloc/test/test-wrong.c +11 -7
|
@@ -33,21 +33,31 @@ mi_arena_id_t _mi_arena_id_none(void) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
mi_arena_t* _mi_arena_from_id(mi_arena_id_t id) {
|
|
36
|
-
|
|
36
|
+
mi_arena_t* const arena = (mi_arena_t*)id;
|
|
37
|
+
mi_assert_internal(arena==NULL || arena->parent==NULL); // id's should never point to sub-arena's
|
|
38
|
+
return arena;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
mi_arena_id_t mi_arena_id_from_arena(mi_arena_t* arena) {
|
|
42
|
+
mi_assert_internal(arena==NULL || arena->parent==NULL);
|
|
43
|
+
return (arena==NULL ? _mi_arena_id_none() : (mi_arena_id_t)arena);
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
|
|
40
|
-
static bool
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
static bool mi_arena_is_suitable(mi_arena_t* arena, mi_arena_t* req_arena) {
|
|
48
|
+
if (arena == req_arena) return true; // they match
|
|
49
|
+
if (arena == NULL) return false;
|
|
50
|
+
if (req_arena == NULL && !arena->is_exclusive) return true; // or the arena is not exclusive, and we didn't request a specific one
|
|
51
|
+
if (arena->parent != NULL && arena->parent == req_arena) return true; // sub-arena? (note that req_arena is never a sub arena)
|
|
52
|
+
return false;
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
bool _mi_arena_memid_is_suitable(mi_memid_t memid, mi_arena_t* request_arena) {
|
|
46
56
|
if (memid.memkind == MI_MEM_ARENA) {
|
|
47
|
-
return
|
|
57
|
+
return mi_arena_is_suitable(memid.mem.arena.arena, request_arena);
|
|
48
58
|
}
|
|
49
59
|
else {
|
|
50
|
-
return
|
|
60
|
+
return mi_arena_is_suitable(NULL, request_arena);
|
|
51
61
|
}
|
|
52
62
|
}
|
|
53
63
|
|
|
@@ -57,7 +67,7 @@ size_t mi_arenas_get_count(mi_subproc_t* subproc) {
|
|
|
57
67
|
|
|
58
68
|
mi_arena_t* mi_arena_from_index(mi_subproc_t* subproc, size_t idx) {
|
|
59
69
|
mi_assert_internal(idx < mi_arenas_get_count(subproc));
|
|
60
|
-
return
|
|
70
|
+
return mi_atomic_load_ptr_acquire(mi_arena_t, &subproc->arenas[idx]);
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
static size_t mi_arena_info_slices(mi_arena_t* arena) {
|
|
@@ -79,6 +89,10 @@ size_t mi_arena_min_alignment(void) {
|
|
|
79
89
|
return MI_ARENA_SLICE_ALIGN;
|
|
80
90
|
}
|
|
81
91
|
|
|
92
|
+
size_t mi_arena_min_size(void) {
|
|
93
|
+
return MI_ARENA_MIN_SIZE;
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
static size_t mi_arena_max_object_size(void) {
|
|
83
97
|
size_t max_size = mi_option_get_size(mi_option_arena_max_object_size);
|
|
84
98
|
max_size = _mi_align_up(max_size, MI_ARENA_SLICE_SIZE);
|
|
@@ -124,15 +138,34 @@ static uint8_t* mi_arena_start(mi_arena_t* arena) {
|
|
|
124
138
|
|
|
125
139
|
// Start of a slice
|
|
126
140
|
uint8_t* mi_arena_slice_start(mi_arena_t* arena, size_t slice_index) {
|
|
141
|
+
mi_assert_internal(slice_index < arena->slice_count);
|
|
127
142
|
return (mi_arena_start(arena) + mi_size_of_slices(slice_index));
|
|
128
143
|
}
|
|
129
144
|
|
|
145
|
+
mi_page_t* mi_arena_page_at_slice(mi_arena_t* arena, size_t slice_index) {
|
|
146
|
+
mi_assert_internal(slice_index < arena->slice_count);
|
|
147
|
+
if (arena->pages_meta != NULL) {
|
|
148
|
+
mi_page_t* const page = &arena->pages_meta[slice_index];
|
|
149
|
+
#if MI_PAGE_META_ALIGNED_FREE_SMALL
|
|
150
|
+
// pages with small blocks still have the page at the start of the slice (and set the `block_size` in pages_meta to 0)
|
|
151
|
+
if (page->block_size>0) return page;
|
|
152
|
+
#else
|
|
153
|
+
return page;
|
|
154
|
+
#endif
|
|
155
|
+
}
|
|
156
|
+
// fall through (for MI_PAGE_META_ALIGNED_FREE_SMALL)
|
|
157
|
+
return (mi_page_t*)mi_arena_slice_start(arena,slice_index);
|
|
158
|
+
}
|
|
159
|
+
|
|
130
160
|
// Arena area
|
|
131
161
|
void* mi_arena_area(mi_arena_id_t arena_id, size_t* size) {
|
|
132
162
|
if (size != NULL) *size = 0;
|
|
133
163
|
mi_arena_t* arena = _mi_arena_from_id(arena_id);
|
|
134
164
|
if (arena == NULL) return NULL;
|
|
135
|
-
if (size != NULL) {
|
|
165
|
+
if (size != NULL) {
|
|
166
|
+
mi_assert_internal(mi_size_of_slices(arena->slice_count) <= arena->total_size);
|
|
167
|
+
*size = arena->total_size;
|
|
168
|
+
}
|
|
136
169
|
return mi_arena_start(arena);
|
|
137
170
|
}
|
|
138
171
|
|
|
@@ -183,7 +216,7 @@ static mi_decl_noinline void* mi_arena_try_alloc_at(
|
|
|
183
216
|
mi_arena_t* arena, size_t slice_count, bool commit, size_t tseq, mi_memid_t* memid)
|
|
184
217
|
{
|
|
185
218
|
size_t slice_index;
|
|
186
|
-
if (!mi_bbitmap_try_find_and_clearN(arena->slices_free,
|
|
219
|
+
if (!mi_bbitmap_try_find_and_clearN(arena->slices_free, tseq, slice_count, &slice_index)) return NULL;
|
|
187
220
|
|
|
188
221
|
// claimed it!
|
|
189
222
|
void* p = mi_arena_slice_start(arena, slice_index);
|
|
@@ -206,7 +239,7 @@ static mi_decl_noinline void* mi_arena_try_alloc_at(
|
|
|
206
239
|
if (already_committed < slice_count) {
|
|
207
240
|
// not all committed, try to commit now
|
|
208
241
|
bool commit_zero = false;
|
|
209
|
-
if (!
|
|
242
|
+
if (!mi_arena_commit(arena, p, mi_size_of_slices(slice_count), &commit_zero, mi_size_of_slices(slice_count - already_committed))) {
|
|
210
243
|
// if the commit fails, release ownership, and return NULL;
|
|
211
244
|
// note: this does not roll back dirty bits but that is ok.
|
|
212
245
|
mi_bbitmap_setN(arena->slices_free, slice_index, slice_count);
|
|
@@ -234,7 +267,7 @@ static mi_decl_noinline void* mi_arena_try_alloc_at(
|
|
|
234
267
|
_mi_os_reuse(p, mi_size_of_slices(slice_count));
|
|
235
268
|
// if the OS has overcommit, and this is the first time we access these pages, then
|
|
236
269
|
// count the commit now (as at arena reserve we didn't count those commits as these are on-demand)
|
|
237
|
-
if (_mi_os_has_overcommit() && touched_slices > 0) {
|
|
270
|
+
if (_mi_os_has_overcommit() && touched_slices > 0 && !arena->memid.is_pinned /* huge pages, issue #1236 */) {
|
|
238
271
|
mi_subproc_stat_increase( arena->subproc, committed, mi_size_of_slices(touched_slices));
|
|
239
272
|
}
|
|
240
273
|
}
|
|
@@ -319,7 +352,7 @@ static bool mi_arena_reserve(mi_subproc_t* subproc, size_t req_size, bool allow_
|
|
|
319
352
|
// commit eagerly?
|
|
320
353
|
bool arena_commit = false;
|
|
321
354
|
const bool overcommit = _mi_os_has_overcommit();
|
|
322
|
-
if (mi_option_get(mi_option_arena_eager_commit) == 2) { arena_commit = overcommit; }
|
|
355
|
+
if (mi_option_get(mi_option_arena_eager_commit) == 2) { arena_commit = overcommit || mi_option_is_enabled(mi_option_allow_large_os_pages); }
|
|
323
356
|
else if (mi_option_get(mi_option_arena_eager_commit) == 1) { arena_commit = true; }
|
|
324
357
|
|
|
325
358
|
// on an OS with overcommit (Linux) we don't count the commit yet as it is on-demand. Once a slice
|
|
@@ -349,9 +382,9 @@ static bool mi_arena_reserve(mi_subproc_t* subproc, size_t req_size, bool allow_
|
|
|
349
382
|
Arena iteration
|
|
350
383
|
----------------------------------------------------------- */
|
|
351
384
|
|
|
352
|
-
static inline bool
|
|
385
|
+
static inline bool mi_arena_is_suitable_ex(mi_arena_t* arena, mi_arena_t* req_arena, bool match_numa, int numa_node, bool allow_pinned) {
|
|
353
386
|
if (!allow_pinned && arena->memid.is_pinned) return false;
|
|
354
|
-
if (!
|
|
387
|
+
if (!mi_arena_is_suitable(arena, req_arena)) return false;
|
|
355
388
|
if (req_arena == NULL) { // if not specific, check numa affinity
|
|
356
389
|
const bool numa_suitable = (numa_node < 0 || arena->numa_node < 0 || arena->numa_node == numa_node);
|
|
357
390
|
if (match_numa) { if (!numa_suitable) return false; }
|
|
@@ -366,7 +399,7 @@ static size_t mi_arena_start_idx(mi_heap_t* heap, size_t tseq, size_t arena_cycl
|
|
|
366
399
|
const size_t hseq = heap->heap_seq;
|
|
367
400
|
const size_t hcount = mi_atomic_load_relaxed(&heap->subproc->heap_count);
|
|
368
401
|
if (arena_cycle <= 1) return 0;
|
|
369
|
-
if (hseq==0 || hcount<=1) return (tseq % arena_cycle); // common for single heap programs
|
|
402
|
+
if (hseq==0 || hcount<=1 || arena_cycle > 0x8FF) return (tseq % arena_cycle); // common for single heap programs
|
|
370
403
|
|
|
371
404
|
// spread heaps evenly among arena's, and then evenly for threads in their fraction
|
|
372
405
|
size_t start;
|
|
@@ -377,8 +410,8 @@ static size_t mi_arena_start_idx(mi_heap_t* heap, size_t tseq, size_t arena_cycl
|
|
|
377
410
|
start = (hseq % arena_cycle);
|
|
378
411
|
}
|
|
379
412
|
else {
|
|
380
|
-
const size_t hspot = (hseq % hcount);
|
|
381
|
-
start = (frac * hspot) / 256;
|
|
413
|
+
const size_t hspot = (hseq % hcount);
|
|
414
|
+
start = (frac * hspot) / 256; // (arena_cycle * (hseq % hcount)) / hcount
|
|
382
415
|
if (frac >= 512) { // at least 2 arena's per heap?
|
|
383
416
|
start = start + (tseq % (frac/256));
|
|
384
417
|
}
|
|
@@ -419,7 +452,7 @@ static size_t mi_arena_start_idx(mi_heap_t* heap, size_t tseq, size_t arena_cycl
|
|
|
419
452
|
|
|
420
453
|
#define mi_forall_suitable_arenas(heap, req_arena, tseq, match_numa, numa_node, allow_large, name_arena) \
|
|
421
454
|
mi_forall_arenas(heap, req_arena,tseq,name_arena) { \
|
|
422
|
-
if (
|
|
455
|
+
if (mi_arena_is_suitable_ex(name_arena, req_arena, match_numa, numa_node, allow_large)) { \
|
|
423
456
|
|
|
424
457
|
#define mi_forall_suitable_arenas_end() \
|
|
425
458
|
}} \
|
|
@@ -481,13 +514,16 @@ static mi_decl_noinline void* mi_arenas_try_alloc(
|
|
|
481
514
|
// don't create arena's while preloading (todo: or should we?)
|
|
482
515
|
if (_mi_preloading()) return NULL;
|
|
483
516
|
|
|
517
|
+
// don't create arena's if OS allocation is disallowed
|
|
518
|
+
if (mi_option_is_enabled(mi_option_disallow_os_alloc)) return NULL;
|
|
519
|
+
|
|
484
520
|
// otherwise, try to reserve a new arena -- but one thread at a time.. (todo: allow 2 or 4 to reduce contention?)
|
|
485
521
|
mi_subproc_t* const subproc = heap->subproc;
|
|
486
522
|
const size_t arena_count = mi_arenas_get_count(subproc);
|
|
487
523
|
mi_lock(&subproc->arena_reserve_lock) {
|
|
488
524
|
if (arena_count == mi_arenas_get_count(subproc)) {
|
|
489
525
|
// we are the first to enter the lock, reserve a fresh arena
|
|
490
|
-
mi_arena_id_t arena_id =
|
|
526
|
+
mi_arena_id_t arena_id = _mi_arena_id_none();
|
|
491
527
|
mi_arena_reserve(subproc, mi_size_of_slices(slice_count), allow_large, &arena_id);
|
|
492
528
|
}
|
|
493
529
|
else {
|
|
@@ -586,7 +622,7 @@ static bool mi_abandoned_page_unown(mi_page_t* page, mi_theap_t* current_theap)
|
|
|
586
622
|
|
|
587
623
|
static bool mi_arena_try_claim_abandoned(size_t slice_index, mi_arena_t* arena, bool* keep_abandoned) {
|
|
588
624
|
// found an abandoned page of the right size
|
|
589
|
-
mi_page_t* const page = (
|
|
625
|
+
mi_page_t* const page = mi_arena_page_at_slice(arena, slice_index);
|
|
590
626
|
// can we claim ownership?
|
|
591
627
|
if (!mi_page_claim_ownership(page)) {
|
|
592
628
|
// there was a concurrent free that reclaims this page ..
|
|
@@ -610,7 +646,7 @@ static mi_arena_pages_t* mi_heap_arena_pages(mi_heap_t* heap, mi_arena_t* arena)
|
|
|
610
646
|
mi_assert_internal(arena!=NULL);
|
|
611
647
|
mi_assert_internal(heap!=NULL);
|
|
612
648
|
mi_assert(arena->arena_idx < MI_MAX_ARENAS);
|
|
613
|
-
return
|
|
649
|
+
return mi_atomic_load_ptr_acquire(mi_arena_pages_t, &heap->arena_pages[arena->arena_idx]);
|
|
614
650
|
}
|
|
615
651
|
|
|
616
652
|
static mi_arena_t* mi_page_arena_pages(mi_page_t* page, size_t* slice_index, size_t* slice_count, mi_arena_pages_t** parena_pages) {
|
|
@@ -655,7 +691,7 @@ static mi_arena_pages_t* mi_heap_ensure_arena_pages(mi_heap_t* heap, mi_arena_t*
|
|
|
655
691
|
|
|
656
692
|
static mi_page_t* mi_arenas_page_try_find_abandoned(mi_theap_t* theap, size_t slice_count, size_t block_size)
|
|
657
693
|
{
|
|
658
|
-
mi_heap_t* const heap = theap
|
|
694
|
+
mi_heap_t* const heap = _mi_theap_heap(theap);
|
|
659
695
|
const size_t tseq = theap->tld->thread_seq;
|
|
660
696
|
mi_arena_t* const req_arena = heap->exclusive_arena;
|
|
661
697
|
|
|
@@ -683,7 +719,7 @@ static mi_page_t* mi_arenas_page_try_find_abandoned(mi_theap_t* theap, size_t sl
|
|
|
683
719
|
if (mi_bitmap_try_find_and_claim(bitmap, tseq, &slice_index, &mi_arena_try_claim_abandoned, arena)) {
|
|
684
720
|
// found an abandoned page of the right size
|
|
685
721
|
// and claimed ownership.
|
|
686
|
-
mi_page_t* page = (
|
|
722
|
+
mi_page_t* page = mi_arena_page_at_slice(arena, slice_index);
|
|
687
723
|
mi_assert_internal(mi_page_is_owned(page));
|
|
688
724
|
mi_assert_internal(mi_page_is_abandoned(page));
|
|
689
725
|
mi_assert_internal(mi_heap_has_page(heap, arena, page));
|
|
@@ -695,8 +731,7 @@ static mi_page_t* mi_arenas_page_try_find_abandoned(mi_theap_t* theap, size_t sl
|
|
|
695
731
|
mi_assert_internal(mi_bbitmap_is_clearN(arena->slices_free, slice_index, slice_count));
|
|
696
732
|
mi_assert_internal(page->slice_committed > 0 || mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count));
|
|
697
733
|
mi_assert_internal(mi_bitmap_is_setN(arena->slices_dirty, slice_index, slice_count));
|
|
698
|
-
mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
|
|
699
|
-
mi_assert_internal(_mi_ptr_page(page)==page);
|
|
734
|
+
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
|
|
700
735
|
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
|
|
701
736
|
mi_assert_internal(mi_page_block_size(page) == block_size);
|
|
702
737
|
mi_assert_internal(!mi_page_is_full(page));
|
|
@@ -708,146 +743,196 @@ static mi_page_t* mi_arenas_page_try_find_abandoned(mi_theap_t* theap, size_t sl
|
|
|
708
743
|
return NULL;
|
|
709
744
|
}
|
|
710
745
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
{
|
|
715
|
-
const bool allow_large = (MI_SECURE < 2); // 2 = guard page at end of each arena page
|
|
716
|
-
const bool os_align = (block_alignment > MI_PAGE_MAX_OVERALLOC_ALIGN);
|
|
746
|
+
static uint8_t* mi_arenas_page_alloc_fresh_area(mi_theap_t* theap, size_t slice_count, size_t block_size, size_t block_alignment, bool os_align, bool commit, mi_memid_t* memid) {
|
|
747
|
+
MI_UNUSED_RELEASE(block_size);
|
|
748
|
+
const bool allow_large = (MI_SECURE < 5); // 5 = guard page at end of each arena page
|
|
717
749
|
const size_t page_alignment = MI_ARENA_SLICE_ALIGN;
|
|
718
750
|
|
|
719
|
-
mi_heap_t* const heap = theap
|
|
751
|
+
mi_heap_t* const heap = _mi_theap_heap(theap);
|
|
720
752
|
mi_tld_t* const tld = theap->tld;
|
|
721
753
|
mi_arena_t* const req_arena = heap->exclusive_arena;
|
|
722
754
|
const int numa_node = (heap->numa_node >= 0 ? heap->numa_node : tld->numa_node);
|
|
723
755
|
|
|
724
|
-
|
|
725
756
|
// try to allocate from free space in arena's
|
|
726
|
-
|
|
727
|
-
|
|
757
|
+
uint8_t* start = NULL;
|
|
758
|
+
*memid = _mi_memid_none();
|
|
728
759
|
const size_t alloc_size = mi_size_of_slices(slice_count);
|
|
729
760
|
if (!mi_option_is_enabled(mi_option_disallow_arena_alloc) && // allowed to allocate from arena's?
|
|
730
761
|
!os_align && // not large alignment
|
|
731
762
|
slice_count <= mi_arena_max_object_size()/MI_ARENA_SLICE_SIZE) // and not too large
|
|
732
763
|
{
|
|
733
|
-
|
|
734
|
-
if (
|
|
735
|
-
mi_arena_pages_t* const arena_pages = mi_heap_ensure_arena_pages(heap, memid
|
|
764
|
+
start = (uint8_t*)mi_arenas_try_alloc(heap, slice_count, page_alignment, commit, allow_large, req_arena, tld->thread_seq, numa_node, memid);
|
|
765
|
+
if (start != NULL) {
|
|
766
|
+
mi_arena_pages_t* const arena_pages = mi_heap_ensure_arena_pages(heap, memid->mem.arena.arena);
|
|
736
767
|
if (arena_pages==NULL) {
|
|
737
|
-
_mi_arenas_free(
|
|
738
|
-
|
|
768
|
+
_mi_arenas_free(start, mi_size_of_slices(slice_count), *memid); // roll back
|
|
769
|
+
start = NULL;
|
|
739
770
|
}
|
|
740
771
|
else {
|
|
741
|
-
|
|
742
|
-
|
|
772
|
+
// note: the following assert should hold if we could check it atomically, but in a concurrent setting we may already allocate in slice_count
|
|
773
|
+
// mi_assert_internal(mi_bitmap_is_clearN(arena_pages->pages, memid->mem.arena.slice_index, memid->mem.arena.slice_count));
|
|
774
|
+
mi_assert_internal(mi_bitmap_is_clear(arena_pages->pages, memid->mem.arena.slice_index));
|
|
775
|
+
mi_bitmap_set(arena_pages->pages, memid->mem.arena.slice_index);
|
|
743
776
|
}
|
|
744
777
|
}
|
|
745
778
|
}
|
|
746
779
|
|
|
747
780
|
// otherwise fall back to the OS
|
|
748
|
-
if (
|
|
781
|
+
if (start == NULL) {
|
|
749
782
|
if (os_align) {
|
|
750
783
|
// note: slice_count already includes the page
|
|
751
784
|
mi_assert_internal(slice_count >= mi_slice_count_of_size(block_size) + mi_slice_count_of_size(page_alignment));
|
|
752
|
-
|
|
785
|
+
start = (uint8_t*)mi_arena_os_alloc_aligned(alloc_size, block_alignment, page_alignment /* align offset */, commit, allow_large, req_arena, memid);
|
|
753
786
|
}
|
|
754
787
|
else {
|
|
755
|
-
|
|
788
|
+
start = (uint8_t*)mi_arena_os_alloc_aligned(alloc_size, page_alignment, 0 /* align offset */, commit, allow_large, req_arena, memid);
|
|
756
789
|
}
|
|
757
790
|
}
|
|
758
791
|
|
|
759
|
-
if (
|
|
760
|
-
mi_assert_internal(_mi_is_aligned(
|
|
761
|
-
mi_assert_internal(!os_align || _mi_is_aligned(
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
#if MI_SECURE < 2
|
|
765
|
-
const size_t page_noguard_size = alloc_size;
|
|
766
|
-
#else
|
|
767
|
-
mi_assert(alloc_size > _mi_os_secure_guard_page_size());
|
|
768
|
-
const size_t page_noguard_size = alloc_size - _mi_os_secure_guard_page_size();
|
|
769
|
-
if (memid.initially_committed) {
|
|
770
|
-
_mi_os_secure_guard_page_set_at((uint8_t*)page + page_noguard_size, memid);
|
|
771
|
-
}
|
|
772
|
-
#endif
|
|
773
|
-
|
|
774
|
-
// claimed free slices: initialize the page partly
|
|
775
|
-
if (!memid.initially_zero && memid.initially_committed) {
|
|
776
|
-
mi_track_mem_undefined(page, slice_count * MI_ARENA_SLICE_SIZE);
|
|
777
|
-
_mi_memzero_aligned(page, sizeof(*page));
|
|
778
|
-
}
|
|
779
|
-
else if (memid.initially_committed) {
|
|
780
|
-
mi_track_mem_defined(page, slice_count * MI_ARENA_SLICE_SIZE);
|
|
781
|
-
}
|
|
782
|
-
#if MI_DEBUG > 1
|
|
783
|
-
if (memid.initially_zero && memid.initially_committed) {
|
|
784
|
-
if (!mi_mem_is_zero(page, page_noguard_size)) {
|
|
785
|
-
_mi_error_message(EFAULT, "internal error: page memory was not zero initialized.\n");
|
|
786
|
-
memid.initially_zero = false;
|
|
787
|
-
_mi_memzero_aligned(page, sizeof(*page));
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
#endif
|
|
791
|
-
mi_assert(MI_PAGE_INFO_SIZE >= mi_page_info_size());
|
|
792
|
+
if (start == NULL) return NULL;
|
|
793
|
+
mi_assert_internal(_mi_is_aligned(start, MI_PAGE_ALIGN));
|
|
794
|
+
mi_assert_internal(!os_align || _mi_is_aligned(start + page_alignment, block_alignment));
|
|
795
|
+
return start;
|
|
796
|
+
}
|
|
792
797
|
|
|
793
|
-
|
|
798
|
+
static size_t mi_page_block_start(size_t block_size, bool os_align)
|
|
799
|
+
{
|
|
794
800
|
#if MI_GUARDED
|
|
795
801
|
// in a guarded build, we align pages with blocks a multiple of an OS page size, to the OS page size
|
|
796
802
|
// this ensures that all blocks in such pages are OS page size aligned (which is needed for the guard pages)
|
|
797
803
|
const size_t os_page_size = _mi_os_page_size();
|
|
798
804
|
mi_assert_internal(MI_PAGE_ALIGN >= os_page_size);
|
|
799
805
|
if (!os_align && block_size % os_page_size == 0 && block_size > os_page_size /* at least 2 or more */ ) {
|
|
800
|
-
|
|
806
|
+
return _mi_align_up(mi_page_info_size(), os_page_size);
|
|
801
807
|
}
|
|
802
808
|
else
|
|
803
809
|
#endif
|
|
804
810
|
if (os_align) {
|
|
805
|
-
|
|
811
|
+
return MI_PAGE_ALIGN;
|
|
806
812
|
}
|
|
807
813
|
else if (_mi_is_power_of_two(block_size) && block_size <= MI_PAGE_MAX_START_BLOCK_ALIGN2) {
|
|
808
814
|
// naturally align power-of-2 blocks up to MI_PAGE_MAX_START_BLOCK_ALIGN2 size (4KiB)
|
|
809
|
-
|
|
815
|
+
return _mi_align_up(mi_page_info_size(), block_size);
|
|
810
816
|
}
|
|
811
817
|
else if (block_size != 0 && (block_size % MI_PAGE_OSPAGE_BLOCK_ALIGN2) == 0) {
|
|
812
818
|
// also align large pages that are a multiple of MI_PAGE_OSPAGE_BLOCK_ALIGN2 (4KiB)
|
|
813
|
-
|
|
819
|
+
return _mi_align_up(mi_page_info_size(), MI_PAGE_OSPAGE_BLOCK_ALIGN2);
|
|
814
820
|
}
|
|
815
821
|
else {
|
|
816
822
|
// otherwise start after the info
|
|
817
|
-
|
|
823
|
+
return mi_page_info_size();
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// Allocate a fresh page
|
|
828
|
+
static mi_page_t* mi_arenas_page_alloc_fresh(mi_theap_t* theap, size_t slice_count, size_t block_size, size_t block_alignment, bool commit)
|
|
829
|
+
{
|
|
830
|
+
const bool os_align = (block_alignment > MI_PAGE_MAX_OVERALLOC_ALIGN);
|
|
831
|
+
const size_t alloc_size = mi_size_of_slices(slice_count);
|
|
832
|
+
mi_memid_t memid = _mi_memid_none();
|
|
833
|
+
uint8_t* const slice_start = mi_arenas_page_alloc_fresh_area(theap,slice_count,block_size,block_alignment,os_align,commit,&memid);
|
|
834
|
+
if (!slice_start) return NULL;
|
|
835
|
+
|
|
836
|
+
// guard page at the end of mimalloc page?
|
|
837
|
+
#if MI_SECURE>=5
|
|
838
|
+
mi_assert(alloc_size > _mi_os_secure_guard_page_size());
|
|
839
|
+
const size_t page_noguard_size = alloc_size - _mi_os_secure_guard_page_size();
|
|
840
|
+
if (memid.initially_committed) {
|
|
841
|
+
_mi_os_secure_guard_page_set_at(slice_start + page_noguard_size, memid);
|
|
842
|
+
}
|
|
843
|
+
#else
|
|
844
|
+
const size_t page_noguard_size = alloc_size;
|
|
845
|
+
#endif
|
|
846
|
+
|
|
847
|
+
// allocate the page meta info
|
|
848
|
+
mi_page_t* page = NULL;
|
|
849
|
+
bool page_meta_is_separate = false;
|
|
850
|
+
size_t block_start = 0;
|
|
851
|
+
|
|
852
|
+
// allocate page meta info at the arena start?
|
|
853
|
+
if (memid.memkind == MI_MEM_ARENA) {
|
|
854
|
+
mi_arena_t* const arena = memid.mem.arena.arena;
|
|
855
|
+
if (arena->pages_meta != NULL) {
|
|
856
|
+
mi_assert_internal(MI_PAGE_META_IS_SEPARATED!=0);
|
|
857
|
+
mi_page_t* const page_meta = &arena->pages_meta[memid.mem.arena.slice_index];
|
|
858
|
+
mi_assert_internal(page_meta->block_size == 0);
|
|
859
|
+
#if MI_PAGE_META_ALIGNED_FREE_SMALL
|
|
860
|
+
// if `block_size <= MI_SMALL_SIZE_MAX` we put the page info in front of the slice,
|
|
861
|
+
// (note: it is important that `page_meta->block_size == 0` for `mi_arena_page_at_slice`)
|
|
862
|
+
if (block_size > MI_SMALL_SIZE_MAX)
|
|
863
|
+
#endif
|
|
864
|
+
{
|
|
865
|
+
page = page_meta;
|
|
866
|
+
page_meta_is_separate = true;
|
|
867
|
+
block_start = 0;
|
|
868
|
+
#if !defined(MI_PAGE_BLOCK_START_MAX_OFFSET)
|
|
869
|
+
#define MI_PAGE_BLOCK_START_MAX_OFFSET (8*MI_INTPTR_BITS) /* 512 */
|
|
870
|
+
#endif
|
|
871
|
+
if (block_size >= MI_INTPTR_SIZE && block_size <= MI_PAGE_BLOCK_START_MAX_OFFSET && _mi_is_power_of_two(block_size)) {
|
|
872
|
+
block_start += block_size;
|
|
873
|
+
}
|
|
874
|
+
mi_assert_internal(page->block_size == 0);
|
|
875
|
+
_mi_memzero_aligned(page, sizeof(*page));
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (page == NULL) {
|
|
880
|
+
// put page meta info in front of the slice
|
|
881
|
+
page = (mi_page_t*)slice_start;
|
|
882
|
+
block_start = mi_page_block_start(block_size, os_align);
|
|
818
883
|
}
|
|
819
|
-
const size_t reserved = (os_align ? 1 : (page_noguard_size - block_start) / block_size);
|
|
820
|
-
mi_assert_internal(reserved > 0 && reserved <= UINT16_MAX);
|
|
821
884
|
|
|
822
885
|
// commit first block?
|
|
823
886
|
size_t commit_size = 0;
|
|
824
887
|
if (!memid.initially_committed) {
|
|
825
888
|
commit_size = _mi_align_up(block_start + block_size, MI_PAGE_MIN_COMMIT_SIZE);
|
|
826
889
|
if (commit_size > page_noguard_size) { commit_size = page_noguard_size; }
|
|
827
|
-
bool is_zero;
|
|
828
|
-
if mi_unlikely(!mi_arena_commit( mi_memid_arena(memid),
|
|
829
|
-
_mi_arenas_free(
|
|
890
|
+
bool is_zero = false;
|
|
891
|
+
if mi_unlikely(!mi_arena_commit( mi_memid_arena(memid), slice_start, commit_size, &is_zero, 0)) {
|
|
892
|
+
_mi_arenas_free(slice_start, alloc_size, memid);
|
|
830
893
|
return NULL;
|
|
831
894
|
}
|
|
832
|
-
|
|
833
|
-
|
|
895
|
+
}
|
|
896
|
+
if (!memid.initially_zero && !page_meta_is_separate) {
|
|
897
|
+
_mi_memzero_aligned(page, sizeof(*page));
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// claimed free slices: initialize the page partly
|
|
901
|
+
if (!memid.initially_zero && memid.initially_committed) {
|
|
902
|
+
mi_track_mem_undefined(slice_start, slice_count * MI_ARENA_SLICE_SIZE);
|
|
903
|
+
}
|
|
904
|
+
else if (memid.initially_committed) {
|
|
905
|
+
mi_track_mem_defined(slice_start, slice_count * MI_ARENA_SLICE_SIZE);
|
|
906
|
+
}
|
|
907
|
+
#if MI_DEBUG > 1
|
|
908
|
+
if (memid.initially_zero && memid.initially_committed) {
|
|
909
|
+
if (!mi_mem_is_zero(slice_start, page_noguard_size)) {
|
|
910
|
+
_mi_error_message(EFAULT, "internal error: page memory was not zero initialized.\n");
|
|
911
|
+
memid.initially_zero = false;
|
|
912
|
+
if (block_start > 0) { _mi_memzero_aligned(page, sizeof(*page)); }
|
|
834
913
|
}
|
|
835
914
|
}
|
|
915
|
+
#endif
|
|
916
|
+
const size_t reserved = (os_align ? 1 : (page_noguard_size - block_start) / block_size);
|
|
917
|
+
mi_assert_internal(reserved > 0 && reserved <= UINT16_MAX);
|
|
836
918
|
|
|
837
919
|
// initialize
|
|
838
920
|
page->reserved = (uint16_t)reserved;
|
|
839
|
-
page->page_start =
|
|
921
|
+
page->page_start = slice_start + block_start;
|
|
840
922
|
page->block_size = block_size;
|
|
841
923
|
page->slice_committed = commit_size;
|
|
842
924
|
page->memid = memid;
|
|
843
925
|
page->free_is_zero = memid.initially_zero;
|
|
926
|
+
mi_assert_internal(page->free==NULL);
|
|
927
|
+
mi_assert_internal(page_meta_is_separate == mi_page_meta_is_separated(page));
|
|
928
|
+
mi_assert_internal(mi_page_slice_start(page) == slice_start);
|
|
844
929
|
|
|
845
930
|
// and own it
|
|
846
931
|
mi_page_claim_ownership(page);
|
|
847
932
|
|
|
848
933
|
// register in the page map
|
|
849
934
|
if mi_unlikely(!_mi_page_map_register(page)) {
|
|
850
|
-
_mi_arenas_free(
|
|
935
|
+
_mi_arenas_free( slice_start, alloc_size, memid );
|
|
851
936
|
return NULL;
|
|
852
937
|
}
|
|
853
938
|
|
|
@@ -855,7 +940,7 @@ static mi_page_t* mi_arenas_page_alloc_fresh(mi_theap_t* theap, size_t slice_cou
|
|
|
855
940
|
mi_theap_stat_increase(theap, pages, 1);
|
|
856
941
|
mi_theap_stat_increase(theap, page_bins[_mi_page_stats_bin(page)], 1);
|
|
857
942
|
|
|
858
|
-
mi_assert_internal(
|
|
943
|
+
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page),MI_PAGE_ALIGN));
|
|
859
944
|
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
|
|
860
945
|
mi_assert_internal(mi_page_block_size(page) == block_size);
|
|
861
946
|
mi_assert_internal(mi_page_is_abandoned(page));
|
|
@@ -937,8 +1022,7 @@ mi_page_t* _mi_arenas_page_alloc(mi_theap_t* theap, size_t block_size, size_t bl
|
|
|
937
1022
|
return NULL;
|
|
938
1023
|
}
|
|
939
1024
|
// mi_assert_internal(page == NULL || _mi_page_segment(page)->subproc == tld->subproc);
|
|
940
|
-
mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
|
|
941
|
-
mi_assert_internal(_mi_ptr_page(page)==page);
|
|
1025
|
+
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
|
|
942
1026
|
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
|
|
943
1027
|
mi_assert_internal(block_alignment <= MI_PAGE_MAX_OVERALLOC_ALIGN || _mi_is_aligned(mi_page_start(page), block_alignment));
|
|
944
1028
|
|
|
@@ -946,8 +1030,8 @@ mi_page_t* _mi_arenas_page_alloc(mi_theap_t* theap, size_t block_size, size_t bl
|
|
|
946
1030
|
}
|
|
947
1031
|
|
|
948
1032
|
void _mi_arenas_page_free(mi_page_t* page, mi_theap_t* current_theapx) {
|
|
949
|
-
mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
|
|
950
|
-
mi_assert_internal(_mi_ptr_page(page)==page);
|
|
1033
|
+
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
|
|
1034
|
+
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
|
|
951
1035
|
mi_assert_internal(mi_page_is_owned(page));
|
|
952
1036
|
mi_assert_internal(mi_page_all_free(page));
|
|
953
1037
|
mi_assert_internal(mi_page_is_abandoned(page));
|
|
@@ -983,9 +1067,9 @@ void _mi_arenas_page_free(mi_page_t* page, mi_theap_t* current_theapx) {
|
|
|
983
1067
|
|
|
984
1068
|
// recommit guard page at the end?
|
|
985
1069
|
// we must do this since we may later allocate large spans over this page and cannot have a guard page in between
|
|
986
|
-
#if MI_SECURE >=
|
|
1070
|
+
#if MI_SECURE >= 5
|
|
987
1071
|
if (!page->memid.is_pinned) {
|
|
988
|
-
_mi_os_secure_guard_page_reset_before((
|
|
1072
|
+
_mi_os_secure_guard_page_reset_before(mi_page_slice_start(page) + mi_page_full_size(page), page->memid);
|
|
989
1073
|
}
|
|
990
1074
|
#endif
|
|
991
1075
|
|
|
@@ -1018,7 +1102,8 @@ void _mi_arenas_page_free(mi_page_t* page, mi_theap_t* current_theapx) {
|
|
|
1018
1102
|
mi_assert_internal(mi_bitmap_is_setN(arena->slices_committed, slice_index, slice_count));
|
|
1019
1103
|
}
|
|
1020
1104
|
}
|
|
1021
|
-
|
|
1105
|
+
if (mi_page_meta_is_separated(page)) { page->block_size = 0; } // for assertion checking
|
|
1106
|
+
_mi_arenas_free( mi_page_slice_start(page), mi_page_full_size(page), page->memid);
|
|
1022
1107
|
}
|
|
1023
1108
|
|
|
1024
1109
|
/* -----------------------------------------------------------
|
|
@@ -1026,8 +1111,8 @@ void _mi_arenas_page_free(mi_page_t* page, mi_theap_t* current_theapx) {
|
|
|
1026
1111
|
----------------------------------------------------------- */
|
|
1027
1112
|
|
|
1028
1113
|
void _mi_arenas_page_abandon(mi_page_t* page, mi_theap_t* current_theap) {
|
|
1029
|
-
mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
|
|
1030
|
-
mi_assert_internal(_mi_ptr_page(page)==page);
|
|
1114
|
+
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
|
|
1115
|
+
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
|
|
1031
1116
|
mi_assert_internal(mi_page_is_owned(page));
|
|
1032
1117
|
mi_assert_internal(mi_page_is_abandoned(page));
|
|
1033
1118
|
mi_assert_internal(!mi_page_all_free(page));
|
|
@@ -1035,7 +1120,7 @@ void _mi_arenas_page_abandon(mi_page_t* page, mi_theap_t* current_theap) {
|
|
|
1035
1120
|
mi_assert_internal(_mi_thread_id()==current_theap->tld->thread_id);
|
|
1036
1121
|
// mi_assert_internal(current_theap == _mi_page_associated_theap(page));
|
|
1037
1122
|
|
|
1038
|
-
mi_heap_t* heap = mi_page_heap(page); mi_assert_internal(heap==current_theap
|
|
1123
|
+
mi_heap_t* heap = mi_page_heap(page); mi_assert_internal(heap==_mi_theap_heap(current_theap));
|
|
1039
1124
|
if (page->memid.memkind==MI_MEM_ARENA && !mi_page_is_full(page)) {
|
|
1040
1125
|
// make available for allocations
|
|
1041
1126
|
size_t bin = _mi_bin(mi_page_block_size(page));
|
|
@@ -1053,7 +1138,7 @@ void _mi_arenas_page_abandon(mi_page_t* page, mi_theap_t* current_theap) {
|
|
|
1053
1138
|
const bool was_clear = mi_bitmap_set(arena_pages->pages_abandoned[bin], slice_index);
|
|
1054
1139
|
MI_UNUSED(was_clear); mi_assert_internal(was_clear);
|
|
1055
1140
|
mi_atomic_increment_relaxed(&heap->abandoned_count[bin]);
|
|
1056
|
-
mi_theap_stat_increase(current_theap, pages_abandoned, 1);
|
|
1141
|
+
mi_theap_stat_increase(current_theap, pages_abandoned, 1);
|
|
1057
1142
|
}
|
|
1058
1143
|
else {
|
|
1059
1144
|
// page is full (or a singleton), or the page is OS/externally allocated
|
|
@@ -1076,8 +1161,8 @@ void _mi_arenas_page_abandon(mi_page_t* page, mi_theap_t* current_theap) {
|
|
|
1076
1161
|
|
|
1077
1162
|
// this is called from `free.c:mi_free_try_collect_mt` only.
|
|
1078
1163
|
bool _mi_arenas_page_try_reabandon_to_mapped(mi_page_t* page) {
|
|
1079
|
-
mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
|
|
1080
|
-
mi_assert_internal(_mi_ptr_page(page)==page);
|
|
1164
|
+
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
|
|
1165
|
+
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
|
|
1081
1166
|
mi_assert_internal(mi_page_is_owned(page));
|
|
1082
1167
|
mi_assert_internal(mi_page_is_abandoned(page));
|
|
1083
1168
|
mi_assert_internal(!mi_page_is_abandoned_mapped(page));
|
|
@@ -1104,8 +1189,8 @@ bool _mi_arenas_page_try_reabandon_to_mapped(mi_page_t* page) {
|
|
|
1104
1189
|
|
|
1105
1190
|
// called from `mi_free` if trying to unabandon an abandoned page
|
|
1106
1191
|
void _mi_arenas_page_unabandon(mi_page_t* page, mi_theap_t* current_theapx) {
|
|
1107
|
-
mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
|
|
1108
|
-
mi_assert_internal(_mi_ptr_page(page)==page);
|
|
1192
|
+
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
|
|
1193
|
+
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
|
|
1109
1194
|
mi_assert_internal(mi_page_is_owned(page));
|
|
1110
1195
|
mi_assert_internal(mi_page_is_abandoned(page));
|
|
1111
1196
|
mi_assert_internal(current_theapx==NULL || _mi_thread_id()==current_theapx->tld->thread_id);
|
|
@@ -1183,7 +1268,7 @@ void _mi_arenas_free(void* p, size_t size, mi_memid_t memid) {
|
|
|
1183
1268
|
}
|
|
1184
1269
|
mi_assert_internal(slice_index < arena->slice_count);
|
|
1185
1270
|
mi_assert_internal(slice_index >= mi_arena_info_slices(arena));
|
|
1186
|
-
if (slice_index < mi_arena_info_slices(arena) || slice_index
|
|
1271
|
+
if (slice_index < mi_arena_info_slices(arena) || slice_index >= arena->slice_count) {
|
|
1187
1272
|
_mi_error_message(EINVAL, "trying to free from an invalid arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid);
|
|
1188
1273
|
return;
|
|
1189
1274
|
}
|
|
@@ -1220,25 +1305,41 @@ void _mi_arenas_collect(bool force_purge, bool visit_all, mi_tld_t* tld) {
|
|
|
1220
1305
|
|
|
1221
1306
|
|
|
1222
1307
|
// Is a pointer contained in the given arena area?
|
|
1223
|
-
bool
|
|
1224
|
-
|
|
1225
|
-
|
|
1308
|
+
static bool mi_arena_strictly_contains(mi_arena_t* arena, const void* p) {
|
|
1309
|
+
return (arena != NULL &&
|
|
1310
|
+
mi_arena_start(arena) <= (const uint8_t*)p &&
|
|
1226
1311
|
mi_arena_start(arena) + mi_size_of_slices(arena->slice_count) >(const uint8_t*)p);
|
|
1227
1312
|
}
|
|
1228
1313
|
|
|
1229
1314
|
// Is a pointer inside any of our arenas?
|
|
1230
|
-
bool
|
|
1315
|
+
static bool mi_arenas_contain_ex(const void* p, mi_arena_t* parent) {
|
|
1231
1316
|
mi_subproc_t* subproc = _mi_subproc();
|
|
1232
1317
|
const size_t max_arena = mi_arenas_get_count(subproc);
|
|
1233
1318
|
for (size_t i = 0; i < max_arena; i++) {
|
|
1234
1319
|
mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &subproc->arenas[i]);
|
|
1235
|
-
if (arena != NULL
|
|
1236
|
-
|
|
1320
|
+
if (arena != NULL) {
|
|
1321
|
+
if (parent==NULL || arena==parent || arena->parent==parent) {
|
|
1322
|
+
if (mi_arena_strictly_contains(arena, p)) {
|
|
1323
|
+
return true;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1237
1326
|
}
|
|
1238
1327
|
}
|
|
1239
1328
|
return false;
|
|
1240
1329
|
}
|
|
1241
1330
|
|
|
1331
|
+
// Is a pointer inside any of our arenas?
|
|
1332
|
+
bool _mi_arenas_contain(const void* p) {
|
|
1333
|
+
return mi_arenas_contain_ex(p, NULL);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
// Is a pointer contained in the given arena area?
|
|
1337
|
+
bool mi_arena_contains(mi_arena_id_t arena_id, const void* p) {
|
|
1338
|
+
mi_arena_t* arena = _mi_arena_from_id(arena_id);
|
|
1339
|
+
if (arena==NULL) return false;
|
|
1340
|
+
else if (mi_arena_strictly_contains(arena, p)) return true;
|
|
1341
|
+
else return mi_arenas_contain_ex(p, arena); // maybe a subarena?
|
|
1342
|
+
}
|
|
1242
1343
|
|
|
1243
1344
|
|
|
1244
1345
|
/* -----------------------------------------------------------
|
|
@@ -1262,7 +1363,7 @@ static void mi_arenas_unsafe_destroy(mi_subproc_t* subproc) {
|
|
|
1262
1363
|
}
|
|
1263
1364
|
// try to lower the max arena.
|
|
1264
1365
|
size_t expected = arena_count;
|
|
1265
|
-
mi_atomic_cas_strong_acq_rel(&subproc->arena_count, &expected, 0);
|
|
1366
|
+
mi_atomic_cas_strong_acq_rel(&subproc->arena_count, &expected, (size_t)0);
|
|
1266
1367
|
}
|
|
1267
1368
|
|
|
1268
1369
|
|
|
@@ -1282,7 +1383,7 @@ static bool mi_arenas_add(mi_subproc_t* subproc, mi_arena_t* arena, mi_arena_id_
|
|
|
1282
1383
|
{
|
|
1283
1384
|
mi_assert_internal(arena != NULL);
|
|
1284
1385
|
mi_assert_internal(arena->slice_count > 0);
|
|
1285
|
-
if (arena_id != NULL) { *arena_id =
|
|
1386
|
+
if (arena_id != NULL) { *arena_id = _mi_arena_id_none(); }
|
|
1286
1387
|
|
|
1287
1388
|
// try to find a NULL entry
|
|
1288
1389
|
mi_arena_t* expected;
|
|
@@ -1293,7 +1394,7 @@ static bool mi_arenas_add(mi_subproc_t* subproc, mi_arena_t* arena, mi_arena_id_
|
|
|
1293
1394
|
expected = NULL;
|
|
1294
1395
|
if (mi_atomic_cas_ptr_strong_release(mi_arena_t, &subproc->arenas[i], &expected, arena)) {
|
|
1295
1396
|
// success
|
|
1296
|
-
if (arena_id != NULL) { *arena_id = arena; }
|
|
1397
|
+
if (arena_id != NULL) { *arena_id = mi_arena_id_from_arena(arena); }
|
|
1297
1398
|
return true;
|
|
1298
1399
|
}
|
|
1299
1400
|
}
|
|
@@ -1306,7 +1407,7 @@ static bool mi_arenas_add(mi_subproc_t* subproc, mi_arena_t* arena, mi_arena_id_
|
|
|
1306
1407
|
expected = NULL;
|
|
1307
1408
|
if (mi_atomic_cas_ptr_strong_release(mi_arena_t, &subproc->arenas[count], &expected, arena)) {
|
|
1308
1409
|
mi_subproc_stat_counter_increase(arena->subproc, arena_count, 1);
|
|
1309
|
-
if (arena_id != NULL) { *arena_id = arena; }
|
|
1410
|
+
if (arena_id != NULL) { *arena_id = mi_arena_id_from_arena(arena); }
|
|
1310
1411
|
return true;
|
|
1311
1412
|
}
|
|
1312
1413
|
}
|
|
@@ -1335,7 +1436,12 @@ static size_t mi_arena_info_slices_needed(size_t slice_count, size_t* bitmap_bas
|
|
|
1335
1436
|
const size_t base_size = _mi_align_up(sizeof(mi_arena_t), MI_BCHUNK_SIZE);
|
|
1336
1437
|
const size_t bitmaps_count = 4 + MI_ARENA_BIN_COUNT; // commit, dirty, purge, pages, and abandoned
|
|
1337
1438
|
const size_t bitmaps_size = bitmaps_count * mi_bitmap_size(slice_count, NULL) + mi_bbitmap_size(slice_count, NULL); // + free
|
|
1338
|
-
|
|
1439
|
+
#if MI_PAGE_META_IS_SEPARATED
|
|
1440
|
+
const size_t pages_size = slice_count * sizeof(mi_page_t);
|
|
1441
|
+
#else
|
|
1442
|
+
const size_t pages_size = 0;
|
|
1443
|
+
#endif
|
|
1444
|
+
const size_t size = base_size + bitmaps_size + pages_size;
|
|
1339
1445
|
|
|
1340
1446
|
const size_t os_page_size = _mi_os_page_size();
|
|
1341
1447
|
const size_t info_size = _mi_align_up(size, os_page_size) + _mi_os_secure_guard_page_size();
|
|
@@ -1372,41 +1478,29 @@ static mi_arena_pages_t* mi_arena_pages_alloc(mi_arena_t* arena) {
|
|
|
1372
1478
|
return arena_pages;
|
|
1373
1479
|
}
|
|
1374
1480
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1481
|
+
static mi_arena_t* mi_arena_initialize(mi_subproc_t* subproc, void* start,
|
|
1482
|
+
size_t slice_count, mi_arena_t* parent, size_t total_size,
|
|
1483
|
+
int numa_node, bool exclusive,
|
|
1484
|
+
mi_memid_t memid, mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id)
|
|
1378
1485
|
{
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
if (arena_id != NULL) { *arena_id = _mi_arena_id_none(); }
|
|
1382
|
-
if (start==NULL) return false;
|
|
1383
|
-
if (!_mi_is_aligned(start,MI_ARENA_SLICE_SIZE)) {
|
|
1384
|
-
// we can align the start since the memid tracks the real base of the memory.
|
|
1385
|
-
void* const aligned_start = _mi_align_up_ptr(start, MI_ARENA_SLICE_SIZE);
|
|
1386
|
-
const size_t diff = (uint8_t*)aligned_start - (uint8_t*)start;
|
|
1387
|
-
if (diff >= size || (size - diff) < MI_ARENA_SLICE_SIZE) {
|
|
1388
|
-
_mi_warning_message("after alignment, the size of the arena becomes too small (memory at %p with size %zu)\n", start, size);
|
|
1389
|
-
return false;
|
|
1390
|
-
}
|
|
1391
|
-
start = aligned_start;
|
|
1392
|
-
size = size - diff;
|
|
1393
|
-
}
|
|
1486
|
+
mi_assert_internal(_mi_is_aligned(start,MI_ARENA_SLICE_ALIGN));
|
|
1487
|
+
mi_assert_internal(mi_size_of_slices(slice_count)>=MI_ARENA_MIN_SIZE);
|
|
1394
1488
|
|
|
1395
|
-
const size_t slice_count = _mi_align_down(size / MI_ARENA_SLICE_SIZE, MI_BCHUNK_BITS);
|
|
1396
1489
|
if (slice_count > MI_BITMAP_MAX_BIT_COUNT) { // 16 GiB for now
|
|
1397
|
-
//
|
|
1398
|
-
_mi_warning_message("cannot use OS memory since it is too large (size %zu MiB, maximum is %zu MiB)",
|
|
1399
|
-
return
|
|
1490
|
+
// note: this should never happen if called from `mi_manage_os_memory` (as that allocates sub-arenas when needed)
|
|
1491
|
+
_mi_warning_message("cannot use OS memory since it is too large (size %zu MiB, maximum is %zu MiB)", mi_size_of_slices(slice_count)/MI_MiB, mi_size_of_slices(MI_BITMAP_MAX_BIT_COUNT)/MI_MiB);
|
|
1492
|
+
return NULL;
|
|
1400
1493
|
}
|
|
1494
|
+
|
|
1401
1495
|
size_t bitmap_base;
|
|
1402
1496
|
const size_t info_slices = mi_arena_info_slices_needed(slice_count, &bitmap_base);
|
|
1403
1497
|
if (slice_count < info_slices+1) {
|
|
1404
|
-
_mi_warning_message("cannot use OS memory since it is not large enough (size %zu KiB, minimum required is %zu KiB)",
|
|
1405
|
-
return
|
|
1498
|
+
_mi_warning_message("cannot use OS memory since it is not large enough (size %zu KiB, minimum required is %zu KiB)", mi_size_of_slices(slice_count)/MI_KiB, mi_size_of_slices(info_slices+1)/MI_KiB);
|
|
1499
|
+
return NULL;
|
|
1406
1500
|
}
|
|
1407
1501
|
else if (info_slices >= MI_ARENA_MAX_CHUNK_OBJ_SLICES) {
|
|
1408
|
-
_mi_warning_message("cannot use OS memory since it is too large with respect to the maximum object size (size %zu MiB, meta-info slices %zu, maximum object slices are %zu)",
|
|
1409
|
-
return
|
|
1502
|
+
_mi_warning_message("cannot use OS memory since it is too large with respect to the maximum object size (size %zu MiB, meta-info slices %zu, maximum object slices are %zu)", mi_size_of_slices(slice_count)/MI_MiB, info_slices, MI_ARENA_MAX_CHUNK_OBJ_SLICES);
|
|
1503
|
+
return NULL;
|
|
1410
1504
|
}
|
|
1411
1505
|
|
|
1412
1506
|
mi_arena_t* arena = (mi_arena_t*)start;
|
|
@@ -1425,11 +1519,11 @@ static bool mi_manage_os_memory_ex2(mi_subproc_t* subproc, void* start, size_t s
|
|
|
1425
1519
|
}
|
|
1426
1520
|
if (!ok) {
|
|
1427
1521
|
_mi_warning_message("unable to commit meta-data for OS memory");
|
|
1428
|
-
return
|
|
1522
|
+
return NULL;
|
|
1429
1523
|
}
|
|
1430
1524
|
}
|
|
1431
1525
|
else if (!memid.is_pinned) {
|
|
1432
|
-
// if MI_SECURE, set a guard page at the end
|
|
1526
|
+
// if MI_SECURE, set a guard page at the end of the arena info
|
|
1433
1527
|
// todo: this does not respect the commit_fun as the memid is of external memory
|
|
1434
1528
|
_mi_os_secure_guard_page_set_before((uint8_t*)arena + mi_size_of_slices(info_slices), memid);
|
|
1435
1529
|
}
|
|
@@ -1438,27 +1532,39 @@ static bool mi_manage_os_memory_ex2(mi_subproc_t* subproc, void* start, size_t s
|
|
|
1438
1532
|
}
|
|
1439
1533
|
|
|
1440
1534
|
// init
|
|
1441
|
-
arena->subproc
|
|
1442
|
-
arena->memid
|
|
1535
|
+
arena->subproc = subproc;
|
|
1536
|
+
arena->memid = memid;
|
|
1443
1537
|
arena->is_exclusive = exclusive;
|
|
1444
|
-
arena->slice_count
|
|
1445
|
-
arena->info_slices
|
|
1446
|
-
|
|
1538
|
+
arena->slice_count = slice_count;
|
|
1539
|
+
arena->info_slices = info_slices;
|
|
1540
|
+
if (numa_node<0 && mi_option_is_enabled(mi_option_arena_is_numa_local)) {
|
|
1541
|
+
arena->numa_node = _mi_os_numa_node();
|
|
1542
|
+
}
|
|
1543
|
+
else {
|
|
1544
|
+
arena->numa_node = numa_node;
|
|
1545
|
+
}
|
|
1447
1546
|
arena->purge_expire = 0;
|
|
1448
|
-
arena->commit_fun
|
|
1547
|
+
arena->commit_fun = commit_fun;
|
|
1449
1548
|
arena->commit_fun_arg = commit_fun_arg;
|
|
1450
|
-
|
|
1549
|
+
arena->parent = parent;
|
|
1550
|
+
arena->total_size = total_size;
|
|
1451
1551
|
|
|
1452
1552
|
// init bitmaps
|
|
1453
1553
|
uint8_t* base = mi_arena_start(arena) + bitmap_base;
|
|
1454
|
-
arena->slices_free = mi_arena_bbitmap_init(slice_count
|
|
1455
|
-
arena->slices_committed = mi_arena_bitmap_init(slice_count
|
|
1456
|
-
arena->slices_dirty = mi_arena_bitmap_init(slice_count
|
|
1554
|
+
arena->slices_free = mi_arena_bbitmap_init(slice_count, &base);
|
|
1555
|
+
arena->slices_committed = mi_arena_bitmap_init(slice_count, &base);
|
|
1556
|
+
arena->slices_dirty = mi_arena_bitmap_init(slice_count, &base);
|
|
1457
1557
|
arena->slices_purge = mi_arena_bitmap_init(slice_count, &base);
|
|
1458
1558
|
arena->pages_main.pages = mi_arena_bitmap_init(slice_count, &base);
|
|
1459
|
-
for(
|
|
1460
|
-
arena->pages_main.pages_abandoned[i] = mi_arena_bitmap_init(slice_count
|
|
1559
|
+
for (size_t i = 0; i < MI_ARENA_BIN_COUNT; i++) {
|
|
1560
|
+
arena->pages_main.pages_abandoned[i] = mi_arena_bitmap_init(slice_count, &base);
|
|
1461
1561
|
}
|
|
1562
|
+
#if MI_PAGE_META_IS_SEPARATED
|
|
1563
|
+
arena->pages_meta = (mi_page_t*)base;
|
|
1564
|
+
base += (slice_count * sizeof(mi_page_t));
|
|
1565
|
+
#else
|
|
1566
|
+
arena->pages_meta = NULL;
|
|
1567
|
+
#endif
|
|
1462
1568
|
mi_assert_internal(mi_size_of_slices(info_slices) >= (size_t)(base - mi_arena_start(arena)));
|
|
1463
1569
|
|
|
1464
1570
|
// reserve our meta info (and reserve slices outside the memory area)
|
|
@@ -1466,19 +1572,83 @@ static bool mi_manage_os_memory_ex2(mi_subproc_t* subproc, void* start, size_t s
|
|
|
1466
1572
|
if (memid.initially_committed) {
|
|
1467
1573
|
mi_bitmap_unsafe_setN(arena->slices_committed, 0, arena->slice_count);
|
|
1468
1574
|
}
|
|
1469
|
-
else {
|
|
1470
|
-
mi_bitmap_setN(arena->slices_committed, 0, info_slices, NULL);
|
|
1471
|
-
}
|
|
1472
1575
|
if (!memid.initially_zero) {
|
|
1473
1576
|
mi_bitmap_unsafe_setN(arena->slices_dirty, 0, arena->slice_count);
|
|
1474
1577
|
}
|
|
1475
|
-
else {
|
|
1476
|
-
mi_bitmap_setN(arena->slices_dirty, 0, info_slices, NULL);
|
|
1477
|
-
}
|
|
1478
1578
|
|
|
1479
|
-
|
|
1579
|
+
if (!mi_arenas_add(subproc, arena, arena_id)) { return NULL; }
|
|
1580
|
+
return arena;
|
|
1480
1581
|
}
|
|
1481
1582
|
|
|
1583
|
+
static bool mi_manage_os_memory_ex2(mi_subproc_t* subproc, void* start, size_t size, int numa_node, bool exclusive,
|
|
1584
|
+
mi_memid_t memid, mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id) mi_attr_noexcept
|
|
1585
|
+
{
|
|
1586
|
+
// checks
|
|
1587
|
+
mi_assert(_mi_is_aligned(start, MI_ARENA_SLICE_SIZE));
|
|
1588
|
+
mi_assert(start!=NULL);
|
|
1589
|
+
if (arena_id != NULL) { *arena_id = _mi_arena_id_none(); }
|
|
1590
|
+
if (start==NULL) return false;
|
|
1591
|
+
if (!_mi_is_aligned(start, MI_ARENA_SLICE_SIZE)) {
|
|
1592
|
+
// we can align the start since the memid tracks the real base of the memory.
|
|
1593
|
+
void* const aligned_start = _mi_align_up_ptr(start, MI_ARENA_SLICE_SIZE);
|
|
1594
|
+
const size_t diff = (uint8_t*)aligned_start - (uint8_t*)start;
|
|
1595
|
+
if (diff >= size || (size - diff) < MI_ARENA_SLICE_SIZE) {
|
|
1596
|
+
_mi_warning_message("after alignment, the size of the arena becomes too small (memory at %p with size %zu)\n", start, size);
|
|
1597
|
+
return false;
|
|
1598
|
+
}
|
|
1599
|
+
start = aligned_start;
|
|
1600
|
+
size = size - diff;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// allocate enough arena's to span the full memory area
|
|
1604
|
+
// the first arena is the owner, the rest are "sub-arena" (with `parent` pointing to the first one)
|
|
1605
|
+
size_t total_slice_count = _mi_align_down(size / MI_ARENA_SLICE_SIZE, MI_BCHUNK_BITS);
|
|
1606
|
+
size_t total_size = mi_size_of_slices(total_slice_count);
|
|
1607
|
+
if (total_size < MI_ARENA_MIN_SIZE) {
|
|
1608
|
+
_mi_warning_message("cannot use OS memory since it is not large enough (size %zu KiB, minimum required is %zu KiB)", size/MI_KiB, MI_ARENA_MIN_SIZE/MI_KiB);
|
|
1609
|
+
return false;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
mi_arena_t* parent = NULL;
|
|
1613
|
+
do {
|
|
1614
|
+
// counting down on the total_slice_count
|
|
1615
|
+
size_t slice_count = total_slice_count;
|
|
1616
|
+
if (slice_count > MI_BITMAP_MAX_BIT_COUNT) { // 16 GiB for now (with 64KiB slices)
|
|
1617
|
+
slice_count = MI_BITMAP_MAX_BIT_COUNT;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// initialize
|
|
1621
|
+
mi_arena_t* arena = mi_arena_initialize( subproc, start, slice_count, parent,
|
|
1622
|
+
(parent==NULL ? total_size : 0), numa_node, exclusive,
|
|
1623
|
+
memid, commit_fun, commit_fun_arg,
|
|
1624
|
+
(parent==NULL ? arena_id : NULL));
|
|
1625
|
+
if (arena==NULL) {
|
|
1626
|
+
// failed to initialize due to failing commit or too many arena's
|
|
1627
|
+
if (parent==NULL) {
|
|
1628
|
+
return false;
|
|
1629
|
+
}
|
|
1630
|
+
else {
|
|
1631
|
+
// partial success, but failed to use the full area..
|
|
1632
|
+
// todo: roll-back in this case? that requires a lock on the arena's array though
|
|
1633
|
+
mi_assert(mi_size_of_slices(total_slice_count) <= parent->total_size);
|
|
1634
|
+
parent->total_size -= mi_size_of_slices(total_slice_count);
|
|
1635
|
+
return true;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// success
|
|
1640
|
+
if (parent==NULL) {
|
|
1641
|
+
parent = arena;
|
|
1642
|
+
memid.memkind = MI_MEM_NONE;
|
|
1643
|
+
}
|
|
1644
|
+
mi_assert(slice_count <= total_slice_count);
|
|
1645
|
+
total_slice_count -= slice_count;
|
|
1646
|
+
start = (uint8_t*)start + mi_size_of_slices(slice_count);
|
|
1647
|
+
}
|
|
1648
|
+
while (total_slice_count > 0);
|
|
1649
|
+
|
|
1650
|
+
return true;
|
|
1651
|
+
}
|
|
1482
1652
|
|
|
1483
1653
|
bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_pinned, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept {
|
|
1484
1654
|
mi_memid_t memid = _mi_memid_create(MI_MEM_EXTERNAL);
|
|
@@ -1490,7 +1660,7 @@ bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is
|
|
|
1490
1660
|
return mi_manage_os_memory_ex2(_mi_subproc(), start, size, numa_node, exclusive, memid, NULL, NULL, arena_id);
|
|
1491
1661
|
}
|
|
1492
1662
|
|
|
1493
|
-
bool mi_manage_memory(void* start, size_t size, bool is_committed, bool
|
|
1663
|
+
bool mi_manage_memory(void* start, size_t size, bool is_committed, bool is_pinned, bool is_zero, int numa_node, bool exclusive, mi_commit_fun_t* commit_fun, void* commit_fun_arg, mi_arena_id_t* arena_id) mi_attr_noexcept
|
|
1494
1664
|
{
|
|
1495
1665
|
mi_memid_t memid = _mi_memid_create(MI_MEM_EXTERNAL);
|
|
1496
1666
|
memid.mem.os.base = start;
|
|
@@ -1543,7 +1713,7 @@ int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noe
|
|
|
1543
1713
|
// Return idx of the slice past the last used slice
|
|
1544
1714
|
static size_t mi_arena_used_slices(mi_arena_t* arena) {
|
|
1545
1715
|
size_t idx;
|
|
1546
|
-
if (
|
|
1716
|
+
if (mi_bbitmap_bsr_inv(arena->slices_free, &idx)) {
|
|
1547
1717
|
return (idx + 1);
|
|
1548
1718
|
}
|
|
1549
1719
|
else {
|
|
@@ -1602,7 +1772,7 @@ static size_t mi_debug_show_page_bfield(char* buf, size_t* k, mi_arena_t* arena,
|
|
|
1602
1772
|
void* start = mi_arena_slice_start(arena, slice_index + bit);
|
|
1603
1773
|
mi_page_t* page = _mi_safe_ptr_page(start);
|
|
1604
1774
|
char c = ' ';
|
|
1605
|
-
if (start==page) {
|
|
1775
|
+
if (page!=NULL && start==mi_page_slice_start(page)) {
|
|
1606
1776
|
mi_assert_internal(bit_of_page <= 0);
|
|
1607
1777
|
bit_set_count++;
|
|
1608
1778
|
c = 'p';
|
|
@@ -1625,7 +1795,7 @@ static size_t mi_debug_show_page_bfield(char* buf, size_t* k, mi_arena_t* arena,
|
|
|
1625
1795
|
// else if (mi_bitmap_is_setN(arena->pages_purge, slice_index + bit, NULL)) { c = '*'; }
|
|
1626
1796
|
else if (mi_bbitmap_is_setN(arena->slices_free, slice_index+bit,1)) {
|
|
1627
1797
|
if (mi_bitmap_is_set(arena->slices_purge, slice_index + bit)) { c = '~'; color = MI_ORANGE; }
|
|
1628
|
-
else if (
|
|
1798
|
+
else if (mi_bitmap_is_set(arena->slices_committed, slice_index + bit)) { c = '_'; color = MI_GRAY; }
|
|
1629
1799
|
else { c = '.'; color = MI_GRAY; }
|
|
1630
1800
|
}
|
|
1631
1801
|
if (bit==MI_BFIELD_BITS-1 && bit_of_page > 1) { c = '>'; }
|
|
@@ -1731,7 +1901,10 @@ static void mi_debug_show_arenas_ex(mi_heap_t* heap, bool show_pages, bool narro
|
|
|
1731
1901
|
if (arena == NULL) break;
|
|
1732
1902
|
mi_assert(arena->subproc == subproc);
|
|
1733
1903
|
// slice_total += arena->slice_count;
|
|
1734
|
-
_mi_raw_message("
|
|
1904
|
+
_mi_raw_message("%sarena %zu at %p: %zu slices (%zu MiB)%s%s, subproc: %p, numa: %i\n",
|
|
1905
|
+
(arena->parent==NULL ? "" : "(sub)"), i, arena, arena->slice_count, (size_t)(mi_size_of_slices(arena->slice_count)/MI_MiB),
|
|
1906
|
+
(arena->memid.is_pinned ? ", pinned" : ""), (arena->is_exclusive ? ", exclusive" : ""),
|
|
1907
|
+
arena->subproc, arena->numa_node);
|
|
1735
1908
|
//if (show_inuse) {
|
|
1736
1909
|
// free_total += mi_debug_show_bbitmap("in-use slices", arena->slice_count, arena->slices_free, true, NULL);
|
|
1737
1910
|
//}
|
|
@@ -1953,15 +2126,21 @@ static bool mi_arena_try_purge_visitor(size_t slice_index, size_t slice_count, m
|
|
|
1953
2126
|
return true; // continue
|
|
1954
2127
|
}
|
|
1955
2128
|
|
|
1956
|
-
// returns
|
|
1957
|
-
|
|
2129
|
+
// returns
|
|
2130
|
+
// -1 = nothing was purged
|
|
2131
|
+
// 0 = nothing was purged yet because have not yet reached the expire time
|
|
2132
|
+
// 1 = some pages in the arena were purged
|
|
2133
|
+
static int mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force)
|
|
1958
2134
|
{
|
|
1959
2135
|
// check pre-conditions
|
|
1960
|
-
if (arena->memid.is_pinned) return
|
|
2136
|
+
if (arena->memid.is_pinned) return -1;
|
|
1961
2137
|
|
|
1962
2138
|
// expired yet?
|
|
1963
2139
|
mi_msecs_t expire = mi_atomic_loadi64_relaxed(&arena->purge_expire);
|
|
1964
|
-
if (!force
|
|
2140
|
+
if (!force) {
|
|
2141
|
+
if (expire==0) return -1;
|
|
2142
|
+
if (expire > now) return 0;
|
|
2143
|
+
}
|
|
1965
2144
|
|
|
1966
2145
|
// reset expire
|
|
1967
2146
|
mi_atomic_storei64_release(&arena->purge_expire, (mi_msecs_t)0);
|
|
@@ -1976,7 +2155,7 @@ static bool mi_arena_try_purge(mi_arena_t* arena, mi_msecs_t now, bool force)
|
|
|
1976
2155
|
const size_t minslices = mi_slice_count_of_size(_mi_os_minimal_purge_size());
|
|
1977
2156
|
_mi_bitmap_forall_setc_rangesn(arena->slices_purge, minslices, &mi_arena_try_purge_visitor, arena, &vinfo);
|
|
1978
2157
|
|
|
1979
|
-
return vinfo.any_purged;
|
|
2158
|
+
return (vinfo.any_purged ? 1 : -1);
|
|
1980
2159
|
}
|
|
1981
2160
|
|
|
1982
2161
|
|
|
@@ -2009,18 +2188,21 @@ static void mi_arenas_try_purge(bool force, bool visit_all, mi_subproc_t* subpro
|
|
|
2009
2188
|
if (i >= max_arena) { i -= max_arena; }
|
|
2010
2189
|
mi_arena_t* arena = mi_arena_from_index(subproc,i);
|
|
2011
2190
|
if (arena != NULL) {
|
|
2012
|
-
|
|
2191
|
+
const int purged = mi_arena_try_purge(arena, now, force);
|
|
2192
|
+
if (purged >= 0) { // purged, or arena expire is not yet reached
|
|
2013
2193
|
any_purged = true;
|
|
2014
|
-
if (
|
|
2015
|
-
|
|
2016
|
-
|
|
2194
|
+
if (purged >= 1) { // purged
|
|
2195
|
+
if (max_purge_count <= 1) {
|
|
2196
|
+
all_visited = false;
|
|
2197
|
+
break;
|
|
2198
|
+
}
|
|
2199
|
+
max_purge_count--;
|
|
2017
2200
|
}
|
|
2018
|
-
max_purge_count--;
|
|
2019
2201
|
}
|
|
2020
2202
|
}
|
|
2021
2203
|
}
|
|
2022
2204
|
if (all_visited && !any_purged) {
|
|
2023
|
-
mi_atomic_storei64_release(&subproc->purge_expire, 0);
|
|
2205
|
+
mi_atomic_storei64_release(&subproc->purge_expire, (mi_msecs_t)0);
|
|
2024
2206
|
}
|
|
2025
2207
|
}
|
|
2026
2208
|
}
|
|
@@ -2055,7 +2237,7 @@ static bool mi_heap_visit_page(mi_page_t* page, mi_heap_visit_info_t* vinfo) {
|
|
|
2055
2237
|
static bool mi_heap_visit_page_at(size_t slice_index, size_t slice_count, mi_arena_t* arena, void* arg) {
|
|
2056
2238
|
MI_UNUSED(slice_count);
|
|
2057
2239
|
mi_heap_visit_info_t* vinfo = (mi_heap_visit_info_t*)arg;
|
|
2058
|
-
mi_page_t* page = (
|
|
2240
|
+
mi_page_t* page = mi_arena_page_at_slice(arena, slice_index);
|
|
2059
2241
|
return mi_heap_visit_page(page, vinfo);
|
|
2060
2242
|
}
|
|
2061
2243
|
|
|
@@ -2121,7 +2303,7 @@ static bool mi_heap_delete_page(const mi_heap_t* heap, const mi_heap_area_t* are
|
|
|
2121
2303
|
MI_UNUSED(block); MI_UNUSED(block_size); MI_UNUSED(heap);
|
|
2122
2304
|
mi_heap_delete_visit_info_t* info = (mi_heap_delete_visit_info_t*)arg;
|
|
2123
2305
|
mi_heap_t* heap_target = info->heap_target;
|
|
2124
|
-
mi_theap_t* const theap = info->theap; mi_assert_internal(theap
|
|
2306
|
+
mi_theap_t* const theap = NULL; // info->theap; mi_assert_internal(_mi_theap_heap(theap) == heap);
|
|
2125
2307
|
mi_page_t* const page = (mi_page_t*)area->reserved1;
|
|
2126
2308
|
|
|
2127
2309
|
mi_page_claim_ownership(page); // claim ownership
|
|
@@ -2154,8 +2336,14 @@ static bool mi_heap_delete_page(const mi_heap_t* heap, const mi_heap_area_t* are
|
|
|
2154
2336
|
mi_arena_t* const arena = mi_page_arena_pages(page, &slice_index, &slice_count, &arena_pages);
|
|
2155
2337
|
mi_assert_internal(mi_bitmap_is_set(arena_pages->pages, slice_index));
|
|
2156
2338
|
mi_bitmap_clear(arena_pages->pages, slice_index);
|
|
2157
|
-
|
|
2158
|
-
|
|
2339
|
+
if (theap != NULL) {
|
|
2340
|
+
mi_theap_stat_decrease(theap, page_bins[sbin], 1);
|
|
2341
|
+
mi_theap_stat_decrease(theap, pages, 1);
|
|
2342
|
+
}
|
|
2343
|
+
else {
|
|
2344
|
+
mi_heap_stat_decrease((mi_heap_t*)heap, page_bins[_mi_page_stats_bin(page)], 1);
|
|
2345
|
+
mi_heap_stat_decrease((mi_heap_t*)heap, pages, 1);
|
|
2346
|
+
}
|
|
2159
2347
|
mi_theap_t* theap_target = info->theap_target;
|
|
2160
2348
|
|
|
2161
2349
|
// and then add it to the new target heap
|
|
@@ -2181,13 +2369,13 @@ static bool mi_heap_delete_page(const mi_heap_t* heap, const mi_heap_area_t* are
|
|
|
2181
2369
|
|
|
2182
2370
|
static void mi_heap_delete_pages(mi_heap_t* heap, mi_heap_t* heap_target) {
|
|
2183
2371
|
mi_theap_t* const theap_target = (heap_target != NULL ? _mi_heap_theap(heap_target) : NULL);
|
|
2184
|
-
mi_theap_t* const theap = _mi_heap_theap(heap);
|
|
2185
|
-
mi_heap_delete_visit_info_t info = { heap_target, theap_target,
|
|
2372
|
+
// mi_theap_t* const theap = _mi_heap_theap(heap);
|
|
2373
|
+
mi_heap_delete_visit_info_t info = { heap_target, theap_target, NULL };
|
|
2186
2374
|
_mi_heap_visit_blocks(heap, false, false, &mi_heap_delete_page, &info);
|
|
2187
2375
|
#if MI_DEBUG>1
|
|
2188
2376
|
// no more arena pages?
|
|
2189
2377
|
for (size_t i = 0; i < MI_ARENA_BIN_COUNT; i++) {
|
|
2190
|
-
mi_arena_pages_t* const arena_pages =
|
|
2378
|
+
mi_arena_pages_t* const arena_pages = mi_atomic_load_ptr_relaxed(mi_arena_pages_t, &heap->arena_pages[i]);
|
|
2191
2379
|
if (arena_pages!=NULL) {
|
|
2192
2380
|
mi_assert_internal(mi_bitmap_is_all_clear(arena_pages->pages));
|
|
2193
2381
|
}
|
|
@@ -2222,7 +2410,7 @@ void _mi_heap_destroy_pages(mi_heap_t* heap_from) {
|
|
|
2222
2410
|
static bool mi_arena_page_register(size_t slice_index, size_t slice_count, mi_arena_t* arena, void* arg) {
|
|
2223
2411
|
MI_UNUSED(arg); MI_UNUSED(slice_count);
|
|
2224
2412
|
mi_assert_internal(slice_count == 1);
|
|
2225
|
-
mi_page_t* page = (
|
|
2413
|
+
mi_page_t* page = mi_arena_page_at_slice(arena, slice_index);
|
|
2226
2414
|
mi_assert_internal(mi_bitmap_is_setN(page->memid.mem.arena.arena->pages, page->memid.mem.arena.slice_index, 1));
|
|
2227
2415
|
if (!_mi_page_map_register(page)) return false; // break
|
|
2228
2416
|
mi_assert_internal(_mi_ptr_page(page)==page);
|