diff --git a/CMakeLists.txt b/CMakeLists.txt index a3acf83e..0641bddc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ option(MI_NO_PADDING "Force no use of padding even in DEBUG mode etc." OF option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) option(MI_NO_THP "Disable transparent huge pages support on Linux/Android for the mimalloc process only" OFF) option(MI_EXTRA_CPPDEFS "Extra pre-processor definitions (use as `-DMI_EXTRA_CPPDEFS=\"opt1=val1;opt2=val2\"`)" "") +option(MI_STAT_LEVEL "Optionally override stats level to 1 or 2 when debug not enable" 0) # negated options for vcpkg features option(MI_NO_USE_CXX "Use plain C compilation (has priority over MI_USE_CXX)" OFF) @@ -78,6 +79,10 @@ else() set(mi_defines "") endif() +if (MI_STAT_LEVEL GREATER 0) + add_compile_definitions(MI_STAT=${MI_STAT_LEVEL}) +endif () + # pass git revision as a define if(EXISTS "${CMAKE_SOURCE_DIR}/.git/index") find_package(Git) diff --git a/include/mimalloc-stats.h b/include/mimalloc-stats.h index 44c4886f..230ea242 100644 --- a/include/mimalloc-stats.h +++ b/include/mimalloc-stats.h @@ -88,6 +88,17 @@ typedef struct mi_stats_s #undef MI_STAT_COUNT #undef MI_STAT_COUNTER +typedef struct mi_os_stats_s { + mi_stat_count_t reserved; + mi_stat_count_t committed; + mi_stat_count_t reset; + mi_stat_count_t purged; + mi_stat_counter_t mmap_calls; + mi_stat_counter_t commit_calls; + mi_stat_counter_t reset_calls; + mi_stat_counter_t purge_calls; +} mi_os_stats_t; + // Exported definitions #ifdef __cplusplus extern "C" { @@ -95,6 +106,15 @@ extern "C" { 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 + +// returns the thread local stats for the current thread local heap. Memory returned is non-owned. +mi_decl_export const mi_stats_t* mi_thread_stats(void) mi_attr_noexcept; + +// returns the thread local stats for the given heap. Memory returned is non-owned. +mi_decl_export const mi_stats_t* mi_thread_heap_stats(const mi_heap_t* heap) mi_attr_noexcept; + +// returns stats related to os memory subsystem. +mi_decl_export mi_os_stats_t mi_os_stats(void) mi_attr_noexcept; #ifdef __cplusplus } diff --git a/src/stats.c b/src/stats.c index 92bc049c..2d5e05da 100644 --- a/src/stats.c +++ b/src/stats.c @@ -118,6 +118,22 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) { } } +static void mi_stat_atomic_copy(mi_stat_count_t* dst, const mi_stat_count_t* src) { + if (dst==src) return; + if (src->total==0) return; + + dst->total = (mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&src->total))); + dst->current = (mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&src->current))); + dst->peak = (mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&src->peak))); +} + +static void mi_stat_counter_atomic_copy(mi_stat_counter_t* dst, const mi_stat_counter_t* src) { + if (dst==src) return; + if (src->total==0) return; + + dst->total = (mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&src->total))); +} + #undef MI_STAT_COUNT #undef MI_STAT_COUNTER @@ -413,6 +429,30 @@ void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept { _mi_stats_print(mi_stats_get_default(), out, arg); } +const mi_stats_t* mi_thread_heap_stats(const mi_heap_t* heap) mi_attr_noexcept { + return &heap->tld->stats; +} + +const mi_stats_t* mi_thread_stats(void) mi_attr_noexcept { + return mi_thread_heap_stats(mi_heap_get_default()); +} + +mi_os_stats_t mi_os_stats(void) mi_attr_noexcept { + mi_os_stats_t stats; + memset(&stats, 0, sizeof(mi_os_stats_t)); + + mi_stat_atomic_copy(&stats.reserved, &_mi_stats_main.reserved); + mi_stat_atomic_copy(&stats.committed, &_mi_stats_main.committed); + mi_stat_atomic_copy(&stats.reset, &_mi_stats_main.reset); + mi_stat_atomic_copy(&stats.purged, &_mi_stats_main.purged); + + mi_stat_counter_atomic_copy(&stats.mmap_calls, &_mi_stats_main.mmap_calls); + mi_stat_counter_atomic_copy(&stats.commit_calls, &_mi_stats_main.commit_calls); + mi_stat_counter_atomic_copy(&stats.reset_calls, &_mi_stats_main.reset_calls); + mi_stat_counter_atomic_copy(&stats.purge_calls, &_mi_stats_main.purge_calls); + + return stats; +} // ---------------------------------------------------------------- // Basic timer for convenience; use milli-seconds to avoid doubles