/* Simple garbage collection for the GNU compiler.
- Copyright (C) 1999-2014 Free Software Foundation, Inc.
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "hash-table.h"
-#include "ggc.h"
-#include "ggc-internal.h"
+#include "timevar.h"
#include "diagnostic-core.h"
+#include "ggc-internal.h"
#include "params.h"
#include "hosthooks.h"
-#include "hosthooks-def.h"
#include "plugin.h"
-#include "vec.h"
-#include "timevar.h"
/* When set, ggc_collect will do collection. */
bool ggc_force_collect;
struct traversal_state;
-static int ggc_htab_delete (void **, void *);
static int compare_ptr_data (const void *, const void *);
static void relocate_ptrs (void *, void *);
static void write_pch_globals (const struct ggc_root_tab * const *tab,
/* Maintain global roots that are preserved during GC. */
-/* Process a slot of an htab by deleting it if it has not been marked. */
-
-static int
-ggc_htab_delete (void **slot, void *info)
-{
- const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info;
-
- if (! (*r->marked_p) (*slot))
- htab_clear_slot (*r->base, slot);
- else
- (*r->cb) (*slot);
-
- return 1;
-}
-
-
/* This extra vector of dynamically registered root_tab-s is used by
ggc_mark_roots and gives the ability to dynamically add new GGC root
tables, for instance from some plugins; this vector is on the heap
extra_root_vec.safe_push (rt);
}
-/* This extra vector of dynamically registered cache_tab-s is used by
- ggc_mark_roots and gives the ability to dynamically add new GGC cache
- tables, for instance from some plugins; this vector is on the heap
- since it is used by GGC internally. */
-typedef const struct ggc_cache_tab *const_ggc_cache_tab_t;
-static vec<const_ggc_cache_tab_t> extra_cache_vec;
-
-/* Dynamically register a new GGC cache table CT. This is useful for
- plugins. */
-
-void
-ggc_register_cache_tab (const struct ggc_cache_tab* ct)
-{
- if (ct)
- extra_cache_vec.safe_push (ct);
-}
-
-/* Scan a hash table that has objects which are to be deleted if they are not
- already marked. */
-
-static void
-ggc_scan_cache_tab (const_ggc_cache_tab_t ctp)
-{
- const struct ggc_cache_tab *cti;
-
- for (cti = ctp; cti->base != NULL; cti++)
- if (*cti->base)
- {
- ggc_set_mark (*cti->base);
- htab_traverse_noresize (*cti->base, ggc_htab_delete,
- CONST_CAST (void *, (const void *)cti));
- ggc_set_mark ((*cti->base)->entries);
- }
-}
-
/* Mark all the roots in the table RT. */
static void
{
const struct ggc_root_tab *const *rt;
const_ggc_root_tab_t rtp, rti;
- const struct ggc_cache_tab *const *ct;
- const_ggc_cache_tab_t ctp;
size_t i;
for (rt = gt_ggc_deletable_rtab; *rt; rt++)
if (ggc_protect_identifiers)
ggc_mark_stringpool ();
- /* Now scan all hash tables that have objects which are to be deleted if
- they are not already marked. */
- for (ct = gt_ggc_cache_rtab; *ct; ct++)
- ggc_scan_cache_tab (*ct);
-
gt_clear_caches ();
- FOR_EACH_VEC_ELT (extra_cache_vec, i, ctp)
- ggc_scan_cache_tab (ctp);
-
if (! ggc_protect_identifiers)
ggc_purge_stringpool ();
gcc_assert (!nl);
}
-/* Print statistics that are independent of the collector in use. */
-#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
- ? (x) \
- : ((x) < 1024*1024*10 \
- ? (x) / 1024 \
- : (x) / (1024*1024))))
-#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
-
void
ggc_print_common_statistics (FILE *stream ATTRIBUTE_UNUSED,
ggc_statistics *stats)
/* Helper for hashing saving_htab. */
-struct saving_hasher : typed_free_remove <ptr_data>
+struct saving_hasher : free_ptr_hash <ptr_data>
{
- typedef ptr_data value_type;
- typedef void compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ typedef void *compare_type;
+ static inline hashval_t hash (const ptr_data *);
+ static inline bool equal (const ptr_data *, const void *);
};
inline hashval_t
-saving_hasher::hash (const value_type *p)
+saving_hasher::hash (const ptr_data *p)
{
return POINTER_HASH (p->obj);
}
inline bool
-saving_hasher::equal (const value_type *p1, const compare_type *p2)
+saving_hasher::equal (const ptr_data *p1, const void *p2)
{
return p1->obj == p2;
}
{
if (fwrite (&ptr, sizeof (void *), 1, state->f)
!= 1)
- fatal_error ("can%'t write PCH file: %m");
+ fatal_error (input_location, "cannot write PCH file: %m");
}
else
{
saving_htab->find_with_hash (ptr, POINTER_HASH (ptr));
if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f)
!= 1)
- fatal_error ("can%'t write PCH file: %m");
+ fatal_error (input_location, "cannot write PCH file: %m");
}
}
}
for (i = 0; i < rti->nelt; i++)
(*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
- for (rt = gt_pch_cache_rtab; *rt; rt++)
- for (rti = *rt; rti->base != NULL; rti++)
- for (i = 0; i < rti->nelt; i++)
- (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
-
/* Prepare the objects for writing, determine addresses and such. */
state.f = f;
state.d = init_ggc_pch ();
for (rt = gt_pch_scalar_rtab; *rt; rt++)
for (rti = *rt; rti->base != NULL; rti++)
if (fwrite (rti->base, rti->stride, 1, f) != 1)
- fatal_error ("can%'t write PCH file: %m");
+ fatal_error (input_location, "cannot write PCH file: %m");
/* Write out all the global pointers, after translation. */
write_pch_globals (gt_ggc_rtab, &state);
- write_pch_globals (gt_pch_cache_rtab, &state);
/* Pad the PCH file so that the mmapped area starts on an allocation
granularity (usually page) boundary. */
long o;
o = ftell (state.f) + sizeof (mmi);
if (o == -1)
- fatal_error ("can%'t get position in PCH file: %m");
+ fatal_error (input_location, "cannot get position in PCH file: %m");
mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment;
if (mmi.offset == mmap_offset_alignment)
mmi.offset = 0;
mmi.offset += o;
}
if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)
- fatal_error ("can%'t write PCH file: %m");
+ fatal_error (input_location, "cannot write PCH file: %m");
if (mmi.offset != 0
&& fseek (state.f, mmi.offset, SEEK_SET) != 0)
- fatal_error ("can%'t write padding to PCH file: %m");
+ fatal_error (input_location, "cannot write padding to PCH file: %m");
ggc_pch_prepare_write (state.d, state.f);
-#if defined ENABLE_VALGRIND_CHECKING && defined VALGRIND_GET_VBITS
+#if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
vec<char> vbits = vNULL;
#endif
this_object_size = state.ptrs[i]->size;
this_object = XRESIZEVAR (char, this_object, this_object_size);
}
-#if defined ENABLE_VALGRIND_CHECKING && defined VALGRIND_GET_VBITS
+#if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
/* obj might contain uninitialized bytes, e.g. in the trailing
padding of the object. Avoid warnings by making the memory
temporarily defined and then restoring previous state. */
state.ptrs[i]->note_ptr_fn == gt_pch_p_S);
if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S)
memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size);
-#if defined ENABLE_VALGRIND_CHECKING && defined VALGRIND_GET_VBITS
+#if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
if (__builtin_expect (get_vbits == 1, 0))
{
(void) VALGRIND_SET_VBITS (state.ptrs[i]->obj, vbits.address (),
}
#endif
}
-#if defined ENABLE_VALGRIND_CHECKING && defined VALGRIND_GET_VBITS
+#if defined ENABLE_VALGRIND_ANNOTATIONS && defined VALGRIND_GET_VBITS
vbits.release ();
#endif
for (rt = gt_pch_scalar_rtab; *rt; rt++)
for (rti = *rt; rti->base != NULL; rti++)
if (fread (rti->base, rti->stride, 1, f) != 1)
- fatal_error ("can%'t read PCH file: %m");
+ fatal_error (input_location, "cannot read PCH file: %m");
/* Read in all the global pointers, in 6 easy loops. */
for (rt = gt_ggc_rtab; *rt; rt++)
for (i = 0; i < rti->nelt; i++)
if (fread ((char *)rti->base + rti->stride * i,
sizeof (void *), 1, f) != 1)
- fatal_error ("can%'t read PCH file: %m");
-
- for (rt = gt_pch_cache_rtab; *rt; rt++)
- for (rti = *rt; rti->base != NULL; rti++)
- for (i = 0; i < rti->nelt; i++)
- if (fread ((char *)rti->base + rti->stride * i,
- sizeof (void *), 1, f) != 1)
- fatal_error ("can%'t read PCH file: %m");
+ fatal_error (input_location, "cannot read PCH file: %m");
if (fread (&mmi, sizeof (mmi), 1, f) != 1)
- fatal_error ("can%'t read PCH file: %m");
+ fatal_error (input_location, "cannot read PCH file: %m");
result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,
fileno (f), mmi.offset);
if (result < 0)
- fatal_error ("had to relocate PCH");
+ fatal_error (input_location, "had to relocate PCH");
if (result == 0)
{
if (fseek (f, mmi.offset, SEEK_SET) != 0
|| fread (mmi.preferred_base, mmi.size, 1, f) != 1)
- fatal_error ("can%'t read PCH file: %m");
+ fatal_error (input_location, "cannot read PCH file: %m");
}
else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
- fatal_error ("can%'t read PCH file: %m");
+ fatal_error (input_location, "cannot read PCH file: %m");
ggc_pch_read (f, mmi.preferred_base);
#endif
}
-/* Datastructure used to store per-call-site statistics. */
-struct ggc_loc_descriptor
+/* GGC memory usage. */
+struct ggc_usage: public mem_usage
{
- const char *file;
- int line;
- const char *function;
- int times;
- size_t allocated;
- size_t overhead;
- size_t freed;
- size_t collected;
-};
+ /* Default constructor. */
+ ggc_usage (): m_freed (0), m_collected (0), m_overhead (0) {}
+ /* Constructor. */
+ ggc_usage (size_t allocated, size_t times, size_t peak,
+ size_t freed, size_t collected, size_t overhead)
+ : mem_usage (allocated, times, peak),
+ m_freed (freed), m_collected (collected), m_overhead (overhead) {}
-/* Hash table helper. */
+ /* Equality operator. */
+ inline bool
+ operator== (const ggc_usage &second) const
+ {
+ return (get_balance () == second.get_balance ()
+ && m_peak == second.m_peak
+ && m_times == second.m_times);
+ }
-struct ggc_loc_desc_hasher : typed_noop_remove <ggc_loc_descriptor>
-{
- typedef ggc_loc_descriptor value_type;
- typedef ggc_loc_descriptor compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
-};
+ /* Comparison operator. */
+ inline bool
+ operator< (const ggc_usage &second) const
+ {
+ if (*this == second)
+ return false;
-inline hashval_t
-ggc_loc_desc_hasher::hash (const value_type *d)
-{
- return htab_hash_pointer (d->function) | d->line;
-}
+ return (get_balance () == second.get_balance () ?
+ (m_peak == second.m_peak ? m_times < second.m_times
+ : m_peak < second.m_peak)
+ : get_balance () < second.get_balance ());
+ }
-inline bool
-ggc_loc_desc_hasher::equal (const value_type *d, const compare_type *d2)
-{
- return (d->file == d2->file && d->line == d2->line
- && d->function == d2->function);
-}
+ /* Register overhead of ALLOCATED and OVERHEAD bytes. */
+ inline void
+ register_overhead (size_t allocated, size_t overhead)
+ {
+ m_allocated += allocated;
+ m_overhead += overhead;
+ m_times++;
+ }
-/* Hashtable used for statistics. */
-static hash_table<ggc_loc_desc_hasher> *loc_hash;
+ /* Release overhead of SIZE bytes. */
+ inline void
+ release_overhead (size_t size)
+ {
+ m_freed += size;
+ }
-struct ggc_ptr_hash_entry
-{
- void *ptr;
- struct ggc_loc_descriptor *loc;
- size_t size;
-};
+ /* Sum the usage with SECOND usage. */
+ ggc_usage
+ operator+ (const ggc_usage &second)
+ {
+ return ggc_usage (m_allocated + second.m_allocated,
+ m_times + second.m_times,
+ m_peak + second.m_peak,
+ m_freed + second.m_freed,
+ m_collected + second.m_collected,
+ m_overhead + second.m_overhead);
+ }
-/* Helper for ptr_hash table. */
+ /* Dump usage with PREFIX, where TOTAL is sum of all rows. */
+ inline void
+ dump (const char *prefix, ggc_usage &total) const
+ {
+ size_t balance = get_balance ();
+ fprintf (stderr,
+ "%-48s " PRsa (9) ":%5.1f%%" PRsa (9) ":%5.1f%%"
+ PRsa (9) ":%5.1f%%" PRsa (9) ":%5.1f%%" PRsa (9) "\n",
+ prefix, SIZE_AMOUNT (m_collected),
+ get_percent (m_collected, total.m_collected),
+ SIZE_AMOUNT (m_freed), get_percent (m_freed, total.m_freed),
+ SIZE_AMOUNT (balance), get_percent (balance, total.get_balance ()),
+ SIZE_AMOUNT (m_overhead),
+ get_percent (m_overhead, total.m_overhead),
+ SIZE_AMOUNT (m_times));
+ }
-struct ptr_hash_hasher : typed_noop_remove <ggc_ptr_hash_entry>
-{
- typedef ggc_ptr_hash_entry value_type;
- typedef void compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
-};
+ /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
+ inline void
+ dump (mem_location *loc, ggc_usage &total) const
+ {
+ char *location_string = loc->to_string ();
-inline hashval_t
-ptr_hash_hasher::hash (const value_type *d)
-{
- return htab_hash_pointer (d->ptr);
-}
+ dump (location_string, total);
-inline bool
-ptr_hash_hasher::equal (const value_type *p, const compare_type *p2)
-{
- return (p->ptr == p2);
-}
+ free (location_string);
+ }
-/* Hashtable converting address of allocated field to loc descriptor. */
-static hash_table<ptr_hash_hasher> *ptr_hash;
+ /* Dump footer. */
+ inline void
+ dump_footer ()
+ {
+ dump ("Total", *this);
+ }
-/* Return descriptor for given call site, create new one if needed. */
-static struct ggc_loc_descriptor *
-make_loc_descriptor (const char *name, int line, const char *function)
-{
- struct ggc_loc_descriptor loc;
- struct ggc_loc_descriptor **slot;
-
- loc.file = name;
- loc.line = line;
- loc.function = function;
- if (!loc_hash)
- loc_hash = new hash_table<ggc_loc_desc_hasher> (10);
-
- slot = loc_hash->find_slot (&loc, INSERT);
- if (*slot)
- return *slot;
- *slot = XCNEW (struct ggc_loc_descriptor);
- (*slot)->file = name;
- (*slot)->line = line;
- (*slot)->function = function;
- return *slot;
-}
+ /* Get balance which is GGC allocation leak. */
+ inline size_t
+ get_balance () const
+ {
+ return m_allocated + m_overhead - m_collected - m_freed;
+ }
+
+ typedef std::pair<mem_location *, ggc_usage *> mem_pair_t;
+
+ /* Compare wrapper used by qsort method. */
+ static int
+ compare (const void *first, const void *second)
+ {
+ const mem_pair_t f = *(const mem_pair_t *)first;
+ const mem_pair_t s = *(const mem_pair_t *)second;
+
+ return s.second->get_balance () - f.second->get_balance ();
+ }
+
+ /* Compare rows in final GGC summary dump. */
+ static int
+ compare_final (const void *first, const void *second)
+ {
+ typedef std::pair<mem_location *, ggc_usage *> mem_pair_t;
+
+ const ggc_usage *f = ((const mem_pair_t *)first)->second;
+ const ggc_usage *s = ((const mem_pair_t *)second)->second;
+
+ size_t a = f->m_allocated + f->m_overhead - f->m_freed;
+ size_t b = s->m_allocated + s->m_overhead - s->m_freed;
+
+ return a == b ? 0 : (a < b ? 1 : -1);
+ }
+
+ /* Dump header with NAME. */
+ static inline void
+ dump_header (const char *name)
+ {
+ fprintf (stderr, "%-48s %11s%17s%17s%16s%17s\n", name, "Garbage", "Freed",
+ "Leak", "Overhead", "Times");
+ }
+
+ /* Freed memory in bytes. */
+ size_t m_freed;
+ /* Collected memory in bytes. */
+ size_t m_collected;
+ /* Overhead memory in bytes. */
+ size_t m_overhead;
+};
+
+/* GCC memory description. */
+static mem_alloc_description<ggc_usage> ggc_mem_desc;
+
+/* Dump per-site memory statistics. */
-/* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */
void
-ggc_record_overhead (size_t allocated, size_t overhead, void *ptr,
- const char *name, int line, const char *function)
+dump_ggc_loc_statistics (bool final)
{
- struct ggc_loc_descriptor *loc = make_loc_descriptor (name, line, function);
- struct ggc_ptr_hash_entry *p = XNEW (struct ggc_ptr_hash_entry);
- ggc_ptr_hash_entry **slot;
-
- p->ptr = ptr;
- p->loc = loc;
- p->size = allocated + overhead;
- if (!ptr_hash)
- ptr_hash = new hash_table<ptr_hash_hasher> (10);
- slot = ptr_hash->find_slot_with_hash (ptr, htab_hash_pointer (ptr), INSERT);
- gcc_assert (!*slot);
- *slot = p;
-
- loc->times++;
- loc->allocated+=allocated;
- loc->overhead+=overhead;
-}
+ if (! GATHER_STATISTICS)
+ return;
-/* Helper function for prune_overhead_list. See if SLOT is still marked and
- remove it from hashtable if it is not. */
-int
-ggc_prune_ptr (ggc_ptr_hash_entry **slot, void *b ATTRIBUTE_UNUSED)
-{
- struct ggc_ptr_hash_entry *p = *slot;
- if (!ggc_marked_p (p->ptr))
- {
- p->loc->collected += p->size;
- ptr_hash->clear_slot (slot);
- free (p);
- }
- return 1;
+ ggc_force_collect = true;
+ ggc_collect ();
+
+ ggc_mem_desc.dump (GGC_ORIGIN, final ? ggc_usage::compare_final : NULL);
+
+ ggc_force_collect = false;
}
-/* After live values has been marked, walk all recorded pointers and see if
- they are still live. */
+/* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */
void
-ggc_prune_overhead_list (void)
+ggc_record_overhead (size_t allocated, size_t overhead, void *ptr MEM_STAT_DECL)
{
- ptr_hash->traverse <void *, ggc_prune_ptr> (NULL);
+ ggc_usage *usage = ggc_mem_desc.register_descriptor (ptr, GGC_ORIGIN, false
+ FINAL_PASS_MEM_STAT);
+
+ ggc_mem_desc.register_object_overhead (usage, allocated + overhead, ptr);
+ usage->register_overhead (allocated, overhead);
}
/* Notice that the pointer has been freed. */
void
ggc_free_overhead (void *ptr)
{
- ggc_ptr_hash_entry **slot
- = ptr_hash->find_slot_with_hash (ptr, htab_hash_pointer (ptr), NO_INSERT);
- struct ggc_ptr_hash_entry *p;
- /* The pointer might be not found if a PCH read happened between allocation
- and ggc_free () call. FIXME: account memory properly in the presence of
- PCH. */
- if (!slot)
- return;
- p = (struct ggc_ptr_hash_entry *) *slot;
- p->loc->freed += p->size;
- ptr_hash->clear_slot (slot);
- free (p);
+ ggc_mem_desc.release_object_overhead (ptr);
}
-/* Helper for qsort; sort descriptors by amount of memory consumed. */
-static int
-final_cmp_statistic (const void *loc1, const void *loc2)
-{
- const struct ggc_loc_descriptor *const l1 =
- *(const struct ggc_loc_descriptor *const *) loc1;
- const struct ggc_loc_descriptor *const l2 =
- *(const struct ggc_loc_descriptor *const *) loc2;
- long diff;
- diff = ((long)(l1->allocated + l1->overhead - l1->freed) -
- (l2->allocated + l2->overhead - l2->freed));
- return diff > 0 ? 1 : diff < 0 ? -1 : 0;
-}
-
-/* Helper for qsort; sort descriptors by amount of memory consumed. */
-static int
-cmp_statistic (const void *loc1, const void *loc2)
-{
- const struct ggc_loc_descriptor *const l1 =
- *(const struct ggc_loc_descriptor *const *) loc1;
- const struct ggc_loc_descriptor *const l2 =
- *(const struct ggc_loc_descriptor *const *) loc2;
- long diff;
-
- diff = ((long)(l1->allocated + l1->overhead - l1->freed - l1->collected) -
- (l2->allocated + l2->overhead - l2->freed - l2->collected));
- if (diff)
- return diff > 0 ? 1 : diff < 0 ? -1 : 0;
- diff = ((long)(l1->allocated + l1->overhead - l1->freed) -
- (l2->allocated + l2->overhead - l2->freed));
- return diff > 0 ? 1 : diff < 0 ? -1 : 0;
-}
-
-/* Collect array of the descriptors from hashtable. */
-static struct ggc_loc_descriptor **loc_array;
-int
-ggc_add_statistics (ggc_loc_descriptor **slot, int *n)
-{
- loc_array[*n] = *slot;
- (*n)++;
- return 1;
-}
-
-/* Dump per-site memory statistics. */
-
+/* After live values has been marked, walk all recorded pointers and see if
+ they are still live. */
void
-dump_ggc_loc_statistics (bool final)
+ggc_prune_overhead_list (void)
{
- int nentries = 0;
- char s[4096];
- size_t collected = 0, freed = 0, allocated = 0, overhead = 0, times = 0;
- int i;
+ typedef hash_map<const void *, std::pair<ggc_usage *, size_t > > map_t;
- if (! GATHER_STATISTICS)
- return;
+ map_t::iterator it = ggc_mem_desc.m_reverse_object_map->begin ();
- ggc_force_collect = true;
- ggc_collect ();
+ for (; it != ggc_mem_desc.m_reverse_object_map->end (); ++it)
+ if (!ggc_marked_p ((*it).first))
+ (*it).second.first->m_collected += (*it).second.second;
- loc_array = XCNEWVEC (struct ggc_loc_descriptor *,
- loc_hash->elements_with_deleted ());
- fprintf (stderr, "-------------------------------------------------------\n");
- fprintf (stderr, "\n%-48s %10s %10s %10s %10s %10s\n",
- "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
- fprintf (stderr, "-------------------------------------------------------\n");
- loc_hash->traverse <int *, ggc_add_statistics> (&nentries);
- qsort (loc_array, nentries, sizeof (*loc_array),
- final ? final_cmp_statistic : cmp_statistic);
- for (i = 0; i < nentries; i++)
- {
- struct ggc_loc_descriptor *d = loc_array[i];
- allocated += d->allocated;
- times += d->times;
- freed += d->freed;
- collected += d->collected;
- overhead += d->overhead;
- }
- for (i = 0; i < nentries; i++)
- {
- struct ggc_loc_descriptor *d = loc_array[i];
- if (d->allocated)
- {
- const char *s1 = d->file;
- const char *s2;
- while ((s2 = strstr (s1, "gcc/")))
- s1 = s2 + 4;
- sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
- s[48] = 0;
- fprintf (stderr, "%-48s %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li\n", s,
- (long)d->collected,
- (d->collected) * 100.0 / collected,
- (long)d->freed,
- (d->freed) * 100.0 / freed,
- (long)(d->allocated + d->overhead - d->freed - d->collected),
- (d->allocated + d->overhead - d->freed - d->collected) * 100.0
- / (allocated + overhead - freed - collected),
- (long)d->overhead,
- d->overhead * 100.0 / overhead,
- (long)d->times);
- }
- }
- fprintf (stderr, "%-48s %10ld %10ld %10ld %10ld %10ld\n",
- "Total", (long)collected, (long)freed,
- (long)(allocated + overhead - freed - collected), (long)overhead,
- (long)times);
- fprintf (stderr, "%-48s %10s %10s %10s %10s %10s\n",
- "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
- fprintf (stderr, "-------------------------------------------------------\n");
- ggc_force_collect = false;
+ delete ggc_mem_desc.m_reverse_object_map;
+ ggc_mem_desc.m_reverse_object_map = new map_t (13, false, false, false);
}