~ubuntu-branches/ubuntu/hardy/cairo/hardy-updates

« back to all changes in this revision

Viewing changes to util/malloc-stats.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-01-17 13:00:59 UTC
  • Revision ID: james.westby@ubuntu.com-20080117130059-3gbudaudr2w8bl4w
Tags: upstream-1.5.6
ImportĀ upstreamĀ versionĀ 1.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
 
2
/*
 
3
 * Copyright Ā© 2007 Red Hat, Inc.
 
4
 *
 
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.
 
15
 *
 
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.
 
23
 *
 
24
 * Author: Behdad Esfahbod <behdad@behdad.org>
 
25
 */
 
26
 
 
27
/* A simple malloc wrapper that prints out statistics on termination */
 
28
 
 
29
#ifndef _GNU_SOURCE
 
30
#define _GNU_SOURCE
 
31
#endif
 
32
 
 
33
#include <stdlib.h>
 
34
#include <stdio.h>
 
35
 
 
36
/* caller-logging */
 
37
 
 
38
#include <string.h>
 
39
 
 
40
struct alloc_stat_t {
 
41
        int num;
 
42
        long size;
 
43
};
 
44
 
 
45
struct alloc_stats_t {
 
46
        struct alloc_stat_t malloc, realloc, total;
 
47
};
 
48
 
 
49
struct func_stat_t {
 
50
        const void *addr;
 
51
        const char *name;
 
52
 
 
53
        struct alloc_stats_t stat;
 
54
};
 
55
 
 
56
static struct func_stat_t *func_stats = NULL;
 
57
static int func_stats_num = 0;
 
58
static int func_stats_size = 0;
 
59
 
 
60
static void
 
61
alloc_stats_add (struct alloc_stats_t *stats, int is_realloc, size_t size)
 
62
{
 
63
        struct alloc_stat_t *stat = is_realloc ? &stats->realloc : &stats->malloc;
 
64
 
 
65
        stats->total.num++;
 
66
        stats->total.size += size;
 
67
 
 
68
        stat->num++;
 
69
        stat->size += size;
 
70
}
 
71
 
 
72
#include <execinfo.h>
 
73
 
 
74
static const char *
 
75
resolve_addr (const void *addr) {
 
76
 
 
77
        char **strings;
 
78
        char *p;
 
79
        const char *name = NULL;
 
80
 
 
81
        if (addr == NULL)
 
82
                return "(other)";
 
83
        if (addr == (void *) -1)
 
84
                return "(total)";
 
85
 
 
86
        strings = backtrace_symbols ((void**)&addr, 1);
 
87
        name = strdup (strings[0]);
 
88
 
 
89
        p = strchr (name, '\t');
 
90
        if (p)
 
91
                name = p + 1;
 
92
 
 
93
        free (strings);
 
94
 
 
95
        return name;
 
96
}
 
97
 
 
98
static void
 
99
func_stats_add (const void *caller, int is_realloc, size_t size)
 
100
{
 
101
        int i;
 
102
        const char *name;
 
103
 
 
104
        if (caller != (void *) -1 && caller != NULL)
 
105
                func_stats_add ((void *) -1, is_realloc, size);
 
106
 
 
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;
 
111
                }
 
112
        }
 
113
 
 
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]));
 
117
        }
 
118
 
 
119
        name = resolve_addr (caller);
 
120
 
 
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;
 
128
        }
 
129
 
 
130
        func_stats_add (NULL, is_realloc, size);
 
131
}
 
132
 
 
133
/* wrapper stuff */
 
134
 
 
135
#include <malloc.h>
 
136
 
 
137
static void *(*old_malloc)(size_t, const void *);
 
138
static void *(*old_realloc)(void *, size_t, const void *);
 
139
 
 
140
static void *my_malloc(size_t, const void *);
 
141
static void *my_realloc(void *, size_t, const void *);
 
142
 
 
143
static void
 
144
save_hooks (void)
 
145
{
 
146
        old_malloc  = __malloc_hook;
 
147
        old_realloc = __realloc_hook;
 
148
}
 
149
 
 
150
static void
 
151
old_hooks (void)
 
152
{
 
153
        __malloc_hook  = old_malloc;
 
154
        __realloc_hook  = old_realloc;
 
155
}
 
156
 
 
157
static void
 
158
my_hooks (void)
 
159
{
 
160
        /* should always save the current value */
 
161
        save_hooks ();
 
162
 
 
163
        __malloc_hook  = my_malloc;
 
164
        __realloc_hook  = my_realloc;
 
165
}
 
166
 
 
167
static void *
 
168
my_malloc(size_t size, const void *caller)
 
169
{
 
170
        void *ret;
 
171
 
 
172
        old_hooks ();
 
173
 
 
174
        func_stats_add (caller, 0, size);
 
175
 
 
176
        ret = malloc (size);
 
177
        my_hooks ();
 
178
 
 
179
        return ret;
 
180
}
 
181
 
 
182
static void *
 
183
my_realloc(void *ptr, size_t size, const void *caller)
 
184
{
 
185
        void *ret;
 
186
 
 
187
        old_hooks ();
 
188
 
 
189
        func_stats_add (caller, 1, size);
 
190
 
 
191
        ret = realloc (ptr, size);
 
192
        my_hooks ();
 
193
 
 
194
        return ret;
 
195
}
 
196
 
 
197
static void
 
198
my_init_hook(void) {
 
199
        my_hooks ();
 
200
}
 
201
 
 
202
void (*__malloc_initialize_hook) (void) = my_init_hook;
 
203
 
 
204
 
 
205
/* reporting */
 
206
 
 
207
#include <locale.h>
 
208
 
 
209
static void
 
210
add_alloc_stats (struct alloc_stats_t *a, struct alloc_stats_t *b)
 
211
{
 
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;
 
218
}
 
219
 
 
220
static void
 
221
dump_alloc_stats (struct alloc_stats_t *stats, const char *name)
 
222
{
 
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);
 
228
}
 
229
 
 
230
static int
 
231
compare_func_stats_name (const void *pa, const void *pb)
 
232
{
 
233
        const struct func_stat_t *a = pa, *b = pb;
 
234
        int i;
 
235
 
 
236
        i = strcmp (a->name, b->name);
 
237
        if (i)
 
238
                return i;
 
239
 
 
240
        return ((char *) a->addr - (char *) b->addr);
 
241
}
 
242
 
 
243
static int
 
244
compare_func_stats (const void *pa, const void *pb)
 
245
{
 
246
        const struct func_stat_t *a = pa, *b = pb;
 
247
 
 
248
        if (a->stat.total.num != b->stat.total.num)
 
249
                return (a->stat.total.num - b->stat.total.num);
 
250
 
 
251
        if (a->stat.total.size != b->stat.total.size)
 
252
                return (a->stat.total.size - b->stat.total.size);
 
253
 
 
254
        return compare_func_stats_name (pa, pb);
 
255
}
 
256
 
 
257
static void
 
258
merge_similar_entries (void)
 
259
{
 
260
        int i, j;
 
261
 
 
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];
 
270
                }
 
271
        }
 
272
        j++;
 
273
        if (j < func_stats_num)
 
274
                func_stats_num = j;
 
275
}
 
276
 
 
277
__attribute__ ((destructor))
 
278
void
 
279
malloc_stats (void)
 
280
{
 
281
        int i;
 
282
 
 
283
        old_hooks ();
 
284
 
 
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);
 
289
 
 
290
        if (func_stats_num) {
 
291
                setlocale (LC_ALL, "");
 
292
 
 
293
                printf ("        TOTAL                   MALLOC                 REALLOC\n");
 
294
                printf ("     num       size         num        size         num        size\n");
 
295
 
 
296
                for (i = 0; i < func_stats_num; i++) {
 
297
                        dump_alloc_stats (&func_stats[i].stat, func_stats[i].name);
 
298
                }
 
299
        }
 
300
}