1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
3 * Copyright © 2007 Red Hat, Inc.
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of
10 * Red Hat, Inc. not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. Red Hat, Inc. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
16 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
22 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: Behdad Esfahbod <behdad@behdad.org>
27 /* A simple malloc wrapper that prints out statistics on termination */
43 unsigned long long size;
46 struct alloc_stats_t {
47 struct alloc_stat_t malloc, realloc, total;
51 struct func_stat_t *next;
56 struct alloc_stats_t stat;
59 static struct alloc_stats_t total_allocations;
60 static struct func_stat_t *func_stats[31627];
61 static int func_stats_num;
63 #define ARRAY_SIZE(A) (sizeof (A)/sizeof (A[0]))
66 alloc_stats_add (struct alloc_stats_t *stats, int is_realloc, size_t size)
68 struct alloc_stat_t *stat = is_realloc ? &stats->realloc : &stats->malloc;
71 stats->total.size += size;
80 _perm_alloc (size_t size)
87 #define SUPERBLOCK_SIZE (1<<23)
88 #define align(x, y) (((x) + ((y)-1)) & ~((y)-1))
90 size = align (size, 2 * sizeof (void *));
91 if (size > rem || rem == 0) {
92 ptr = malloc (SUPERBLOCK_SIZE);
95 rem = SUPERBLOCK_SIZE;
98 #undef SUPERBLOCK_SIZE
109 resolve_addrs (struct func_stat_t *func_stats, int num)
115 addrs = malloc (num * sizeof (void *));
116 for (i = 0; i < num; i++)
117 addrs[i] = (void *) func_stats[i].addr;
119 strings = backtrace_symbols (addrs, num);
121 for (i = 0; i < num; i++) {
126 p = strchr (strings[i], '\t');
132 len = strlen (p) + 1;
133 name = _perm_alloc (len);
134 memcpy (name, p, len);
135 func_stats[i].name = name;
143 func_stats_add (const void *caller, int is_realloc, size_t size)
146 struct func_stat_t *elt;
148 alloc_stats_add (&total_allocations, is_realloc, size);
150 i = ((uintptr_t) caller ^ 1215497) % ARRAY_SIZE (func_stats);
151 for (elt = func_stats[i]; elt != NULL; elt = elt->next) {
152 if (elt->addr == caller)
159 elt = _perm_alloc (sizeof (struct func_stat_t));
160 elt->next = func_stats[i];
164 memset (&elt->stat, 0, sizeof (struct alloc_stats_t));
167 alloc_stats_add (&elt->stat, is_realloc, size);
174 static void *(*old_malloc)(size_t, const void *);
175 static void *(*old_realloc)(void *, size_t, const void *);
177 static void *my_malloc(size_t, const void *);
178 static void *my_realloc(void *, size_t, const void *);
183 old_malloc = __malloc_hook;
184 old_realloc = __realloc_hook;
190 __malloc_hook = old_malloc;
191 __realloc_hook = old_realloc;
197 /* should always save the current value */
200 __malloc_hook = my_malloc;
201 __realloc_hook = my_realloc;
205 my_malloc(size_t size, const void *caller)
211 func_stats_add (caller, 0, size);
220 my_realloc(void *ptr, size_t size, const void *caller)
226 func_stats_add (caller, 1, size);
228 ret = realloc (ptr, size);
239 void (*__malloc_initialize_hook) (void) = my_init_hook;
247 add_alloc_stats (struct alloc_stats_t *a, struct alloc_stats_t *b)
249 a->total.num += b->total.num;
250 a->total.size += b->total.size;
251 a->malloc.num += b->malloc.num;
252 a->malloc.size += b->malloc.size;
253 a->realloc.num += b->realloc.num;
254 a->realloc.size += b->realloc.size;
258 dump_alloc_stats (struct alloc_stats_t *stats, const char *name)
260 printf ("%8u %'11llu %8u %'11llu %8u %'11llu %s\n",
261 stats->total.num, stats->total.size,
262 stats->malloc.num, stats->malloc.size,
263 stats->realloc.num, stats->realloc.size,
268 compare_func_stats_name (const void *pa, const void *pb)
270 const struct func_stat_t *a = pa, *b = pb;
273 i = strcmp (a->name, b->name);
277 return ((char *) a->addr - (char *) b->addr);
281 compare_func_stats (const void *pa, const void *pb)
283 const struct func_stat_t *a = pa, *b = pb;
285 if (a->stat.total.num != b->stat.total.num)
286 return (a->stat.total.num - b->stat.total.num);
288 if (a->stat.total.size != b->stat.total.size)
289 return (a->stat.total.size - b->stat.total.size);
291 return compare_func_stats_name (pa, pb);
295 merge_similar_entries (struct func_stat_t *func_stats, int num)
300 for (i = 1; i < num; i++) {
301 if (i != j && 0 == strcmp (func_stats[i].name, func_stats[j].name)) {
302 add_alloc_stats (&func_stats[j].stat, &func_stats[i].stat);
306 func_stats[j] = func_stats[i];
314 __attribute__ ((destructor))
319 struct func_stat_t *sorted_func_stats;
323 if (! func_stats_num)
326 sorted_func_stats = malloc (sizeof (struct func_stat_t) * (func_stats_num + 1));
327 if (sorted_func_stats == NULL)
331 for (i = 0; i < ARRAY_SIZE (func_stats); i++) {
332 struct func_stat_t *elt;
333 for (elt = func_stats[i]; elt != NULL; elt = elt->next)
334 sorted_func_stats[j++] = *elt;
337 resolve_addrs (sorted_func_stats, j);
339 /* merge entries with same name */
340 qsort (sorted_func_stats, j,
341 sizeof (struct func_stat_t), compare_func_stats_name);
342 j = merge_similar_entries (sorted_func_stats, j);
344 qsort (sorted_func_stats, j,
345 sizeof (struct func_stat_t), compare_func_stats);
348 sorted_func_stats[j].next = NULL;
349 sorted_func_stats[j].addr = (void *) -1;
350 sorted_func_stats[j].name = "(total)";
351 sorted_func_stats[j].stat = total_allocations;
354 setlocale (LC_ALL, "");
356 printf (" TOTAL MALLOC REALLOC\n");
357 printf (" num size num size num size\n");
359 for (i = 0; i < j; i++) {
360 dump_alloc_stats (&sorted_func_stats[i].stat,
361 sorted_func_stats[i].name);
364 /* XXX free other stuff? */
366 free (sorted_func_stats);