]>
Commit | Line | Data |
---|---|---|
ada55151 | 1 | /* Vector API for GNU compiler. |
66647d44 | 2 | Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. |
ada55151 NS |
3 | Contributed by Nathan Sidwell <nathan@codesourcery.com> |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under | |
8 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 9 | Software Foundation; either version 3, or (at your option) any later |
ada55151 NS |
10 | version. |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ | |
ada55151 | 20 | |
2d5bc016 DD |
21 | /* This file is compiled twice: once for the generator programs |
22 | once for the compiler. */ | |
23 | #ifdef GENERATOR_FILE | |
24 | #include "bconfig.h" | |
25 | #else | |
ada55151 | 26 | #include "config.h" |
2d5bc016 DD |
27 | #endif |
28 | ||
ada55151 NS |
29 | #include "system.h" |
30 | #include "ggc.h" | |
31 | #include "vec.h" | |
ada55151 | 32 | #include "coretypes.h" |
4c714dd4 | 33 | #include "toplev.h" |
d3492572 | 34 | #include "hashtab.h" |
ada55151 | 35 | |
b8698a0f | 36 | struct vec_prefix |
ada55151 | 37 | { |
3cbf09de NS |
38 | unsigned num; |
39 | unsigned alloc; | |
ada55151 NS |
40 | void *vec[1]; |
41 | }; | |
42 | ||
d3492572 JH |
43 | |
44 | #ifdef GATHER_STATISTICS | |
45 | ||
46 | /* Store information about each particular vector. */ | |
47 | struct vec_descriptor | |
48 | { | |
49 | const char *function; | |
50 | const char *file; | |
51 | int line; | |
52 | size_t allocated; | |
53 | size_t times; | |
54 | size_t peak; | |
55 | }; | |
56 | ||
57 | ||
58 | /* Hashtable mapping vec addresses to descriptors. */ | |
59 | static htab_t vec_desc_hash; | |
60 | ||
61 | /* Hashtable helpers. */ | |
62 | static hashval_t | |
63 | hash_descriptor (const void *p) | |
64 | { | |
65 | const struct vec_descriptor *const d = | |
66 | (const struct vec_descriptor *) p; | |
67 | return htab_hash_pointer (d->file) + d->line; | |
68 | } | |
69 | static int | |
70 | eq_descriptor (const void *p1, const void *p2) | |
71 | { | |
72 | const struct vec_descriptor *const d = (const struct vec_descriptor *) p1; | |
73 | const struct vec_descriptor *const l = (const struct vec_descriptor *) p2; | |
74 | return d->file == l->file && d->function == l->function && d->line == l->line; | |
75 | } | |
76 | ||
77 | /* Hashtable converting address of allocated field to loc descriptor. */ | |
78 | static htab_t ptr_hash; | |
79 | struct ptr_hash_entry | |
80 | { | |
81 | void *ptr; | |
82 | struct vec_descriptor *loc; | |
83 | size_t allocated; | |
84 | }; | |
85 | ||
86 | /* Hash table helpers functions. */ | |
87 | static hashval_t | |
88 | hash_ptr (const void *p) | |
89 | { | |
90 | const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p; | |
91 | ||
92 | return htab_hash_pointer (d->ptr); | |
93 | } | |
94 | ||
95 | static int | |
96 | eq_ptr (const void *p1, const void *p2) | |
97 | { | |
98 | const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1; | |
99 | ||
100 | return (p->ptr == p2); | |
101 | } | |
102 | ||
103 | /* Return descriptor for given call site, create new one if needed. */ | |
104 | static struct vec_descriptor * | |
105 | vec_descriptor (const char *name, int line, const char *function) | |
106 | { | |
107 | struct vec_descriptor loc; | |
108 | struct vec_descriptor **slot; | |
109 | ||
110 | loc.file = name; | |
111 | loc.line = line; | |
112 | loc.function = function; | |
113 | if (!vec_desc_hash) | |
114 | vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL); | |
115 | ||
f136c8ae RAE |
116 | slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc, |
117 | INSERT); | |
d3492572 JH |
118 | if (*slot) |
119 | return *slot; | |
120 | *slot = XCNEW (struct vec_descriptor); | |
121 | (*slot)->file = name; | |
122 | (*slot)->line = line; | |
123 | (*slot)->function = function; | |
124 | (*slot)->allocated = 0; | |
125 | (*slot)->peak = 0; | |
126 | return *slot; | |
127 | } | |
128 | ||
129 | /* Account the overhead. */ | |
130 | static void | |
131 | register_overhead (struct vec_prefix *ptr, size_t size, | |
132 | const char *name, int line, const char *function) | |
133 | { | |
134 | struct vec_descriptor *loc = vec_descriptor (name, line, function); | |
135 | struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry); | |
136 | PTR *slot; | |
137 | ||
138 | p->ptr = ptr; | |
139 | p->loc = loc; | |
140 | p->allocated = size; | |
141 | if (!ptr_hash) | |
142 | ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL); | |
143 | slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT); | |
144 | gcc_assert (!*slot); | |
145 | *slot = p; | |
146 | ||
147 | loc->allocated += size; | |
148 | if (loc->peak < loc->allocated) | |
149 | loc->peak += loc->allocated; | |
150 | loc->times++; | |
151 | } | |
152 | ||
153 | /* Notice that the pointer has been freed. */ | |
154 | static void | |
155 | free_overhead (struct vec_prefix *ptr) | |
156 | { | |
157 | PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), | |
158 | NO_INSERT); | |
159 | struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot; | |
160 | p->loc->allocated -= p->allocated; | |
161 | htab_clear_slot (ptr_hash, slot); | |
162 | free (p); | |
163 | } | |
164 | ||
165 | void | |
166 | vec_heap_free (void *ptr) | |
167 | { | |
168 | free_overhead ((struct vec_prefix *)ptr); | |
169 | free (ptr); | |
170 | } | |
171 | #endif | |
172 | ||
efb7e1e0 ILT |
173 | /* Calculate the new ALLOC value, making sure that RESERVE slots are |
174 | free. If EXACT grow exactly, otherwise grow exponentially. */ | |
d4e6fecb NS |
175 | |
176 | static inline unsigned | |
efb7e1e0 | 177 | calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact) |
d4e6fecb NS |
178 | { |
179 | unsigned alloc = 0; | |
180 | unsigned num = 0; | |
181 | ||
efb7e1e0 ILT |
182 | gcc_assert (reserve >= 0); |
183 | ||
d4e6fecb NS |
184 | if (pfx) |
185 | { | |
186 | alloc = pfx->alloc; | |
187 | num = pfx->num; | |
188 | } | |
189 | else if (!reserve) | |
190 | /* If there's no prefix, and we've not requested anything, then we | |
191 | will create a NULL vector. */ | |
192 | return 0; | |
b8698a0f | 193 | |
d4e6fecb | 194 | /* We must have run out of room. */ |
efb7e1e0 | 195 | gcc_assert (alloc - num < (unsigned) reserve); |
b8698a0f | 196 | |
efb7e1e0 | 197 | if (exact) |
d4e6fecb | 198 | /* Exact size. */ |
efb7e1e0 | 199 | alloc = num + reserve; |
d4e6fecb NS |
200 | else |
201 | { | |
202 | /* Exponential growth. */ | |
203 | if (!alloc) | |
204 | alloc = 4; | |
205 | else if (alloc < 16) | |
206 | /* Double when small. */ | |
207 | alloc = alloc * 2; | |
208 | else | |
209 | /* Grow slower when large. */ | |
210 | alloc = (alloc * 3 / 2); | |
b8698a0f | 211 | |
d4e6fecb NS |
212 | /* If this is still too small, set it to the right size. */ |
213 | if (alloc < num + reserve) | |
214 | alloc = num + reserve; | |
215 | } | |
216 | return alloc; | |
217 | } | |
218 | ||
efb7e1e0 ILT |
219 | /* Ensure there are at least RESERVE free slots in VEC. If EXACT grow |
220 | exactly, else grow exponentially. As a special case, if VEC is | |
221 | NULL and RESERVE is 0, no vector will be created. The vector's | |
222 | trailing array is at VEC_OFFSET offset and consists of ELT_SIZE | |
223 | sized elements. */ | |
ada55151 | 224 | |
efb7e1e0 ILT |
225 | static void * |
226 | vec_gc_o_reserve_1 (void *vec, int reserve, size_t vec_offset, size_t elt_size, | |
227 | bool exact MEM_STAT_DECL) | |
ada55151 | 228 | { |
3d9a9f94 | 229 | struct vec_prefix *pfx = (struct vec_prefix *) vec; |
415a06c2 | 230 | unsigned alloc = calculate_allocation (pfx, reserve, exact); |
b8698a0f | 231 | |
d4e6fecb | 232 | if (!alloc) |
d3492572 JH |
233 | { |
234 | if (pfx) | |
235 | ggc_free (pfx); | |
236 | return NULL; | |
237 | } | |
b8698a0f | 238 | |
7de5bccc NS |
239 | vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT); |
240 | ((struct vec_prefix *)vec)->alloc = alloc; | |
241 | if (!pfx) | |
242 | ((struct vec_prefix *)vec)->num = 0; | |
b8698a0f | 243 | |
ada55151 NS |
244 | return vec; |
245 | } | |
246 | ||
efb7e1e0 ILT |
247 | /* Ensure there are at least RESERVE free slots in VEC, growing |
248 | exponentially. If RESERVE < 0 grow exactly, else grow | |
249 | exponentially. As a special case, if VEC is NULL, and RESERVE is | |
250 | 0, no vector will be created. */ | |
4c254e68 NS |
251 | |
252 | void * | |
efb7e1e0 | 253 | vec_gc_p_reserve (void *vec, int reserve MEM_STAT_DECL) |
4c254e68 | 254 | { |
efb7e1e0 ILT |
255 | return vec_gc_o_reserve_1 (vec, reserve, |
256 | offsetof (struct vec_prefix, vec), | |
257 | sizeof (void *), false | |
4c254e68 NS |
258 | PASS_MEM_STAT); |
259 | } | |
260 | ||
efb7e1e0 ILT |
261 | /* Ensure there are at least RESERVE free slots in VEC, growing |
262 | exactly. If RESERVE < 0 grow exactly, else grow exponentially. As | |
263 | a special case, if VEC is NULL, and RESERVE is 0, no vector will be | |
264 | created. */ | |
4c254e68 NS |
265 | |
266 | void * | |
efb7e1e0 ILT |
267 | vec_gc_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL) |
268 | { | |
269 | return vec_gc_o_reserve_1 (vec, reserve, | |
270 | offsetof (struct vec_prefix, vec), | |
271 | sizeof (void *), true | |
272 | PASS_MEM_STAT); | |
273 | } | |
274 | ||
275 | /* As for vec_gc_p_reserve, but for object vectors. The vector's | |
276 | trailing array is at VEC_OFFSET offset and consists of ELT_SIZE | |
277 | sized elements. */ | |
278 | ||
279 | void * | |
280 | vec_gc_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size | |
281 | MEM_STAT_DECL) | |
282 | { | |
283 | return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, false | |
284 | PASS_MEM_STAT); | |
285 | } | |
286 | ||
287 | /* As for vec_gc_p_reserve_exact, but for object vectors. The | |
288 | vector's trailing array is at VEC_OFFSET offset and consists of | |
289 | ELT_SIZE sized elements. */ | |
290 | ||
291 | void * | |
292 | vec_gc_o_reserve_exact (void *vec, int reserve, size_t vec_offset, | |
293 | size_t elt_size MEM_STAT_DECL) | |
294 | { | |
295 | return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, true | |
296 | PASS_MEM_STAT); | |
297 | } | |
298 | ||
299 | /* As for vec_gc_o_reserve_1, but for heap allocated vectors. */ | |
300 | ||
301 | static void * | |
302 | vec_heap_o_reserve_1 (void *vec, int reserve, size_t vec_offset, | |
303 | size_t elt_size, bool exact MEM_STAT_DECL) | |
4c254e68 | 304 | { |
3d9a9f94 | 305 | struct vec_prefix *pfx = (struct vec_prefix *) vec; |
efb7e1e0 | 306 | unsigned alloc = calculate_allocation (pfx, reserve, exact); |
4c254e68 | 307 | |
d4e6fecb | 308 | if (!alloc) |
d3492572 JH |
309 | { |
310 | if (pfx) | |
311 | vec_heap_free (pfx); | |
312 | return NULL; | |
313 | } | |
314 | ||
315 | #ifdef GATHER_STATISTICS | |
316 | if (vec) | |
317 | free_overhead (pfx); | |
318 | #endif | |
b8698a0f | 319 | |
4c254e68 NS |
320 | vec = xrealloc (vec, vec_offset + alloc * elt_size); |
321 | ((struct vec_prefix *)vec)->alloc = alloc; | |
322 | if (!pfx) | |
323 | ((struct vec_prefix *)vec)->num = 0; | |
d3492572 JH |
324 | #ifdef GATHER_STATISTICS |
325 | if (vec) | |
326 | register_overhead ((struct vec_prefix *)vec, | |
327 | vec_offset + alloc * elt_size PASS_MEM_STAT); | |
328 | #endif | |
b8698a0f | 329 | |
4c254e68 NS |
330 | return vec; |
331 | } | |
332 | ||
efb7e1e0 ILT |
333 | /* As for vec_gc_p_reserve, but for heap allocated vectors. */ |
334 | ||
335 | void * | |
336 | vec_heap_p_reserve (void *vec, int reserve MEM_STAT_DECL) | |
337 | { | |
338 | return vec_heap_o_reserve_1 (vec, reserve, | |
339 | offsetof (struct vec_prefix, vec), | |
340 | sizeof (void *), false | |
341 | PASS_MEM_STAT); | |
342 | } | |
343 | ||
344 | /* As for vec_gc_p_reserve_exact, but for heap allocated vectors. */ | |
345 | ||
346 | void * | |
347 | vec_heap_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL) | |
348 | { | |
349 | return vec_heap_o_reserve_1 (vec, reserve, | |
350 | offsetof (struct vec_prefix, vec), | |
351 | sizeof (void *), true | |
352 | PASS_MEM_STAT); | |
353 | } | |
354 | ||
355 | /* As for vec_gc_o_reserve, but for heap allocated vectors. */ | |
356 | ||
357 | void * | |
358 | vec_heap_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size | |
359 | MEM_STAT_DECL) | |
360 | { | |
361 | return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, false | |
362 | PASS_MEM_STAT); | |
363 | } | |
364 | ||
365 | /* As for vec_gc_o_reserve_exact, but for heap allocated vectors. */ | |
366 | ||
367 | void * | |
368 | vec_heap_o_reserve_exact (void *vec, int reserve, size_t vec_offset, | |
369 | size_t elt_size MEM_STAT_DECL) | |
370 | { | |
371 | return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, true | |
372 | PASS_MEM_STAT); | |
373 | } | |
374 | ||
c2569604 ILT |
375 | /* Stack vectors are a little different. VEC_alloc turns into a call |
376 | to vec_stack_p_reserve_exact1 and passes in space allocated via a | |
377 | call to alloca. We record that pointer so that we know that we | |
378 | shouldn't free it. If the vector is resized, we resize it on the | |
379 | heap. We record the pointers in a vector and search it in LIFO | |
380 | order--i.e., we look for the newest stack vectors first. We don't | |
381 | expect too many stack vectors at any one level, and searching from | |
382 | the end should normally be efficient even if they are used in a | |
383 | recursive function. */ | |
384 | ||
385 | typedef void *void_p; | |
386 | DEF_VEC_P(void_p); | |
387 | DEF_VEC_ALLOC_P(void_p,heap); | |
388 | ||
389 | static VEC(void_p,heap) *stack_vecs; | |
390 | ||
391 | /* Allocate a vector which uses alloca for the initial allocation. | |
392 | SPACE is space allocated using alloca, ALLOC is the number of | |
393 | entries allocated. */ | |
394 | ||
395 | void * | |
396 | vec_stack_p_reserve_exact_1 (int alloc, void *space) | |
397 | { | |
398 | struct vec_prefix *pfx = (struct vec_prefix *) space; | |
399 | ||
400 | VEC_safe_push (void_p, heap, stack_vecs, space); | |
401 | ||
402 | pfx->num = 0; | |
403 | pfx->alloc = alloc; | |
404 | ||
405 | return space; | |
406 | } | |
407 | ||
408 | /* Grow a vector allocated using alloca. When this happens, we switch | |
409 | back to heap allocation. We remove the vector from stack_vecs, if | |
410 | it is there, since we no longer need to avoid freeing it. */ | |
411 | ||
412 | static void * | |
413 | vec_stack_o_reserve_1 (void *vec, int reserve, size_t vec_offset, | |
414 | size_t elt_size, bool exact MEM_STAT_DECL) | |
415 | { | |
416 | bool found; | |
417 | unsigned int ix; | |
418 | void *newvec; | |
419 | ||
420 | found = false; | |
421 | for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix) | |
422 | { | |
423 | if (VEC_index (void_p, stack_vecs, ix - 1) == vec) | |
424 | { | |
425 | VEC_unordered_remove (void_p, stack_vecs, ix - 1); | |
426 | found = true; | |
427 | break; | |
428 | } | |
429 | } | |
430 | ||
431 | if (!found) | |
432 | { | |
433 | /* VEC is already on the heap. */ | |
434 | return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, | |
435 | exact PASS_MEM_STAT); | |
436 | } | |
437 | ||
438 | /* Move VEC to the heap. */ | |
439 | reserve += ((struct vec_prefix *) vec)->num; | |
440 | newvec = vec_heap_o_reserve_1 (NULL, reserve, vec_offset, elt_size, | |
441 | exact PASS_MEM_STAT); | |
442 | if (newvec && vec) | |
443 | { | |
444 | ((struct vec_prefix *) newvec)->num = ((struct vec_prefix *) vec)->num; | |
445 | memcpy (((struct vec_prefix *) newvec)->vec, | |
446 | ((struct vec_prefix *) vec)->vec, | |
447 | ((struct vec_prefix *) vec)->num * elt_size); | |
448 | } | |
449 | return newvec; | |
450 | } | |
451 | ||
452 | /* Grow a vector allocated on the stack. */ | |
453 | ||
454 | void * | |
455 | vec_stack_p_reserve (void *vec, int reserve MEM_STAT_DECL) | |
456 | { | |
457 | return vec_stack_o_reserve_1 (vec, reserve, | |
458 | offsetof (struct vec_prefix, vec), | |
459 | sizeof (void *), false | |
460 | PASS_MEM_STAT); | |
461 | } | |
462 | ||
463 | /* Exact version of vec_stack_p_reserve. */ | |
464 | ||
465 | void * | |
466 | vec_stack_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL) | |
467 | { | |
468 | return vec_stack_o_reserve_1 (vec, reserve, | |
469 | offsetof (struct vec_prefix, vec), | |
470 | sizeof (void *), true | |
471 | PASS_MEM_STAT); | |
472 | } | |
473 | ||
474 | /* Like vec_stack_p_reserve, but for objects. */ | |
475 | ||
476 | void * | |
477 | vec_stack_o_reserve (void *vec, int reserve, size_t vec_offset, | |
478 | size_t elt_size MEM_STAT_DECL) | |
479 | { | |
480 | return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, false | |
481 | PASS_MEM_STAT); | |
482 | } | |
483 | ||
484 | /* Like vec_stack_p_reserve_exact, but for objects. */ | |
485 | ||
486 | void * | |
487 | vec_stack_o_reserve_exact (void *vec, int reserve, size_t vec_offset, | |
488 | size_t elt_size MEM_STAT_DECL) | |
489 | { | |
490 | return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, true | |
491 | PASS_MEM_STAT); | |
492 | } | |
493 | ||
494 | /* Free a vector allocated on the stack. Don't actually free it if we | |
495 | find it in the hash table. */ | |
496 | ||
497 | void | |
498 | vec_stack_free (void *vec) | |
499 | { | |
500 | unsigned int ix; | |
501 | ||
502 | for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix) | |
503 | { | |
504 | if (VEC_index (void_p, stack_vecs, ix - 1) == vec) | |
505 | { | |
506 | VEC_unordered_remove (void_p, stack_vecs, ix - 1); | |
507 | return; | |
508 | } | |
509 | } | |
510 | ||
511 | /* VEC was not on the list of vecs allocated on the stack, so it | |
512 | must be allocated on the heap. */ | |
513 | vec_heap_free (vec); | |
514 | } | |
515 | ||
ada55151 NS |
516 | #if ENABLE_CHECKING |
517 | /* Issue a vector domain error, and then fall over. */ | |
518 | ||
519 | void | |
520 | vec_assert_fail (const char *op, const char *struct_name, | |
dae1dd2e | 521 | const char *file, unsigned int line, const char *function) |
ada55151 NS |
522 | { |
523 | internal_error ("vector %s %s domain error, in %s at %s:%u", | |
70ce47b5 | 524 | struct_name, op, function, trim_filename (file), line); |
ada55151 NS |
525 | } |
526 | #endif | |
d3492572 JH |
527 | |
528 | #ifdef GATHER_STATISTICS | |
529 | /* Helper for qsort; sort descriptors by amount of memory consumed. */ | |
530 | static int | |
531 | cmp_statistic (const void *loc1, const void *loc2) | |
532 | { | |
533 | const struct vec_descriptor *const l1 = | |
534 | *(const struct vec_descriptor *const *) loc1; | |
535 | const struct vec_descriptor *const l2 = | |
536 | *(const struct vec_descriptor *const *) loc2; | |
537 | long diff; | |
538 | diff = l1->allocated - l2->allocated; | |
539 | if (!diff) | |
540 | diff = l1->peak - l2->peak; | |
541 | if (!diff) | |
542 | diff = l1->times - l2->times; | |
543 | return diff > 0 ? 1 : diff < 0 ? -1 : 0; | |
544 | } | |
545 | /* Collect array of the descriptors from hashtable. */ | |
546 | static struct vec_descriptor **loc_array; | |
547 | static int | |
548 | add_statistics (void **slot, void *b) | |
549 | { | |
550 | int *n = (int *)b; | |
551 | loc_array[*n] = (struct vec_descriptor *) *slot; | |
552 | (*n)++; | |
553 | return 1; | |
554 | } | |
555 | ||
556 | /* Dump per-site memory statistics. */ | |
557 | #endif | |
558 | void | |
559 | dump_vec_loc_statistics (void) | |
560 | { | |
561 | #ifdef GATHER_STATISTICS | |
562 | int nentries = 0; | |
563 | char s[4096]; | |
564 | size_t allocated = 0; | |
565 | size_t times = 0; | |
566 | int i; | |
567 | ||
568 | loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements); | |
569 | fprintf (stderr, "Heap vectors:\n"); | |
570 | fprintf (stderr, "\n%-48s %10s %10s %10s\n", | |
571 | "source location", "Leak", "Peak", "Times"); | |
572 | fprintf (stderr, "-------------------------------------------------------\n"); | |
573 | htab_traverse (vec_desc_hash, add_statistics, &nentries); | |
574 | qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic); | |
575 | for (i = 0; i < nentries; i++) | |
576 | { | |
577 | struct vec_descriptor *d = loc_array[i]; | |
578 | allocated += d->allocated; | |
579 | times += d->times; | |
580 | } | |
581 | for (i = 0; i < nentries; i++) | |
582 | { | |
583 | struct vec_descriptor *d = loc_array[i]; | |
584 | const char *s1 = d->file; | |
585 | const char *s2; | |
586 | while ((s2 = strstr (s1, "gcc/"))) | |
587 | s1 = s2 + 4; | |
588 | sprintf (s, "%s:%i (%s)", s1, d->line, d->function); | |
589 | s[48] = 0; | |
590 | fprintf (stderr, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s, | |
591 | (long)d->allocated, | |
592 | (d->allocated) * 100.0 / allocated, | |
593 | (long)d->peak, | |
594 | (long)d->times, | |
595 | (d->times) * 100.0 / times); | |
596 | } | |
597 | fprintf (stderr, "%-48s %10ld %10ld\n", | |
598 | "Total", (long)allocated, (long)times); | |
599 | fprintf (stderr, "\n%-48s %10s %10s %10s\n", | |
600 | "source location", "Leak", "Peak", "Times"); | |
601 | fprintf (stderr, "-------------------------------------------------------\n"); | |
602 | #endif | |
603 | } |