diff options
Diffstat (limited to 'libs/cairo-1.16.0/util/malloc-stats.c')
-rw-r--r-- | libs/cairo-1.16.0/util/malloc-stats.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/libs/cairo-1.16.0/util/malloc-stats.c b/libs/cairo-1.16.0/util/malloc-stats.c new file mode 100644 index 0000000..55ed51c --- /dev/null +++ b/libs/cairo-1.16.0/util/malloc-stats.c @@ -0,0 +1,368 @@ +/* -*- 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); +} |