mirror of
https://github.com/microsoft/mimalloc.git
synced 2024-12-26 21:04:27 +08:00
merge from dev
This commit is contained in:
commit
abb8eab9b2
@ -426,6 +426,7 @@ typedef struct mi_segment_s {
|
|||||||
|
|
||||||
// from here is zero initialized
|
// from here is zero initialized
|
||||||
struct mi_segment_s* next; // the list of freed segments in the cache (must be first field, see `segment.c:mi_segment_init`)
|
struct mi_segment_s* next; // the list of freed segments in the cache (must be first field, see `segment.c:mi_segment_init`)
|
||||||
|
bool was_reclaimed; // true if it was reclaimed (used to limit on-free reclamation)
|
||||||
|
|
||||||
size_t abandoned; // abandoned pages (i.e. the original owning thread stopped) (`abandoned <= used`)
|
size_t abandoned; // 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_visits; // count how often this segment is visited in the abandoned list (to force reclaim it it is too long)
|
||||||
@ -653,6 +654,7 @@ typedef struct mi_segments_tld_s {
|
|||||||
size_t peak_count; // peak number of segments
|
size_t peak_count; // peak number of segments
|
||||||
size_t current_size; // current size of all segments
|
size_t current_size; // current size of all segments
|
||||||
size_t peak_size; // peak size of all segments
|
size_t peak_size; // peak size of all segments
|
||||||
|
size_t reclaim_count;// number of reclaimed (abandoned) segments
|
||||||
mi_stats_t* stats; // points to tld stats
|
mi_stats_t* stats; // points to tld stats
|
||||||
mi_os_tld_t* os; // points to os stats
|
mi_os_tld_t* os; // points to os stats
|
||||||
} mi_segments_tld_t;
|
} mi_segments_tld_t;
|
||||||
|
@ -132,7 +132,7 @@ mi_decl_cache_align static const mi_tld_t tld_empty = {
|
|||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
{ MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, tld_empty_stats, tld_empty_os }, // segments
|
{ MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, 0, tld_empty_stats, tld_empty_os }, // segments
|
||||||
{ 0, tld_empty_stats }, // os
|
{ 0, tld_empty_stats }, // os
|
||||||
{ MI_STATS_NULL } // stats
|
{ MI_STATS_NULL } // stats
|
||||||
};
|
};
|
||||||
@ -149,7 +149,7 @@ extern mi_heap_t _mi_heap_main;
|
|||||||
static mi_tld_t tld_main = {
|
static mi_tld_t tld_main = {
|
||||||
0, false,
|
0, false,
|
||||||
&_mi_heap_main, & _mi_heap_main,
|
&_mi_heap_main, & _mi_heap_main,
|
||||||
{ MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, &tld_main.stats, &tld_main.os }, // segments
|
{ MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, 0, &tld_main.stats, &tld_main.os }, // segments
|
||||||
{ 0, &tld_main.stats }, // os
|
{ 0, &tld_main.stats }, // os
|
||||||
{ MI_STATS_NULL } // stats
|
{ MI_STATS_NULL } // stats
|
||||||
};
|
};
|
||||||
|
@ -380,6 +380,10 @@ static void mi_segment_os_free(mi_segment_t* segment, mi_segments_tld_t* tld) {
|
|||||||
segment->thread_id = 0;
|
segment->thread_id = 0;
|
||||||
_mi_segment_map_freed_at(segment);
|
_mi_segment_map_freed_at(segment);
|
||||||
mi_segments_track_size(-((long)mi_segment_size(segment)),tld);
|
mi_segments_track_size(-((long)mi_segment_size(segment)),tld);
|
||||||
|
if (segment->was_reclaimed) {
|
||||||
|
tld->reclaim_count--;
|
||||||
|
segment->was_reclaimed = false;
|
||||||
|
}
|
||||||
if (MI_SECURE>0) {
|
if (MI_SECURE>0) {
|
||||||
// _mi_os_unprotect(segment, mi_segment_size(segment)); // ensure no more guard pages are set
|
// _mi_os_unprotect(segment, mi_segment_size(segment)); // ensure no more guard pages are set
|
||||||
// unprotect the guard pages; we cannot just unprotect the whole segment size as part may be decommitted
|
// unprotect the guard pages; we cannot just unprotect the whole segment size as part may be decommitted
|
||||||
@ -1085,6 +1089,10 @@ static void mi_segment_abandon(mi_segment_t* segment, mi_segments_tld_t* tld) {
|
|||||||
mi_segments_track_size(-((long)mi_segment_size(segment)), tld);
|
mi_segments_track_size(-((long)mi_segment_size(segment)), tld);
|
||||||
segment->thread_id = 0;
|
segment->thread_id = 0;
|
||||||
segment->abandoned_visits = 1; // from 0 to 1 to signify it is abandoned
|
segment->abandoned_visits = 1; // from 0 to 1 to signify it is abandoned
|
||||||
|
if (segment->was_reclaimed) {
|
||||||
|
tld->reclaim_count--;
|
||||||
|
segment->was_reclaimed = false;
|
||||||
|
}
|
||||||
_mi_arena_segment_mark_abandoned(segment);
|
_mi_arena_segment_mark_abandoned(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1171,6 +1179,8 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap,
|
|||||||
mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0 || mi_atomic_load_relaxed(&segment->thread_id) == _mi_thread_id());
|
mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0 || mi_atomic_load_relaxed(&segment->thread_id) == _mi_thread_id());
|
||||||
mi_atomic_store_release(&segment->thread_id, _mi_thread_id());
|
mi_atomic_store_release(&segment->thread_id, _mi_thread_id());
|
||||||
segment->abandoned_visits = 0;
|
segment->abandoned_visits = 0;
|
||||||
|
segment->was_reclaimed = true;
|
||||||
|
tld->reclaim_count++;
|
||||||
mi_segments_track_size((long)mi_segment_size(segment), tld);
|
mi_segments_track_size((long)mi_segment_size(segment), tld);
|
||||||
mi_assert_internal(segment->next == NULL);
|
mi_assert_internal(segment->next == NULL);
|
||||||
_mi_stat_decrease(&tld->stats->segments_abandoned, 1);
|
_mi_stat_decrease(&tld->stats->segments_abandoned, 1);
|
||||||
@ -1229,6 +1239,9 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap,
|
|||||||
// attempt to reclaim a particular segment (called from multi threaded free `alloc.c:mi_free_block_mt`)
|
// attempt to reclaim a particular segment (called from multi threaded free `alloc.c:mi_free_block_mt`)
|
||||||
bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) {
|
bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) {
|
||||||
if (mi_atomic_load_relaxed(&segment->thread_id) != 0) return false; // it is not abandoned
|
if (mi_atomic_load_relaxed(&segment->thread_id) != 0) return false; // it is not abandoned
|
||||||
|
// don't reclaim more from a free than half the current segments
|
||||||
|
// this is to prevent a pure free-ing thread to start owning too many segments
|
||||||
|
if (heap->tld->segments.reclaim_count * 2 > heap->tld->segments.count) return false;
|
||||||
if (_mi_arena_segment_clear_abandoned(segment)) { // atomically unabandon
|
if (_mi_arena_segment_clear_abandoned(segment)) { // atomically unabandon
|
||||||
mi_segment_t* res = mi_segment_reclaim(segment, heap, 0, NULL, &heap->tld->segments);
|
mi_segment_t* res = mi_segment_reclaim(segment, heap, 0, NULL, &heap->tld->segments);
|
||||||
mi_assert_internal(res == segment);
|
mi_assert_internal(res == segment);
|
||||||
|
@ -37,11 +37,12 @@ static int ITER = 50; // N full iterations destructing and re-creating a
|
|||||||
// static int THREADS = 8; // more repeatable if THREADS <= #processors
|
// static int THREADS = 8; // more repeatable if THREADS <= #processors
|
||||||
// static int SCALE = 100; // scaling factor
|
// static int SCALE = 100; // scaling factor
|
||||||
|
|
||||||
#define STRESS // undefine for leak test
|
#define STRESS // undefine for leak test
|
||||||
|
|
||||||
static bool allow_large_objects = true; // allow very large objects? (set to `true` if SCALE>100)
|
static bool allow_large_objects = true; // allow very large objects? (set to `true` if SCALE>100)
|
||||||
static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`?
|
static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`?
|
||||||
|
|
||||||
|
static bool main_participates = false; // main thread participates as a worker too
|
||||||
|
|
||||||
// #define USE_STD_MALLOC
|
// #define USE_STD_MALLOC
|
||||||
#ifdef USE_STD_MALLOC
|
#ifdef USE_STD_MALLOC
|
||||||
@ -301,14 +302,15 @@ static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) {
|
|||||||
thread_entry_fun = fun;
|
thread_entry_fun = fun;
|
||||||
DWORD* tids = (DWORD*)custom_calloc(nthreads,sizeof(DWORD));
|
DWORD* tids = (DWORD*)custom_calloc(nthreads,sizeof(DWORD));
|
||||||
HANDLE* thandles = (HANDLE*)custom_calloc(nthreads,sizeof(HANDLE));
|
HANDLE* thandles = (HANDLE*)custom_calloc(nthreads,sizeof(HANDLE));
|
||||||
for (uintptr_t i = 1; i < nthreads; i++) {
|
const size_t start = (main_participates ? 1 : 0);
|
||||||
|
for (size_t i = start; i < nthreads; i++) {
|
||||||
thandles[i] = CreateThread(0, 8*1024, &thread_entry, (void*)(i), 0, &tids[i]);
|
thandles[i] = CreateThread(0, 8*1024, &thread_entry, (void*)(i), 0, &tids[i]);
|
||||||
}
|
}
|
||||||
fun(0); // run the main thread as well
|
if (main_participates) fun(0); // run the main thread as well
|
||||||
for (size_t i = 1; i < nthreads; i++) {
|
for (size_t i = start; i < nthreads; i++) {
|
||||||
WaitForSingleObject(thandles[i], INFINITE);
|
WaitForSingleObject(thandles[i], INFINITE);
|
||||||
}
|
}
|
||||||
for (size_t i = 1; i < nthreads; i++) {
|
for (size_t i = start; i < nthreads; i++) {
|
||||||
CloseHandle(thandles[i]);
|
CloseHandle(thandles[i]);
|
||||||
}
|
}
|
||||||
custom_free(tids);
|
custom_free(tids);
|
||||||
@ -335,12 +337,13 @@ static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) {
|
|||||||
thread_entry_fun = fun;
|
thread_entry_fun = fun;
|
||||||
pthread_t* threads = (pthread_t*)custom_calloc(nthreads,sizeof(pthread_t));
|
pthread_t* threads = (pthread_t*)custom_calloc(nthreads,sizeof(pthread_t));
|
||||||
memset(threads, 0, sizeof(pthread_t) * nthreads);
|
memset(threads, 0, sizeof(pthread_t) * nthreads);
|
||||||
|
const size_t start = (main_participates ? 1 : 0);
|
||||||
//pthread_setconcurrency(nthreads);
|
//pthread_setconcurrency(nthreads);
|
||||||
for (size_t i = 1; i < nthreads; i++) {
|
for (size_t i = start; i < nthreads; i++) {
|
||||||
pthread_create(&threads[i], NULL, &thread_entry, (void*)i);
|
pthread_create(&threads[i], NULL, &thread_entry, (void*)i);
|
||||||
}
|
}
|
||||||
fun(0); // run the main thread as well
|
if (main_participates) fun(0); // run the main thread as well
|
||||||
for (size_t i = 1; i < nthreads; i++) {
|
for (size_t i = start; i < nthreads; i++) {
|
||||||
pthread_join(threads[i], NULL);
|
pthread_join(threads[i], NULL);
|
||||||
}
|
}
|
||||||
custom_free(threads);
|
custom_free(threads);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user