]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
New memory allocation statistics infrastructure.
authorMartin Liska <mliska@suse.cz>
Wed, 27 May 2015 12:47:22 +0000 (14:47 +0200)
committerMartin Liska <marxin@gcc.gnu.org>
Wed, 27 May 2015 12:47:22 +0000 (12:47 +0000)
* 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

23 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/alloc-pool.c
gcc/bitmap.c
gcc/bitmap.h
gcc/emit-rtl.c
gcc/genmatch.c
gcc/genpreds.c
gcc/ggc-common.c
gcc/hash-map-traits.h [new file with mode: 0644]
gcc/hash-map.h
gcc/hash-set.h
gcc/hash-table.c
gcc/hash-table.h
gcc/inchash.c
gcc/inchash.h
gcc/mem-stats-traits.h [new file with mode: 0644]
gcc/mem-stats.h [new file with mode: 0644]
gcc/sese.c
gcc/toplev.c
gcc/tree-sra.c
gcc/vec.c
gcc/vec.h

index ffde59c1584c3a288e0fe3e61d3394e4e2b53117..fa6ce5cd08b4941f1371dde94701704094f3db3e 100644 (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
index 45f210a7f3a3f77565f920d490a38923ff0413de..03c2ac6a62ee15102b8c6ea24d3bf940d1fdc85d 100644 (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) \
index 81909d8a247f45775f9b823a541f6010ce73eabb..e34acdb3500edfd623677dbffcae4fb8f0d5be13 100644 (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);
 }
index 58f443243a2068fc916a5092d4869e8793c8d11e..5fc46548beb93ec2580ff35e8604114f864f89a7 100644 (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
index 3f9bbf3271c4b81ea7b7d6b732c9c05a9c7e880e..40562f64c3493a4aa8dfa488955a063f72f026b2 100644 (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.  */
 
index 360f37d3793a84ed0e398c2e157def8c26678a59..49a15090fc163ec81d22eea5de7d40ad0b378b0a 100644 (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;
index 03947ba2fce3c1723ca4cdfd1c9aa3a91593648a..9dc3b8cf9521cfddfaae302c22c58df88abc6eb7 100644 (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"
index dd14e20449aeae58dad87a2e8e259f3cd3f92877..576be8647021d26062bcecdc6b67395687622dda 100644 (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\
index eff326a36c5b28f5ddf522ecc012bc63b3c2fb38..2e94ca4a6ef0d6742d9d09ecfea0df34314de36e 100644 (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,273 +831,181 @@ 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) {}
 
-/* Hash table helper.  */
+  /* 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 ());
+  }
 
-struct ggc_loc_desc_hasher : typed_noop_remove <ggc_loc_descriptor>
-{
-  typedef ggc_loc_descriptor *value_type;
-  typedef ggc_loc_descriptor *compare_type;
-  static inline hashval_t hash (const ggc_loc_descriptor *);
-  static inline bool equal (const ggc_loc_descriptor *,
-                           const ggc_loc_descriptor *);
-};
+  /* 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++;
+  }
 
-inline hashval_t
-ggc_loc_desc_hasher::hash (const ggc_loc_descriptor *d)
-{
-  return htab_hash_pointer (d->function) | d->line;
-}
+  /* Release overhead of SIZE bytes.  */
+  inline void release_overhead (size_t size)
+  {
+    m_freed += size;
+  }
 
-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);
-}
+  /* 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);
+  }
 
-/* Hashtable used for statistics.  */
-static hash_table<ggc_loc_desc_hasher> *loc_hash;
+  /* 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);
+  }
 
-struct ggc_ptr_hash_entry
-{
-  void *ptr;
-  struct ggc_loc_descriptor *loc;
-  size_t size;
-};
+  /* 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';
 
-/* Helper for ptr_hash table.  */
+    dump (s, total);
+  }
 
-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 *);
-};
+  /* Dump footer.  */
+  inline void dump_footer ()
+  {
+    print_dash_line ();
+    dump ("Total", *this);
+    print_dash_line ();
+  }
 
-inline hashval_t
-ptr_hash_hasher::hash (const ggc_ptr_hash_entry *d)
-{
-  return htab_hash_pointer (d->ptr);
-}
+  /* Get balance which is GGC allocation leak.  */
+  inline long get_balance () const
+  {
+    return m_allocated + m_overhead - m_collected - m_freed;
+  }
 
-inline bool
-ptr_hash_hasher::equal (const ggc_ptr_hash_entry *p, const void *p2)
-{
-  return (p->ptr == p2);
-}
+  typedef std::pair<mem_location *, ggc_usage *> mem_pair_t;
 
-/* Hashtable converting address of allocated field to loc descriptor.  */
-static hash_table<ptr_hash_hasher> *ptr_hash;
+  /* 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 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;
-}
+    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;
+};
+
+/* GCC memory description.  */
+static mem_alloc_description<ggc_usage> ggc_mem_desc;
+
+/* Dump per-site memory statistics.  */
 
-/* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION).  */
 void
-ggc_record_overhead (size_t allocated, size_t overhead, void *ptr,
-                    const char *name, int line, const char *function)
+dump_ggc_loc_statistics (bool final)
 {
-  struct ggc_loc_descriptor *loc = make_loc_descriptor (name, line, function);
-  struct ggc_ptr_hash_entry *p = XNEW (struct ggc_ptr_hash_entry);
-  ggc_ptr_hash_entry **slot;
-
-  p->ptr = ptr;
-  p->loc = loc;
-  p->size = allocated + overhead;
-  if (!ptr_hash)
-    ptr_hash = new hash_table<ptr_hash_hasher> (10);
-  slot = ptr_hash->find_slot_with_hash (ptr, htab_hash_pointer (ptr), INSERT);
-  gcc_assert (!*slot);
-  *slot = p;
-
-  loc->times++;
-  loc->allocated+=allocated;
-  loc->overhead+=overhead;
-}
+  if (! GATHER_STATISTICS)
+    return;
 
-/* Helper function for prune_overhead_list.  See if SLOT is still marked and
-   remove it from hashtable if it is not.  */
-int
-ggc_prune_ptr (ggc_ptr_hash_entry **slot, void *b ATTRIBUTE_UNUSED)
-{
-  struct ggc_ptr_hash_entry *p = *slot;
-  if (!ggc_marked_p (p->ptr))
-    {
-      p->loc->collected += p->size;
-      ptr_hash->clear_slot (slot);
-      free (p);
-    }
-  return 1;
+  ggc_force_collect = true;
+  ggc_collect ();
+
+  ggc_mem_desc.dump (GGC, final ? ggc_usage::compare_final : NULL);
+
+  ggc_force_collect = false;
 }
 
-/* After live values has been marked, walk all recorded pointers and see if
-   they are still live.  */
+/* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION).  */
 void
-ggc_prune_overhead_list (void)
+ggc_record_overhead (size_t allocated, size_t overhead, void *ptr MEM_STAT_DECL)
 {
-  ptr_hash->traverse <void *, ggc_prune_ptr> (NULL);
+  ggc_usage *usage = ggc_mem_desc.register_descriptor (ptr, GGC, false
+                                                      FINAL_PASS_MEM_STAT);
+
+  ggc_mem_desc.register_object_overhead (usage, allocated + overhead, ptr);
+  usage->register_overhead (allocated, overhead);
 }
 
 /* Notice that the pointer has been freed.  */
 void
 ggc_free_overhead (void *ptr)
 {
-  ggc_ptr_hash_entry **slot
-    = ptr_hash->find_slot_with_hash (ptr, htab_hash_pointer (ptr), NO_INSERT);
-  struct ggc_ptr_hash_entry *p;
-  /* The pointer might be not found if a PCH read happened between allocation
-     and ggc_free () call.  FIXME: account memory properly in the presence of
-     PCH. */
-  if (!slot)
-      return;
-  p = (struct ggc_ptr_hash_entry *) *slot;
-  p->loc->freed += p->size;
-  ptr_hash->clear_slot (slot);
-  free (p);
-}
-
-/* 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;
+  ggc_mem_desc.release_object_overhead (ptr);
 }
 
-/* Helper for qsort; sort descriptors by amount of memory consumed.  */
-static int
-cmp_statistic (const void *loc1, const void *loc2)
-{
-  const struct ggc_loc_descriptor *const l1 =
-    *(const struct ggc_loc_descriptor *const *) loc1;
-  const struct ggc_loc_descriptor *const l2 =
-    *(const struct ggc_loc_descriptor *const *) loc2;
-  long diff;
-
-  diff = ((long)(l1->allocated + l1->overhead - l1->freed - l1->collected) -
-         (l2->allocated + l2->overhead - l2->freed - l2->collected));
-  if (diff)
-    return diff > 0 ? 1 : diff < 0 ? -1 : 0;
-  diff =  ((long)(l1->allocated + l1->overhead - l1->freed) -
-          (l2->allocated + l2->overhead - l2->freed));
-  return diff > 0 ? 1 : diff < 0 ? -1 : 0;
-}
-
-/* Collect array of the descriptors from hashtable.  */
-static struct ggc_loc_descriptor **loc_array;
-int
-ggc_add_statistics (ggc_loc_descriptor **slot, int *n)
-{
-  loc_array[*n] = *slot;
-  (*n)++;
-  return 1;
-}
-
-/* Dump per-site memory statistics.  */
-
+/* After live values has been marked, walk all recorded pointers and see if
+   they are still live.  */
 void
-dump_ggc_loc_statistics (bool final)
+ggc_prune_overhead_list (void)
 {
-  int nentries = 0;
-  char s[4096];
-  size_t collected = 0, freed = 0, allocated = 0, overhead = 0, times = 0;
-  int i;
+  typedef hash_map<const void *, std::pair<ggc_usage *, size_t > > map_t;
 
-  if (! GATHER_STATISTICS)
-    return;
+  map_t::iterator it = ggc_mem_desc.m_reverse_object_map->begin ();
 
-  ggc_force_collect = true;
-  ggc_collect ();
+  for (; it != ggc_mem_desc.m_reverse_object_map->end (); ++it)
+    if (!ggc_marked_p ((*it).first))
+      (*it).second.first->m_collected += (*it).second.second;
 
-  loc_array = XCNEWVEC (struct ggc_loc_descriptor *,
-                       loc_hash->elements_with_deleted ());
-  fprintf (stderr, "-------------------------------------------------------\n");
-  fprintf (stderr, "\n%-48s %10s       %10s       %10s       %10s       %10s\n",
-          "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
-  fprintf (stderr, "-------------------------------------------------------\n");
-  loc_hash->traverse <int *, ggc_add_statistics> (&nentries);
-  qsort (loc_array, nentries, sizeof (*loc_array),
-        final ? final_cmp_statistic : cmp_statistic);
-  for (i = 0; i < nentries; i++)
-    {
-      struct ggc_loc_descriptor *d = loc_array[i];
-      allocated += d->allocated;
-      times += d->times;
-      freed += d->freed;
-      collected += d->collected;
-      overhead += d->overhead;
-    }
-  for (i = 0; i < nentries; i++)
-    {
-      struct ggc_loc_descriptor *d = loc_array[i];
-      if (d->allocated)
-       {
-         const char *s1 = d->file;
-         const char *s2;
-         while ((s2 = strstr (s1, "gcc/")))
-           s1 = s2 + 4;
-         sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
-         s[48] = 0;
-         fprintf (stderr, "%-48s %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li\n", s,
-                  (long)d->collected,
-                  (d->collected) * 100.0 / collected,
-                  (long)d->freed,
-                  (d->freed) * 100.0 / freed,
-                  (long)(d->allocated + d->overhead - d->freed - d->collected),
-                  (d->allocated + d->overhead - d->freed - d->collected) * 100.0
-                  / (allocated + overhead - freed - collected),
-                  (long)d->overhead,
-                  d->overhead * 100.0 / overhead,
-                  (long)d->times);
-       }
-    }
-  fprintf (stderr, "%-48s %10ld       %10ld       %10ld       %10ld       %10ld\n",
-          "Total", (long)collected, (long)freed,
-          (long)(allocated + overhead - freed - collected), (long)overhead,
-          (long)times);
-  fprintf (stderr, "%-48s %10s       %10s       %10s       %10s       %10s\n",
-          "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
-  fprintf (stderr, "-------------------------------------------------------\n");
-  ggc_force_collect = false;
+  delete ggc_mem_desc.m_reverse_object_map;
+  ggc_mem_desc.m_reverse_object_map = new map_t (13, false, false);
 }
diff --git a/gcc/hash-map-traits.h b/gcc/hash-map-traits.h
new file mode 100644 (file)
index 0000000..ce9c4a7
--- /dev/null
@@ -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
index 4cca702a0e2f768a938a69017bcf5821a993c4a6..fb1a522a25d6950b08be6ed45538feb1df83efc1 100644 (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;
     }
 
index 906545143a7ea3966d373d2910a6eb95a7171d9f..b4db21acedb4e994115b9f7f640580633e350d8c 100644 (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.  */
 
index 3127e9c839432ad43b381548b404aebd638d9bc2..012b241906de7598ac61105acd8994c913702619 100644 (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);
+    }
+}
+
index f6375d1ec71e554dcf45e51bc8a629a8074886dd..74c3722bbf3d5f71355a1f09f62953d86c4fd6ce 100644 (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;
index c555046dd3a874248c658f124e4b842653dc76e2..90c62e828671e1e67e70bf30a7af2dde024f025c 100644 (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;
-    }
-}
index 54fb0d853b2e0afd7ad944763d5f73091cf25afa..4bb1272c1a9eea78c7fdbc925b23e2e98b62d1c6 100644 (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
diff --git a/gcc/mem-stats-traits.h b/gcc/mem-stats-traits.h
new file mode 100644 (file)
index 0000000..de1614e
--- /dev/null
@@ -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
diff --git a/gcc/mem-stats.h b/gcc/mem-stats.h
new file mode 100644 (file)
index 0000000..ac47231
--- /dev/null
@@ -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
index fb5b6365b026d79405946bd8c97e3a6605ec0767..c274547c85a5d87b68558034a743c40162f2cb22 100644 (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"
index 18a725a779f8abad1b69becd5eea7c0674105aa7..3b57b482c3d93024ea8d8e4289a1f51dbdab7ac2 100644 (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);
index 4b0d2a8b389492d2009e3f4fd643dba1d3330e35..d799751da30796e24a1f2079eb0b74c84ac8aea5 100644 (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"
index 06b887b44773f05d2aaf616e17ea5c9289d11183..d4a7a0229beaca1fd5d3958c2759f86450a4e0de 100644 (file)
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -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);
 }
index aa9a255bf97687a8c251e7197a858336269cfa9f..7b9697922ad6ebec924804c4c125e3b46677299e 100644 (file)
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -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;
 }