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 */
45 struct alloc_stats_t
{
46 struct alloc_stat_t malloc
, realloc
, total
;
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;
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
;
66 stats
->total
.size
+= size
;
75 resolve_addr (const void *addr
) {
79 const char *name
= NULL
;
83 if (addr
== (void *) -1)
86 strings
= backtrace_symbols ((void**)&addr
, 1);
87 name
= strdup (strings
[0]);
89 p
= strchr (name
, '\t');
99 func_stats_add (const void *caller
, int is_realloc
, size_t size
)
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
);
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
);
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
);
130 func_stats_add (NULL
, is_realloc
, size
);
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 *);
146 old_malloc
= __malloc_hook
;
147 old_realloc
= __realloc_hook
;
153 __malloc_hook
= old_malloc
;
154 __realloc_hook
= old_realloc
;
160 /* should always save the current value */
163 __malloc_hook
= my_malloc
;
164 __realloc_hook
= my_realloc
;
168 my_malloc(size_t size
, const void *caller
)
174 func_stats_add (caller
, 0, size
);
183 my_realloc(void *ptr
, size_t size
, const void *caller
)
189 func_stats_add (caller
, 1, size
);
191 ret
= realloc (ptr
, size
);
202 void (*__malloc_initialize_hook
) (void) = my_init_hook
;
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
;
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
,
231 compare_func_stats_name (const void *pa
, const void *pb
)
233 const struct func_stat_t
*a
= pa
, *b
= pb
;
236 i
= strcmp (a
->name
, b
->name
);
240 return ((char *) a
->addr
- (char *) b
->addr
);
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
);
258 merge_similar_entries (void)
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
);
269 func_stats
[j
] = func_stats
[i
];
273 if (j
< func_stats_num
)
277 __attribute__ ((destructor
))
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
);