Add stubs for Direct3D9 backend.
[cairo/gpu.git] / util / malloc-stats.c
blobddf884929d15fe5ab422ee09aca7951614e74b18
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>
35 #include <stdint.h>
37 /* caller-logging */
39 #include <string.h>
41 struct alloc_stat_t {
42 unsigned int num;
43 unsigned long long size;
46 struct alloc_stats_t {
47 struct alloc_stat_t malloc, realloc, total;
50 struct func_stat_t {
51 struct func_stat_t *next;
53 const void *addr;
54 const char *name;
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]))
65 static void
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;
70 stats->total.num++;
71 stats->total.size += size;
73 stat->num++;
74 stat->size += size;
77 #include <execinfo.h>
79 static void *
80 _perm_alloc (size_t size)
82 static uint8_t *ptr;
83 static size_t rem;
85 void *ret;
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);
93 if (ptr == NULL)
94 exit (1);
95 rem = SUPERBLOCK_SIZE;
98 #undef SUPERBLOCK_SIZE
99 #undef align
101 ret = ptr;
102 rem -= size;
103 ptr += size;
105 return ret;
108 static const char *
109 resolve_addr (const void *addr) {
111 char **strings;
112 char *p;
113 char *name;
114 int len;
116 if (addr == NULL)
117 return "(other)";
118 if (addr == (void *) -1)
119 return "(total)";
121 strings = backtrace_symbols ((void**)&addr, 1);
123 p = strchr (strings[0], '\t');
124 if (p)
125 p++;
126 else
127 p = strings[0];
129 len = strlen (p) + 1;
130 name = _perm_alloc (len);
131 memcpy (name, p, len);
133 free (strings);
135 return name;
138 static void
139 resolve_addrs (struct func_stat_t *func_stats, int num)
141 int i;
142 void **addrs;
143 char **strings;
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++) {
152 char *p;
153 char *name;
154 int len;
156 p = strchr (strings[i], '\t');
157 if (p)
158 p++;
159 else
160 p = strings[i];
162 len = strlen (p) + 1;
163 name = _perm_alloc (len);
164 memcpy (name, p, len);
165 func_stats[i].name = name;
168 free (strings);
169 free (addrs);
172 static void
173 func_stats_add (const void *caller, int is_realloc, size_t size)
175 int i;
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)
183 break;
186 if (elt == NULL) {
187 func_stats_num++;
189 elt = _perm_alloc (sizeof (struct func_stat_t));
190 elt->next = func_stats[i];
191 func_stats[i] = elt;
192 elt->addr = caller;
193 elt->name = NULL;
194 memset (&elt->stat, 0, sizeof (struct alloc_stats_t));
197 alloc_stats_add (&elt->stat, is_realloc, size);
200 /* wrapper stuff */
202 #include <malloc.h>
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 *);
210 static void
211 save_hooks (void)
213 old_malloc = __malloc_hook;
214 old_realloc = __realloc_hook;
217 static void
218 old_hooks (void)
220 __malloc_hook = old_malloc;
221 __realloc_hook = old_realloc;
224 static void
225 my_hooks (void)
227 /* should always save the current value */
228 save_hooks ();
230 __malloc_hook = my_malloc;
231 __realloc_hook = my_realloc;
234 static void *
235 my_malloc(size_t size, const void *caller)
237 void *ret;
239 old_hooks ();
241 func_stats_add (caller, 0, size);
243 ret = malloc (size);
244 my_hooks ();
246 return ret;
249 static void *
250 my_realloc(void *ptr, size_t size, const void *caller)
252 void *ret;
254 old_hooks ();
256 func_stats_add (caller, 1, size);
258 ret = realloc (ptr, size);
259 my_hooks ();
261 return ret;
264 static void
265 my_init_hook(void) {
266 my_hooks ();
269 void (*__malloc_initialize_hook) (void) = my_init_hook;
272 /* reporting */
274 #include <locale.h>
276 static void
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;
287 static void
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,
294 name);
297 static int
298 compare_func_stats_name (const void *pa, const void *pb)
300 const struct func_stat_t *a = pa, *b = pb;
301 int i;
303 i = strcmp (a->name, b->name);
304 if (i)
305 return i;
307 return ((char *) a->addr - (char *) b->addr);
310 static int
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);
324 static int
325 merge_similar_entries (struct func_stat_t *func_stats, int num)
327 int i, j;
329 j = 0;
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);
333 } else {
334 j++;
335 if (i != j)
336 func_stats[j] = func_stats[i];
339 j++;
341 return j;
344 __attribute__ ((destructor))
345 void
346 malloc_stats (void)
348 unsigned int i, j;
349 struct func_stat_t *sorted_func_stats;
351 old_hooks ();
353 if (! func_stats_num)
354 return;
356 sorted_func_stats = malloc (sizeof (struct func_stat_t) * (func_stats_num + 1));
357 if (sorted_func_stats == NULL)
358 return;
360 j = 0;
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);
377 /* add total */
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;
382 j++;
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);