New memory allocation statistics infrastructure.

* Makefile.in: Add additional dependencies related to memory report
	enhancement.
	* alloc-pool.c (allocate_pool_descriptor): Use new ctor.
	* bitmap.c (struct bitmap_descriptor_d): Remove.
	(struct loc): Likewise.
	(struct bitmap_desc_hasher): Likewise.
	(bitmap_desc_hasher::hash): Likewise.
	(bitmap_desc_hasher::equal): Likewise.
	(get_bitmap_descriptor): Likewise.
	(bitmap_register): User new memory descriptor API.
	(register_overhead): Likewise.
	(bitmap_find_bit): Register nsearches and search_iter statistics.
	(struct bitmap_output_info): Remove.
	(print_statistics): Likewise.
	(dump_bitmap_statistics): Use new memory descriptor.
	* bitmap.h (struct bitmap_usage): New class.
	* genmatch.c: Extend header file inclusion.
	* genpreds.c: Likewise.
	* ggc-common.c (struct ggc_usage): New class.
	(struct ggc_loc_desc_hasher): Remove.
	(ggc_loc_desc_hasher::hash): Likewise.
	(ggc_loc_desc_hasher::equal): Likewise.
	(struct ggc_ptr_hash_entry): Likewise.
	(struct ptr_hash_hasher): Likewise.
	(ptr_hash_hasher::hash): Likewise.
	(ptr_hash_hasher::equal): Likewise.
	(make_loc_descriptor): Likewise.
	(ggc_prune_ptr): Likewise.
	(dump_ggc_loc_statistics): Use new memory descriptor.
	(ggc_record_overhead): Likewise.
	(ggc_free_overhead): Likewise.
	(final_cmp_statistic): Remove.
	(cmp_statistic): Likewise.
	(ggc_add_statistics): Liekwise.
	(ggc_prune_overhead_list): Likewise.
	* hash-map-traits.h: New file.
	* hash-map.h (struct default_hashmap_traits): Move the traits to a
	separate header file.
	* hash-set.h: Pass memory statistics info to ctor.
	* hash-table.c (void dump_hash_table_loc_statistics): New function.
	* hash-table.h (hash_table::hash_table): Add new ctor arguments.
	(hash_table::~hash_table): Register memory release operation.
	(hash_table::alloc_entries): Handle memory allocation operation.
	(hash_table::expand): Likewise.
	* inchash.c (iterative_hash_hashval_t): Move implementation to header
	file.
	(iterative_hash_host_wide_int): Likewise.
	* inchash.h (class hash): Likewise.
	* mem-stats-traits.h: New file.
	* mem-stats.h: New file.
	(mem_location): Add new class.
	(mem_usage): Likewise.
	(mem_alloc_description): Likewise.
	* sese.c: Add new header file inclusision.
	* toplev.c (dump_memory_report): Add report for hash_table, hash_map
	and hash_set.
	* tree-sra.c: Add new header file inclusision.
	* vec.c (struct vec_descriptor): Remove.
	(hash_descriptor): Likewise.
	(struct vec_usage): Likewise.
	(struct ptr_hash_entry): Likewise.
	(hash_ptr): Likewise.
	(eq_ptr): Likewise.
	(vec_prefix::register_overhead): Use new memory descriptor API.
	(vec_prefix::release_overhead): Likewise.
	(add_statistics): Remove.
	(dump_vec_loc_statistics): Use new memory descriptor API.
	* vec.h (struct vec_prefix): Likewise.
	(va_heap::reserve): Likewise.
	(va_heap::release): Likewise.
	* emit-rtl.c (gen_raw_REG): Fix passing MEM_STAT.

From-SVN: r223748
This commit is contained in:
Martin Liska 2015-05-27 14:47:22 +02:00 committed by Martin Liska
parent 151fbaac5c
commit 2d44c7dea7
23 changed files with 1225 additions and 746 deletions

View File

@ -1,3 +1,77 @@
2015-05-27 Martin Liska <mliska@suse.cz>
* Makefile.in: Add additional dependencies related to memory report
enhancement.
* alloc-pool.c (allocate_pool_descriptor): Use new ctor.
* bitmap.c (struct bitmap_descriptor_d): Remove.
(struct loc): Likewise.
(struct bitmap_desc_hasher): Likewise.
(bitmap_desc_hasher::hash): Likewise.
(bitmap_desc_hasher::equal): Likewise.
(get_bitmap_descriptor): Likewise.
(bitmap_register): User new memory descriptor API.
(register_overhead): Likewise.
(bitmap_find_bit): Register nsearches and search_iter statistics.
(struct bitmap_output_info): Remove.
(print_statistics): Likewise.
(dump_bitmap_statistics): Use new memory descriptor.
* bitmap.h (struct bitmap_usage): New class.
* genmatch.c: Extend header file inclusion.
* genpreds.c: Likewise.
* ggc-common.c (struct ggc_usage): New class.
(struct ggc_loc_desc_hasher): Remove.
(ggc_loc_desc_hasher::hash): Likewise.
(ggc_loc_desc_hasher::equal): Likewise.
(struct ggc_ptr_hash_entry): Likewise.
(struct ptr_hash_hasher): Likewise.
(ptr_hash_hasher::hash): Likewise.
(ptr_hash_hasher::equal): Likewise.
(make_loc_descriptor): Likewise.
(ggc_prune_ptr): Likewise.
(dump_ggc_loc_statistics): Use new memory descriptor.
(ggc_record_overhead): Likewise.
(ggc_free_overhead): Likewise.
(final_cmp_statistic): Remove.
(cmp_statistic): Likewise.
(ggc_add_statistics): Liekwise.
(ggc_prune_overhead_list): Likewise.
* hash-map-traits.h: New file.
* hash-map.h (struct default_hashmap_traits): Move the traits to a
separate header file.
* hash-set.h: Pass memory statistics info to ctor.
* hash-table.c (void dump_hash_table_loc_statistics): New function.
* hash-table.h (hash_table::hash_table): Add new ctor arguments.
(hash_table::~hash_table): Register memory release operation.
(hash_table::alloc_entries): Handle memory allocation operation.
(hash_table::expand): Likewise.
* inchash.c (iterative_hash_hashval_t): Move implementation to header
file.
(iterative_hash_host_wide_int): Likewise.
* inchash.h (class hash): Likewise.
* mem-stats-traits.h: New file.
* mem-stats.h: New file.
(mem_location): Add new class.
(mem_usage): Likewise.
(mem_alloc_description): Likewise.
* sese.c: Add new header file inclusision.
* toplev.c (dump_memory_report): Add report for hash_table, hash_map
and hash_set.
* tree-sra.c: Add new header file inclusision.
* vec.c (struct vec_descriptor): Remove.
(hash_descriptor): Likewise.
(struct vec_usage): Likewise.
(struct ptr_hash_entry): Likewise.
(hash_ptr): Likewise.
(eq_ptr): Likewise.
(vec_prefix::register_overhead): Use new memory descriptor API.
(vec_prefix::release_overhead): Likewise.
(add_statistics): Remove.
(dump_vec_loc_statistics): Use new memory descriptor API.
* vec.h (struct vec_prefix): Likewise.
(va_heap::reserve): Likewise.
(va_heap::release): Likewise.
* emit-rtl.c (gen_raw_REG): Fix passing MEM_STAT.
2015-05-27 Richard Biener <rguenther@suse.de>
* tree-vect-stmts.c (vectorizable_load): Initialize slp_perm

View File

@ -1028,7 +1028,7 @@ BUILD_LIBS = $(BUILD_LIBIBERTY)
BUILD_RTL = build/rtl.o build/read-rtl.o build/ggc-none.o \
build/vec.o build/min-insn-modes.o build/gensupport.o \
build/print-rtl.o
build/print-rtl.o build/hash-table.o
BUILD_MD = build/read-md.o
BUILD_ERRORS = build/errors.o
@ -1501,7 +1501,7 @@ OBJS = \
# Objects in libcommon.a, potentially used by all host binaries and with
# no target dependencies.
OBJS-libcommon = diagnostic.o diagnostic-color.o pretty-print.o intl.o \
vec.o input.o version.o
vec.o input.o version.o hash-table.o ggc-none.o
# Objects in libcommon-target.a, used by drivers and by the core
# compiler and containing target-dependent code.
@ -1937,7 +1937,7 @@ gcc-nm.c: gcc-ar.c
cp $^ $@
COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o vec.o ggc-none.o \
collect-utils.o file-find.o
collect-utils.o file-find.o hash-table.o
COLLECT2_LIBS = @COLLECT2_LIBS@
collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
# Don't try modifying collect2 (aka ld) in place--it might be linking this.
@ -2651,10 +2651,12 @@ s-iov: build/gcov-iov$(build_exeext) $(BASEVER) $(DEVPHASE)
GCOV_OBJS = gcov.o
gcov$(exeext): $(GCOV_OBJS) $(LIBDEPS)
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_OBJS) $(LIBS) -o $@
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_OBJS) \
build/hash-table.o ggc-none.o $(LIBS) -o $@
GCOV_DUMP_OBJS = gcov-dump.o
gcov-dump$(exeext): $(GCOV_DUMP_OBJS) $(LIBDEPS)
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_DUMP_OBJS) \
build/hash-table.o build/ggc-none.o\
$(LIBS) -o $@
GCOV_TOOL_DEP_FILES = $(srcdir)/../libgcc/libgcov-util.c gcov-io.c $(GCOV_IO_H) \

View File

@ -91,7 +91,9 @@ static struct alloc_pool_descriptor *
allocate_pool_descriptor (const char *name)
{
if (!alloc_pool_hash)
alloc_pool_hash = new hash_map<const char *, alloc_pool_descriptor> (10);
alloc_pool_hash = new hash_map<const char *, alloc_pool_descriptor> (10,
false,
false);
return &alloc_pool_hash->get_or_insert (name);
}

View File

@ -25,112 +25,26 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "hash-table.h"
#include "vec.h"
#include "inchash.h"
#include "mem-stats.h"
#include "hash-map.h"
/* Store information about each particular bitmap, per allocation site. */
struct bitmap_descriptor_d
{
int id;
const char *function;
const char *file;
int line;
int created;
uint64_t allocated;
uint64_t peak;
uint64_t current;
uint64_t nsearches;
uint64_t search_iter;
};
typedef struct bitmap_descriptor_d *bitmap_descriptor;
typedef const struct bitmap_descriptor_d *const_bitmap_descriptor;
/* Next available unique id number for bitmap desciptors. */
static int next_bitmap_desc_id = 0;
/* Vector mapping descriptor ids to descriptors. */
static vec<bitmap_descriptor> bitmap_descriptors;
/* Hashtable helpers. */
struct loc
{
const char *file;
const char *function;
int line;
};
struct bitmap_desc_hasher : typed_noop_remove <bitmap_descriptor_d>
{
typedef bitmap_descriptor_d *value_type;
typedef loc *compare_type;
static inline hashval_t hash (const bitmap_descriptor_d *);
static inline bool equal (const bitmap_descriptor_d *, const loc *);
};
inline hashval_t
bitmap_desc_hasher::hash (const bitmap_descriptor_d *d)
{
return htab_hash_pointer (d->file) + d->line;
}
inline bool
bitmap_desc_hasher::equal (const bitmap_descriptor_d *d, const loc *l)
{
return d->file == l->file && d->function == l->function && d->line == l->line;
}
/* Hashtable mapping bitmap names to descriptors. */
static hash_table<bitmap_desc_hasher> *bitmap_desc_hash;
/* For given file and line, return descriptor, create new if needed. */
static bitmap_descriptor
get_bitmap_descriptor (const char *file, int line, const char *function)
{
bitmap_descriptor_d **slot;
struct loc loc;
loc.file = file;
loc.function = function;
loc.line = line;
if (!bitmap_desc_hash)
bitmap_desc_hash = new hash_table<bitmap_desc_hasher> (10);
slot
= bitmap_desc_hash->find_slot_with_hash (&loc,
htab_hash_pointer (file) + line,
INSERT);
if (*slot)
return *slot;
*slot = XCNEW (struct bitmap_descriptor_d);
bitmap_descriptors.safe_push (*slot);
(*slot)->id = next_bitmap_desc_id++;
(*slot)->file = file;
(*slot)->function = function;
(*slot)->line = line;
return *slot;
}
/* Memory allocation statistics purpose instance. */
mem_alloc_description<bitmap_usage> bitmap_mem_desc;
/* Register new bitmap. */
void
bitmap_register (bitmap b MEM_STAT_DECL)
{
bitmap_descriptor desc = get_bitmap_descriptor (ALONE_FINAL_PASS_MEM_STAT);
desc->created++;
b->descriptor_id = desc->id;
bitmap_mem_desc.register_descriptor (b, BITMAP, false FINAL_PASS_MEM_STAT);
}
/* Account the overhead. */
static void
register_overhead (bitmap b, int amount)
{
bitmap_descriptor desc = bitmap_descriptors[b->descriptor_id];
desc->current += amount;
if (amount > 0)
desc->allocated += amount;
if (desc->peak < desc->current)
desc->peak = desc->current;
if (bitmap_mem_desc.contains_descriptor_for_instance (b))
bitmap_mem_desc.register_instance_overhead (amount, b);
}
/* Global data */
@ -579,10 +493,14 @@ bitmap_find_bit (bitmap head, unsigned int bit)
&& head->first->next == NULL)
return NULL;
/* Usage can be NULL due to allocated bitmaps for which we do not
call initialize function. */
bitmap_usage *usage = bitmap_mem_desc.get_descriptor_for_instance (head);
/* This bitmap has more than one element, and we're going to look
through the elements list. Count that as a search. */
if (GATHER_STATISTICS)
bitmap_descriptors[head->descriptor_id]->nsearches++;
if (GATHER_STATISTICS && usage)
usage->m_nsearches++;
if (head->indx < indx)
/* INDX is beyond head->indx. Search from head->current
@ -591,8 +509,8 @@ bitmap_find_bit (bitmap head, unsigned int bit)
element->next != 0 && element->indx < indx;
element = element->next)
{
if (GATHER_STATISTICS)
bitmap_descriptors[head->descriptor_id]->search_iter++;
if (GATHER_STATISTICS && usage)
usage->m_search_iter++;
}
else if (head->indx / 2 < indx)
@ -602,8 +520,8 @@ bitmap_find_bit (bitmap head, unsigned int bit)
element->prev != 0 && element->indx > indx;
element = element->prev)
{
if (GATHER_STATISTICS)
bitmap_descriptors[head->descriptor_id]->search_iter++;
if (GATHER_STATISTICS && usage)
usage->m_search_iter++;
}
else
@ -612,9 +530,9 @@ bitmap_find_bit (bitmap head, unsigned int bit)
for (element = head->first;
element->next != 0 && element->indx < indx;
element = element->next)
if (GATHER_STATISTICS)
if (GATHER_STATISTICS && usage)
{
bitmap_descriptors[head->descriptor_id]->search_iter++;
usage->m_search_iter++;
}
/* `element' is the nearest to the one we want. If it's not the one we
@ -2157,68 +2075,14 @@ bitmap_print (FILE *file, const_bitmap head, const char *prefix,
fputs (suffix, file);
}
/* Used to accumulate statistics about bitmap sizes. */
struct bitmap_output_info
{
uint64_t size;
uint64_t count;
};
/* Called via hash_table::traverse. Output bitmap descriptor pointed out by
SLOT and update statistics. */
int
print_statistics (bitmap_descriptor_d **slot, bitmap_output_info *i)
{
bitmap_descriptor d = *slot;
char s[4096];
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[41] = 0;
fprintf (stderr,
"%-41s %9u %15" PRId64" %15" PRId64" %15" PRId64
" %10" PRId64" %10" PRId64"\n",
s, d->created,
d->allocated, d->peak, d->current,
d->nsearches, d->search_iter);
i->size += d->allocated;
i->count += d->created;
}
return 1;
}
/* Output per-bitmap memory usage statistics. */
void
dump_bitmap_statistics (void)
{
struct bitmap_output_info info;
if (! GATHER_STATISTICS)
return;
if (!bitmap_desc_hash)
return;
fprintf (stderr,
"\n%-41s %9s %15s %15s %15s %10s %10s\n",
"Bitmap", "Overall",
"Allocated", "Peak", "Leak",
"searched", "search_itr");
fprintf (stderr, "---------------------------------------------------------------------------------\n");
info.count = 0;
info.size = 0;
bitmap_desc_hash->traverse <bitmap_output_info *, print_statistics> (&info);
fprintf (stderr, "---------------------------------------------------------------------------------\n");
fprintf (stderr,
"%-41s %9" PRId64" %15" PRId64"\n",
"Total", info.count, info.size);
fprintf (stderr, "---------------------------------------------------------------------------------\n");
bitmap_mem_desc.dump (BITMAP);
}
DEBUG_FUNCTION void

View File

@ -130,6 +130,62 @@ along with GCC; see the file COPYING3. If not see
#include "hashtab.h"
#include "statistics.h"
#include "obstack.h"
#include "mem-stats.h"
/* Bitmap memory usage. */
struct bitmap_usage: public mem_usage
{
/* Default contructor. */
bitmap_usage (): m_nsearches (0), m_search_iter (0) {}
/* Constructor. */
bitmap_usage (size_t allocated, size_t times, size_t peak,
uint64_t nsearches, uint64_t search_iter)
: mem_usage (allocated, times, peak),
m_nsearches (nsearches), m_search_iter (search_iter) {}
/* Sum the usage with SECOND usage. */
bitmap_usage operator+ (const bitmap_usage &second)
{
return bitmap_usage (m_allocated + second.m_allocated,
m_times + second.m_times,
m_peak + second.m_peak,
m_nsearches + second.m_nsearches,
m_search_iter + second.m_search_iter);
}
/* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
inline void dump (mem_location *loc, mem_usage &total) const
{
char s[4096];
sprintf (s, "%s:%i (%s)", loc->get_trimmed_filename (),
loc->m_line, loc->m_function);
s[48] = '\0';
fprintf (stderr, "%-48s %10li:%5.1f%%%10li%10li:%5.1f%%%12li%12li%10s\n", s,
(long)m_allocated, get_percent (m_allocated, total.m_allocated),
(long)m_peak, (long)m_times,
get_percent (m_times, total.m_times),
(long)m_nsearches, (long)m_search_iter,
loc->m_ggc ? "ggc" : "heap");
}
/* Dump header with NAME. */
static inline void dump_header (const char *name)
{
fprintf (stderr, "%-48s %11s%16s%17s%12s%12s%10s\n", name, "Leak", "Peak",
"Times", "N searches", "Search iter", "Type");
print_dash_line ();
}
/* Number search operations. */
uint64_t m_nsearches;
/* Number of search iterations. */
uint64_t m_search_iter;
};
/* Bitmap memory description. */
extern mem_alloc_description<bitmap_usage> bitmap_mem_desc;
/* Fundamental storage type for bitmap. */

View File

@ -454,7 +454,7 @@ set_mode_and_regno (rtx x, machine_mode mode, unsigned int regno)
rtx
gen_raw_REG (machine_mode mode, unsigned int regno)
{
rtx x = rtx_alloc_stat (REG PASS_MEM_STAT);
rtx x = rtx_alloc_stat (REG MEM_STAT_INFO);
set_mode_and_regno (x, mode, regno);
REG_ATTRS (x) = NULL;
ORIGINAL_REGNO (x) = regno;

View File

@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "errors.h"
#include "hashtab.h"
#include "hash-table.h"
#include "inchash.h"
#include "hash-map.h"
#include "hash-set.h"
#include "vec.h"

View File

@ -1492,6 +1492,7 @@ write_insn_preds_c (void)
#include \"rtl.h\"\n\
#include \"hash-set.h\"\n\
#include \"machmode.h\"\n\
#include \"hash-map.h\"\n\
#include \"vec.h\"\n\
#include \"double-int.h\"\n\
#include \"input.h\"\n\

View File

@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
#include "plugin.h"
#include "vec.h"
#include "timevar.h"
#include "mem-stats.h"
/* When set, ggc_collect will do collection. */
bool ggc_force_collect;
@ -830,138 +831,166 @@ init_ggc_heuristics (void)
#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) {}
/* Comparison 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
: m_peak < second.m_peak)
: get_balance () < second.get_balance ());
}
/* 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++;
}
/* Release overhead of SIZE bytes. */
inline void release_overhead (size_t size)
{
m_freed += 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);
}
/* Dump usage with PREFIX, where TOTAL is sum of all rows. */
inline void dump (const char *prefix, ggc_usage &total) const
{
long balance = get_balance ();
fprintf (stderr,
"%-48s %10li:%5.1f%%%10li:%5.1f%%"
"%10li:%5.1f%%%10li:%5.1f%%%10li\n",
prefix, (long)m_collected,
get_percent (m_collected, total.m_collected),
(long)m_freed, get_percent (m_freed, total.m_freed),
(long)balance, get_percent (balance, total.get_balance ()),
(long)m_overhead, get_percent (m_overhead, total.m_overhead),
(long)m_times);
}
/* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
inline void dump (mem_location *loc, ggc_usage &total) const
{
char s[4096];
sprintf (s, "%s:%i (%s)", loc->get_trimmed_filename (),
loc->m_line, loc->m_function);
s[48] = '\0';
dump (s, total);
}
/* Dump footer. */
inline void dump_footer ()
{
print_dash_line ();
dump ("Total", *this);
print_dash_line ();
}
/* Get balance which is GGC allocation leak. */
inline long 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 (*f.second) < (*s.second);
}
/* 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");
print_dash_line ();
}
/* Freed memory in bytes. */
size_t m_freed;
/* Collected memory in bytes. */
size_t m_collected;
/* Overhead memory in bytes. */
size_t m_overhead;
};
/* Hash table helper. */
/* GCC memory description. */
static mem_alloc_description<ggc_usage> ggc_mem_desc;
struct ggc_loc_desc_hasher : typed_noop_remove <ggc_loc_descriptor>
/* Dump per-site memory statistics. */
void
dump_ggc_loc_statistics (bool final)
{
typedef ggc_loc_descriptor *value_type;
typedef ggc_loc_descriptor *compare_type;
static inline hashval_t hash (const ggc_loc_descriptor *);
static inline bool equal (const ggc_loc_descriptor *,
const ggc_loc_descriptor *);
};
if (! GATHER_STATISTICS)
return;
inline hashval_t
ggc_loc_desc_hasher::hash (const ggc_loc_descriptor *d)
{
return htab_hash_pointer (d->function) | d->line;
}
ggc_force_collect = true;
ggc_collect ();
inline bool
ggc_loc_desc_hasher::equal (const ggc_loc_descriptor *d,
const ggc_loc_descriptor *d2)
{
return (d->file == d2->file && d->line == d2->line
&& d->function == d2->function);
}
ggc_mem_desc.dump (GGC, final ? ggc_usage::compare_final : NULL);
/* Hashtable used for statistics. */
static hash_table<ggc_loc_desc_hasher> *loc_hash;
struct ggc_ptr_hash_entry
{
void *ptr;
struct ggc_loc_descriptor *loc;
size_t size;
};
/* Helper for ptr_hash table. */
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 ggc_ptr_hash_entry *);
static inline bool equal (const ggc_ptr_hash_entry *, const void *);
};
inline hashval_t
ptr_hash_hasher::hash (const ggc_ptr_hash_entry *d)
{
return htab_hash_pointer (d->ptr);
}
inline bool
ptr_hash_hasher::equal (const ggc_ptr_hash_entry *p, const void *p2)
{
return (p->ptr == p2);
}
/* Hashtable converting address of allocated field to loc descriptor. */
static hash_table<ptr_hash_hasher> *ptr_hash;
/* 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;
ggc_force_collect = false;
}
/* 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)
ggc_record_overhead (size_t allocated, size_t overhead, void *ptr MEM_STAT_DECL)
{
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;
ggc_usage *usage = ggc_mem_desc.register_descriptor (ptr, GGC, false
FINAL_PASS_MEM_STAT);
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;
ggc_mem_desc.register_object_overhead (usage, allocated + overhead, ptr);
usage->register_overhead (allocated, overhead);
}
/* 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)
/* Notice that the pointer has been freed. */
void
ggc_free_overhead (void *ptr)
{
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_mem_desc.release_object_overhead (ptr);
}
/* After live values has been marked, walk all recorded pointers and see if
@ -969,134 +998,14 @@ ggc_prune_ptr (ggc_ptr_hash_entry **slot, void *b ATTRIBUTE_UNUSED)
void
ggc_prune_overhead_list (void)
{
ptr_hash->traverse <void *, ggc_prune_ptr> (NULL);
}
/* 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);
}
/* 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. */
void
dump_ggc_loc_statistics (bool final)
{
int nentries = 0;
char s[4096];
size_t collected = 0, freed = 0, allocated = 0, overhead = 0, times = 0;
int i;
if (! GATHER_STATISTICS)
return;
ggc_force_collect = true;
ggc_collect ();
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;
typedef hash_map<const void *, std::pair<ggc_usage *, size_t > > map_t;
map_t::iterator it = ggc_mem_desc.m_reverse_object_map->begin ();
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;
delete ggc_mem_desc.m_reverse_object_map;
ggc_mem_desc.m_reverse_object_map = new map_t (13, false, false);
}

104
gcc/hash-map-traits.h Normal file
View File

@ -0,0 +1,104 @@
/* A hash map traits.
Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef HASH_MAP_TRAITS_H
#define HASH_MAP_TRAITS_H
/* Bacause mem-stats.h uses default hashmap traits, we have to
put the class to this separate header file. */
/* implement default behavior for traits when types allow it. */
struct default_hashmap_traits
{
/* Hashes the passed in key. */
template<typename T>
static hashval_t
hash (T *p)
{
return uintptr_t (p) >> 3;
}
/* If the value converts to hashval_t just use it. */
template<typename T> static hashval_t hash (T v) { return v; }
/* Return true if the two keys passed as arguments are equal. */
template<typename T>
static bool
equal_keys (const T &a, const T &b)
{
return a == b;
}
/* Called to dispose of the key and value before marking the entry as
deleted. */
template<typename T> static void remove (T &v) { v.~T (); }
/* Mark the passed in entry as being deleted. */
template<typename T>
static void
mark_deleted (T &e)
{
mark_key_deleted (e.m_key);
}
/* Mark the passed in entry as being empty. */
template<typename T>
static void
mark_empty (T &e)
{
mark_key_empty (e.m_key);
}
/* Return true if the passed in entry is marked as deleted. */
template<typename T>
static bool
is_deleted (T &e)
{
return e.m_key == (void *)1;
}
/* Return true if the passed in entry is marked as empty. */
template<typename T> static bool is_empty (T &e) { return e.m_key == NULL; }
private:
template<typename T>
static void
mark_key_deleted (T *&k)
{
k = reinterpret_cast<T *> (1);
}
template<typename T>
static void
mark_key_empty (T *&k)
{
k = static_cast<T *> (0);
}
};
#endif // HASH_MAP_TRAITS_H

View File

@ -24,87 +24,12 @@ along with GCC; see the file COPYING3. If not see
#include <new>
#include <utility>
#include "hash-table.h"
/* implement default behavior for traits when types allow it. */
struct default_hashmap_traits
{
/* Hashes the passed in key. */
template<typename T>
static hashval_t
hash (T *p)
{
return uintptr_t(p) >> 3;
}
/* If the value converts to hashval_t just use it. */
template<typename T> static hashval_t hash (T v) { return v; }
/* Return true if the two keys passed as arguments are equal. */
template<typename T>
static bool
equal_keys (const T &a, const T &b)
{
return a == b;
}
/* Called to dispose of the key and value before marking the entry as
deleted. */
template<typename T> static void remove (T &v) { v.~T (); }
/* Mark the passed in entry as being deleted. */
template<typename T>
static void
mark_deleted (T &e)
{
mark_key_deleted (e.m_key);
}
/* Mark the passed in entry as being empty. */
template<typename T>
static void
mark_empty (T &e)
{
mark_key_empty (e.m_key);
}
/* Return true if the passed in entry is marked as deleted. */
template<typename T>
static bool
is_deleted (T &e)
{
return e.m_key == (void *)1;
}
/* Return true if the passed in entry is marked as empty. */
template<typename T> static bool is_empty (T &e) { return e.m_key == NULL; }
private:
template<typename T>
static void
mark_key_deleted (T *&k)
{
k = reinterpret_cast<T *> (1);
}
template<typename T>
static void
mark_key_empty (T *&k)
{
k = static_cast<T *> (0);
}
};
#include "hash-map-traits.h"
#include "mem-stats.h"
#include "vec.h"
template<typename Key, typename Value,
typename Traits = default_hashmap_traits>
typename Traits>
class GTY((user)) hash_map
{
struct hash_entry
@ -187,13 +112,16 @@ class GTY((user)) hash_map
};
public:
explicit hash_map (size_t n = 13, bool ggc = false) : m_table (n, ggc) {}
explicit hash_map (size_t n = 13, bool ggc = false,
bool gather_mem_stats = true CXX_MEM_STAT_INFO)
: m_table (n, ggc, gather_mem_stats, HASH_MAP PASS_MEM_STAT) {}
/* Create a hash_map in ggc memory. */
static hash_map *create_ggc (size_t size)
static hash_map *create_ggc (size_t size, bool gather_mem_stats = true
CXX_MEM_STAT_INFO)
{
hash_map *map = ggc_alloc<hash_map> ();
new (map) hash_map (size, true);
new (map) hash_map (size, true, gather_mem_stats PASS_MEM_STAT);
return map;
}

View File

@ -33,7 +33,7 @@ struct default_hashset_traits
static hashval_t
hash (T *p)
{
return uintptr_t(p) >> 3;
return uintptr_t (p) >> 3;
}
template<typename T> static hashval_t hash(const T &v) { return v; }
@ -180,7 +180,8 @@ class hash_set
};
public:
explicit hash_set (size_t n = 13, bool ggc = false) : m_table (n, ggc) {}
explicit hash_set (size_t n = 13, bool ggc = false CXX_MEM_STAT_INFO)
: m_table (n, ggc, true, HASH_SET PASS_MEM_STAT) {}
/* Create a hash_set in gc memory with space for at least n elements. */

View File

@ -31,7 +31,6 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "hash-table.h"
/* Table of primes and multiplicative inverses.
Note that these are not minimally reduced inverses. Unlike when generating
@ -99,3 +98,15 @@ hash_table_higher_prime_index (unsigned long n)
return low;
}
mem_alloc_description<mem_usage> hash_table_usage;
/* Support function for statistics. */
void dump_hash_table_loc_statistics (void)
{
for (unsigned i = HASH_TABLE; i <= HASH_SET; i++)
{
mem_alloc_origin origin = (mem_alloc_origin) i;
hash_table_usage.dump (origin);
}
}

View File

@ -199,6 +199,7 @@ along with GCC; see the file COPYING3. If not see
#include "ggc.h"
#include "hashtab.h"
#include <new>
#include "mem-stats-traits.h"
template<typename, typename, typename> class hash_map;
template<typename, typename> class hash_set;
@ -551,6 +552,8 @@ struct mark_empty_helper<Type *, Traits, false>
}
};
class mem_usage;
/* User-facing hash table type.
The table stores elements of type Descriptor::value_type.
@ -583,16 +586,18 @@ class hash_table
typedef typename Descriptor::compare_type compare_type;
public:
explicit hash_table (size_t, bool ggc = false CXX_MEM_STAT_INFO);
explicit hash_table (size_t, bool ggc = false, bool gather_mem_stats = true,
mem_alloc_origin origin = HASH_TABLE
CXX_MEM_STAT_INFO);
~hash_table ();
/* Create a hash_table in gc memory. */
static hash_table *
create_ggc (size_t n)
create_ggc (size_t n CXX_MEM_STAT_INFO)
{
hash_table *table = ggc_alloc<hash_table> ();
new (table) hash_table (n, true);
new (table) hash_table (n, true, true, HASH_TABLE PASS_MEM_STAT);
return table;
}
@ -759,19 +764,40 @@ private:
/* if m_entries is stored in ggc memory. */
bool m_ggc;
/* If we should gather memory statistics for the table. */
bool m_gather_mem_stats;
};
/* As mem-stats.h heavily utilizes hash maps (hash tables), we have to include
mem-stats.h after hash_table declaration. */
#include "mem-stats.h"
#include "hash-map.h"
#include "vec.h"
extern mem_alloc_description<mem_usage> hash_table_usage;
/* Support function for statistics. */
extern void dump_hash_table_loc_statistics (void);
template<typename Descriptor, template<typename Type> class Allocator>
hash_table<Descriptor, Allocator>::hash_table (size_t size, bool ggc
MEM_STAT_DECL) :
hash_table<Descriptor, Allocator>::hash_table (size_t size, bool ggc, bool
gather_mem_stats,
mem_alloc_origin origin
MEM_STAT_DECL) :
m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0),
m_ggc (ggc)
m_ggc (ggc), m_gather_mem_stats (gather_mem_stats)
{
unsigned int size_prime_index;
size_prime_index = hash_table_higher_prime_index (size);
size = prime_tab[size_prime_index].prime;
if (m_gather_mem_stats)
hash_table_usage.register_descriptor (this, origin, ggc
FINAL_PASS_MEM_STAT);
m_entries = alloc_entries (size PASS_MEM_STAT);
m_size = size;
m_size_prime_index = size_prime_index;
@ -788,6 +814,11 @@ hash_table<Descriptor, Allocator>::~hash_table ()
Allocator <value_type> ::data_free (m_entries);
else
ggc_free (m_entries);
if (m_gather_mem_stats)
hash_table_usage.release_instance_overhead (this,
sizeof (value_type) * m_size,
true);
}
/* This function returns an array of empty hash table elements. */
@ -798,6 +829,9 @@ hash_table<Descriptor, Allocator>::alloc_entries (size_t n MEM_STAT_DECL) const
{
value_type *nentries;
if (m_gather_mem_stats)
hash_table_usage.register_instance_overhead (sizeof (value_type) * n, this);
if (!m_ggc)
nentries = Allocator <value_type> ::data_alloc (n);
else
@ -881,6 +915,11 @@ hash_table<Descriptor, Allocator>::expand ()
}
value_type *nentries = alloc_entries (nsize);
if (m_gather_mem_stats)
hash_table_usage.release_instance_overhead (this, sizeof (value_type)
* osize);
m_entries = nentries;
m_size = nsize;
m_size_prime_index = nindex;

View File

@ -26,54 +26,3 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "hashtab.h"
#include "inchash.h"
/* Borrowed from hashtab.c iterative_hash implementation. */
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<< 8); \
c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \
a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \
b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
}
/* Produce good hash value combining VAL and VAL2. */
hashval_t
iterative_hash_hashval_t (hashval_t val, hashval_t val2)
{
/* the golden ratio; an arbitrary value. */
hashval_t a = 0x9e3779b9;
mix (a, val, val2);
return val2;
}
/* Produce good hash value combining VAL and VAL2. */
hashval_t
iterative_hash_host_wide_int (HOST_WIDE_INT val, hashval_t val2)
{
if (sizeof (HOST_WIDE_INT) == sizeof (hashval_t))
return iterative_hash_hashval_t (val, val2);
else
{
hashval_t a = (hashval_t) val;
/* Avoid warnings about shifting of more than the width of the type on
hosts that won't execute this path. */
int zero = 0;
hashval_t b = (hashval_t) (val >> (sizeof (hashval_t) * 8 + zero));
mix (a, b, val2);
if (sizeof (HOST_WIDE_INT) > 2 * sizeof (hashval_t))
{
hashval_t a = (hashval_t) (val >> (sizeof (hashval_t) * 16 + zero));
hashval_t b = (hashval_t) (val >> (sizeof (hashval_t) * 24 + zero));
mix (a, b, val2);
}
return val2;
}
}

View File

@ -36,8 +36,8 @@ along with GCC; see the file COPYING3. If not see
Currently it just implements the plain old jhash based
incremental hash from gcc's tree.c. */
extern hashval_t iterative_hash_host_wide_int (HOST_WIDE_INT, hashval_t);
extern hashval_t iterative_hash_hashval_t (hashval_t, hashval_t);
hashval_t iterative_hash_host_wide_int (HOST_WIDE_INT, hashval_t);
hashval_t iterative_hash_hashval_t (hashval_t, hashval_t);
namespace inchash
{
@ -72,7 +72,7 @@ class hash
}
/* Hash in pointer PTR. */
void add_ptr (void *ptr)
void add_ptr (const void *ptr)
{
add (&ptr, sizeof (ptr));
}
@ -121,13 +121,13 @@ class hash
{
if (a.end() > b.end())
{
merge (b);
merge (b);
merge (a);
}
else
{
merge (a);
merge (b);
merge (a);
merge (b);
}
}
@ -138,4 +138,57 @@ class hash
}
/* Borrowed from hashtab.c iterative_hash implementation. */
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<< 8); \
c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \
a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \
b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
}
/* Produce good hash value combining VAL and VAL2. */
inline
hashval_t
iterative_hash_hashval_t (hashval_t val, hashval_t val2)
{
/* the golden ratio; an arbitrary value. */
hashval_t a = 0x9e3779b9;
mix (a, val, val2);
return val2;
}
/* Produce good hash value combining VAL and VAL2. */
inline
hashval_t
iterative_hash_host_wide_int (HOST_WIDE_INT val, hashval_t val2)
{
if (sizeof (HOST_WIDE_INT) == sizeof (hashval_t))
return iterative_hash_hashval_t (val, val2);
else
{
hashval_t a = (hashval_t) val;
/* Avoid warnings about shifting of more than the width of the type on
hosts that won't execute this path. */
int zero = 0;
hashval_t b = (hashval_t) (val >> (sizeof (hashval_t) * 8 + zero));
mix (a, b, val2);
if (sizeof (HOST_WIDE_INT) > 2 * sizeof (hashval_t))
{
hashval_t a = (hashval_t) (val >> (sizeof (hashval_t) * 16 + zero));
hashval_t b = (hashval_t) (val >> (sizeof (hashval_t) * 24 + zero));
mix (a, b, val2);
}
return val2;
}
}
#endif

20
gcc/mem-stats-traits.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef GCC_MEM_STATS_TRAITS_H
#define GCC_MEM_STATS_TRAITS_H
/* Memory allocation origin. */
enum mem_alloc_origin
{
HASH_TABLE,
HASH_MAP,
HASH_SET,
VEC,
BITMAP,
GGC,
MEM_ALLOC_ORIGIN_LENGTH
};
/* Verbose names of the memory allocation origin. */
static const char * mem_alloc_origin_names[] = { "Hash tables", "Hash maps",
"Hash sets", "Heap vectors", "Bitmaps", "GGC memory" };
#endif // GCC_MEM_STATS_TRAITS_H

550
gcc/mem-stats.h Normal file
View File

@ -0,0 +1,550 @@
#ifndef GCC_MEM_STATS_H
#define GCC_MEM_STATS_H
#include "hash-map-traits.h"
#include "inchash.h"
#include "mem-stats-traits.h"
#include "vec.h"
/* Forward declaration. */
template<typename Key, typename Value,
typename Traits = default_hashmap_traits>
class hash_map;
/* Memory allocation location. */
struct mem_location
{
/* Default constructor. */
inline mem_location () {}
/* Constructor. */
inline mem_location (const char *filename, const char *function, int line,
mem_alloc_origin origin, bool ggc):
m_filename (filename), m_function (function), m_line (line), m_origin
(origin), m_ggc (ggc) {}
/* Compute hash value based on file name, function name and line in
source code. As there is just a single pointer registered for every
constant that points to e.g. the same file name, we can use hash
of the pointer. */
hashval_t hash ()
{
inchash::hash hash;
hash.add_ptr (m_filename);
hash.add_ptr (m_function);
hash.add_int (m_line);
return hash.end ();
}
/* Return true if the memory location is equal to OTHER. */
int equal (mem_location &other)
{
return m_filename == other.m_filename && m_function == other.m_function
&& m_line == other.m_line;
}
/* Return trimmed filename for the location. */
inline const char *get_trimmed_filename ()
{
const char *s1 = m_filename;
const char *s2;
while ((s2 = strstr (s1, "gcc/")))
s1 = s2 + 4;
return s1;
}
/* Return display name associated to ORIGIN type. */
static const char *get_origin_name (mem_alloc_origin origin)
{
return mem_alloc_origin_names[(unsigned) origin];
}
/* File name of source code. */
const char *m_filename;
/* Funcation name. */
const char *m_function;
/* Line number in source code. */
int m_line;
/* Origin type. */
mem_alloc_origin m_origin;
/* Flag if used by GGC allocation. */
bool m_ggc;
};
/* Memory usage register to a memory location. */
struct mem_usage
{
/* Default constructor. */
mem_usage (): m_allocated (0), m_times (0), m_peak (0) {}
/* Constructor. */
mem_usage (size_t allocated, size_t times, size_t peak):
m_allocated (allocated), m_times (times), m_peak (peak) {}
/* Register overhead of SIZE bytes. */
inline void register_overhead (size_t size)
{
m_allocated += size;
m_times++;
if (m_peak < m_allocated)
m_peak = m_allocated;
}
/* Release overhead of SIZE bytes. */
inline void release_overhead (size_t size)
{
gcc_assert (size <= m_allocated);
m_allocated -= size;
}
/* Sum the usage with SECOND usage. */
mem_usage operator+ (const mem_usage &second)
{
return mem_usage (m_allocated + second.m_allocated,
m_times + second.m_times,
m_peak + second.m_peak);
}
/* Comparison operator. */
inline bool operator< (const mem_usage &second) const
{
return (m_allocated == second.m_allocated ?
(m_peak == second.m_peak ? m_times < second.m_times
: m_peak < second.m_peak) : m_allocated < second.m_allocated);
}
/* Compare wrapper used by qsort method. */
static int compare (const void *first, const void *second)
{
typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
const mem_pair_t f = *(const mem_pair_t *)first;
const mem_pair_t s = *(const mem_pair_t *)second;
return (*f.second) < (*s.second);
}
/* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
inline void dump (mem_location *loc, mem_usage &total) const
{
char s[4096];
sprintf (s, "%s:%i (%s)", loc->get_trimmed_filename (),
loc->m_line, loc->m_function);
s[48] = '\0';
fprintf (stderr, "%-48s %10li:%5.1f%%%10li%10li:%5.1f%%%10s\n", s,
(long)m_allocated, get_percent (m_allocated, total.m_allocated),
(long)m_peak, (long)m_times,
get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
}
/* Dump footer. */
inline void dump_footer ()
{
print_dash_line ();
fprintf (stderr, "%s%54li%27li\n", "Total", (long)m_allocated,
(long)m_times);
print_dash_line ();
}
/* Return fraction of NOMINATOR and DENOMINATOR in percent. */
static inline float get_percent (size_t nominator, size_t denominator)
{
return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
}
/* Print line made of dashes. */
static inline void print_dash_line ()
{
fprintf (stderr, "%s\n", std::string (128, '-').c_str ());
}
/* Dump header with NAME. */
static inline void dump_header (const char *name)
{
fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
"Times", "Type");
print_dash_line ();
}
/* Current number of allocated bytes. */
size_t m_allocated;
/* Number of allocations. */
size_t m_times;
/* Peak allocation in bytes. */
size_t m_peak;
};
/* Memory usage pair that connectes memory usage and number
of allocated bytes. */
template <class T>
struct mem_usage_pair
{
mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
allocated (allocated_) {}
T *usage;
size_t allocated;
};
/* Memory allocation description. */
template <class T>
class mem_alloc_description
{
public:
struct mem_alloc_hashmap_traits: default_hashmap_traits
{
static hashval_t
hash (const mem_location *l)
{
inchash::hash hstate;
hstate.add_ptr ((const void *)l->m_filename);
hstate.add_ptr (l->m_function);
hstate.add_int (l->m_line);
return hstate.end ();
}
static bool
equal_keys (const mem_location *l1, const mem_location *l2)
{
return l1->m_filename == l2->m_filename
&& l1->m_function == l2->m_function
&& l1->m_line == l2->m_line;
}
};
/* Internal class type definitions. */
typedef hash_map <mem_location *, T *, mem_alloc_hashmap_traits> mem_map_t;
typedef hash_map <const void *, mem_usage_pair<T>, default_hashmap_traits>
reverse_mem_map_t;
typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
typedef std::pair <mem_location *, T *> mem_list_t;
/* Default contructor. */
mem_alloc_description ();
/* Default destructor. */
~mem_alloc_description ();
/* Returns true if instance PTR is registered by the memory description. */
bool contains_descriptor_for_instance (const void *ptr);
/* Return descriptor for instance PTR. */
T *get_descriptor_for_instance (const void *ptr);
/* Register memory allocation descriptor for container PTR. ORIGIN identifies
type of container and GGC identifes if the allocation is handled in GGC
memory. Each location is identified by file NAME, LINE in source code and
FUNCTION name. */
T *register_descriptor (const void *ptr, mem_alloc_origin origin,
bool ggc, const char *name, int line,
const char *function);
/* Register instance overhead identified by PTR pointer. Allocation takes
SIZE bytes. */
T *register_instance_overhead (size_t size, const void *ptr);
/* For containers (and GGC) where we want to track every instance object,
we register allocation of SIZE bytes, identified by PTR pointer, belonging
to USAGE descriptor. */
void register_object_overhead (T *usage, size_t size, const void *ptr);
/* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
remove the instance from reverse map. */
void release_instance_overhead (void *ptr, size_t size,
bool remove_from_map = false);
/* Release intance object identified by PTR pointer. */
void release_object_overhead (void *ptr);
/* Get sum value for ORIGIN type of allocation for the descriptor. */
T get_sum (mem_alloc_origin origin);
/* Get all tracked instances registered by the description. Items
are filtered by ORIGIN type, LENGTH is return value where we register
the number of elements in the list. If we want to process custom order,
CMP comparator can be provided. */
mem_list_t *get_list (mem_alloc_origin origin, unsigned *length,
int (*cmp) (const void *first, const void *second)
= NULL);
/* Dump all tracked instances of type ORIGIN. If we want to process custom
order, CMP comparator can be provided. */
void dump (mem_alloc_origin origin,
int (*cmp) (const void *first, const void *second) = NULL);
/* Reverse object map used for every object allocation mapping. */
reverse_object_map_t *m_reverse_object_map;
private:
/* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
in NAME source file, at LINE in source code, in FUNCTION. */
T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
int line, const char *function, const void *ptr);
/* Allocation location coupled to the description. */
mem_location m_location;
/* Location to usage mapping. */
mem_map_t *m_map;
/* Reverse pointer to usage mapping. */
reverse_mem_map_t *m_reverse_map;
};
#include "hash-map.h"
/* Returns true if instance PTR is registered by the memory description. */
template <class T>
inline bool
mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
{
return m_reverse_map->get (ptr);
}
/* Return descriptor for instance PTR. */
template <class T>
inline T*
mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
{
return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
}
/* Register memory allocation descriptor for container PTR. ORIGIN identifies
type of container and GGC identifes if the allocation is handled in GGC
memory. Each location is identified by file NAME, LINE in source code and
FUNCTION name. */
template <class T>
inline T*
mem_alloc_description<T>::register_descriptor (const void *ptr,
mem_alloc_origin origin,
bool ggc,
const char *filename,
int line,
const char *function)
{
mem_location *l = new mem_location (filename, function, line, origin, ggc);
T *usage = NULL;
T **slot = m_map->get (l);
if (slot)
{
delete l;
usage = *slot;
}
else
{
usage = new T ();
m_map->put (l, usage);
}
if (!m_reverse_map->get (ptr))
m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
return usage;
}
/* Register instance overhead identified by PTR pointer. Allocation takes
SIZE bytes. */
template <class T>
inline T*
mem_alloc_description<T>::register_instance_overhead (size_t size,
const void *ptr)
{
mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
if (!slot)
{
/* Due to PCH, it can really happen. */
return NULL;
}
T *usage = (*slot).usage;
usage->register_overhead (size);
return usage;
}
/* For containers (and GGC) where we want to track every instance object,
we register allocation of SIZE bytes, identified by PTR pointer, belonging
to USAGE descriptor. */
template <class T>
void
mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
const void *ptr)
{
/* In case of GGC, it is possible to have already occupied the memory
location. */
m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
}
/* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
in NAME source file, at LINE in source code, in FUNCTION. */
template <class T>
inline T*
mem_alloc_description<T>::register_overhead (size_t size,
mem_alloc_origin origin,
const char *filename,
int line,
const char *function,
const void *ptr)
{
T *usage = register_descriptor (ptr, origin, filename, line, function);
usage->register_overhead (size);
return usage;
}
/* Release PTR pointer of SIZE bytes. */
template <class T>
inline void
mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
bool remove_from_map)
{
mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
if (!slot)
{
/* Due to PCH, it can really happen. */
return;
}
mem_usage_pair<T> usage_pair = *slot;
usage_pair.usage->release_overhead (size);
if (remove_from_map)
m_reverse_map->remove (ptr);
}
/* Release intance object identified by PTR pointer. */
template <class T>
inline void
mem_alloc_description<T>::release_object_overhead (void *ptr)
{
std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
if (entry)
{
entry->first->release_overhead (entry->second);
m_reverse_object_map->remove (ptr);
}
}
/* Default contructor. */
template <class T>
inline
mem_alloc_description<T>::mem_alloc_description ()
{
m_map = new mem_map_t (13, false, false);
m_reverse_map = new reverse_mem_map_t (13, false, false);
m_reverse_object_map = new reverse_object_map_t (13, false, false);
}
/* Default destructor. */
template <class T>
inline
mem_alloc_description<T>::~mem_alloc_description ()
{
for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
++it)
{
delete (*it).first;
delete (*it).second;
}
delete m_map;
delete m_reverse_map;
delete m_reverse_object_map;
}
/* Get all tracked instances registered by the description. Items are filtered
by ORIGIN type, LENGTH is return value where we register the number of
elements in the list. If we want to process custom order, CMP comparator
can be provided. */
template <class T>
inline
typename mem_alloc_description<T>::mem_list_t *
mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
int (*cmp) (const void *first, const void *second))
{
/* vec data structure is not used because all vectors generate memory
allocation info a it would create a cycle. */
size_t element_size = sizeof (mem_list_t);
mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
unsigned i = 0;
for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
++it)
if ((*it).first->m_origin == origin)
list[i++] = std::pair<mem_location*, T*> (*it);
qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
*length = i;
return list;
}
/* Get sum value for ORIGIN type of allocation for the descriptor. */
template <class T>
inline T
mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
{
unsigned length;
mem_list_t *list = get_list (origin, &length);
T sum;
for (unsigned i = 0; i < length; i++)
sum = sum + *list[i].second;
XDELETEVEC (list);
return sum;
}
/* Dump all tracked instances of type ORIGIN. If we want to process custom
order, CMP comparator can be provided. */
template <class T>
inline void
mem_alloc_description<T>::dump (mem_alloc_origin origin,
int (*cmp) (const void *first,
const void *second))
{
unsigned length;
fprintf (stderr, "\n");
mem_list_t *list = get_list (origin, &length, cmp);
T total = get_sum (origin);
T::dump_header (mem_location::get_origin_name (origin));
for (int i = length - 1; i >= 0; i--)
list[i].second->dump (list[i].first, total);
total.dump_footer ();
XDELETEVEC (list);
fprintf (stderr, "\n");
}
#endif // GCC_MEM_STATS_H

View File

@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "mem-stats.h"
#include "hash-map.h"
#include "hash-set.h"
#include "machmode.h"

View File

@ -1963,6 +1963,7 @@ dump_memory_report (bool final)
dump_rtx_statistics ();
dump_alloc_pool_statistics ();
dump_bitmap_statistics ();
dump_hash_table_loc_statistics ();
dump_vec_loc_statistics ();
dump_ggc_loc_statistics (final);
dump_alias_stats (stderr);

View File

@ -74,6 +74,7 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "mem-stats.h"
#include "hash-map.h"
#include "hash-table.h"
#include "alloc-pool.h"

278
gcc/vec.c
View File

@ -33,6 +33,9 @@ along with GCC; see the file COPYING3. If not see
#include "vec.h"
#include "diagnostic-core.h"
#include "hashtab.h"
#include "mem-stats.h"
#include "hash-map.h"
#include "mem-stats.h"
/* vNULL is an empty type with a template cast operation that returns
a zero-initialized vec<T, A, L> instance. Use this when you want
@ -44,129 +47,110 @@ along with GCC; see the file COPYING3. If not see
they cannot have ctors/dtors. */
vnull vNULL;
/* Store information about each particular vector. */
struct vec_descriptor
/* Vector memory usage. */
struct vec_usage: public mem_usage
{
const char *function;
const char *file;
int line;
size_t allocated;
size_t times;
size_t peak;
/* Default constructor. */
vec_usage (): m_items (0), m_items_peak (0) {}
/* Constructor. */
vec_usage (size_t allocated, size_t times, size_t peak,
size_t items, size_t items_peak)
: mem_usage (allocated, times, peak),
m_items (items), m_items_peak (items_peak) {}
/* Comparison operator. */
inline bool operator< (const vec_usage &second) const
{
return (m_allocated == second.m_allocated ?
(m_peak == second.m_peak ? m_times < second.m_times
: m_peak < second.m_peak) : m_allocated < second.m_allocated);
}
/* Sum the usage with SECOND usage. */
vec_usage operator+ (const vec_usage &second)
{
return vec_usage (m_allocated + second.m_allocated,
m_times + second.m_times,
m_peak + second.m_peak,
m_items + second.m_items,
m_items_peak + second.m_items_peak);
}
/* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
inline void dump (mem_location *loc, mem_usage &total) const
{
char s[4096];
sprintf (s, "%s:%i (%s)", loc->get_trimmed_filename (),
loc->m_line, loc->m_function);
s[48] = '\0';
fprintf (stderr, "%-48s %10li:%4.1f%%%10li%10li:%4.1f%%%11li%11li\n", s,
(long)m_allocated, m_allocated * 100.0 / total.m_allocated,
(long)m_peak, (long)m_times, m_times * 100.0 / total.m_times,
(long)m_items, (long)m_items_peak);
}
/* Dump footer. */
inline void dump_footer ()
{
print_dash_line ();
fprintf (stderr, "%s%55li%25li%17li\n", "Total", (long)m_allocated,
(long)m_times, (long)m_items);
print_dash_line ();
}
/* Dump header with NAME. */
static inline void dump_header (const char *name)
{
fprintf (stderr, "%-48s %11s%15s%10s%17s%11s\n", name, "Leak", "Peak",
"Times", "Leak items", "Peak items");
print_dash_line ();
}
/* Compare wrapper used by qsort method. */
static int compare (const void *first, const void *second)
{
typedef std::pair<mem_location *, vec_usage *> mem_pair_t;
const mem_pair_t f = *(const mem_pair_t *)first;
const mem_pair_t s = *(const mem_pair_t *)second;
return (*f.second) < (*s.second);
}
/* Current number of items allocated. */
size_t m_items;
/* Peak value of number of allocated items. */
size_t m_items_peak;
};
/* Hashtable mapping vec addresses to descriptors. */
static htab_t vec_desc_hash;
/* Hashtable helpers. */
static hashval_t
hash_descriptor (const void *p)
{
const struct vec_descriptor *const d =
(const struct vec_descriptor *) p;
return htab_hash_pointer (d->file) + d->line;
}
static int
eq_descriptor (const void *p1, const void *p2)
{
const struct vec_descriptor *const d = (const struct vec_descriptor *) p1;
const struct vec_descriptor *const l = (const struct vec_descriptor *) p2;
return d->file == l->file && d->function == l->function && d->line == l->line;
}
/* Hashtable converting address of allocated field to loc descriptor. */
static htab_t ptr_hash;
struct ptr_hash_entry
{
void *ptr;
struct vec_descriptor *loc;
size_t allocated;
};
/* Hash table helpers functions. */
static hashval_t
hash_ptr (const void *p)
{
const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
return htab_hash_pointer (d->ptr);
}
static int
eq_ptr (const void *p1, const void *p2)
{
const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
return (p->ptr == p2);
}
/* Return descriptor for given call site, create new one if needed. */
static struct vec_descriptor *
vec_descriptor (const char *name, int line, const char *function)
{
struct vec_descriptor loc;
struct vec_descriptor **slot;
loc.file = name;
loc.line = line;
loc.function = function;
if (!vec_desc_hash)
vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc,
INSERT);
if (*slot)
return *slot;
*slot = XCNEW (struct vec_descriptor);
(*slot)->file = name;
(*slot)->line = line;
(*slot)->function = function;
(*slot)->allocated = 0;
(*slot)->peak = 0;
return *slot;
}
/* Vector memory description. */
static mem_alloc_description <vec_usage> vec_mem_desc;
/* Account the overhead. */
void
vec_prefix::register_overhead (size_t size, const char *name, int line,
const char *function)
vec_prefix::register_overhead (void *ptr, size_t size, size_t elements
MEM_STAT_DECL)
{
struct vec_descriptor *loc = vec_descriptor (name, line, function);
struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
PTR *slot;
p->ptr = this;
p->loc = loc;
p->allocated = size;
if (!ptr_hash)
ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
slot = htab_find_slot_with_hash (ptr_hash, this, htab_hash_pointer (this),
INSERT);
gcc_assert (!*slot);
*slot = p;
loc->allocated += size;
if (loc->peak < loc->allocated)
loc->peak += loc->allocated;
loc->times++;
vec_mem_desc.register_descriptor (ptr, VEC, false FINAL_PASS_MEM_STAT);
vec_usage *usage = vec_mem_desc.register_instance_overhead (size, ptr);
usage->m_items += elements;
if (usage->m_items_peak < usage->m_items)
usage->m_items_peak = usage->m_items;
}
/* Notice that the memory allocated for the vector has been freed. */
void
vec_prefix::release_overhead (void)
vec_prefix::release_overhead (void *ptr, size_t size, bool in_dtor
MEM_STAT_DECL)
{
PTR *slot = htab_find_slot_with_hash (ptr_hash, this,
htab_hash_pointer (this),
NO_INSERT);
struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
p->loc->allocated -= p->allocated;
htab_clear_slot (ptr_hash, slot);
::free (p);
if (!vec_mem_desc.contains_descriptor_for_instance (ptr))
vec_mem_desc.register_descriptor (ptr, VEC, false FINAL_PASS_MEM_STAT);
vec_mem_desc.release_instance_overhead (ptr, size, in_dtor);
}
@ -195,84 +179,10 @@ vec_prefix::calculate_allocation_1 (unsigned alloc, unsigned desired)
return alloc;
}
/* Helper for qsort; sort descriptors by amount of memory consumed. */
static int
cmp_statistic (const void *loc1, const void *loc2)
{
const struct vec_descriptor *const l1 =
*(const struct vec_descriptor *const *) loc1;
const struct vec_descriptor *const l2 =
*(const struct vec_descriptor *const *) loc2;
long diff;
diff = l1->allocated - l2->allocated;
if (!diff)
diff = l1->peak - l2->peak;
if (!diff)
diff = l1->times - l2->times;
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
}
/* Collect array of the descriptors from hashtable. */
static struct vec_descriptor **loc_array;
static int
add_statistics (void **slot, void *b)
{
int *n = (int *)b;
loc_array[*n] = (struct vec_descriptor *) *slot;
(*n)++;
return 1;
}
/* Dump per-site memory statistics. */
void
dump_vec_loc_statistics (void)
{
int nentries = 0;
char s[4096];
size_t allocated = 0;
size_t times = 0;
int i;
if (! GATHER_STATISTICS)
return;
loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements);
fprintf (stderr, "Heap vectors:\n");
fprintf (stderr, "\n%-48s %10s %10s %10s\n",
"source location", "Leak", "Peak", "Times");
fprintf (stderr, "-------------------------------------------------------\n");
htab_traverse (vec_desc_hash, add_statistics, &nentries);
qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
for (i = 0; i < nentries; i++)
{
struct vec_descriptor *d = loc_array[i];
allocated += d->allocated;
times += d->times;
}
for (i = 0; i < nentries; i++)
{
struct vec_descriptor *d = loc_array[i];
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 %10li:%4.1f%% \n", s,
(long)d->allocated,
(d->allocated) * 100.0 / allocated,
(long)d->peak,
(long)d->times,
(d->times) * 100.0 / times);
}
fprintf (stderr, "%-48s %10ld %10ld\n",
"Total", (long)allocated, (long)times);
fprintf (stderr, "\n%-48s %10s %10s %10s\n",
"source location", "Leak", "Peak", "Times");
fprintf (stderr, "-------------------------------------------------------\n");
vec_mem_desc.dump (VEC);
}

View File

@ -51,7 +51,7 @@ along with GCC; see the file COPYING3. If not see
extern void ggc_free (void *);
extern size_t ggc_round_alloc_size (size_t requested_size);
extern void *ggc_realloc (void *, size_t CXX_MEM_STAT_INFO);
extern void *ggc_realloc (void *, size_t MEM_STAT_DECL);
# endif // GCC_GGC_H
#endif // VEC_GC_ENABLED
@ -206,6 +206,8 @@ along with GCC; see the file COPYING3. If not see
/* Support function for statistics. */
extern void dump_vec_loc_statistics (void);
/* Hashtable mapping vec addresses to descriptors. */
extern htab_t vec_mem_usage_hash;
/* Control data for vectors. This contains the number of allocated
and used slots inside a vector. */
@ -216,8 +218,8 @@ struct vec_prefix
compilers that have stricter notions of PODness for types. */
/* Memory allocation support routines in vec.c. */
void register_overhead (size_t, const char *, int, const char *);
void release_overhead (void);
void register_overhead (void *, size_t, size_t CXX_MEM_STAT_INFO);
void release_overhead (void *, size_t, bool CXX_MEM_STAT_INFO);
static unsigned calculate_allocation (vec_prefix *, unsigned, bool);
static unsigned calculate_allocation_1 (unsigned, unsigned);
@ -303,7 +305,7 @@ va_heap::reserve (vec<T, va_heap, vl_embed> *&v, unsigned reserve, bool exact
gcc_checking_assert (alloc);
if (GATHER_STATISTICS && v)
v->m_vecpfx.release_overhead ();
v->m_vecpfx.release_overhead (v, v->allocated (), false);
size_t size = vec<T, va_heap, vl_embed>::embedded_size (alloc);
unsigned nelem = v ? v->length () : 0;
@ -311,7 +313,7 @@ va_heap::reserve (vec<T, va_heap, vl_embed> *&v, unsigned reserve, bool exact
v->embedded_init (alloc, nelem);
if (GATHER_STATISTICS)
v->m_vecpfx.register_overhead (size FINAL_PASS_MEM_STAT);
v->m_vecpfx.register_overhead (v, alloc, nelem PASS_MEM_STAT);
}
@ -325,7 +327,7 @@ va_heap::release (vec<T, va_heap, vl_embed> *&v)
return;
if (GATHER_STATISTICS)
v->m_vecpfx.release_overhead ();
v->m_vecpfx.release_overhead (v, v->allocated (), true);
::free (v);
v = NULL;
}