Commit 2d44c7de by Martin Liska Committed by Martin Liska

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
parent 151fbaac
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
......
......@@ -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) \
......
......@@ -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);
}
......
......@@ -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
......
......@@ -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. */
......
......@@ -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;
......
......@@ -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"
......
......@@ -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\
......
/* 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
......@@ -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;
}
......
......@@ -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. */
......
......@@ -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);
}
}
......@@ -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;
......
......@@ -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;
}
}
......@@ -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
#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
This diff is collapsed. Click to expand it.
......@@ -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"
......
......@@ -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);
......
......@@ -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"
......
......@@ -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
{
const char *function;
const char *file;
int line;
size_t allocated;
size_t times;
size_t 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)
/* Vector memory usage. */
struct vec_usage: public mem_usage
{
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;
/* 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;
};
/* 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);
}
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment