| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
- /*
- * Copyright © 2007 Red Hat, Inc.
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of
- * Red Hat, Inc. not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. Red Hat, Inc. makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Behdad Esfahbod <behdad@behdad.org>
- */
- /* A simple malloc wrapper that prints out statistics on termination */
- #ifndef _GNU_SOURCE
- #define _GNU_SOURCE
- #endif
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdint.h>
- /* caller-logging */
- #include <string.h>
- struct alloc_stat_t {
- unsigned int num;
- unsigned long long size;
- };
- struct alloc_stats_t {
- struct alloc_stat_t malloc, realloc, total;
- };
- struct func_stat_t {
- struct func_stat_t *next;
- const void *addr;
- const char *name;
- struct alloc_stats_t stat;
- };
- static struct alloc_stats_t total_allocations;
- static struct func_stat_t *func_stats[31627];
- static int func_stats_num;
- #ifndef ARRAY_LENGTH
- #define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
- #endif
- static void
- alloc_stats_add (struct alloc_stats_t *stats, int is_realloc, size_t size)
- {
- struct alloc_stat_t *stat = is_realloc ? &stats->realloc : &stats->malloc;
- stats->total.num++;
- stats->total.size += size;
- stat->num++;
- stat->size += size;
- }
- #include <execinfo.h>
- static void *
- _perm_alloc (size_t size)
- {
- static uint8_t *ptr;
- static size_t rem;
- void *ret;
- #define SUPERBLOCK_SIZE (1<<23)
- #define align(x, y) (((x) + ((y)-1)) & ~((y)-1))
- size = align (size, 2 * sizeof (void *));
- if (size > rem || rem == 0) {
- ptr = malloc (SUPERBLOCK_SIZE);
- if (ptr == NULL)
- exit (1);
- rem = SUPERBLOCK_SIZE;
- }
- #undef SUPERBLOCK_SIZE
- #undef align
- ret = ptr;
- rem -= size;
- ptr += size;
- return ret;
- }
- static void
- resolve_addrs (struct func_stat_t *func_stats, int num)
- {
- int i;
- void **addrs;
- char **strings;
- addrs = malloc (num * sizeof (void *));
- for (i = 0; i < num; i++)
- addrs[i] = (void *) func_stats[i].addr;
- strings = backtrace_symbols (addrs, num);
- for (i = 0; i < num; i++) {
- char *p;
- char *name;
- int len;
- p = strchr (strings[i], '\t');
- if (p)
- p++;
- else
- p = strings[i];
- len = strlen (p) + 1;
- name = _perm_alloc (len);
- memcpy (name, p, len);
- func_stats[i].name = name;
- }
- free (strings);
- free (addrs);
- }
- static void
- func_stats_add (const void *caller, int is_realloc, size_t size)
- {
- int i;
- struct func_stat_t *elt;
- alloc_stats_add (&total_allocations, is_realloc, size);
- i = ((uintptr_t) caller ^ 1215497) % ARRAY_LENGTH (func_stats);
- for (elt = func_stats[i]; elt != NULL; elt = elt->next) {
- if (elt->addr == caller)
- break;
- }
- if (elt == NULL) {
- func_stats_num++;
- elt = _perm_alloc (sizeof (struct func_stat_t));
- elt->next = func_stats[i];
- func_stats[i] = elt;
- elt->addr = caller;
- elt->name = NULL;
- memset (&elt->stat, 0, sizeof (struct alloc_stats_t));
- }
- alloc_stats_add (&elt->stat, is_realloc, size);
- }
- /* wrapper stuff */
- #include <malloc.h>
- static void *(*old_malloc)(size_t, const void *);
- static void *(*old_realloc)(void *, size_t, const void *);
- static void *my_malloc(size_t, const void *);
- static void *my_realloc(void *, size_t, const void *);
- static void
- save_hooks (void)
- {
- old_malloc = __malloc_hook;
- old_realloc = __realloc_hook;
- }
- static void
- old_hooks (void)
- {
- __malloc_hook = old_malloc;
- __realloc_hook = old_realloc;
- }
- static void
- my_hooks (void)
- {
- /* should always save the current value */
- save_hooks ();
- __malloc_hook = my_malloc;
- __realloc_hook = my_realloc;
- }
- static void *
- my_malloc(size_t size, const void *caller)
- {
- void *ret;
- old_hooks ();
- func_stats_add (caller, 0, size);
- ret = malloc (size);
- my_hooks ();
- return ret;
- }
- static void *
- my_realloc(void *ptr, size_t size, const void *caller)
- {
- void *ret;
- old_hooks ();
- func_stats_add (caller, 1, size);
- ret = realloc (ptr, size);
- my_hooks ();
- return ret;
- }
- static void
- my_init_hook(void) {
- my_hooks ();
- }
- void (*__volatile __malloc_initialize_hook) (void) = my_init_hook;
- /* reporting */
- #include <locale.h>
- static void
- add_alloc_stats (struct alloc_stats_t *a, struct alloc_stats_t *b)
- {
- a->total.num += b->total.num;
- a->total.size += b->total.size;
- a->malloc.num += b->malloc.num;
- a->malloc.size += b->malloc.size;
- a->realloc.num += b->realloc.num;
- a->realloc.size += b->realloc.size;
- }
- static void
- dump_alloc_stats (struct alloc_stats_t *stats, const char *name)
- {
- printf ("%8u %'11llu %8u %'11llu %8u %'11llu %s\n",
- stats->total.num, stats->total.size,
- stats->malloc.num, stats->malloc.size,
- stats->realloc.num, stats->realloc.size,
- name);
- }
- static int
- compare_func_stats_name (const void *pa, const void *pb)
- {
- const struct func_stat_t *a = pa, *b = pb;
- int i;
- i = strcmp (a->name, b->name);
- if (i)
- return i;
- return ((char *) a->addr - (char *) b->addr);
- }
- static int
- compare_func_stats (const void *pa, const void *pb)
- {
- const struct func_stat_t *a = pa, *b = pb;
- if (a->stat.total.num != b->stat.total.num)
- return (a->stat.total.num - b->stat.total.num);
- if (a->stat.total.size != b->stat.total.size)
- return (a->stat.total.size - b->stat.total.size);
- return compare_func_stats_name (pa, pb);
- }
- static int
- merge_similar_entries (struct func_stat_t *func_stats, int num)
- {
- int i, j;
- j = 0;
- for (i = 1; i < num; i++) {
- if (i != j && 0 == strcmp (func_stats[i].name, func_stats[j].name)) {
- add_alloc_stats (&func_stats[j].stat, &func_stats[i].stat);
- } else {
- j++;
- if (i != j)
- func_stats[j] = func_stats[i];
- }
- }
- j++;
- return j;
- }
- __attribute__ ((destructor))
- void
- malloc_stats (void)
- {
- unsigned int i, j;
- struct func_stat_t *sorted_func_stats;
- old_hooks ();
- if (! func_stats_num)
- return;
- sorted_func_stats = malloc (sizeof (struct func_stat_t) * (func_stats_num + 1));
- if (sorted_func_stats == NULL)
- return;
- j = 0;
- for (i = 0; i < ARRAY_LENGTH (func_stats); i++) {
- struct func_stat_t *elt;
- for (elt = func_stats[i]; elt != NULL; elt = elt->next)
- sorted_func_stats[j++] = *elt;
- }
- resolve_addrs (sorted_func_stats, j);
- /* merge entries with same name */
- qsort (sorted_func_stats, j,
- sizeof (struct func_stat_t), compare_func_stats_name);
- j = merge_similar_entries (sorted_func_stats, j);
- qsort (sorted_func_stats, j,
- sizeof (struct func_stat_t), compare_func_stats);
- /* add total */
- sorted_func_stats[j].next = NULL;
- sorted_func_stats[j].addr = (void *) -1;
- sorted_func_stats[j].name = "(total)";
- sorted_func_stats[j].stat = total_allocations;
- j++;
- setlocale (LC_ALL, "");
- printf (" TOTAL MALLOC REALLOC\n");
- printf (" num size num size num size\n");
- for (i = 0; i < j; i++) {
- dump_alloc_stats (&sorted_func_stats[i].stat,
- sorted_func_stats[i].name);
- }
- /* XXX free other stuff? */
- free (sorted_func_stats);
- }
|