mirror of
https://github.com/microsoft/mimalloc.git
synced 2024-12-27 13:33:18 +08:00
merge from dev-reset
This commit is contained in:
commit
2715191f58
@ -322,11 +322,10 @@ typedef enum mi_option_e {
|
|||||||
mi_option_show_stats, // print statistics on termination
|
mi_option_show_stats, // print statistics on termination
|
||||||
mi_option_verbose, // print verbose messages
|
mi_option_verbose, // print verbose messages
|
||||||
// the following options are experimental (see src/options.h)
|
// the following options are experimental (see src/options.h)
|
||||||
// (deprecated options are kept for binary backward compatibility with v1.x versions)
|
mi_option_eager_commit,
|
||||||
mi_option_segment_eager_commit,
|
|
||||||
mi_option_arena_eager_commit,
|
mi_option_arena_eager_commit,
|
||||||
mi_option_purge_decommits,
|
mi_option_purge_decommits,
|
||||||
mi_option_large_os_pages, // use large (2MiB) OS pages, implies eager commit
|
mi_option_allow_large_os_pages, // enable large (2MiB) OS pages, implies eager commit
|
||||||
mi_option_reserve_huge_os_pages, // reserve N huge OS pages (1GiB) at startup
|
mi_option_reserve_huge_os_pages, // reserve N huge OS pages (1GiB) at startup
|
||||||
mi_option_reserve_huge_os_pages_at, // reserve huge OS pages at a specific NUMA node
|
mi_option_reserve_huge_os_pages_at, // reserve huge OS pages at a specific NUMA node
|
||||||
mi_option_reserve_os_memory, // reserve specified amount of OS memory at startup
|
mi_option_reserve_os_memory, // reserve specified amount of OS memory at startup
|
||||||
@ -349,10 +348,11 @@ typedef enum mi_option_e {
|
|||||||
mi_option_purge_extend_delay,
|
mi_option_purge_extend_delay,
|
||||||
_mi_option_last,
|
_mi_option_last,
|
||||||
// legacy options
|
// legacy options
|
||||||
mi_option_eager_commit = mi_option_segment_eager_commit,
|
mi_option_large_os_pages = mi_option_allow_large_os_pages,
|
||||||
mi_option_eager_region_commit = mi_option_arena_eager_commit,
|
mi_option_eager_region_commit = mi_option_arena_eager_commit,
|
||||||
mi_option_reset_decommits = mi_option_purge_decommits,
|
mi_option_reset_decommits = mi_option_purge_decommits,
|
||||||
mi_option_reset_delay = mi_option_purge_delay
|
mi_option_reset_delay = mi_option_purge_delay,
|
||||||
|
mi_option_abandoned_page_reset = mi_option_abandoned_page_purge
|
||||||
} mi_option_t;
|
} mi_option_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,6 +101,7 @@ bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats);
|
|||||||
bool _mi_os_protect(void* addr, size_t size);
|
bool _mi_os_protect(void* addr, size_t size);
|
||||||
bool _mi_os_unprotect(void* addr, size_t size);
|
bool _mi_os_unprotect(void* addr, size_t size);
|
||||||
bool _mi_os_purge(void* p, size_t size, mi_stats_t* stats);
|
bool _mi_os_purge(void* p, size_t size, mi_stats_t* stats);
|
||||||
|
bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, mi_stats_t* stats);
|
||||||
|
|
||||||
void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, bool* is_zero, mi_stats_t* stats);
|
void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, bool* is_zero, mi_stats_t* stats);
|
||||||
void* _mi_os_alloc_aligned_offset(size_t size, size_t alignment, size_t align_offset, bool commit, bool* large, bool* is_zero, mi_stats_t* tld_stats);
|
void* _mi_os_alloc_aligned_offset(size_t size, size_t alignment, size_t align_offset, bool commit, bool* large, bool* is_zero, mi_stats_t* tld_stats);
|
||||||
@ -115,7 +116,7 @@ void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* stats);
|
|||||||
|
|
||||||
// arena.c
|
// arena.c
|
||||||
mi_arena_id_t _mi_arena_id_none(void);
|
mi_arena_id_t _mi_arena_id_none(void);
|
||||||
void _mi_arena_free(void* p, size_t size, size_t alignment, size_t align_offset, size_t memid, bool all_committed, mi_stats_t* stats);
|
void _mi_arena_free(void* p, size_t size, size_t alignment, size_t align_offset, size_t memid, size_t committed, mi_stats_t* stats);
|
||||||
void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld);
|
void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld);
|
||||||
void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld);
|
void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset, bool* commit, bool* large, bool* is_pinned, bool* is_zero, mi_arena_id_t req_arena_id, size_t* memid, mi_os_tld_t* tld);
|
||||||
bool _mi_arena_memid_is_suitable(size_t arena_memid, mi_arena_id_t request_arena_id);
|
bool _mi_arena_memid_is_suitable(size_t arena_memid, mi_arena_id_t request_arena_id);
|
||||||
|
@ -541,6 +541,7 @@ typedef struct mi_stats_s {
|
|||||||
mi_stat_count_t reserved;
|
mi_stat_count_t reserved;
|
||||||
mi_stat_count_t committed;
|
mi_stat_count_t committed;
|
||||||
mi_stat_count_t reset;
|
mi_stat_count_t reset;
|
||||||
|
mi_stat_count_t purged;
|
||||||
mi_stat_count_t page_committed;
|
mi_stat_count_t page_committed;
|
||||||
mi_stat_count_t segments_abandoned;
|
mi_stat_count_t segments_abandoned;
|
||||||
mi_stat_count_t pages_abandoned;
|
mi_stat_count_t pages_abandoned;
|
||||||
@ -553,6 +554,8 @@ typedef struct mi_stats_s {
|
|||||||
mi_stat_counter_t pages_extended;
|
mi_stat_counter_t pages_extended;
|
||||||
mi_stat_counter_t mmap_calls;
|
mi_stat_counter_t mmap_calls;
|
||||||
mi_stat_counter_t commit_calls;
|
mi_stat_counter_t commit_calls;
|
||||||
|
mi_stat_counter_t reset_calls;
|
||||||
|
mi_stat_counter_t purge_calls;
|
||||||
mi_stat_counter_t page_no_retire;
|
mi_stat_counter_t page_no_retire;
|
||||||
mi_stat_counter_t searches;
|
mi_stat_counter_t searches;
|
||||||
mi_stat_counter_t normal_count;
|
mi_stat_counter_t normal_count;
|
||||||
|
37
src/arena.c
37
src/arena.c
@ -384,11 +384,24 @@ static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks,
|
|||||||
mi_assert_internal(arena->allow_decommit);
|
mi_assert_internal(arena->allow_decommit);
|
||||||
const size_t size = mi_arena_block_size(blocks);
|
const size_t size = mi_arena_block_size(blocks);
|
||||||
void* const p = arena->start + mi_arena_block_size(mi_bitmap_index_bit(bitmap_idx));
|
void* const p = arena->start + mi_arena_block_size(mi_bitmap_index_bit(bitmap_idx));
|
||||||
const bool decommitted = _mi_os_purge(p, size, stats);
|
bool needs_recommit;
|
||||||
|
if (_mi_bitmap_is_claimed_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx)) {
|
||||||
|
// all blocks are committed, we can purge freely
|
||||||
|
needs_recommit = _mi_os_purge(p, size, stats);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// some blocks are not committed -- this can happen when a partially committed block is freed
|
||||||
|
// in `_mi_arena_free` and it is conservatively marked as uncommitted but still scheduled for a purge
|
||||||
|
// we need to ensure we do not try to reset, and also not count the decommit stats (as it was already adjusted)
|
||||||
|
mi_assert_internal(mi_option_is_enabled(mi_option_purge_decommits));
|
||||||
|
needs_recommit = _mi_os_purge_ex(p, size, false /* allow reset? */, stats);
|
||||||
|
_mi_stat_increase(&stats->committed, size);
|
||||||
|
}
|
||||||
|
|
||||||
// clear the purged blocks
|
// clear the purged blocks
|
||||||
_mi_bitmap_unclaim_across(arena->blocks_purge, arena->field_count, blocks, bitmap_idx);
|
_mi_bitmap_unclaim_across(arena->blocks_purge, arena->field_count, blocks, bitmap_idx);
|
||||||
// update committed bitmap
|
// update committed bitmap
|
||||||
if (decommitted) {
|
if (needs_recommit) {
|
||||||
_mi_bitmap_unclaim_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx);
|
_mi_bitmap_unclaim_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,13 +538,20 @@ static void mi_arenas_try_purge( bool force, bool visit_all, mi_stats_t* stats )
|
|||||||
Arena free
|
Arena free
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
void _mi_arena_free(void* p, size_t size, size_t alignment, size_t align_offset, size_t memid, bool all_committed, mi_stats_t* stats) {
|
void _mi_arena_free(void* p, size_t size, size_t alignment, size_t align_offset, size_t memid, size_t committed_size, mi_stats_t* stats) {
|
||||||
mi_assert_internal(size > 0 && stats != NULL);
|
mi_assert_internal(size > 0 && stats != NULL);
|
||||||
|
mi_assert_internal(committed_size <= size);
|
||||||
if (p==NULL) return;
|
if (p==NULL) return;
|
||||||
if (size==0) return;
|
if (size==0) return;
|
||||||
|
const bool all_committed = (committed_size == size);
|
||||||
|
|
||||||
|
|
||||||
if (memid == MI_MEMID_OS) {
|
if (memid == MI_MEMID_OS) {
|
||||||
// was a direct OS allocation, pass through
|
// was a direct OS allocation, pass through
|
||||||
|
if (!all_committed && committed_size > 0) {
|
||||||
|
// if partially committed, adjust the committed stats
|
||||||
|
_mi_stat_decrease(&stats->committed, committed_size);
|
||||||
|
}
|
||||||
_mi_os_free_aligned(p, size, alignment, align_offset, all_committed, stats);
|
_mi_os_free_aligned(p, size, alignment, align_offset, all_committed, stats);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -566,10 +586,19 @@ void _mi_arena_free(void* p, size_t size, size_t alignment, size_t align_offset,
|
|||||||
else {
|
else {
|
||||||
mi_assert_internal(arena->blocks_committed != NULL);
|
mi_assert_internal(arena->blocks_committed != NULL);
|
||||||
mi_assert_internal(arena->blocks_purge != NULL);
|
mi_assert_internal(arena->blocks_purge != NULL);
|
||||||
|
|
||||||
if (!all_committed) {
|
if (!all_committed) {
|
||||||
// assume the entire range as no longer committed
|
// mark the entire range as no longer committed (so we recommit the full range when re-using)
|
||||||
_mi_bitmap_unclaim_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx);
|
_mi_bitmap_unclaim_across(arena->blocks_committed, arena->field_count, blocks, bitmap_idx);
|
||||||
mi_track_mem_noaccess(p,size);
|
mi_track_mem_noaccess(p,size);
|
||||||
|
if (committed_size > 0) {
|
||||||
|
// if partially committed, adjust the committed stats (is it will be recommitted when re-using)
|
||||||
|
// in the delayed purge, we now need to not count a decommit if the range is not marked as committed.
|
||||||
|
_mi_stat_decrease(&stats->committed, committed_size);
|
||||||
|
}
|
||||||
|
// note: if not all committed, it may be that the purge will reset/decommit the entire range
|
||||||
|
// that contains already decommitted parts. Since purge consistently uses reset or decommit that
|
||||||
|
// works (as we should never reset decommitted parts).
|
||||||
}
|
}
|
||||||
// (delay) purge the entire range
|
// (delay) purge the entire range
|
||||||
mi_arena_schedule_purge(arena, bitmap_idx, blocks, stats);
|
mi_arena_schedule_purge(arena, bitmap_idx, blocks, stats);
|
||||||
|
@ -82,8 +82,9 @@ const mi_page_t _mi_page_empty = {
|
|||||||
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
||||||
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
||||||
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
||||||
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \
|
MI_STAT_COUNT_NULL(), \
|
||||||
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } \
|
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \
|
||||||
|
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } \
|
||||||
MI_STAT_COUNT_END_NULL()
|
MI_STAT_COUNT_END_NULL()
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,38 +59,38 @@ static mi_option_desc_t options[_mi_option_last] =
|
|||||||
{ 0, UNINIT, MI_OPTION(verbose) },
|
{ 0, UNINIT, MI_OPTION(verbose) },
|
||||||
|
|
||||||
// the following options are experimental and not all combinations make sense.
|
// the following options are experimental and not all combinations make sense.
|
||||||
{ 1, UNINIT, MI_OPTION_LEGACY(segment_eager_commit,eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`)
|
{ 1, UNINIT, MI_OPTION(eager_commit) }, // commit per segment directly (4MiB) (but see also `eager_commit_delay`)
|
||||||
{ 2, UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux)
|
{ 2, UNINIT, MI_OPTION_LEGACY(arena_eager_commit,eager_region_commit) }, // eager commit arena's? 2 is used to enable this only on an OS that has overcommit (i.e. linux)
|
||||||
{ 1, UNINIT, MI_OPTION_LEGACY(purge_decommits,reset_decommits) }, // purge decommits memory (instead of reset) (note: on linux this uses MADV_DONTNEED for decommit)
|
{ 1, UNINIT, MI_OPTION_LEGACY(purge_decommits,reset_decommits) }, // purge decommits memory (instead of reset) (note: on linux this uses MADV_DONTNEED for decommit)
|
||||||
{ 0, UNINIT, MI_OPTION(large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's
|
{ 0, UNINIT, MI_OPTION_LEGACY(allow_large_os_pages,large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's
|
||||||
{ 0, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages
|
{ 0, UNINIT, MI_OPTION(reserve_huge_os_pages) }, // per 1GiB huge pages
|
||||||
{ -1, UNINIT, MI_OPTION(reserve_huge_os_pages_at) }, // reserve huge pages at node N
|
{-1, UNINIT, MI_OPTION(reserve_huge_os_pages_at) }, // reserve huge pages at node N
|
||||||
{ 0, UNINIT, MI_OPTION(reserve_os_memory) },
|
{ 0, UNINIT, MI_OPTION(reserve_os_memory) },
|
||||||
{ 0, UNINIT, MI_OPTION(deprecated_segment_cache) }, // cache N segments per thread
|
{ 0, UNINIT, MI_OPTION(deprecated_segment_cache) }, // cache N segments per thread
|
||||||
{ 0, UNINIT, MI_OPTION(page_reset) }, // reset page memory on free
|
{ 0, UNINIT, MI_OPTION(page_reset) }, // reset page memory on free
|
||||||
{ 0, UNINIT, MI_OPTION_LEGACY(abandoned_page_purge, abandoned_page_decommit) },// decommit free page memory when a thread terminates
|
{ 0, UNINIT, MI_OPTION_LEGACY(abandoned_page_purge,abandoned_page_reset) }, // reset free page memory when a thread terminates
|
||||||
{ 0, UNINIT, MI_OPTION(deprecated_segment_reset) },
|
{ 0, UNINIT, MI_OPTION(deprecated_segment_reset) }, // reset segment memory on free (needs eager commit)
|
||||||
#if defined(__NetBSD__)
|
#if defined(__NetBSD__)
|
||||||
{ 0, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed
|
{ 0, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed
|
||||||
#else
|
#else
|
||||||
{ 1, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed (but per page in the segment on demand)
|
{ 1, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed (but per page in the segment on demand)
|
||||||
#endif
|
#endif
|
||||||
{ 10, UNINIT, MI_OPTION_LEGACY(purge_delay, reset_delay) }, // page decommit delay in milli-seconds
|
{ 10, UNINIT, MI_OPTION_LEGACY(purge_delay,reset_delay) }, // purge delay in milli-seconds
|
||||||
{ 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes.
|
{ 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes.
|
||||||
{ 0, UNINIT, MI_OPTION(limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas)
|
{ 0, UNINIT, MI_OPTION(limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas)
|
||||||
{ 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose
|
{ 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose
|
||||||
{ 16, UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output
|
{ 16, UNINIT, MI_OPTION(max_errors) }, // maximum errors that are output
|
||||||
{ 16, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output
|
{ 16, UNINIT, MI_OPTION(max_warnings) }, // maximum warnings that are output
|
||||||
{ 8, UNINIT, MI_OPTION(max_segment_reclaim)},// max. number of segment reclaims from the abandoned segments per try.
|
{ 8, UNINIT, MI_OPTION(max_segment_reclaim)}, // max. number of segment reclaims from the abandoned segments per try.
|
||||||
{ 0, UNINIT, MI_OPTION(destroy_on_exit)}, // release all OS memory on process exit; careful with dangling pointer or after-exit frees!
|
{ 0, UNINIT, MI_OPTION(destroy_on_exit)}, // release all OS memory on process exit; careful with dangling pointer or after-exit frees!
|
||||||
#if (MI_INTPTR_SIZE>4)
|
#if (MI_INTPTR_SIZE>4)
|
||||||
{ 1024L * 1024L, UNINIT, MI_OPTION(arena_reserve) }, // reserve memory N KiB at a time
|
{ 1024L * 1024L, UNINIT, MI_OPTION(arena_reserve) }, // reserve memory N KiB at a time
|
||||||
#else
|
#else
|
||||||
{ 128L * 1024L, UNINIT, MI_OPTION(arena_reserve) },
|
{ 128L * 1024L, UNINIT, MI_OPTION(arena_reserve) },
|
||||||
#endif
|
#endif
|
||||||
{ 100, UNINIT, MI_OPTION(arena_purge_delay) }, // reset/decommit delay in milli-seconds for arena allocation
|
{ 100, UNINIT, MI_OPTION(arena_purge_delay) }, // reset/decommit delay in milli-seconds for arena allocation
|
||||||
{ 1, UNINIT, MI_OPTION(allow_purge) }, // allow decommit/reset to free (physical) memory back to the OS
|
{ 1, UNINIT, MI_OPTION(allow_purge) }, // allow decommit/reset to free (physical) memory back to the OS
|
||||||
{ 1, UNINIT, MI_OPTION_LEGACY(purge_extend_delay, decommit_extend_delay) },
|
{ 1, UNINIT, MI_OPTION_LEGACY(purge_extend_delay, decommit_extend_delay) },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mi_option_init(mi_option_desc_t* desc);
|
static void mi_option_init(mi_option_desc_t* desc);
|
||||||
|
16
src/os.c
16
src/os.c
@ -46,7 +46,7 @@ size_t _mi_os_large_page_size(void) {
|
|||||||
|
|
||||||
bool _mi_os_use_large_page(size_t size, size_t alignment) {
|
bool _mi_os_use_large_page(size_t size, size_t alignment) {
|
||||||
// if we have access, check the size and alignment requirements
|
// if we have access, check the size and alignment requirements
|
||||||
if (mi_os_mem_config.large_page_size == 0 || !mi_option_is_enabled(mi_option_large_os_pages)) return false;
|
if (mi_os_mem_config.large_page_size == 0 || !mi_option_is_enabled(mi_option_allow_large_os_pages)) return false;
|
||||||
return ((size % mi_os_mem_config.large_page_size) == 0 && (alignment % mi_os_mem_config.large_page_size) == 0);
|
return ((size % mi_os_mem_config.large_page_size) == 0 && (alignment % mi_os_mem_config.large_page_size) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +411,7 @@ bool _mi_os_reset(void* addr, size_t size, mi_stats_t* stats) {
|
|||||||
void* start = mi_os_page_align_area_conservative(addr, size, &csize);
|
void* start = mi_os_page_align_area_conservative(addr, size, &csize);
|
||||||
if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr)
|
if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr)
|
||||||
_mi_stat_increase(&stats->reset, csize);
|
_mi_stat_increase(&stats->reset, csize);
|
||||||
|
_mi_stat_counter_increase(&stats->reset_calls, 1);
|
||||||
|
|
||||||
#if (MI_DEBUG>1) && !MI_SECURE && !MI_TRACK_ENABLED // && !MI_TSAN
|
#if (MI_DEBUG>1) && !MI_SECURE && !MI_TRACK_ENABLED // && !MI_TSAN
|
||||||
memset(start, 0, csize); // pretend it is eagerly reset
|
memset(start, 0, csize); // pretend it is eagerly reset
|
||||||
@ -429,9 +430,11 @@ bool _mi_os_reset(void* addr, size_t size, mi_stats_t* stats) {
|
|||||||
|
|
||||||
// either resets or decommits memory, returns true if the memory needs
|
// either resets or decommits memory, returns true if the memory needs
|
||||||
// to be recommitted if it is to be re-used later on.
|
// to be recommitted if it is to be re-used later on.
|
||||||
bool _mi_os_purge(void* p, size_t size, mi_stats_t* stats)
|
bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset, mi_stats_t* stats)
|
||||||
{
|
{
|
||||||
if (!mi_option_is_enabled(mi_option_allow_purge)) return false;
|
if (!mi_option_is_enabled(mi_option_allow_purge)) return false;
|
||||||
|
_mi_stat_counter_increase(&stats->purge_calls, 1);
|
||||||
|
_mi_stat_increase(&stats->purged, size);
|
||||||
|
|
||||||
if (mi_option_is_enabled(mi_option_purge_decommits) && // should decommit?
|
if (mi_option_is_enabled(mi_option_purge_decommits) && // should decommit?
|
||||||
!_mi_preloading()) // don't decommit during preloading (unsafe)
|
!_mi_preloading()) // don't decommit during preloading (unsafe)
|
||||||
@ -441,11 +444,18 @@ bool _mi_os_purge(void* p, size_t size, mi_stats_t* stats)
|
|||||||
return needs_recommit;
|
return needs_recommit;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_mi_os_reset(p, size, stats);
|
if (allow_reset) { // this can sometimes be not allowed if the range is not fully committed
|
||||||
|
_mi_os_reset(p, size, stats);
|
||||||
|
}
|
||||||
return false; // not decommitted
|
return false; // not decommitted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// either resets or decommits memory, returns true if the memory needs
|
||||||
|
// to be recommitted if it is to be re-used later on.
|
||||||
|
bool _mi_os_purge(void* p, size_t size, mi_stats_t * stats) {
|
||||||
|
return _mi_os_purge_ex(p, size, true, stats);
|
||||||
|
}
|
||||||
|
|
||||||
// Protect a region in memory to be not accessible.
|
// Protect a region in memory to be not accessible.
|
||||||
static bool mi_os_protectx(void* addr, size_t size, bool protect) {
|
static bool mi_os_protectx(void* addr, size_t size, bool protect) {
|
||||||
|
@ -143,7 +143,7 @@ void _mi_prim_mem_init( mi_os_mem_config_t* config )
|
|||||||
pGetNumaProcessorNode = (PGetNumaProcessorNode)(void (*)(void))GetProcAddress(hDll, "GetNumaProcessorNode");
|
pGetNumaProcessorNode = (PGetNumaProcessorNode)(void (*)(void))GetProcAddress(hDll, "GetNumaProcessorNode");
|
||||||
FreeLibrary(hDll);
|
FreeLibrary(hDll);
|
||||||
}
|
}
|
||||||
if (mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) {
|
if (mi_option_is_enabled(mi_option_allow_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) {
|
||||||
win_enable_large_os_pages(&config->large_page_size);
|
win_enable_large_os_pages(&config->large_page_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,6 +400,8 @@ static void mi_segment_os_free(mi_segment_t* segment, mi_segments_tld_t* tld) {
|
|||||||
|| !_mi_segment_cache_push(segment, size, segment->memid, &segment->commit_mask, &segment->purge_mask, segment->mem_is_large, segment->mem_is_pinned, tld->os))
|
|| !_mi_segment_cache_push(segment, size, segment->memid, &segment->commit_mask, &segment->purge_mask, segment->mem_is_large, segment->mem_is_pinned, tld->os))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
const size_t csize = _mi_commit_mask_committed_size(&segment->commit_mask, size);
|
||||||
|
/*
|
||||||
// if not all committed, an arena may decommit the whole area, but that double counts
|
// if not all committed, an arena may decommit the whole area, but that double counts
|
||||||
// the already decommitted parts; adjust for that in the stats.
|
// the already decommitted parts; adjust for that in the stats.
|
||||||
if (!mi_commit_mask_is_full(&segment->commit_mask)) {
|
if (!mi_commit_mask_is_full(&segment->commit_mask)) {
|
||||||
@ -409,9 +411,9 @@ static void mi_segment_os_free(mi_segment_t* segment, mi_segments_tld_t* tld) {
|
|||||||
_mi_stat_increase(&_mi_stats_main.committed, size - csize);
|
_mi_stat_increase(&_mi_stats_main.committed, size - csize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
_mi_abandoned_await_readers(); // wait until safe to free
|
_mi_abandoned_await_readers(); // wait until safe to free
|
||||||
_mi_arena_free(segment, mi_segment_size(segment), segment->mem_alignment, segment->mem_align_offset, segment->memid,
|
_mi_arena_free(segment, mi_segment_size(segment), segment->mem_alignment, segment->mem_align_offset, segment->memid, csize, tld->stats);
|
||||||
mi_commit_mask_is_full(&segment->commit_mask) /* all committed? */, tld->stats);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
src/stats.c
35
src/stats.c
@ -96,6 +96,7 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) {
|
|||||||
mi_stat_add(&stats->reserved, &src->reserved, 1);
|
mi_stat_add(&stats->reserved, &src->reserved, 1);
|
||||||
mi_stat_add(&stats->committed, &src->committed, 1);
|
mi_stat_add(&stats->committed, &src->committed, 1);
|
||||||
mi_stat_add(&stats->reset, &src->reset, 1);
|
mi_stat_add(&stats->reset, &src->reset, 1);
|
||||||
|
mi_stat_add(&stats->purged, &src->purged, 1);
|
||||||
mi_stat_add(&stats->page_committed, &src->page_committed, 1);
|
mi_stat_add(&stats->page_committed, &src->page_committed, 1);
|
||||||
|
|
||||||
mi_stat_add(&stats->pages_abandoned, &src->pages_abandoned, 1);
|
mi_stat_add(&stats->pages_abandoned, &src->pages_abandoned, 1);
|
||||||
@ -111,7 +112,9 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) {
|
|||||||
mi_stat_counter_add(&stats->pages_extended, &src->pages_extended, 1);
|
mi_stat_counter_add(&stats->pages_extended, &src->pages_extended, 1);
|
||||||
mi_stat_counter_add(&stats->mmap_calls, &src->mmap_calls, 1);
|
mi_stat_counter_add(&stats->mmap_calls, &src->mmap_calls, 1);
|
||||||
mi_stat_counter_add(&stats->commit_calls, &src->commit_calls, 1);
|
mi_stat_counter_add(&stats->commit_calls, &src->commit_calls, 1);
|
||||||
|
mi_stat_counter_add(&stats->reset_calls, &src->reset_calls, 1);
|
||||||
|
mi_stat_counter_add(&stats->purge_calls, &src->purge_calls, 1);
|
||||||
|
|
||||||
mi_stat_counter_add(&stats->page_no_retire, &src->page_no_retire, 1);
|
mi_stat_counter_add(&stats->page_no_retire, &src->page_no_retire, 1);
|
||||||
mi_stat_counter_add(&stats->searches, &src->searches, 1);
|
mi_stat_counter_add(&stats->searches, &src->searches, 1);
|
||||||
mi_stat_counter_add(&stats->normal_count, &src->normal_count, 1);
|
mi_stat_counter_add(&stats->normal_count, &src->normal_count, 1);
|
||||||
@ -143,7 +146,7 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void*
|
|||||||
const int64_t pos = (n < 0 ? -n : n);
|
const int64_t pos = (n < 0 ? -n : n);
|
||||||
if (pos < base) {
|
if (pos < base) {
|
||||||
if (n!=1 || suffix[0] != 'B') { // skip printing 1 B for the unit column
|
if (n!=1 || suffix[0] != 'B') { // skip printing 1 B for the unit column
|
||||||
snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix));
|
snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -158,7 +161,7 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void*
|
|||||||
snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix);
|
snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix);
|
||||||
snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc);
|
snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc);
|
||||||
}
|
}
|
||||||
_mi_fprintf(out, arg, (fmt==NULL ? "%11s" : fmt), buf);
|
_mi_fprintf(out, arg, (fmt==NULL ? "%12s" : fmt), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -167,7 +170,7 @@ static void mi_print_amount(int64_t n, int64_t unit, mi_output_fun* out, void* a
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out, void* arg) {
|
static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out, void* arg) {
|
||||||
if (unit==1) _mi_fprintf(out, arg, "%11s"," ");
|
if (unit==1) _mi_fprintf(out, arg, "%12s"," ");
|
||||||
else mi_print_amount(n,0,out,arg);
|
else mi_print_amount(n,0,out,arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +185,7 @@ static void mi_stat_print_ex(const mi_stat_count_t* stat, const char* msg, int64
|
|||||||
mi_print_count(stat->allocated, unit, out, arg);
|
mi_print_count(stat->allocated, unit, out, arg);
|
||||||
if (stat->allocated > stat->freed) {
|
if (stat->allocated > stat->freed) {
|
||||||
_mi_fprintf(out, arg, " ");
|
_mi_fprintf(out, arg, " ");
|
||||||
_mi_fprintf(out, arg, (notok == NULL ? "not all freed!" : notok));
|
_mi_fprintf(out, arg, (notok == NULL ? "not all freed" : notok));
|
||||||
_mi_fprintf(out, arg, "\n");
|
_mi_fprintf(out, arg, "\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -195,7 +198,7 @@ static void mi_stat_print_ex(const mi_stat_count_t* stat, const char* msg, int64
|
|||||||
mi_print_amount(stat->freed, -1, out, arg);
|
mi_print_amount(stat->freed, -1, out, arg);
|
||||||
mi_print_amount(stat->current, -1, out, arg);
|
mi_print_amount(stat->current, -1, out, arg);
|
||||||
if (unit==-1) {
|
if (unit==-1) {
|
||||||
_mi_fprintf(out, arg, "%22s", "");
|
_mi_fprintf(out, arg, "%24s", "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mi_print_amount(-unit, 1, out, arg);
|
mi_print_amount(-unit, 1, out, arg);
|
||||||
@ -219,12 +222,19 @@ static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t
|
|||||||
mi_stat_print_ex(stat, msg, unit, out, arg, NULL);
|
mi_stat_print_ex(stat, msg, unit, out, arg, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mi_stat_peak_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg) {
|
||||||
|
_mi_fprintf(out, arg, "%10s:", msg);
|
||||||
|
mi_print_amount(stat->peak, unit, out, arg);
|
||||||
|
_mi_fprintf(out, arg, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg ) {
|
static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg ) {
|
||||||
_mi_fprintf(out, arg, "%10s:", msg);
|
_mi_fprintf(out, arg, "%10s:", msg);
|
||||||
mi_print_amount(stat->total, -1, out, arg);
|
mi_print_amount(stat->total, -1, out, arg);
|
||||||
_mi_fprintf(out, arg, "\n");
|
_mi_fprintf(out, arg, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg) {
|
static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg) {
|
||||||
const int64_t avg_tens = (stat->count == 0 ? 0 : (stat->total*10 / stat->count));
|
const int64_t avg_tens = (stat->count == 0 ? 0 : (stat->total*10 / stat->count));
|
||||||
const long avg_whole = (long)(avg_tens/10);
|
const long avg_whole = (long)(avg_tens/10);
|
||||||
@ -234,7 +244,7 @@ static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char*
|
|||||||
|
|
||||||
|
|
||||||
static void mi_print_header(mi_output_fun* out, void* arg ) {
|
static void mi_print_header(mi_output_fun* out, void* arg ) {
|
||||||
_mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "current ", "unit ", "count ");
|
_mi_fprintf(out, arg, "%10s: %11s %11s %11s %11s %11s %11s\n", "heap stats", "peak ", "total ", "freed ", "current ", "unit ", "count ");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MI_STAT>1
|
#if MI_STAT>1
|
||||||
@ -321,7 +331,8 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0)
|
|||||||
#endif
|
#endif
|
||||||
mi_stat_print_ex(&stats->reserved, "reserved", 1, out, arg, "");
|
mi_stat_print_ex(&stats->reserved, "reserved", 1, out, arg, "");
|
||||||
mi_stat_print_ex(&stats->committed, "committed", 1, out, arg, "");
|
mi_stat_print_ex(&stats->committed, "committed", 1, out, arg, "");
|
||||||
mi_stat_print(&stats->reset, "reset", 1, out, arg);
|
mi_stat_peak_print(&stats->reset, "reset", 1, out, arg );
|
||||||
|
mi_stat_peak_print(&stats->purged, "purged", 1, out, arg );
|
||||||
mi_stat_print(&stats->page_committed, "touched", 1, out, arg);
|
mi_stat_print(&stats->page_committed, "touched", 1, out, arg);
|
||||||
mi_stat_print(&stats->segments, "segments", -1, out, arg);
|
mi_stat_print(&stats->segments, "segments", -1, out, arg);
|
||||||
mi_stat_print(&stats->segments_abandoned, "-abandoned", -1, out, arg);
|
mi_stat_print(&stats->segments_abandoned, "-abandoned", -1, out, arg);
|
||||||
@ -331,10 +342,12 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0)
|
|||||||
mi_stat_counter_print(&stats->pages_extended, "-extended", out, arg);
|
mi_stat_counter_print(&stats->pages_extended, "-extended", out, arg);
|
||||||
mi_stat_counter_print(&stats->page_no_retire, "-noretire", out, arg);
|
mi_stat_counter_print(&stats->page_no_retire, "-noretire", out, arg);
|
||||||
mi_stat_counter_print(&stats->mmap_calls, "mmaps", out, arg);
|
mi_stat_counter_print(&stats->mmap_calls, "mmaps", out, arg);
|
||||||
mi_stat_counter_print(&stats->commit_calls, "commits", out, arg);
|
mi_stat_counter_print(&stats->commit_calls, "commits", out, arg);
|
||||||
|
mi_stat_counter_print(&stats->reset_calls, "resets", out, arg);
|
||||||
|
mi_stat_counter_print(&stats->purge_calls, "purges", out, arg);
|
||||||
mi_stat_print(&stats->threads, "threads", -1, out, arg);
|
mi_stat_print(&stats->threads, "threads", -1, out, arg);
|
||||||
mi_stat_counter_print_avg(&stats->searches, "searches", out, arg);
|
mi_stat_counter_print_avg(&stats->searches, "searches", out, arg);
|
||||||
_mi_fprintf(out, arg, "%10s: %7zu\n", "numa nodes", _mi_os_numa_node_count());
|
_mi_fprintf(out, arg, "%10s: %5zu\n", "numa nodes", _mi_os_numa_node_count());
|
||||||
|
|
||||||
size_t elapsed;
|
size_t elapsed;
|
||||||
size_t user_time;
|
size_t user_time;
|
||||||
@ -345,7 +358,7 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0)
|
|||||||
size_t peak_commit;
|
size_t peak_commit;
|
||||||
size_t page_faults;
|
size_t page_faults;
|
||||||
mi_process_info(&elapsed, &user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults);
|
mi_process_info(&elapsed, &user_time, &sys_time, ¤t_rss, &peak_rss, ¤t_commit, &peak_commit, &page_faults);
|
||||||
_mi_fprintf(out, arg, "%10s: %7ld.%03ld s\n", "elapsed", elapsed/1000, elapsed%1000);
|
_mi_fprintf(out, arg, "%10s: %5ld.%03ld s\n", "elapsed", elapsed/1000, elapsed%1000);
|
||||||
_mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, rss: ", "process",
|
_mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, rss: ", "process",
|
||||||
user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, (unsigned long)page_faults );
|
user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, (unsigned long)page_faults );
|
||||||
mi_printf_amount((int64_t)peak_rss, 1, out, arg, "%s");
|
mi_printf_amount((int64_t)peak_rss, 1, out, arg, "%s");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user