2009-12-03 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / cairo / util / malloc-stats.c
blob59a78873dfa8d3656a39eb166b298a4556608fef
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /*
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 */
29 #ifndef _GNU_SOURCE
30 #define _GNU_SOURCE
31 #endif
33 #include <stdlib.h>
34 #include <stdio.h>
36 /* caller-logging */
38 #include <string.h>
40 struct alloc_stat_t {
41 int num;
42 long size;
45 struct alloc_stats_t {
46 struct alloc_stat_t malloc, realloc, total;
49 struct func_stat_t {
50 const void *addr;
51 const char *name;
53 struct alloc_stats_t stat;
56 static struct func_stat_t *func_stats = NULL;
57 static int func_stats_num = 0;
58 static int func_stats_size = 0;
60 static void
61 alloc_stats_add (struct alloc_stats_t *stats, int is_realloc, size_t size)
63 struct alloc_stat_t *stat = is_realloc ? &stats->realloc : &stats->malloc;
65 stats->total.num++;
66 stats->total.size += size;
68 stat->num++;
69 stat->size += size;
72 #include <execinfo.h>
74 static const char *
75 resolve_addr (const void *addr) {
77 char **strings;
78 char *p;
79 const char *name = NULL;
81 if (addr == NULL)
82 return "(other)";
83 if (addr == (void *) -1)
84 return "(total)";
86 strings = backtrace_symbols ((void**)&addr, 1);
87 name = strdup (strings[0]);
89 p = strchr (name, '\t');
90 if (p)
91 name = p + 1;
93 free (strings);
95 return name;
98 static void
99 func_stats_add (const void *caller, int is_realloc, size_t size)
101 int i;
102 const char *name;
104 if (caller != (void *) -1 && caller != NULL)
105 func_stats_add ((void *) -1, is_realloc, size);
107 for (i = 0; i < func_stats_num; i++) {
108 if (func_stats[i].addr == caller) {
109 alloc_stats_add (&func_stats[i].stat, is_realloc, size);
110 return;
114 if (i == func_stats_size) {
115 func_stats_size = func_stats_size ? func_stats_size * 2 : 16;
116 func_stats = realloc (func_stats, func_stats_size * sizeof (func_stats[0]));
119 name = resolve_addr (caller);
121 if (name) {
122 func_stats_num++;
123 func_stats[i].addr = caller;
124 func_stats[i].name = name;
125 memset (&func_stats[i].stat, 0, sizeof (func_stats[i].stat));
126 alloc_stats_add (&func_stats[i].stat, is_realloc, size);
127 return;
130 func_stats_add (NULL, is_realloc, size);
133 /* wrapper stuff */
135 #include <malloc.h>
137 static void *(*old_malloc)(size_t, const void *);
138 static void *(*old_realloc)(void *, size_t, const void *);
140 static void *my_malloc(size_t, const void *);
141 static void *my_realloc(void *, size_t, const void *);
143 static void
144 save_hooks (void)
146 old_malloc = __malloc_hook;
147 old_realloc = __realloc_hook;
150 static void
151 old_hooks (void)
153 __malloc_hook = old_malloc;
154 __realloc_hook = old_realloc;
157 static void
158 my_hooks (void)
160 /* should always save the current value */
161 save_hooks ();
163 __malloc_hook = my_malloc;
164 __realloc_hook = my_realloc;
167 static void *
168 my_malloc(size_t size, const void *caller)
170 void *ret;
172 old_hooks ();
174 func_stats_add (caller, 0, size);
176 ret = malloc (size);
177 my_hooks ();
179 return ret;
182 static void *
183 my_realloc(void *ptr, size_t size, const void *caller)
185 void *ret;
187 old_hooks ();
189 func_stats_add (caller, 1, size);
191 ret = realloc (ptr, size);
192 my_hooks ();
194 return ret;
197 static void
198 my_init_hook(void) {
199 my_hooks ();
202 void (*__malloc_initialize_hook) (void) = my_init_hook;
205 /* reporting */
207 #include <locale.h>
209 static void
210 add_alloc_stats (struct alloc_stats_t *a, struct alloc_stats_t *b)
212 a->total.num += b->total.num;
213 a->total.size += b->total.size;
214 a->malloc.num += b->malloc.num;
215 a->malloc.size += b->malloc.size;
216 a->realloc.num += b->realloc.num;
217 a->realloc.size += b->realloc.size;
220 static void
221 dump_alloc_stats (struct alloc_stats_t *stats, const char *name)
223 printf ("%8d %'11ld %8d %'11ld %8d %'11ld %s\n",
224 stats->total.num, stats->total.size,
225 stats->malloc.num, stats->malloc.size,
226 stats->realloc.num, stats->realloc.size,
227 name);
230 static int
231 compare_func_stats_name (const void *pa, const void *pb)
233 const struct func_stat_t *a = pa, *b = pb;
234 int i;
236 i = strcmp (a->name, b->name);
237 if (i)
238 return i;
240 return ((char *) a->addr - (char *) b->addr);
243 static int
244 compare_func_stats (const void *pa, const void *pb)
246 const struct func_stat_t *a = pa, *b = pb;
248 if (a->stat.total.num != b->stat.total.num)
249 return (a->stat.total.num - b->stat.total.num);
251 if (a->stat.total.size != b->stat.total.size)
252 return (a->stat.total.size - b->stat.total.size);
254 return compare_func_stats_name (pa, pb);
257 static void
258 merge_similar_entries (void)
260 int i, j;
262 j = 0;
263 for (i = 1; i < func_stats_num; i++) {
264 if (i != j && 0 == strcmp (func_stats[i].name, func_stats[j].name)) {
265 add_alloc_stats (&func_stats[j].stat, &func_stats[i].stat);
266 } else {
267 j++;
268 if (i != j)
269 func_stats[j] = func_stats[i];
272 j++;
273 if (j < func_stats_num)
274 func_stats_num = j;
277 __attribute__ ((destructor))
278 void
279 malloc_stats (void)
281 int i;
283 old_hooks ();
285 /* merge entries with same name */
286 qsort (func_stats, func_stats_num, sizeof (func_stats[0]), compare_func_stats_name);
287 merge_similar_entries ();
288 qsort (func_stats, func_stats_num, sizeof (func_stats[0]), compare_func_stats);
290 if (func_stats_num) {
291 setlocale (LC_ALL, "");
293 printf (" TOTAL MALLOC REALLOC\n");
294 printf (" num size num size num size\n");
296 for (i = 0; i < func_stats_num; i++) {
297 dump_alloc_stats (&func_stats[i].stat, func_stats[i].name);