From 004a093ec7cbb42ee10f108e709a65cb9187bc0b Mon Sep 17 00:00:00 2001 From: Daan Date: Thu, 13 Mar 2025 13:22:58 -0700 Subject: [PATCH] add mi_stats_get_bin_size and chunk counters --- include/mimalloc-stats.h | 19 ++++++++++++++++--- include/mimalloc/internal.h | 2 ++ src/bitmap.c | 6 ++++-- src/bitmap.h | 11 +---------- src/init.c | 3 ++- src/page-queue.c | 1 + src/stats.c | 7 ++++++- 7 files changed, 32 insertions(+), 17 deletions(-) diff --git a/include/mimalloc-stats.h b/include/mimalloc-stats.h index 44c4886f..93b728bd 100644 --- a/include/mimalloc-stats.h +++ b/include/mimalloc-stats.h @@ -11,7 +11,7 @@ terms of the MIT license. A copy of the license can be found in the file #include #include -#define MI_STAT_VERSION 1 // increased on every backward incompatible change +#define MI_STAT_VERSION 2 // increased on every backward incompatible change // count allocation over time typedef struct mi_stat_count_s { @@ -65,6 +65,17 @@ typedef struct mi_stat_counter_s { MI_STAT_COUNTER(pages_unabandon_busy_wait) \ +// Size bins for chunks +typedef enum mi_bbin_e { + MI_BBIN_SMALL, // slice_count == 1 + MI_BBIN_OTHER, // slice_count: any other from the other bins, and 1 <= slice_count <= MI_BCHUNK_BITS + MI_BBIN_MEDIUM, // slice_count == 8 + MI_BBIN_LARGE, // slice_count == MI_SIZE_BITS (only used if MI_ENABLE_LARGE_PAGES is 1) + MI_BBIN_NONE, // no bin assigned yet (the chunk is completely free) + MI_BBIN_COUNT +} mi_bbin_t; + + // Define the statistics structure #define MI_BIN_HUGE (73U) // see types.h #define MI_STAT_COUNT(stat) mi_stat_count_t stat; @@ -83,6 +94,7 @@ typedef struct mi_stats_s // size segregated statistics mi_stat_count_t malloc_bins[MI_BIN_HUGE+1]; // allocation per size bin mi_stat_count_t page_bins[MI_BIN_HUGE+1]; // pages allocated per size bin + mi_stat_count_t chunk_bins[MI_BBIN_COUNT]; // chunks per page sizes } mi_stats_t; #undef MI_STAT_COUNT @@ -93,8 +105,9 @@ typedef struct mi_stats_s extern "C" { #endif -mi_decl_export void mi_stats_get( size_t stats_size, mi_stats_t* stats ) mi_attr_noexcept; -mi_decl_export char* mi_stats_get_json( size_t buf_size, char* buf ) mi_attr_noexcept; // use mi_free to free the result if the input buf == NULL +mi_decl_export void mi_stats_get( size_t stats_size, mi_stats_t* stats ) mi_attr_noexcept; +mi_decl_export char* mi_stats_get_json( size_t buf_size, char* buf ) mi_attr_noexcept; // use mi_free to free the result if the input buf == NULL +mi_decl_export size_t mi_stats_get_bin_size(size_t bin) mi_attr_noexcept; #ifdef __cplusplus } diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 8a880b8d..f57f1087 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -299,7 +299,9 @@ void _mi_assert_fail(const char* assertion, const char* fname, unsigned int line #define MI_INIT64(x) MI_INIT32(x),MI_INIT32(x) #define MI_INIT128(x) MI_INIT64(x),MI_INIT64(x) #define MI_INIT256(x) MI_INIT128(x),MI_INIT128(x) + #define MI_INIT74(x) MI_INIT64(x),MI_INIT8(x),x(),x() +#define MI_INIT5(x) MI_INIT4(x),x() #include // initialize a local variable to zero; use memset as compilers optimize constant sized memset's diff --git a/src/bitmap.c b/src/bitmap.c index f7f94ddb..f010a421 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -1415,10 +1415,12 @@ static void mi_bbitmap_set_chunk_bin(mi_bbitmap_t* bbitmap, size_t chunk_idx, mi mi_assert_internal(chunk_idx < mi_bbitmap_chunk_count(bbitmap)); for (mi_bbin_t ibin = MI_BBIN_SMALL; ibin < MI_BBIN_NONE; ibin = mi_bbin_inc(ibin)) { if (ibin == bin) { - mi_bchunk_set(& bbitmap->chunkmap_bins[ibin], chunk_idx, NULL); + const bool was_clear = mi_bchunk_set(& bbitmap->chunkmap_bins[ibin], chunk_idx, NULL); + if (was_clear) { mi_os_stat_increase(chunk_bins[ibin],1); } } else { - mi_bchunk_clear(&bbitmap->chunkmap_bins[ibin], chunk_idx, NULL); + const bool was_set = mi_bchunk_clear(&bbitmap->chunkmap_bins[ibin], chunk_idx, NULL); + if (was_set) { mi_os_stat_decrease(chunk_bins[ibin],1); } } } } diff --git a/src/bitmap.h b/src/bitmap.h index 0237d005..83af74ee 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -212,16 +212,7 @@ bool _mi_bitmap_forall_setc_ranges(mi_bitmap_t* bitmap, mi_forall_set_fun_t* vis much fragmentation since we keep chunks for larger blocks separate. ---------------------------------------------------------------------------- */ -// Size bins; larger bins are allowed to go into smaller bins. -// SMALL can only be in small (and NONE), so they cannot fragment the larger bins. -typedef enum mi_bbin_e { - MI_BBIN_SMALL, // slice_count == 1 - MI_BBIN_OTHER, // slice_count: any other from the other bins, and 1 <= slice_count <= MI_BCHUNK_BITS - MI_BBIN_MEDIUM, // slice_count == 8 - MI_BBIN_LARGE, // slice_count == MI_BFIELD_BITS -- only used if MI_ENABLE_LARGE_PAGES is 1 - MI_BBIN_NONE, // no bin assigned yet (the chunk is completely free) - MI_BBIN_COUNT -} mi_bbin_t; +// mi_bbin_t is defined in mimalloc-stats.h static inline mi_bbin_t mi_bbin_inc(mi_bbin_t bbin) { mi_assert_internal(bbin < MI_BBIN_COUNT); diff --git a/src/init.c b/src/init.c index 54905dc8..6d4ce65e 100644 --- a/src/init.c +++ b/src/init.c @@ -83,7 +83,8 @@ const mi_page_t _mi_page_empty = { { { 0 }, { 0 }, { 0 }, { 0 } }, \ \ { MI_INIT74(MI_STAT_COUNT_NULL) }, \ - { MI_INIT74(MI_STAT_COUNT_NULL) } + { MI_INIT74(MI_STAT_COUNT_NULL) }, \ + { MI_INIT5(MI_STAT_COUNT_NULL) } // -------------------------------------------------------- // Statically allocate an empty heap as the initial diff --git a/src/page-queue.c b/src/page-queue.c index 4c30c970..3e2315cc 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -106,6 +106,7 @@ size_t _mi_bin(size_t size) { } size_t _mi_bin_size(size_t bin) { + mi_assert_internal(bin <= MI_BIN_HUGE); return _mi_heap_empty.pages[bin].block_size; } diff --git a/src/stats.c b/src/stats.c index 27dc69d0..7a761d82 100644 --- a/src/stats.c +++ b/src/stats.c @@ -479,6 +479,11 @@ mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, s // Return statistics // -------------------------------------------------------- +size_t mi_stats_get_bin_size(size_t bin) mi_attr_noexcept { + if (bin > MI_BIN_HUGE) return 0; + return _mi_bin_size(bin); +} + void mi_stats_get(size_t stats_size, mi_stats_t* stats) mi_attr_noexcept { if (stats == NULL || stats_size == 0) return; _mi_memzero(stats, stats_size); @@ -529,7 +534,7 @@ static void mi_heap_buf_print(mi_heap_buf_t* hbuf, const char* msg) { } static void mi_heap_buf_print_count_bin(mi_heap_buf_t* hbuf, const char* prefix, mi_stat_count_t* stat, size_t bin, bool add_comma) { - const size_t binsize = _mi_bin_size(bin); + const size_t binsize = mi_stats_get_bin_size(bin); const size_t pagesize = (binsize <= MI_SMALL_MAX_OBJ_SIZE ? MI_SMALL_PAGE_SIZE : (binsize <= MI_MEDIUM_MAX_OBJ_SIZE ? MI_MEDIUM_PAGE_SIZE : (binsize <= MI_LARGE_MAX_OBJ_SIZE ? MI_LARGE_PAGE_SIZE : 0)));