start abandoned search randomized

This commit is contained in:
daanx 2024-03-01 10:51:18 -08:00
parent 71bcf1c76b
commit cf8f73098e
3 changed files with 37 additions and 23 deletions

View file

@ -124,9 +124,16 @@ bool _mi_arena_contains(const void* p);
void _mi_arena_collect(bool force_purge, mi_stats_t* stats); void _mi_arena_collect(bool force_purge, mi_stats_t* stats);
void _mi_arena_unsafe_destroy_all(mi_stats_t* stats); void _mi_arena_unsafe_destroy_all(mi_stats_t* stats);
bool _mi_arena_segment_clear_abandoned(mi_memid_t memid); bool _mi_arena_segment_clear_abandoned(mi_memid_t memid);
void _mi_arena_segment_mark_abandoned(mi_memid_t memid); void _mi_arena_segment_mark_abandoned(mi_memid_t memid);
mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_id_t* current_id, size_t* current_idx);
typedef struct mi_arena_field_cursor_s { // abstract
mi_arena_id_t start;
int count;
size_t bitmap_idx;
} mi_arena_field_cursor_t;
void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_arena_field_cursor_t* current);
mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous);
// "segment-map.c" // "segment-map.c"
void _mi_segment_map_allocated_at(const mi_segment_t* segment); void _mi_segment_map_allocated_at(const mi_segment_t* segment);

View file

@ -775,17 +775,27 @@ void _mi_arena_segment_mark_abandoned(mi_memid_t memid)
mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx));
} }
// reclaim abandoned segments // start a cursor at a randomized arena
mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_id_t* previous_id, size_t* previous_idx ) void _mi_arena_field_cursor_init(mi_heap_t* heap, mi_arena_field_cursor_t* current) {
{ const size_t max_arena = mi_atomic_load_relaxed(&mi_arena_count);
if (mi_atomic_load_relaxed(&abandoned_count) == 0) return false; current->start = (max_arena == 0 ? 0 : (mi_arena_id_t)( _mi_heap_random_next(heap) % max_arena));
current->count = 0;
current->bitmap_idx = 0;
}
// reclaim abandoned segments
mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* previous )
{
const int max_arena = (int)mi_atomic_load_relaxed(&mi_arena_count); const int max_arena = (int)mi_atomic_load_relaxed(&mi_arena_count);
int arena_idx = *previous_id; if (max_arena <= 0 || mi_atomic_load_relaxed(&abandoned_count) == 0) return NULL;
size_t field_idx = mi_bitmap_index_field(*previous_idx);
size_t bit_idx = mi_bitmap_index_bit_in_field(*previous_idx) + 1; int count = previous->count;
size_t field_idx = mi_bitmap_index_field(previous->bitmap_idx);
size_t bit_idx = mi_bitmap_index_bit_in_field(previous->bitmap_idx) + 1;
// visit arena's (from previous) // visit arena's (from previous)
for( ; arena_idx < max_arena; arena_idx++, field_idx = 0, bit_idx = 0) { for (; count < max_arena; count++, field_idx = 0, bit_idx = 0) {
mi_arena_id_t arena_idx = previous->start + count;
if (arena_idx >= max_arena) { arena_idx = arena_idx % max_arena; } // wrap around
mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]); mi_arena_t* arena = mi_atomic_load_ptr_acquire(mi_arena_t, &mi_arenas[arena_idx]);
if (arena != NULL) { if (arena != NULL) {
// visit the abandoned fields (starting at previous_idx) // visit the abandoned fields (starting at previous_idx)
@ -801,8 +811,8 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_id_t* previous_id,
// try to reclaim it atomically // try to reclaim it atomically
if (_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) { if (_mi_bitmap_unclaim(arena->blocks_abandoned, arena->field_count, 1, bitmap_idx)) {
mi_atomic_decrement_relaxed(&abandoned_count); mi_atomic_decrement_relaxed(&abandoned_count);
*previous_idx = bitmap_idx; previous->bitmap_idx = bitmap_idx;
*previous_id = arena_idx; previous->count = count;
mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx)); mi_assert_internal(_mi_bitmap_is_claimed(arena->blocks_inuse, arena->field_count, 1, bitmap_idx));
//mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx)); //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx));
return (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx); return (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx);
@ -814,8 +824,8 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_id_t* previous_id,
} }
} }
// no more found // no more found
*previous_idx = 0; previous->bitmap_idx = 0;
*previous_id = 0; previous->count = 0;
return NULL; return NULL;
} }

View file

@ -910,22 +910,19 @@ bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment) {
void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) { void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld) {
mi_segment_t* segment; mi_segment_t* segment;
mi_arena_id_t current_id = 0; mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap, &current);
size_t current_idx = 0; while ((segment = _mi_arena_segment_clear_abandoned_next(&current)) != NULL) {
while ((segment = _mi_arena_segment_clear_abandoned_next(&current_id, &current_idx)) != NULL) {
mi_segment_reclaim(segment, heap, 0, NULL, tld); mi_segment_reclaim(segment, heap, 0, NULL, tld);
} }
} }
static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, mi_page_kind_t page_kind, bool* reclaimed, mi_segments_tld_t* tld) static mi_segment_t* mi_segment_try_reclaim(mi_heap_t* heap, size_t block_size, mi_page_kind_t page_kind, bool* reclaimed, mi_segments_tld_t* tld)
{ {
*reclaimed = false; *reclaimed = false;
mi_segment_t* segment; mi_segment_t* segment;
mi_arena_id_t current_id = 0; mi_arena_field_cursor_t current; _mi_arena_field_cursor_init(heap,&current);
size_t current_idx = 0;
long max_tries = mi_option_get_clamp(mi_option_max_segment_reclaim, 0, 1024); // limit the work to bound allocation times long max_tries = mi_option_get_clamp(mi_option_max_segment_reclaim, 0, 1024); // limit the work to bound allocation times
while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(&current_id, &current_idx)) != NULL)) while ((max_tries-- > 0) && ((segment = _mi_arena_segment_clear_abandoned_next(&current)) != NULL))
{ {
segment->abandoned_visits++; segment->abandoned_visits++;
// todo: an arena exclusive heap will potentially visit many abandoned unsuitable segments // todo: an arena exclusive heap will potentially visit many abandoned unsuitable segments