This commit is contained in:
Michael Clark 2022-04-12 20:11:38 -04:00 committed by GitHub
commit cc07ed336b
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 1 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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));

View file

@ -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

View file

@ -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.

View file

@ -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
// --------------------------------------------------------