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_addr (const void *addr
) {
118 if (addr
== (void *) -1)
121 strings
= backtrace_symbols ((void**)&addr
, 1);
123 p
= strchr (strings
[0], '\t');
129 len
= strlen (p
) + 1;
130 name
= _perm_alloc (len
);
131 memcpy (name
, p
, len
);
139 resolve_addrs (struct func_stat_t
*func_stats
, int num
)
145 addrs
= malloc (num
* sizeof (void *));
146 for (i
= 0; i
< num
; i
++)
147 addrs
[i
] = (void *) func_stats
[i
].addr
;
149 strings
= backtrace_symbols (addrs
, num
);
151 for (i
= 0; i
< num
; i
++) {
156 p
= strchr (strings
[i
], '\t');
162 len
= strlen (p
) + 1;
163 name
= _perm_alloc (len
);
164 memcpy (name
, p
, len
);
165 func_stats
[i
].name
= name
;
173 func_stats_add (const void *caller
, int is_realloc
, size_t size
)
176 struct func_stat_t
*elt
;
178 alloc_stats_add (&total_allocations
, is_realloc
, size
);
180 i
= ((uintptr_t) caller
^ 1215497) % ARRAY_SIZE (func_stats
);
181 for (elt
= func_stats
[i
]; elt
!= NULL
; elt
= elt
->next
) {
182 if (elt
->addr
== caller
)
189 elt
= _perm_alloc (sizeof (struct func_stat_t
));
190 elt
->next
= func_stats
[i
];
194 memset (&elt
->stat
, 0, sizeof (struct alloc_stats_t
));
197 alloc_stats_add (&elt
->stat
, is_realloc
, size
);
204 static void *(*old_malloc
)(size_t, const void *);
205 static void *(*old_realloc
)(void *, size_t, const void *);
207 static void *my_malloc(size_t, const void *);
208 static void *my_realloc(void *, size_t, const void *);
213 old_malloc
= __malloc_hook
;
214 old_realloc
= __realloc_hook
;
220 __malloc_hook
= old_malloc
;
221 __realloc_hook
= old_realloc
;
227 /* should always save the current value */
230 __malloc_hook
= my_malloc
;
231 __realloc_hook
= my_realloc
;
235 my_malloc(size_t size
, const void *caller
)
241 func_stats_add (caller
, 0, size
);
250 my_realloc(void *ptr
, size_t size
, const void *caller
)
256 func_stats_add (caller
, 1, size
);
258 ret
= realloc (ptr
, size
);
269 void (*__malloc_initialize_hook
) (void) = my_init_hook
;
277 add_alloc_stats (struct alloc_stats_t
*a
, struct alloc_stats_t
*b
)
279 a
->total
.num
+= b
->total
.num
;
280 a
->total
.size
+= b
->total
.size
;
281 a
->malloc
.num
+= b
->malloc
.num
;
282 a
->malloc
.size
+= b
->malloc
.size
;
283 a
->realloc
.num
+= b
->realloc
.num
;
284 a
->realloc
.size
+= b
->realloc
.size
;
288 dump_alloc_stats (struct alloc_stats_t
*stats
, const char *name
)
290 printf ("%8u %'11llu %8u %'11llu %8u %'11llu %s\n",
291 stats
->total
.num
, stats
->total
.size
,
292 stats
->malloc
.num
, stats
->malloc
.size
,
293 stats
->realloc
.num
, stats
->realloc
.size
,
298 compare_func_stats_name (const void *pa
, const void *pb
)
300 const struct func_stat_t
*a
= pa
, *b
= pb
;
303 i
= strcmp (a
->name
, b
->name
);
307 return ((char *) a
->addr
- (char *) b
->addr
);
311 compare_func_stats (const void *pa
, const void *pb
)
313 const struct func_stat_t
*a
= pa
, *b
= pb
;
315 if (a
->stat
.total
.num
!= b
->stat
.total
.num
)
316 return (a
->stat
.total
.num
- b
->stat
.total
.num
);
318 if (a
->stat
.total
.size
!= b
->stat
.total
.size
)
319 return (a
->stat
.total
.size
- b
->stat
.total
.size
);
321 return compare_func_stats_name (pa
, pb
);
325 merge_similar_entries (struct func_stat_t
*func_stats
, int num
)
330 for (i
= 1; i
< num
; i
++) {
331 if (i
!= j
&& 0 == strcmp (func_stats
[i
].name
, func_stats
[j
].name
)) {
332 add_alloc_stats (&func_stats
[j
].stat
, &func_stats
[i
].stat
);
336 func_stats
[j
] = func_stats
[i
];
344 __attribute__ ((destructor
))
349 struct func_stat_t
*sorted_func_stats
;
353 if (! func_stats_num
)
356 sorted_func_stats
= malloc (sizeof (struct func_stat_t
) * (func_stats_num
+ 1));
357 if (sorted_func_stats
== NULL
)
361 for (i
= 0; i
< ARRAY_SIZE (func_stats
); i
++) {
362 struct func_stat_t
*elt
;
363 for (elt
= func_stats
[i
]; elt
!= NULL
; elt
= elt
->next
)
364 sorted_func_stats
[j
++] = *elt
;
367 resolve_addrs (sorted_func_stats
, j
);
369 /* merge entries with same name */
370 qsort (sorted_func_stats
, j
,
371 sizeof (struct func_stat_t
), compare_func_stats_name
);
372 j
= merge_similar_entries (sorted_func_stats
, j
);
374 qsort (sorted_func_stats
, j
,
375 sizeof (struct func_stat_t
), compare_func_stats
);
378 sorted_func_stats
[j
].next
= NULL
;
379 sorted_func_stats
[j
].addr
= (void *) -1;
380 sorted_func_stats
[j
].name
= "(total)";
381 sorted_func_stats
[j
].stat
= total_allocations
;
384 setlocale (LC_ALL
, "");
386 printf (" TOTAL MALLOC REALLOC\n");
387 printf (" num size num size num size\n");
389 for (i
= 0; i
< j
; i
++) {
390 dump_alloc_stats (&sorted_func_stats
[i
].stat
,
391 sorted_func_stats
[i
].name
);
394 /* XXX free other stuff? */
396 free (sorted_func_stats
);