Mercurial > hg > CbC > CbC_gcc
comparison gcc/ggc-common.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Simple garbage collection for the GNU compiler. | 1 /* Simple garbage collection for the GNU compiler. |
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, | 2 Copyright (C) 1999-2017 Free Software Foundation, Inc. |
3 2009, 2010 Free Software Foundation, Inc. | |
4 | 3 |
5 This file is part of GCC. | 4 This file is part of GCC. |
6 | 5 |
7 GCC is free software; you can redistribute it and/or modify it under | 6 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 | 7 the terms of the GNU General Public License as published by the Free |
22 any particular GC implementation. */ | 21 any particular GC implementation. */ |
23 | 22 |
24 #include "config.h" | 23 #include "config.h" |
25 #include "system.h" | 24 #include "system.h" |
26 #include "coretypes.h" | 25 #include "coretypes.h" |
27 #include "hashtab.h" | 26 #include "timevar.h" |
28 #include "ggc.h" | 27 #include "diagnostic-core.h" |
29 #include "ggc-internal.h" | 28 #include "ggc-internal.h" |
30 #include "diagnostic-core.h" | |
31 #include "params.h" | 29 #include "params.h" |
32 #include "hosthooks.h" | 30 #include "hosthooks.h" |
33 #include "hosthooks-def.h" | |
34 #include "plugin.h" | 31 #include "plugin.h" |
35 #include "vec.h" | |
36 #include "timevar.h" | |
37 | 32 |
38 /* When set, ggc_collect will do collection. */ | 33 /* When set, ggc_collect will do collection. */ |
39 bool ggc_force_collect; | 34 bool ggc_force_collect; |
40 | 35 |
41 /* When true, protect the contents of the identifier hash table. */ | 36 /* When true, protect the contents of the identifier hash table. */ |
44 /* Statistics about the allocation. */ | 39 /* Statistics about the allocation. */ |
45 static ggc_statistics *ggc_stats; | 40 static ggc_statistics *ggc_stats; |
46 | 41 |
47 struct traversal_state; | 42 struct traversal_state; |
48 | 43 |
49 static int ggc_htab_delete (void **, void *); | |
50 static hashval_t saving_htab_hash (const void *); | |
51 static int saving_htab_eq (const void *, const void *); | |
52 static int call_count (void **, void *); | |
53 static int call_alloc (void **, void *); | |
54 static int compare_ptr_data (const void *, const void *); | 44 static int compare_ptr_data (const void *, const void *); |
55 static void relocate_ptrs (void *, void *); | 45 static void relocate_ptrs (void *, void *); |
56 static void write_pch_globals (const struct ggc_root_tab * const *tab, | 46 static void write_pch_globals (const struct ggc_root_tab * const *tab, |
57 struct traversal_state *state); | 47 struct traversal_state *state); |
58 | 48 |
59 /* Maintain global roots that are preserved during GC. */ | 49 /* Maintain global roots that are preserved during GC. */ |
60 | |
61 /* Process a slot of an htab by deleting it if it has not been marked. */ | |
62 | |
63 static int | |
64 ggc_htab_delete (void **slot, void *info) | |
65 { | |
66 const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info; | |
67 | |
68 if (! (*r->marked_p) (*slot)) | |
69 htab_clear_slot (*r->base, slot); | |
70 else | |
71 (*r->cb) (*slot); | |
72 | |
73 return 1; | |
74 } | |
75 | |
76 | 50 |
77 /* This extra vector of dynamically registered root_tab-s is used by | 51 /* This extra vector of dynamically registered root_tab-s is used by |
78 ggc_mark_roots and gives the ability to dynamically add new GGC root | 52 ggc_mark_roots and gives the ability to dynamically add new GGC root |
79 tables, for instance from some plugins; this vector is on the heap | 53 tables, for instance from some plugins; this vector is on the heap |
80 since it is used by GGC internally. */ | 54 since it is used by GGC internally. */ |
81 typedef const struct ggc_root_tab *const_ggc_root_tab_t; | 55 typedef const struct ggc_root_tab *const_ggc_root_tab_t; |
82 DEF_VEC_P(const_ggc_root_tab_t); | 56 static vec<const_ggc_root_tab_t> extra_root_vec; |
83 DEF_VEC_ALLOC_P(const_ggc_root_tab_t, heap); | |
84 static VEC(const_ggc_root_tab_t, heap) *extra_root_vec; | |
85 | 57 |
86 /* Dynamically register a new GGC root table RT. This is useful for | 58 /* Dynamically register a new GGC root table RT. This is useful for |
87 plugins. */ | 59 plugins. */ |
88 | 60 |
89 void | 61 void |
90 ggc_register_root_tab (const struct ggc_root_tab* rt) | 62 ggc_register_root_tab (const struct ggc_root_tab* rt) |
91 { | 63 { |
92 if (rt) | 64 if (rt) |
93 VEC_safe_push (const_ggc_root_tab_t, heap, extra_root_vec, rt); | 65 extra_root_vec.safe_push (rt); |
94 } | |
95 | |
96 /* This extra vector of dynamically registered cache_tab-s is used by | |
97 ggc_mark_roots and gives the ability to dynamically add new GGC cache | |
98 tables, for instance from some plugins; this vector is on the heap | |
99 since it is used by GGC internally. */ | |
100 typedef const struct ggc_cache_tab *const_ggc_cache_tab_t; | |
101 DEF_VEC_P(const_ggc_cache_tab_t); | |
102 DEF_VEC_ALLOC_P(const_ggc_cache_tab_t, heap); | |
103 static VEC(const_ggc_cache_tab_t, heap) *extra_cache_vec; | |
104 | |
105 /* Dynamically register a new GGC cache table CT. This is useful for | |
106 plugins. */ | |
107 | |
108 void | |
109 ggc_register_cache_tab (const struct ggc_cache_tab* ct) | |
110 { | |
111 if (ct) | |
112 VEC_safe_push (const_ggc_cache_tab_t, heap, extra_cache_vec, ct); | |
113 } | |
114 | |
115 /* Scan a hash table that has objects which are to be deleted if they are not | |
116 already marked. */ | |
117 | |
118 static void | |
119 ggc_scan_cache_tab (const_ggc_cache_tab_t ctp) | |
120 { | |
121 const struct ggc_cache_tab *cti; | |
122 | |
123 for (cti = ctp; cti->base != NULL; cti++) | |
124 if (*cti->base) | |
125 { | |
126 ggc_set_mark (*cti->base); | |
127 htab_traverse_noresize (*cti->base, ggc_htab_delete, | |
128 CONST_CAST (void *, (const void *)cti)); | |
129 ggc_set_mark ((*cti->base)->entries); | |
130 } | |
131 } | 66 } |
132 | 67 |
133 /* Mark all the roots in the table RT. */ | 68 /* Mark all the roots in the table RT. */ |
134 | 69 |
135 static void | 70 static void |
147 void | 82 void |
148 ggc_mark_roots (void) | 83 ggc_mark_roots (void) |
149 { | 84 { |
150 const struct ggc_root_tab *const *rt; | 85 const struct ggc_root_tab *const *rt; |
151 const_ggc_root_tab_t rtp, rti; | 86 const_ggc_root_tab_t rtp, rti; |
152 const struct ggc_cache_tab *const *ct; | |
153 const_ggc_cache_tab_t ctp; | |
154 size_t i; | 87 size_t i; |
155 | 88 |
156 for (rt = gt_ggc_deletable_rtab; *rt; rt++) | 89 for (rt = gt_ggc_deletable_rtab; *rt; rt++) |
157 for (rti = *rt; rti->base != NULL; rti++) | 90 for (rti = *rt; rti->base != NULL; rti++) |
158 memset (rti->base, 0, rti->stride); | 91 memset (rti->base, 0, rti->stride); |
159 | 92 |
160 for (rt = gt_ggc_rtab; *rt; rt++) | 93 for (rt = gt_ggc_rtab; *rt; rt++) |
161 ggc_mark_root_tab (*rt); | 94 ggc_mark_root_tab (*rt); |
162 | 95 |
163 FOR_EACH_VEC_ELT (const_ggc_root_tab_t, extra_root_vec, i, rtp) | 96 FOR_EACH_VEC_ELT (extra_root_vec, i, rtp) |
164 ggc_mark_root_tab (rtp); | 97 ggc_mark_root_tab (rtp); |
165 | 98 |
166 if (ggc_protect_identifiers) | 99 if (ggc_protect_identifiers) |
167 ggc_mark_stringpool (); | 100 ggc_mark_stringpool (); |
168 | 101 |
169 /* Now scan all hash tables that have objects which are to be deleted if | 102 gt_clear_caches (); |
170 they are not already marked. */ | |
171 for (ct = gt_ggc_cache_rtab; *ct; ct++) | |
172 ggc_scan_cache_tab (*ct); | |
173 | |
174 FOR_EACH_VEC_ELT (const_ggc_cache_tab_t, extra_cache_vec, i, ctp) | |
175 ggc_scan_cache_tab (ctp); | |
176 | 103 |
177 if (! ggc_protect_identifiers) | 104 if (! ggc_protect_identifiers) |
178 ggc_purge_stringpool (); | 105 ggc_purge_stringpool (); |
179 | 106 |
180 /* Some plugins may call ggc_set_mark from here. */ | 107 /* Some plugins may call ggc_set_mark from here. */ |
181 invoke_plugin_callbacks (PLUGIN_GGC_MARKING, NULL); | 108 invoke_plugin_callbacks (PLUGIN_GGC_MARKING, NULL); |
182 } | 109 } |
183 | 110 |
184 /* Allocate a block of memory, then clear it. */ | 111 /* Allocate a block of memory, then clear it. */ |
185 void * | 112 void * |
186 ggc_internal_cleared_alloc_stat (size_t size MEM_STAT_DECL) | 113 ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t s, size_t n |
187 { | 114 MEM_STAT_DECL) |
188 void *buf = ggc_internal_alloc_stat (size PASS_MEM_STAT); | 115 { |
116 void *buf = ggc_internal_alloc (size, f, s, n PASS_MEM_STAT); | |
189 memset (buf, 0, size); | 117 memset (buf, 0, size); |
190 return buf; | 118 return buf; |
191 } | 119 } |
192 | 120 |
193 /* Resize a block of memory, possibly re-allocating it. */ | 121 /* Resize a block of memory, possibly re-allocating it. */ |
194 void * | 122 void * |
195 ggc_realloc_stat (void *x, size_t size MEM_STAT_DECL) | 123 ggc_realloc (void *x, size_t size MEM_STAT_DECL) |
196 { | 124 { |
197 void *r; | 125 void *r; |
198 size_t old_size; | 126 size_t old_size; |
199 | 127 |
200 if (x == NULL) | 128 if (x == NULL) |
201 return ggc_internal_alloc_stat (size PASS_MEM_STAT); | 129 return ggc_internal_alloc (size PASS_MEM_STAT); |
202 | 130 |
203 old_size = ggc_get_size (x); | 131 old_size = ggc_get_size (x); |
204 | 132 |
205 if (size <= old_size) | 133 if (size <= old_size) |
206 { | 134 { |
218 old_size - size)); | 146 old_size - size)); |
219 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, size)); | 147 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, size)); |
220 return x; | 148 return x; |
221 } | 149 } |
222 | 150 |
223 r = ggc_internal_alloc_stat (size PASS_MEM_STAT); | 151 r = ggc_internal_alloc (size PASS_MEM_STAT); |
224 | 152 |
225 /* Since ggc_get_size returns the size of the pool, not the size of the | 153 /* Since ggc_get_size returns the size of the pool, not the size of the |
226 individually allocated object, we'd access parts of the old object | 154 individually allocated object, we'd access parts of the old object |
227 that were marked invalid with the memcpy below. We lose a bit of the | 155 that were marked invalid with the memcpy below. We lose a bit of the |
228 initialization-tracking since some of it may be uninitialized. */ | 156 initialization-tracking since some of it may be uninitialized. */ |
239 void * | 167 void * |
240 ggc_cleared_alloc_htab_ignore_args (size_t c ATTRIBUTE_UNUSED, | 168 ggc_cleared_alloc_htab_ignore_args (size_t c ATTRIBUTE_UNUSED, |
241 size_t n ATTRIBUTE_UNUSED) | 169 size_t n ATTRIBUTE_UNUSED) |
242 { | 170 { |
243 gcc_assert (c * n == sizeof (struct htab)); | 171 gcc_assert (c * n == sizeof (struct htab)); |
244 return ggc_alloc_cleared_htab (); | 172 return ggc_cleared_alloc<htab> (); |
245 } | 173 } |
246 | 174 |
247 /* TODO: once we actually use type information in GGC, create a new tag | 175 /* TODO: once we actually use type information in GGC, create a new tag |
248 gt_gcc_ptr_array and use it for pointer arrays. */ | 176 gt_gcc_ptr_array and use it for pointer arrays. */ |
249 void * | 177 void * |
250 ggc_cleared_alloc_ptr_array_two_args (size_t c, size_t n) | 178 ggc_cleared_alloc_ptr_array_two_args (size_t c, size_t n) |
251 { | 179 { |
252 gcc_assert (sizeof (PTR *) == n); | 180 gcc_assert (sizeof (PTR *) == n); |
253 return ggc_internal_cleared_vec_alloc (sizeof (PTR *), c); | 181 return ggc_cleared_vec_alloc<PTR *> (c); |
254 } | 182 } |
255 | 183 |
256 /* These are for splay_tree_new_ggc. */ | 184 /* These are for splay_tree_new_ggc. */ |
257 void * | 185 void * |
258 ggc_splay_alloc (enum gt_types_enum obj_type ATTRIBUTE_UNUSED, int sz, | 186 ggc_splay_alloc (int sz, void *nl) |
259 void *nl) | |
260 { | 187 { |
261 gcc_assert (!nl); | 188 gcc_assert (!nl); |
262 return ggc_internal_alloc (sz); | 189 return ggc_internal_alloc (sz); |
263 } | 190 } |
264 | 191 |
293 ggc_stats = NULL; | 220 ggc_stats = NULL; |
294 } | 221 } |
295 | 222 |
296 /* Functions for saving and restoring GCable memory to disk. */ | 223 /* Functions for saving and restoring GCable memory to disk. */ |
297 | 224 |
298 static htab_t saving_htab; | |
299 | |
300 struct ptr_data | 225 struct ptr_data |
301 { | 226 { |
302 void *obj; | 227 void *obj; |
303 void *note_ptr_cookie; | 228 void *note_ptr_cookie; |
304 gt_note_pointers note_ptr_fn; | 229 gt_note_pointers note_ptr_fn; |
305 gt_handle_reorder reorder_fn; | 230 gt_handle_reorder reorder_fn; |
306 size_t size; | 231 size_t size; |
307 void *new_addr; | 232 void *new_addr; |
308 enum gt_types_enum type; | |
309 }; | 233 }; |
310 | 234 |
311 #define POINTER_HASH(x) (hashval_t)((long)x >> 3) | 235 #define POINTER_HASH(x) (hashval_t)((intptr_t)x >> 3) |
236 | |
237 /* Helper for hashing saving_htab. */ | |
238 | |
239 struct saving_hasher : free_ptr_hash <ptr_data> | |
240 { | |
241 typedef void *compare_type; | |
242 static inline hashval_t hash (const ptr_data *); | |
243 static inline bool equal (const ptr_data *, const void *); | |
244 }; | |
245 | |
246 inline hashval_t | |
247 saving_hasher::hash (const ptr_data *p) | |
248 { | |
249 return POINTER_HASH (p->obj); | |
250 } | |
251 | |
252 inline bool | |
253 saving_hasher::equal (const ptr_data *p1, const void *p2) | |
254 { | |
255 return p1->obj == p2; | |
256 } | |
257 | |
258 static hash_table<saving_hasher> *saving_htab; | |
312 | 259 |
313 /* Register an object in the hash table. */ | 260 /* Register an object in the hash table. */ |
314 | 261 |
315 int | 262 int |
316 gt_pch_note_object (void *obj, void *note_ptr_cookie, | 263 gt_pch_note_object (void *obj, void *note_ptr_cookie, |
317 gt_note_pointers note_ptr_fn, | 264 gt_note_pointers note_ptr_fn) |
318 enum gt_types_enum type) | |
319 { | 265 { |
320 struct ptr_data **slot; | 266 struct ptr_data **slot; |
321 | 267 |
322 if (obj == NULL || obj == (void *) 1) | 268 if (obj == NULL || obj == (void *) 1) |
323 return 0; | 269 return 0; |
324 | 270 |
325 slot = (struct ptr_data **) | 271 slot = (struct ptr_data **) |
326 htab_find_slot_with_hash (saving_htab, obj, POINTER_HASH (obj), | 272 saving_htab->find_slot_with_hash (obj, POINTER_HASH (obj), INSERT); |
327 INSERT); | |
328 if (*slot != NULL) | 273 if (*slot != NULL) |
329 { | 274 { |
330 gcc_assert ((*slot)->note_ptr_fn == note_ptr_fn | 275 gcc_assert ((*slot)->note_ptr_fn == note_ptr_fn |
331 && (*slot)->note_ptr_cookie == note_ptr_cookie); | 276 && (*slot)->note_ptr_cookie == note_ptr_cookie); |
332 return 0; | 277 return 0; |
338 (*slot)->note_ptr_cookie = note_ptr_cookie; | 283 (*slot)->note_ptr_cookie = note_ptr_cookie; |
339 if (note_ptr_fn == gt_pch_p_S) | 284 if (note_ptr_fn == gt_pch_p_S) |
340 (*slot)->size = strlen ((const char *)obj) + 1; | 285 (*slot)->size = strlen ((const char *)obj) + 1; |
341 else | 286 else |
342 (*slot)->size = ggc_get_size (obj); | 287 (*slot)->size = ggc_get_size (obj); |
343 (*slot)->type = type; | |
344 return 1; | 288 return 1; |
345 } | 289 } |
346 | 290 |
347 /* Register an object in the hash table. */ | 291 /* Register an object in the hash table. */ |
348 | 292 |
354 | 298 |
355 if (obj == NULL || obj == (void *) 1) | 299 if (obj == NULL || obj == (void *) 1) |
356 return; | 300 return; |
357 | 301 |
358 data = (struct ptr_data *) | 302 data = (struct ptr_data *) |
359 htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj)); | 303 saving_htab->find_with_hash (obj, POINTER_HASH (obj)); |
360 gcc_assert (data && data->note_ptr_cookie == note_ptr_cookie); | 304 gcc_assert (data && data->note_ptr_cookie == note_ptr_cookie); |
361 | 305 |
362 data->reorder_fn = reorder_fn; | 306 data->reorder_fn = reorder_fn; |
363 } | |
364 | |
365 /* Hash and equality functions for saving_htab, callbacks for htab_create. */ | |
366 | |
367 static hashval_t | |
368 saving_htab_hash (const void *p) | |
369 { | |
370 return POINTER_HASH (((const struct ptr_data *)p)->obj); | |
371 } | |
372 | |
373 static int | |
374 saving_htab_eq (const void *p1, const void *p2) | |
375 { | |
376 return ((const struct ptr_data *)p1)->obj == p2; | |
377 } | 307 } |
378 | 308 |
379 /* Handy state for the traversal functions. */ | 309 /* Handy state for the traversal functions. */ |
380 | 310 |
381 struct traversal_state | 311 struct traversal_state |
387 size_t ptrs_i; | 317 size_t ptrs_i; |
388 }; | 318 }; |
389 | 319 |
390 /* Callbacks for htab_traverse. */ | 320 /* Callbacks for htab_traverse. */ |
391 | 321 |
392 static int | 322 int |
393 call_count (void **slot, void *state_p) | 323 ggc_call_count (ptr_data **slot, traversal_state *state) |
394 { | 324 { |
395 struct ptr_data *d = (struct ptr_data *)*slot; | 325 struct ptr_data *d = *slot; |
396 struct traversal_state *state = (struct traversal_state *)state_p; | |
397 | 326 |
398 ggc_pch_count_object (state->d, d->obj, d->size, | 327 ggc_pch_count_object (state->d, d->obj, d->size, |
399 d->note_ptr_fn == gt_pch_p_S, | 328 d->note_ptr_fn == gt_pch_p_S); |
400 d->type); | |
401 state->count++; | 329 state->count++; |
402 return 1; | 330 return 1; |
403 } | 331 } |
404 | 332 |
405 static int | 333 int |
406 call_alloc (void **slot, void *state_p) | 334 ggc_call_alloc (ptr_data **slot, traversal_state *state) |
407 { | 335 { |
408 struct ptr_data *d = (struct ptr_data *)*slot; | 336 struct ptr_data *d = *slot; |
409 struct traversal_state *state = (struct traversal_state *)state_p; | |
410 | 337 |
411 d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size, | 338 d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size, |
412 d->note_ptr_fn == gt_pch_p_S, | 339 d->note_ptr_fn == gt_pch_p_S); |
413 d->type); | |
414 state->ptrs[state->ptrs_i++] = d; | 340 state->ptrs[state->ptrs_i++] = d; |
415 return 1; | 341 return 1; |
416 } | 342 } |
417 | 343 |
418 /* Callback for qsort. */ | 344 /* Callback for qsort. */ |
438 | 364 |
439 if (*ptr == NULL || *ptr == (void *)1) | 365 if (*ptr == NULL || *ptr == (void *)1) |
440 return; | 366 return; |
441 | 367 |
442 result = (struct ptr_data *) | 368 result = (struct ptr_data *) |
443 htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr)); | 369 saving_htab->find_with_hash (*ptr, POINTER_HASH (*ptr)); |
444 gcc_assert (result); | 370 gcc_assert (result); |
445 *ptr = result->new_addr; | 371 *ptr = result->new_addr; |
446 } | 372 } |
447 | 373 |
448 /* Write out, after relocation, the pointers in TAB. */ | 374 /* Write out, after relocation, the pointers in TAB. */ |
462 struct ptr_data *new_ptr; | 388 struct ptr_data *new_ptr; |
463 if (ptr == NULL || ptr == (void *)1) | 389 if (ptr == NULL || ptr == (void *)1) |
464 { | 390 { |
465 if (fwrite (&ptr, sizeof (void *), 1, state->f) | 391 if (fwrite (&ptr, sizeof (void *), 1, state->f) |
466 != 1) | 392 != 1) |
467 fatal_error ("can%'t write PCH file: %m"); | 393 fatal_error (input_location, "can%'t write PCH file: %m"); |
468 } | 394 } |
469 else | 395 else |
470 { | 396 { |
471 new_ptr = (struct ptr_data *) | 397 new_ptr = (struct ptr_data *) |
472 htab_find_with_hash (saving_htab, ptr, POINTER_HASH (ptr)); | 398 saving_htab->find_with_hash (ptr, POINTER_HASH (ptr)); |
473 if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f) | 399 if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f) |
474 != 1) | 400 != 1) |
475 fatal_error ("can%'t write PCH file: %m"); | 401 fatal_error (input_location, "can%'t write PCH file: %m"); |
476 } | 402 } |
477 } | 403 } |
478 } | 404 } |
479 | 405 |
480 /* Hold the information we need to mmap the file back in. */ | 406 /* Hold the information we need to mmap the file back in. */ |
496 size_t i; | 422 size_t i; |
497 struct traversal_state state; | 423 struct traversal_state state; |
498 char *this_object = NULL; | 424 char *this_object = NULL; |
499 size_t this_object_size = 0; | 425 size_t this_object_size = 0; |
500 struct mmap_info mmi; | 426 struct mmap_info mmi; |
501 const size_t mmap_offset_alignment = host_hooks.gt_pch_alloc_granularity(); | 427 const size_t mmap_offset_alignment = host_hooks.gt_pch_alloc_granularity (); |
502 | 428 |
503 gt_pch_save_stringpool (); | 429 gt_pch_save_stringpool (); |
504 | 430 |
505 timevar_push (TV_PCH_PTR_REALLOC); | 431 timevar_push (TV_PCH_PTR_REALLOC); |
506 saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free); | 432 saving_htab = new hash_table<saving_hasher> (50000); |
507 | 433 |
508 for (rt = gt_ggc_rtab; *rt; rt++) | 434 for (rt = gt_ggc_rtab; *rt; rt++) |
509 for (rti = *rt; rti->base != NULL; rti++) | 435 for (rti = *rt; rti->base != NULL; rti++) |
510 for (i = 0; i < rti->nelt; i++) | 436 for (i = 0; i < rti->nelt; i++) |
511 (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i)); | 437 (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i)); |
512 | 438 |
513 for (rt = gt_pch_cache_rtab; *rt; rt++) | |
514 for (rti = *rt; rti->base != NULL; rti++) | |
515 for (i = 0; i < rti->nelt; i++) | |
516 (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i)); | |
517 | |
518 /* Prepare the objects for writing, determine addresses and such. */ | 439 /* Prepare the objects for writing, determine addresses and such. */ |
519 state.f = f; | 440 state.f = f; |
520 state.d = init_ggc_pch (); | 441 state.d = init_ggc_pch (); |
521 state.count = 0; | 442 state.count = 0; |
522 htab_traverse (saving_htab, call_count, &state); | 443 saving_htab->traverse <traversal_state *, ggc_call_count> (&state); |
523 | 444 |
524 mmi.size = ggc_pch_total_size (state.d); | 445 mmi.size = ggc_pch_total_size (state.d); |
525 | 446 |
526 /* Try to arrange things so that no relocation is necessary, but | 447 /* Try to arrange things so that no relocation is necessary, but |
527 don't try very hard. On most platforms, this will always work, | 448 don't try very hard. On most platforms, this will always work, |
533 ggc_pch_this_base (state.d, mmi.preferred_base); | 454 ggc_pch_this_base (state.d, mmi.preferred_base); |
534 | 455 |
535 state.ptrs = XNEWVEC (struct ptr_data *, state.count); | 456 state.ptrs = XNEWVEC (struct ptr_data *, state.count); |
536 state.ptrs_i = 0; | 457 state.ptrs_i = 0; |
537 | 458 |
538 htab_traverse (saving_htab, call_alloc, &state); | 459 saving_htab->traverse <traversal_state *, ggc_call_alloc> (&state); |
539 timevar_pop (TV_PCH_PTR_REALLOC); | 460 timevar_pop (TV_PCH_PTR_REALLOC); |
540 | 461 |
541 timevar_push (TV_PCH_PTR_SORT); | 462 timevar_push (TV_PCH_PTR_SORT); |
542 qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data); | 463 qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data); |
543 timevar_pop (TV_PCH_PTR_SORT); | 464 timevar_pop (TV_PCH_PTR_SORT); |
544 | 465 |
545 /* Write out all the scalar variables. */ | 466 /* Write out all the scalar variables. */ |
546 for (rt = gt_pch_scalar_rtab; *rt; rt++) | 467 for (rt = gt_pch_scalar_rtab; *rt; rt++) |
547 for (rti = *rt; rti->base != NULL; rti++) | 468 for (rti = *rt; rti->base != NULL; rti++) |
548 if (fwrite (rti->base, rti->stride, 1, f) != 1) | 469 if (fwrite (rti->base, rti->stride, 1, f) != 1) |
549 fatal_error ("can%'t write PCH file: %m"); | 470 fatal_error (input_location, "can%'t write PCH file: %m"); |
550 | 471 |
551 /* Write out all the global pointers, after translation. */ | 472 /* Write out all the global pointers, after translation. */ |
552 write_pch_globals (gt_ggc_rtab, &state); | 473 write_pch_globals (gt_ggc_rtab, &state); |
553 write_pch_globals (gt_pch_cache_rtab, &state); | |
554 | 474 |
555 /* Pad the PCH file so that the mmapped area starts on an allocation | 475 /* Pad the PCH file so that the mmapped area starts on an allocation |
556 granularity (usually page) boundary. */ | 476 granularity (usually page) boundary. */ |
557 { | 477 { |
558 long o; | 478 long o; |
559 o = ftell (state.f) + sizeof (mmi); | 479 o = ftell (state.f) + sizeof (mmi); |
560 if (o == -1) | 480 if (o == -1) |
561 fatal_error ("can%'t get position in PCH file: %m"); | 481 fatal_error (input_location, "can%'t get position in PCH file: %m"); |
562 mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment; | 482 mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment; |
563 if (mmi.offset == mmap_offset_alignment) | 483 if (mmi.offset == mmap_offset_alignment) |
564 mmi.offset = 0; | 484 mmi.offset = 0; |
565 mmi.offset += o; | 485 mmi.offset += o; |
566 } | 486 } |
567 if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1) | 487 if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1) |
568 fatal_error ("can%'t write PCH file: %m"); | 488 fatal_error (input_location, "can%'t write PCH file: %m"); |
569 if (mmi.offset != 0 | 489 if (mmi.offset != 0 |
570 && fseek (state.f, mmi.offset, SEEK_SET) != 0) | 490 && fseek (state.f, mmi.offset, SEEK_SET) != 0) |
571 fatal_error ("can%'t write padding to PCH file: %m"); | 491 fatal_error (input_location, "can%'t write padding to PCH file: %m"); |
572 | 492 |
573 ggc_pch_prepare_write (state.d, state.f); | 493 ggc_pch_prepare_write (state.d, state.f); |
494 | |
495 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS | |
496 vec<char> vbits = vNULL; | |
497 #endif | |
574 | 498 |
575 /* Actually write out the objects. */ | 499 /* Actually write out the objects. */ |
576 for (i = 0; i < state.count; i++) | 500 for (i = 0; i < state.count; i++) |
577 { | 501 { |
578 if (this_object_size < state.ptrs[i]->size) | 502 if (this_object_size < state.ptrs[i]->size) |
579 { | 503 { |
580 this_object_size = state.ptrs[i]->size; | 504 this_object_size = state.ptrs[i]->size; |
581 this_object = XRESIZEVAR (char, this_object, this_object_size); | 505 this_object = XRESIZEVAR (char, this_object, this_object_size); |
582 } | 506 } |
507 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS | |
508 /* obj might contain uninitialized bytes, e.g. in the trailing | |
509 padding of the object. Avoid warnings by making the memory | |
510 temporarily defined and then restoring previous state. */ | |
511 int get_vbits = 0; | |
512 size_t valid_size = state.ptrs[i]->size; | |
513 if (__builtin_expect (RUNNING_ON_VALGRIND, 0)) | |
514 { | |
515 if (vbits.length () < valid_size) | |
516 vbits.safe_grow (valid_size); | |
517 get_vbits = VALGRIND_GET_VBITS (state.ptrs[i]->obj, | |
518 vbits.address (), valid_size); | |
519 if (get_vbits == 3) | |
520 { | |
521 /* We assume that first part of obj is addressable, and | |
522 the rest is unaddressable. Find out where the boundary is | |
523 using binary search. */ | |
524 size_t lo = 0, hi = valid_size; | |
525 while (hi > lo) | |
526 { | |
527 size_t mid = (lo + hi) / 2; | |
528 get_vbits = VALGRIND_GET_VBITS ((char *) state.ptrs[i]->obj | |
529 + mid, vbits.address (), | |
530 1); | |
531 if (get_vbits == 3) | |
532 hi = mid; | |
533 else if (get_vbits == 1) | |
534 lo = mid + 1; | |
535 else | |
536 break; | |
537 } | |
538 if (get_vbits == 1 || get_vbits == 3) | |
539 { | |
540 valid_size = lo; | |
541 get_vbits = VALGRIND_GET_VBITS (state.ptrs[i]->obj, | |
542 vbits.address (), | |
543 valid_size); | |
544 } | |
545 } | |
546 if (get_vbits == 1) | |
547 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (state.ptrs[i]->obj, | |
548 state.ptrs[i]->size)); | |
549 } | |
550 #endif | |
583 memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size); | 551 memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size); |
584 if (state.ptrs[i]->reorder_fn != NULL) | 552 if (state.ptrs[i]->reorder_fn != NULL) |
585 state.ptrs[i]->reorder_fn (state.ptrs[i]->obj, | 553 state.ptrs[i]->reorder_fn (state.ptrs[i]->obj, |
586 state.ptrs[i]->note_ptr_cookie, | 554 state.ptrs[i]->note_ptr_cookie, |
587 relocate_ptrs, &state); | 555 relocate_ptrs, &state); |
591 ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj, | 559 ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj, |
592 state.ptrs[i]->new_addr, state.ptrs[i]->size, | 560 state.ptrs[i]->new_addr, state.ptrs[i]->size, |
593 state.ptrs[i]->note_ptr_fn == gt_pch_p_S); | 561 state.ptrs[i]->note_ptr_fn == gt_pch_p_S); |
594 if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S) | 562 if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S) |
595 memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size); | 563 memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size); |
564 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS | |
565 if (__builtin_expect (get_vbits == 1, 0)) | |
566 { | |
567 (void) VALGRIND_SET_VBITS (state.ptrs[i]->obj, vbits.address (), | |
568 valid_size); | |
569 if (valid_size != state.ptrs[i]->size) | |
570 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *) | |
571 state.ptrs[i]->obj | |
572 + valid_size, | |
573 state.ptrs[i]->size | |
574 - valid_size)); | |
575 } | |
576 #endif | |
596 } | 577 } |
578 #if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS | |
579 vbits.release (); | |
580 #endif | |
581 | |
597 ggc_pch_finish (state.d, state.f); | 582 ggc_pch_finish (state.d, state.f); |
598 gt_pch_fixup_stringpool (); | 583 gt_pch_fixup_stringpool (); |
599 | 584 |
600 free (state.ptrs); | 585 XDELETE (state.ptrs); |
601 htab_delete (saving_htab); | 586 XDELETE (this_object); |
587 delete saving_htab; | |
588 saving_htab = NULL; | |
602 } | 589 } |
603 | 590 |
604 /* Read the state of the compiler back in from F. */ | 591 /* Read the state of the compiler back in from F. */ |
605 | 592 |
606 void | 593 void |
621 | 608 |
622 /* Read in all the scalar variables. */ | 609 /* Read in all the scalar variables. */ |
623 for (rt = gt_pch_scalar_rtab; *rt; rt++) | 610 for (rt = gt_pch_scalar_rtab; *rt; rt++) |
624 for (rti = *rt; rti->base != NULL; rti++) | 611 for (rti = *rt; rti->base != NULL; rti++) |
625 if (fread (rti->base, rti->stride, 1, f) != 1) | 612 if (fread (rti->base, rti->stride, 1, f) != 1) |
626 fatal_error ("can%'t read PCH file: %m"); | 613 fatal_error (input_location, "can%'t read PCH file: %m"); |
627 | 614 |
628 /* Read in all the global pointers, in 6 easy loops. */ | 615 /* Read in all the global pointers, in 6 easy loops. */ |
629 for (rt = gt_ggc_rtab; *rt; rt++) | 616 for (rt = gt_ggc_rtab; *rt; rt++) |
630 for (rti = *rt; rti->base != NULL; rti++) | 617 for (rti = *rt; rti->base != NULL; rti++) |
631 for (i = 0; i < rti->nelt; i++) | 618 for (i = 0; i < rti->nelt; i++) |
632 if (fread ((char *)rti->base + rti->stride * i, | 619 if (fread ((char *)rti->base + rti->stride * i, |
633 sizeof (void *), 1, f) != 1) | 620 sizeof (void *), 1, f) != 1) |
634 fatal_error ("can%'t read PCH file: %m"); | 621 fatal_error (input_location, "can%'t read PCH file: %m"); |
635 | |
636 for (rt = gt_pch_cache_rtab; *rt; rt++) | |
637 for (rti = *rt; rti->base != NULL; rti++) | |
638 for (i = 0; i < rti->nelt; i++) | |
639 if (fread ((char *)rti->base + rti->stride * i, | |
640 sizeof (void *), 1, f) != 1) | |
641 fatal_error ("can%'t read PCH file: %m"); | |
642 | 622 |
643 if (fread (&mmi, sizeof (mmi), 1, f) != 1) | 623 if (fread (&mmi, sizeof (mmi), 1, f) != 1) |
644 fatal_error ("can%'t read PCH file: %m"); | 624 fatal_error (input_location, "can%'t read PCH file: %m"); |
645 | 625 |
646 result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size, | 626 result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size, |
647 fileno (f), mmi.offset); | 627 fileno (f), mmi.offset); |
648 if (result < 0) | 628 if (result < 0) |
649 fatal_error ("had to relocate PCH"); | 629 fatal_error (input_location, "had to relocate PCH"); |
650 if (result == 0) | 630 if (result == 0) |
651 { | 631 { |
652 if (fseek (f, mmi.offset, SEEK_SET) != 0 | 632 if (fseek (f, mmi.offset, SEEK_SET) != 0 |
653 || fread (mmi.preferred_base, mmi.size, 1, f) != 1) | 633 || fread (mmi.preferred_base, mmi.size, 1, f) != 1) |
654 fatal_error ("can%'t read PCH file: %m"); | 634 fatal_error (input_location, "can%'t read PCH file: %m"); |
655 } | 635 } |
656 else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0) | 636 else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0) |
657 fatal_error ("can%'t read PCH file: %m"); | 637 fatal_error (input_location, "can%'t read PCH file: %m"); |
658 | 638 |
659 ggc_pch_read (f, mmi.preferred_base); | 639 ggc_pch_read (f, mmi.preferred_base); |
660 | 640 |
661 gt_pch_restore_stringpool (); | 641 gt_pch_restore_stringpool (); |
662 } | 642 } |
691 same as pagesize. */ | 671 same as pagesize. */ |
692 | 672 |
693 size_t | 673 size_t |
694 default_gt_pch_alloc_granularity (void) | 674 default_gt_pch_alloc_granularity (void) |
695 { | 675 { |
696 return getpagesize(); | 676 return getpagesize (); |
697 } | 677 } |
698 | 678 |
699 #if HAVE_MMAP_FILE | 679 #if HAVE_MMAP_FILE |
700 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is present. | 680 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is present. |
701 We temporarily allocate SIZE bytes, and let the kernel place the data | 681 We temporarily allocate SIZE bytes, and let the kernel place the data |
779 | 759 |
780 /* Heuristic to set a default for GGC_MIN_EXPAND. */ | 760 /* Heuristic to set a default for GGC_MIN_EXPAND. */ |
781 static int | 761 static int |
782 ggc_min_expand_heuristic (void) | 762 ggc_min_expand_heuristic (void) |
783 { | 763 { |
784 double min_expand = physmem_total(); | 764 double min_expand = physmem_total (); |
785 | 765 |
786 /* Adjust for rlimits. */ | 766 /* Adjust for rlimits. */ |
787 min_expand = ggc_rlimit_bound (min_expand); | 767 min_expand = ggc_rlimit_bound (min_expand); |
788 | 768 |
789 /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding | 769 /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding |
798 | 778 |
799 /* Heuristic to set a default for GGC_MIN_HEAPSIZE. */ | 779 /* Heuristic to set a default for GGC_MIN_HEAPSIZE. */ |
800 static int | 780 static int |
801 ggc_min_heapsize_heuristic (void) | 781 ggc_min_heapsize_heuristic (void) |
802 { | 782 { |
803 double phys_kbytes = physmem_total(); | 783 double phys_kbytes = physmem_total (); |
804 double limit_kbytes = ggc_rlimit_bound (phys_kbytes * 2); | 784 double limit_kbytes = ggc_rlimit_bound (phys_kbytes * 2); |
805 | 785 |
806 phys_kbytes /= 1024; /* Convert to Kbytes. */ | 786 phys_kbytes /= 1024; /* Convert to Kbytes. */ |
807 limit_kbytes /= 1024; | 787 limit_kbytes /= 1024; |
808 | 788 |
843 set_default_param_value (GGC_MIN_EXPAND, ggc_min_expand_heuristic ()); | 823 set_default_param_value (GGC_MIN_EXPAND, ggc_min_expand_heuristic ()); |
844 set_default_param_value (GGC_MIN_HEAPSIZE, ggc_min_heapsize_heuristic ()); | 824 set_default_param_value (GGC_MIN_HEAPSIZE, ggc_min_heapsize_heuristic ()); |
845 #endif | 825 #endif |
846 } | 826 } |
847 | 827 |
848 #ifdef GATHER_STATISTICS | 828 /* GGC memory usage. */ |
849 | 829 struct ggc_usage: public mem_usage |
850 /* Datastructure used to store per-call-site statistics. */ | 830 { |
851 struct loc_descriptor | 831 /* Default constructor. */ |
852 { | 832 ggc_usage (): m_freed (0), m_collected (0), m_overhead (0) {} |
853 const char *file; | 833 /* Constructor. */ |
854 int line; | 834 ggc_usage (size_t allocated, size_t times, size_t peak, |
855 const char *function; | 835 size_t freed, size_t collected, size_t overhead) |
856 int times; | 836 : mem_usage (allocated, times, peak), |
857 size_t allocated; | 837 m_freed (freed), m_collected (collected), m_overhead (overhead) {} |
858 size_t overhead; | 838 |
859 size_t freed; | 839 /* Comparison operator. */ |
860 size_t collected; | 840 inline bool |
841 operator< (const ggc_usage &second) const | |
842 { | |
843 return (get_balance () == second.get_balance () ? | |
844 (m_peak == second.m_peak ? m_times < second.m_times | |
845 : m_peak < second.m_peak) | |
846 : get_balance () < second.get_balance ()); | |
847 } | |
848 | |
849 /* Register overhead of ALLOCATED and OVERHEAD bytes. */ | |
850 inline void | |
851 register_overhead (size_t allocated, size_t overhead) | |
852 { | |
853 m_allocated += allocated; | |
854 m_overhead += overhead; | |
855 m_times++; | |
856 } | |
857 | |
858 /* Release overhead of SIZE bytes. */ | |
859 inline void | |
860 release_overhead (size_t size) | |
861 { | |
862 m_freed += size; | |
863 } | |
864 | |
865 /* Sum the usage with SECOND usage. */ | |
866 ggc_usage | |
867 operator+ (const ggc_usage &second) | |
868 { | |
869 return ggc_usage (m_allocated + second.m_allocated, | |
870 m_times + second.m_times, | |
871 m_peak + second.m_peak, | |
872 m_freed + second.m_freed, | |
873 m_collected + second.m_collected, | |
874 m_overhead + second.m_overhead); | |
875 } | |
876 | |
877 /* Dump usage with PREFIX, where TOTAL is sum of all rows. */ | |
878 inline void | |
879 dump (const char *prefix, ggc_usage &total) const | |
880 { | |
881 long balance = get_balance (); | |
882 fprintf (stderr, | |
883 "%-48s %10li:%5.1f%%%10li:%5.1f%%" | |
884 "%10li:%5.1f%%%10li:%5.1f%%%10li\n", | |
885 prefix, (long)m_collected, | |
886 get_percent (m_collected, total.m_collected), | |
887 (long)m_freed, get_percent (m_freed, total.m_freed), | |
888 (long)balance, get_percent (balance, total.get_balance ()), | |
889 (long)m_overhead, get_percent (m_overhead, total.m_overhead), | |
890 (long)m_times); | |
891 } | |
892 | |
893 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */ | |
894 inline void | |
895 dump (mem_location *loc, ggc_usage &total) const | |
896 { | |
897 char *location_string = loc->to_string (); | |
898 | |
899 dump (location_string, total); | |
900 | |
901 free (location_string); | |
902 } | |
903 | |
904 /* Dump footer. */ | |
905 inline void | |
906 dump_footer () | |
907 { | |
908 print_dash_line (); | |
909 dump ("Total", *this); | |
910 print_dash_line (); | |
911 } | |
912 | |
913 /* Get balance which is GGC allocation leak. */ | |
914 inline long | |
915 get_balance () const | |
916 { | |
917 return m_allocated + m_overhead - m_collected - m_freed; | |
918 } | |
919 | |
920 typedef std::pair<mem_location *, ggc_usage *> mem_pair_t; | |
921 | |
922 /* Compare wrapper used by qsort method. */ | |
923 static int | |
924 compare (const void *first, const void *second) | |
925 { | |
926 const mem_pair_t f = *(const mem_pair_t *)first; | |
927 const mem_pair_t s = *(const mem_pair_t *)second; | |
928 | |
929 return (*f.second) < (*s.second); | |
930 } | |
931 | |
932 /* Compare rows in final GGC summary dump. */ | |
933 static int | |
934 compare_final (const void *first, const void *second) | |
935 { | |
936 typedef std::pair<mem_location *, ggc_usage *> mem_pair_t; | |
937 | |
938 const ggc_usage *f = ((const mem_pair_t *)first)->second; | |
939 const ggc_usage *s = ((const mem_pair_t *)second)->second; | |
940 | |
941 size_t a = f->m_allocated + f->m_overhead - f->m_freed; | |
942 size_t b = s->m_allocated + s->m_overhead - s->m_freed; | |
943 | |
944 return a == b ? 0 : (a < b ? 1 : -1); | |
945 } | |
946 | |
947 /* Dump header with NAME. */ | |
948 static inline void | |
949 dump_header (const char *name) | |
950 { | |
951 fprintf (stderr, "%-48s %11s%17s%17s%16s%17s\n", name, "Garbage", "Freed", | |
952 "Leak", "Overhead", "Times"); | |
953 print_dash_line (); | |
954 } | |
955 | |
956 /* Freed memory in bytes. */ | |
957 size_t m_freed; | |
958 /* Collected memory in bytes. */ | |
959 size_t m_collected; | |
960 /* Overhead memory in bytes. */ | |
961 size_t m_overhead; | |
861 }; | 962 }; |
862 | 963 |
863 /* Hashtable used for statistics. */ | 964 /* GCC memory description. */ |
864 static htab_t loc_hash; | 965 static mem_alloc_description<ggc_usage> ggc_mem_desc; |
865 | 966 |
866 /* Hash table helpers functions. */ | 967 /* Dump per-site memory statistics. */ |
867 static hashval_t | 968 |
868 hash_descriptor (const void *p) | 969 void |
869 { | 970 dump_ggc_loc_statistics (bool final) |
870 const struct loc_descriptor *const d = (const struct loc_descriptor *) p; | 971 { |
871 | 972 if (! GATHER_STATISTICS) |
872 return htab_hash_pointer (d->function) | d->line; | 973 return; |
873 } | 974 |
874 | 975 ggc_force_collect = true; |
875 static int | 976 ggc_collect (); |
876 eq_descriptor (const void *p1, const void *p2) | 977 |
877 { | 978 ggc_mem_desc.dump (GGC_ORIGIN, final ? ggc_usage::compare_final : NULL); |
878 const struct loc_descriptor *const d = (const struct loc_descriptor *) p1; | 979 |
879 const struct loc_descriptor *const d2 = (const struct loc_descriptor *) p2; | 980 ggc_force_collect = false; |
880 | |
881 return (d->file == d2->file && d->line == d2->line | |
882 && d->function == d2->function); | |
883 } | |
884 | |
885 /* Hashtable converting address of allocated field to loc descriptor. */ | |
886 static htab_t ptr_hash; | |
887 struct ptr_hash_entry | |
888 { | |
889 void *ptr; | |
890 struct loc_descriptor *loc; | |
891 size_t size; | |
892 }; | |
893 | |
894 /* Hash table helpers functions. */ | |
895 static hashval_t | |
896 hash_ptr (const void *p) | |
897 { | |
898 const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p; | |
899 | |
900 return htab_hash_pointer (d->ptr); | |
901 } | |
902 | |
903 static int | |
904 eq_ptr (const void *p1, const void *p2) | |
905 { | |
906 const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1; | |
907 | |
908 return (p->ptr == p2); | |
909 } | |
910 | |
911 /* Return descriptor for given call site, create new one if needed. */ | |
912 static struct loc_descriptor * | |
913 loc_descriptor (const char *name, int line, const char *function) | |
914 { | |
915 struct loc_descriptor loc; | |
916 struct loc_descriptor **slot; | |
917 | |
918 loc.file = name; | |
919 loc.line = line; | |
920 loc.function = function; | |
921 if (!loc_hash) | |
922 loc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL); | |
923 | |
924 slot = (struct loc_descriptor **) htab_find_slot (loc_hash, &loc, INSERT); | |
925 if (*slot) | |
926 return *slot; | |
927 *slot = XCNEW (struct loc_descriptor); | |
928 (*slot)->file = name; | |
929 (*slot)->line = line; | |
930 (*slot)->function = function; | |
931 return *slot; | |
932 } | 981 } |
933 | 982 |
934 /* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */ | 983 /* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */ |
935 void | 984 void |
936 ggc_record_overhead (size_t allocated, size_t overhead, void *ptr, | 985 ggc_record_overhead (size_t allocated, size_t overhead, void *ptr MEM_STAT_DECL) |
937 const char *name, int line, const char *function) | 986 { |
938 { | 987 ggc_usage *usage = ggc_mem_desc.register_descriptor (ptr, GGC_ORIGIN, false |
939 struct loc_descriptor *loc = loc_descriptor (name, line, function); | 988 FINAL_PASS_MEM_STAT); |
940 struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry); | 989 |
941 PTR *slot; | 990 ggc_mem_desc.register_object_overhead (usage, allocated + overhead, ptr); |
942 | 991 usage->register_overhead (allocated, overhead); |
943 p->ptr = ptr; | 992 } |
944 p->loc = loc; | 993 |
945 p->size = allocated + overhead; | 994 /* Notice that the pointer has been freed. */ |
946 if (!ptr_hash) | 995 void |
947 ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL); | 996 ggc_free_overhead (void *ptr) |
948 slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT); | 997 { |
949 gcc_assert (!*slot); | 998 ggc_mem_desc.release_object_overhead (ptr); |
950 *slot = p; | |
951 | |
952 loc->times++; | |
953 loc->allocated+=allocated; | |
954 loc->overhead+=overhead; | |
955 } | |
956 | |
957 /* Helper function for prune_overhead_list. See if SLOT is still marked and | |
958 remove it from hashtable if it is not. */ | |
959 static int | |
960 ggc_prune_ptr (void **slot, void *b ATTRIBUTE_UNUSED) | |
961 { | |
962 struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot; | |
963 if (!ggc_marked_p (p->ptr)) | |
964 { | |
965 p->loc->collected += p->size; | |
966 htab_clear_slot (ptr_hash, slot); | |
967 free (p); | |
968 } | |
969 return 1; | |
970 } | 999 } |
971 | 1000 |
972 /* After live values has been marked, walk all recorded pointers and see if | 1001 /* After live values has been marked, walk all recorded pointers and see if |
973 they are still live. */ | 1002 they are still live. */ |
974 void | 1003 void |
975 ggc_prune_overhead_list (void) | 1004 ggc_prune_overhead_list (void) |
976 { | 1005 { |
977 htab_traverse (ptr_hash, ggc_prune_ptr, NULL); | 1006 typedef hash_map<const void *, std::pair<ggc_usage *, size_t > > map_t; |
978 } | 1007 |
979 | 1008 map_t::iterator it = ggc_mem_desc.m_reverse_object_map->begin (); |
980 /* Notice that the pointer has been freed. */ | 1009 |
981 void | 1010 for (; it != ggc_mem_desc.m_reverse_object_map->end (); ++it) |
982 ggc_free_overhead (void *ptr) | 1011 if (!ggc_marked_p ((*it).first)) |
983 { | 1012 (*it).second.first->m_collected += (*it).second.second; |
984 PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), | 1013 |
985 NO_INSERT); | 1014 delete ggc_mem_desc.m_reverse_object_map; |
986 struct ptr_hash_entry *p; | 1015 ggc_mem_desc.m_reverse_object_map = new map_t (13, false, false); |
987 /* The pointer might be not found if a PCH read happened between allocation | 1016 } |
988 and ggc_free () call. FIXME: account memory properly in the presence of | |
989 PCH. */ | |
990 if (!slot) | |
991 return; | |
992 p = (struct ptr_hash_entry *) *slot; | |
993 p->loc->freed += p->size; | |
994 htab_clear_slot (ptr_hash, slot); | |
995 free (p); | |
996 } | |
997 | |
998 /* Helper for qsort; sort descriptors by amount of memory consumed. */ | |
999 static int | |
1000 final_cmp_statistic (const void *loc1, const void *loc2) | |
1001 { | |
1002 const struct loc_descriptor *const l1 = | |
1003 *(const struct loc_descriptor *const *) loc1; | |
1004 const struct loc_descriptor *const l2 = | |
1005 *(const struct loc_descriptor *const *) loc2; | |
1006 long diff; | |
1007 diff = ((long)(l1->allocated + l1->overhead - l1->freed) - | |
1008 (l2->allocated + l2->overhead - l2->freed)); | |
1009 return diff > 0 ? 1 : diff < 0 ? -1 : 0; | |
1010 } | |
1011 | |
1012 /* Helper for qsort; sort descriptors by amount of memory consumed. */ | |
1013 static int | |
1014 cmp_statistic (const void *loc1, const void *loc2) | |
1015 { | |
1016 const struct loc_descriptor *const l1 = | |
1017 *(const struct loc_descriptor *const *) loc1; | |
1018 const struct loc_descriptor *const l2 = | |
1019 *(const struct loc_descriptor *const *) loc2; | |
1020 long diff; | |
1021 | |
1022 diff = ((long)(l1->allocated + l1->overhead - l1->freed - l1->collected) - | |
1023 (l2->allocated + l2->overhead - l2->freed - l2->collected)); | |
1024 if (diff) | |
1025 return diff > 0 ? 1 : diff < 0 ? -1 : 0; | |
1026 diff = ((long)(l1->allocated + l1->overhead - l1->freed) - | |
1027 (l2->allocated + l2->overhead - l2->freed)); | |
1028 return diff > 0 ? 1 : diff < 0 ? -1 : 0; | |
1029 } | |
1030 | |
1031 /* Collect array of the descriptors from hashtable. */ | |
1032 static struct loc_descriptor **loc_array; | |
1033 static int | |
1034 add_statistics (void **slot, void *b) | |
1035 { | |
1036 int *n = (int *)b; | |
1037 loc_array[*n] = (struct loc_descriptor *) *slot; | |
1038 (*n)++; | |
1039 return 1; | |
1040 } | |
1041 | |
1042 /* Dump per-site memory statistics. */ | |
1043 #endif | |
1044 void | |
1045 dump_ggc_loc_statistics (bool final ATTRIBUTE_UNUSED) | |
1046 { | |
1047 #ifdef GATHER_STATISTICS | |
1048 int nentries = 0; | |
1049 char s[4096]; | |
1050 size_t collected = 0, freed = 0, allocated = 0, overhead = 0, times = 0; | |
1051 int i; | |
1052 | |
1053 ggc_force_collect = true; | |
1054 ggc_collect (); | |
1055 | |
1056 loc_array = XCNEWVEC (struct loc_descriptor *, loc_hash->n_elements); | |
1057 fprintf (stderr, "-------------------------------------------------------\n"); | |
1058 fprintf (stderr, "\n%-48s %10s %10s %10s %10s %10s\n", | |
1059 "source location", "Garbage", "Freed", "Leak", "Overhead", "Times"); | |
1060 fprintf (stderr, "-------------------------------------------------------\n"); | |
1061 htab_traverse (loc_hash, add_statistics, &nentries); | |
1062 qsort (loc_array, nentries, sizeof (*loc_array), | |
1063 final ? final_cmp_statistic : cmp_statistic); | |
1064 for (i = 0; i < nentries; i++) | |
1065 { | |
1066 struct loc_descriptor *d = loc_array[i]; | |
1067 allocated += d->allocated; | |
1068 times += d->times; | |
1069 freed += d->freed; | |
1070 collected += d->collected; | |
1071 overhead += d->overhead; | |
1072 } | |
1073 for (i = 0; i < nentries; i++) | |
1074 { | |
1075 struct loc_descriptor *d = loc_array[i]; | |
1076 if (d->allocated) | |
1077 { | |
1078 const char *s1 = d->file; | |
1079 const char *s2; | |
1080 while ((s2 = strstr (s1, "gcc/"))) | |
1081 s1 = s2 + 4; | |
1082 sprintf (s, "%s:%i (%s)", s1, d->line, d->function); | |
1083 s[48] = 0; | |
1084 fprintf (stderr, "%-48s %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li\n", s, | |
1085 (long)d->collected, | |
1086 (d->collected) * 100.0 / collected, | |
1087 (long)d->freed, | |
1088 (d->freed) * 100.0 / freed, | |
1089 (long)(d->allocated + d->overhead - d->freed - d->collected), | |
1090 (d->allocated + d->overhead - d->freed - d->collected) * 100.0 | |
1091 / (allocated + overhead - freed - collected), | |
1092 (long)d->overhead, | |
1093 d->overhead * 100.0 / overhead, | |
1094 (long)d->times); | |
1095 } | |
1096 } | |
1097 fprintf (stderr, "%-48s %10ld %10ld %10ld %10ld %10ld\n", | |
1098 "Total", (long)collected, (long)freed, | |
1099 (long)(allocated + overhead - freed - collected), (long)overhead, | |
1100 (long)times); | |
1101 fprintf (stderr, "%-48s %10s %10s %10s %10s %10s\n", | |
1102 "source location", "Garbage", "Freed", "Leak", "Overhead", "Times"); | |
1103 fprintf (stderr, "-------------------------------------------------------\n"); | |
1104 ggc_force_collect = false; | |
1105 #endif | |
1106 } |