mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-20 22:19:30 +03:00
Merge e5bcfae95f
into 9afdf762a6
This commit is contained in:
commit
cc07ed336b
6 changed files with 96 additions and 1 deletions
|
@ -131,6 +131,8 @@ void _mi_heap_set_default_direct(mi_heap_t* heap);
|
|||
|
||||
// "stats.c"
|
||||
void _mi_stats_done(mi_stats_t* stats);
|
||||
void _mi_histogram_log(size_t size);
|
||||
void _mi_histogram_print(mi_output_fun* out);
|
||||
|
||||
mi_msecs_t _mi_clock_now(void);
|
||||
mi_msecs_t _mi_clock_end(mi_msecs_t start);
|
||||
|
|
|
@ -304,6 +304,7 @@ typedef enum mi_option_e {
|
|||
// stable options
|
||||
mi_option_show_errors, // print error messages
|
||||
mi_option_show_stats, // print statistics on termination
|
||||
mi_option_show_histogram, // print histogram
|
||||
mi_option_verbose, // print verbose messages
|
||||
// the following options are experimental (see src/options.h)
|
||||
mi_option_eager_commit,
|
||||
|
|
|
@ -98,7 +98,11 @@ extern inline mi_decl_restrict void* mi_malloc_small(size_t size) mi_attr_noexce
|
|||
// The main allocation function
|
||||
extern inline mi_decl_restrict void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept {
|
||||
if (mi_likely(size <= MI_SMALL_SIZE_MAX)) {
|
||||
return mi_heap_malloc_small(heap, size);
|
||||
void *p = mi_heap_malloc_small(heap, size);
|
||||
#if MI_STAT>1
|
||||
if (p) { _mi_histogram_log(size); }
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
else {
|
||||
mi_assert(heap!=NULL);
|
||||
|
@ -106,6 +110,9 @@ extern inline mi_decl_restrict void* mi_heap_malloc(mi_heap_t* heap, size_t size
|
|||
void* const p = _mi_malloc_generic(heap, size + MI_PADDING_SIZE); // note: size can overflow but it is detected in malloc_generic
|
||||
mi_assert_internal(p == NULL || mi_usable_size(p) >= size);
|
||||
#if MI_STAT>1
|
||||
if (p) { _mi_histogram_log(size); }
|
||||
#endif
|
||||
#if MI_STAT>1
|
||||
if (p != NULL) {
|
||||
if (!mi_heap_is_initialized(heap)) { heap = mi_get_default_heap(); }
|
||||
mi_heap_stat_increase(heap, malloc, mi_usable_size(p));
|
||||
|
|
|
@ -603,6 +603,11 @@ static void mi_process_done(void) {
|
|||
if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) {
|
||||
mi_stats_print(NULL);
|
||||
}
|
||||
#if MI_STAT>1
|
||||
if (mi_option_is_enabled(mi_option_show_histogram)) {
|
||||
_mi_histogram_print(NULL);
|
||||
}
|
||||
#endif
|
||||
mi_allocator_done();
|
||||
_mi_verbose_message("process done: 0x%zx\n", _mi_heap_main.thread_id);
|
||||
os_preloading = true; // don't call the C runtime anymore
|
||||
|
|
|
@ -63,6 +63,7 @@ static mi_option_desc_t options[_mi_option_last] =
|
|||
{ 0, UNINIT, MI_OPTION(show_errors) },
|
||||
#endif
|
||||
{ 0, UNINIT, MI_OPTION(show_stats) },
|
||||
{ 0, UNINIT, MI_OPTION(show_histogram) },
|
||||
{ 0, UNINIT, MI_OPTION(verbose) },
|
||||
|
||||
// the following options are experimental and not all combinations make sense.
|
||||
|
|
79
src/stats.c
79
src/stats.c
|
@ -451,6 +451,85 @@ mi_msecs_t _mi_clock_end(mi_msecs_t start) {
|
|||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Histogram of allocations sizes (power of 2)
|
||||
----------------------------------------------------------- */
|
||||
|
||||
static _Atomic(size_t) mi_hist[MI_SIZE_BITS] = { 0 };
|
||||
|
||||
void _mi_histogram_log(size_t size)
|
||||
{
|
||||
if (mi_unlikely(size == 0)) return;
|
||||
size_t bucket = mi_bsr(size);
|
||||
mi_atomic_increment_relaxed(mi_hist + bucket);
|
||||
}
|
||||
|
||||
static char* _mi_make_bar(char *buf, size_t buflen, size_t value, size_t max, size_t width)
|
||||
{
|
||||
/* we can't dynamically detect if the terminal supports unicode block characters */
|
||||
#if defined(_WIN32)
|
||||
size_t v = value * width / max;
|
||||
buf[0] = '\0';
|
||||
while (v > 0) {
|
||||
strncat(buf, "*", buflen--);
|
||||
v--;
|
||||
}
|
||||
#else
|
||||
static const char* a[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
|
||||
size_t v = value * width * 8 / max;
|
||||
buf[0] = '\0';
|
||||
while (v > 8) {
|
||||
strncat(buf, a[8], buflen--);
|
||||
v-=8;
|
||||
}
|
||||
strncat(buf, a[v], buflen--);
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char* _mi_format_bytes(char *buf, size_t buflen, size_t count)
|
||||
{
|
||||
#if MI_SIZE_BITS > 32
|
||||
if (count & ~((((size_t)1) << 50) - (size_t)1)) {
|
||||
snprintf(buf, buflen, "%zuPiB", (count+1) >> 50);
|
||||
} else
|
||||
if (count & ~((((size_t)1) << 40) - (size_t)1)) {
|
||||
snprintf(buf, buflen, "%zuTiB", (count+1) >> 40);
|
||||
} else
|
||||
#endif
|
||||
if (count & ~((((size_t)1) << 30) - (size_t)1)) {
|
||||
snprintf(buf, buflen, "%zuGiB", (count+1) >> 30);
|
||||
} else
|
||||
if (count & ~((((size_t)1) << 20) - (size_t)1)) {
|
||||
snprintf(buf, buflen, "%zuMiB", (count+1) >> 20);
|
||||
} else
|
||||
if (count & ~((((size_t)1) << 10) - (size_t)1)) {
|
||||
snprintf(buf, buflen, "%zuKiB", (count+1) >> 10);
|
||||
} else {
|
||||
snprintf(buf, buflen, "%zuB", count);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void _mi_histogram_print(mi_output_fun* out)
|
||||
{
|
||||
#define _NCOLS 50
|
||||
char bar[_NCOLS*3+1], num1[16], num2[16];
|
||||
size_t max_allocs = 0;
|
||||
for (size_t i = 0; i < MI_SIZE_BITS; i++) {
|
||||
if (mi_hist[i] > max_allocs) { max_allocs = mi_hist[i]; }
|
||||
}
|
||||
_mi_fputs(out, NULL, NULL, "\nhistogram of allocation sizes\n");
|
||||
for (size_t i = 0; i < MI_SIZE_BITS; i++) {
|
||||
if (mi_hist[i]) {
|
||||
_mi_fprintf(out, NULL, "%9s - %-9s [ %-9zu ] %s\n",
|
||||
_mi_format_bytes(num1, sizeof(num1), ((size_t)1 << i)),
|
||||
_mi_format_bytes(num2, sizeof(num2), ((size_t)1 << (i+1))-1),
|
||||
mi_hist[i], _mi_make_bar(bar, sizeof(bar), mi_hist[i], max_allocs, _NCOLS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Basic process statistics
|
||||
// --------------------------------------------------------
|
||||
|
|
Loading…
Add table
Reference in a new issue