summaryrefslogtreecommitdiff
path: root/libs/cairo-1.16.0/util/malloc-stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cairo-1.16.0/util/malloc-stats.c')
-rw-r--r--libs/cairo-1.16.0/util/malloc-stats.c368
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);
+}