Hello list,

this is the second part of my patch. It collects and prints some memory statistics for hash tables that I've measured as the hottest ones. Tested together with previous patch on i386. Example output:


libcpp symtab string pool:
        identifiers     32644 (100.00%)
        entries         32644 (49.81%)
        deleted         0
        slots           65536
        string bytes    445k (4064  obstack_memory_used)
        table size      256k
        searches        234217
        collisions      86838
        coll/search     0.3708
        ins/search      0.1394
        avg. entry      13.97 bytes (+/- 6.42)
        longest entry   52
No gimple statistics

??? tree nodes created

(No per-node statistics)
DECL_DEBUG_EXPR  hash: size 1021, 23 elements, 0.000000 collisions
DECL_VALUE_EXPR  hash: size 1021, 0 elements, 0.000000 collisions

tree.c:type_hash_table stats
        slots           32749
        identifiers     5605
        entries         5605 (17.12%)
        deleted         0
        struct htab     60  B
        table size      127 kB
        element         8  B
        total contents  43 kB
        searches        27032
        collisions      9148
        coll/search     0.3384

emit-rtl.c:mem_attrs_htab hash table:
        slots           8191
        identifiers     2295
        entries         2295 (28.02%)
        deleted         0
        struct htab     60  B
        table size      31 kB
        element         24  B
        total contents  53 kB
        searches        7166
        collisions      3784
        coll/search     0.5280

cgraph.c:cgraph_hash hash table stats:
        slots           8191
        identifiers     198
        entries         3100 (37.85%)
        deleted         2902
        struct htab     60  B
        table size      31 kB
        element         160  B
        total contents  30 kB
        searches        103425
        collisions      32761
        coll/search     0.3168

var-tracking.c stats
        2363 vars->htab hash tables:
                total searches          483055
                total collisions        68621
                total coll/search       0.1421
        54 changed_variables hash tables
                total searches          33417
                total collisions        14253
                total coll/search       0.4265
        54 value_chains hash tables
                total searches          43924
                total collisions        14027
                total coll/search       0.3193

cselib stats for 614 hash tables
        total searches          52840
        total collisions        9597
        total coll/search       0.1816



Changelog:

2011-08-09  Dimitrios Apostolou  <ji...@gmx.net>

        * cgraph.c, cgraph.h (cgraph_dump_stats): New function to dump
        stats about cgraph_hash hash table.
        * cselib.c, cselib.h (cselib_dump_stats): New function to dump
        stats about cselib_hash_table.
        * cselib.c (cselib_finish): Keep statistics by increasing values
        of new global variables cselib_htab_{num,searches,collisions} if
        -fmem-report.
        * emit-rtl.c, emit-rtl.h (mem_attrs_dump_stats): New function to
        dump statistics about mem_attrs_htab hash table.
        * tree.c (print_type_hash_statistics): Used the new
        htab_dump_statistics() function.
        * var-tracking.c (shared_hash_destroy): Keep statistics by
        increasing values of new global variables
        vars_htab_{num,searches,collisions} if -fmem-report.
        (vt_finalize): Keep statistics by increasing values of new global
        variables cv_htab_{num,searches,collisions} and
        vc_htab_{num,searches,collisions} if -fmem-report.
        * var-tracking.c, rtl.h (vt_dump_stats): New function to dump
        stats about vars->htab, changed_variables and value_chains hash
        tables.
        * toplev.c: Included cselib.h for cselib_dump_stats().
        (dump_memory_report): Call all the above functions to provide
        better statistics.
        * hashtab.c, hashtab.h (htab_dump_statistics, htab_collisions_num)
        (htab_searches_num): New functions for statistics.
        * hashtab.c: Included assert.h for checks in htab_dump_statistics.
        * symtab.c (ht_dump_statistics): Beautified stats output.


Thanks,
Dimitris
=== modified file 'gcc/cgraph.c'
--- gcc/cgraph.c        2011-06-06 17:12:25 +0000
+++ gcc/cgraph.c        2011-08-09 01:01:19 +0000
@@ -2897,4 +2897,11 @@ cgraph_used_from_object_file_p (struct c
   return false;
 }
 
+void
+cgraph_dump_stats (void)
+{
+  fprintf (stderr, "\ncgraph.c:cgraph_hash hash table stats:\n");
+  htab_dump_statistics (cgraph_hash, sizeof (struct cgraph_node));
+}
+
 #include "gt-cgraph.h"

=== modified file 'gcc/cgraph.h'
--- gcc/cgraph.h        2011-05-31 14:58:49 +0000
+++ gcc/cgraph.h        2011-08-08 23:19:51 +0000
@@ -540,6 +540,7 @@ bool cgraph_can_remove_if_no_direct_call
 bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution 
resolution);
 bool cgraph_used_from_object_file_p (struct cgraph_node *node);
 bool varpool_used_from_object_file_p (struct varpool_node *node);
+void cgraph_dump_stats (void);
 
 /* In cgraphunit.c  */
 extern FILE *cgraph_dump_file;

=== modified file 'gcc/cselib.c'
--- gcc/cselib.c        2011-05-31 19:14:21 +0000
+++ gcc/cselib.c        2011-08-09 01:38:54 +0000
@@ -2518,6 +2518,10 @@ cselib_init (int record_what)
   next_uid = 1;
 }
 
+static unsigned int cselib_htab_num;
+static unsigned long cselib_htab_searches;
+static unsigned long cselib_htab_collisions;
+
 /* Called when the current user is done with cselib.  */
 
 void
@@ -2531,6 +2535,12 @@ cselib_finish (void)
   free_alloc_pool (elt_loc_list_pool);
   free_alloc_pool (cselib_val_pool);
   free_alloc_pool (value_pool);
+  if (mem_report)
+    {
+      cselib_htab_num++;
+      cselib_htab_searches += htab_searches_num (cselib_hash_table);
+      cselib_htab_collisions += htab_collisions_num (cselib_hash_table);
+    }
   cselib_clear_table ();
   htab_delete (cselib_hash_table);
   free (used_regs);
@@ -2630,4 +2640,17 @@ dump_cselib_table (FILE *out)
   fprintf (out, "next uid %i\n", next_uid);
 }
 
+void
+cselib_dump_stats (void)
+{
+  if (cselib_htab_num > 0)
+    {
+      fprintf (stderr, "\ncselib stats for %u hash tables\n", cselib_htab_num);
+      fprintf (stderr, "\ttotal searches\t\t%lu\n", cselib_htab_searches);
+      fprintf (stderr, "\ttotal collisions\t%lu\n", cselib_htab_collisions);
+      fprintf (stderr, "\ttotal coll/search\t%.4f\n",
+              (float) cselib_htab_collisions / cselib_htab_searches);
+    }
+}
+
 #include "gt-cselib.h"

=== modified file 'gcc/cselib.h'
--- gcc/cselib.h        2011-02-03 06:04:04 +0000
+++ gcc/cselib.h        2011-08-09 01:35:31 +0000
@@ -98,3 +98,4 @@ extern void cselib_preserve_only_values 
 extern void cselib_preserve_cfa_base_value (cselib_val *, unsigned int);
 
 extern void dump_cselib_table (FILE *);
+extern void cselib_dump_stats (void);

=== modified file 'gcc/emit-rtl.c'
--- gcc/emit-rtl.c      2011-05-29 17:40:05 +0000
+++ gcc/emit-rtl.c      2011-08-09 01:02:24 +0000
@@ -5425,6 +5425,13 @@ gen_rtx_CONST_VECTOR (enum machine_mode 
   return gen_rtx_raw_CONST_VECTOR (mode, v);
 }
 
+void
+mem_attrs_dump_stats (void)
+{
+  fprintf (stderr, "\nemit-rtl.c:mem_attrs_htab hash table:\n");
+  htab_dump_statistics (mem_attrs_htab, sizeof (mem_attrs));
+}
+
 /* Initialise global register information required by all functions.  */
 
 void

=== modified file 'gcc/emit-rtl.h'
--- gcc/emit-rtl.h      2011-01-03 20:52:22 +0000
+++ gcc/emit-rtl.h      2011-08-08 15:44:42 +0000
@@ -62,6 +62,7 @@ extern void set_reg_attrs_for_parm (rtx,
 extern void set_reg_attrs_for_decl_rtl (tree t, rtx x);
 extern void adjust_reg_mode (rtx, enum machine_mode);
 extern int mem_expr_equal_p (const_tree, const_tree);
+extern void mem_attrs_dump_stats (void);
 
 /* Return the first insn of the current sequence or current function.  */
 

=== modified file 'gcc/rtl.h'
--- gcc/rtl.h   2011-05-03 13:08:36 +0000
+++ gcc/rtl.h   2011-08-08 22:34:19 +0000
@@ -2527,6 +2527,7 @@ extern bool expensive_function_p (int);
 
 /* In var-tracking.c */
 extern unsigned int variable_tracking_main (void);
+extern void vt_dump_stats (void);
 
 /* In stor-layout.c.  */
 extern void get_mode_bounds (enum machine_mode, int, enum machine_mode,

=== modified file 'gcc/toplev.c'
--- gcc/toplev.c        2011-05-25 11:00:14 +0000
+++ gcc/toplev.c        2011-08-09 01:40:53 +0000
@@ -77,6 +77,7 @@ along with GCC; see the file COPYING3.  
 #include "gimple.h"
 #include "tree-ssa-alias.h"
 #include "plugin.h"
+#include "cselib.h"            /* only for cselib_dump_stats() */
 
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -1824,8 +1825,13 @@ dump_memory_report (bool final)
 {
   ggc_print_statistics ();
   stringpool_statistics ();
-  dump_tree_statistics ();
   dump_gimple_statistics ();
+  dump_tree_statistics ();
+  mem_attrs_dump_stats ();
+  cgraph_dump_stats ();
+  if (flag_var_tracking)
+    vt_dump_stats ();
+  cselib_dump_stats ();
   dump_rtx_statistics ();
   dump_alloc_pool_statistics ();
   dump_bitmap_statistics ();

=== modified file 'gcc/tree.c'
--- gcc/tree.c  2011-06-07 14:37:39 +0000
+++ gcc/tree.c  2011-08-09 01:04:09 +0000
@@ -6225,10 +6225,8 @@ type_hash_marked_p (const void *p)
 static void
 print_type_hash_statistics (void)
 {
-  fprintf (stderr, "Type hash: size %ld, %ld elements, %f collisions\n",
-          (long) htab_size (type_hash_table),
-          (long) htab_elements (type_hash_table),
-          htab_collisions (type_hash_table));
+  fprintf (stderr, "\ntree.c:type_hash_table stats\n");
+  htab_dump_statistics (type_hash_table, sizeof (struct type_hash));
 }
 
 /* Compute a hash code for a list of attributes (chain of TREE_LIST nodes
@@ -8564,10 +8562,10 @@ dump_tree_statistics (void)
 #else
   fprintf (stderr, "(No per-node statistics)\n");
 #endif
-  print_type_hash_statistics ();
   print_debug_expr_statistics ();
   print_value_expr_statistics ();
   lang_hooks.print_statistics ();
+  print_type_hash_statistics ();
 }
 
 #define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"

=== modified file 'gcc/var-tracking.c'
--- gcc/var-tracking.c  2011-06-03 01:42:31 +0000
+++ gcc/var-tracking.c  2011-08-09 01:34:31 +0000
@@ -1422,6 +1422,10 @@ shared_hash_copy (shared_hash vars)
   return vars;
 }
 
+static unsigned long vars_htab_searches;
+static unsigned long vars_htab_collisions;
+static unsigned int vars_htab_num;
+
 /* Decrement reference counter and destroy hash table if not shared
    anymore.  */
 
@@ -1431,6 +1435,12 @@ shared_hash_destroy (shared_hash vars)
   gcc_checking_assert (vars->refcount > 0);
   if (--vars->refcount == 0)
     {
+      if (mem_report)
+       {
+         vars_htab_num++;
+         vars_htab_searches += htab_searches_num (vars->htab);
+         vars_htab_collisions += htab_collisions_num (vars->htab);
+       }
       htab_delete (vars->htab);
       pool_free (shared_hash_pool, vars);
     }
@@ -8982,6 +8992,10 @@ vt_debug_insns_local (bool skipped ATTRI
   delete_debug_insns ();
 }
 
+static unsigned long cv_htab_searches, vc_htab_searches;
+static unsigned long cv_htab_collisions, vc_htab_collisions;
+static unsigned int cv_htab_num, vc_htab_num;
+
 /* Free the data structures needed for variable tracking.  */
 
 static void
@@ -9006,6 +9020,12 @@ vt_finalize (void)
     }
   free_aux_for_blocks ();
   htab_delete (empty_shared_hash->htab);
+  if (mem_report)
+    {
+      cv_htab_num++;
+      cv_htab_searches += htab_searches_num (changed_variables);
+      cv_htab_collisions += htab_collisions_num (changed_variables);
+    }
   htab_delete (changed_variables);
   free_alloc_pool (attrs_pool);
   free_alloc_pool (var_pool);
@@ -9014,6 +9034,12 @@ vt_finalize (void)
 
   if (MAY_HAVE_DEBUG_INSNS)
     {
+      if (mem_report)
+       {
+         vc_htab_num++;
+         vc_htab_searches += htab_searches_num (value_chains);
+         vc_htab_collisions += htab_collisions_num (value_chains);
+       }
       htab_delete (value_chains);
       free_alloc_pool (value_chain_pool);
       free_alloc_pool (valvar_pool);
@@ -9029,6 +9055,33 @@ vt_finalize (void)
   vui_allocated = 0;
 }
 
+void
+vt_dump_stats (void)
+{
+  fprintf (stderr, "\nvar-tracking.c stats\n");
+  
+  fprintf (stderr, "\t%u vars->htab hash tables:\n", vars_htab_num);
+  fprintf (stderr, "\t\ttotal searches\t\t%lu\n", vars_htab_searches);
+  fprintf (stderr, "\t\ttotal collisions\t%lu\n", vars_htab_collisions);
+  fprintf (stderr, "\t\ttotal coll/search\t%.4f\n",
+          (float) vars_htab_collisions / vars_htab_searches);
+
+  fprintf (stderr, "\t%u changed_variables hash tables\n", cv_htab_num);
+  fprintf (stderr, "\t\ttotal searches\t\t%lu\n", cv_htab_searches);
+  fprintf (stderr, "\t\ttotal collisions\t%lu\n", cv_htab_collisions);
+  fprintf (stderr, "\t\ttotal coll/search\t%.4f\n",
+          (float) cv_htab_collisions / cv_htab_searches);
+
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      fprintf (stderr, "\t%u value_chains hash tables\n", vc_htab_num);
+      fprintf (stderr, "\t\ttotal searches\t\t%lu\n", vc_htab_searches);
+      fprintf (stderr, "\t\ttotal collisions\t%lu\n", vc_htab_collisions);
+      fprintf (stderr, "\t\ttotal coll/search\t%.4f\n",
+              (float) vc_htab_collisions / vc_htab_searches);
+    }
+}
+
 /* The entry point to variable tracking pass.  */
 
 static inline unsigned int

=== modified file 'include/hashtab.h'
--- include/hashtab.h   2010-06-08 06:25:24 +0000
+++ include/hashtab.h   2011-08-06 22:04:26 +0000
@@ -187,6 +187,9 @@ extern void htab_traverse_noresize (htab
 extern size_t  htab_size (htab_t);
 extern size_t  htab_elements (htab_t);
 extern double  htab_collisions (htab_t);
+extern void     htab_dump_statistics (htab_t, size_t);
+extern unsigned int    htab_collisions_num (htab_t);
+extern unsigned int    htab_searches_num (htab_t);
 
 /* A hash function for pointers.  */
 extern htab_hash htab_hash_pointer;

=== modified file 'libcpp/symtab.c'
--- libcpp/symtab.c     2011-08-09 02:39:45 +0000
+++ libcpp/symtab.c     2011-08-09 03:24:09 +0000
@@ -276,7 +276,7 @@ ht_load (hash_table *ht, hashnode *entri
 void
 ht_dump_statistics (hash_table *table)
 {
-  size_t nelts, nids, overhead, headers;
+  size_t nelts, nids, obmem, overhead, headers;
   size_t total_bytes, longest, deleted = 0;
   double sum_of_squares, exp_len, exp_len2, exp2_len;
   hashnode *p, *limit;
@@ -307,34 +307,40 @@ ht_dump_statistics (hash_table *table)
   while (++p < limit);
 
   nelts = table->nelements;
-  overhead = obstack_memory_used (&table->stack) - total_bytes;
+  obmem= obstack_memory_used (&table->stack);
+  overhead = obmem - total_bytes;
   headers = table->nslots * sizeof (hashnode);
 
-  fprintf (stderr, "\nString pool\nentries\t\t%lu\n",
-          (unsigned long) nelts);
-  fprintf (stderr, "identifiers\t%lu (%.2f%%)\n",
+  fprintf (stderr, "\nlibcpp symtab string pool:\n");
+  fprintf (stderr, "\tidentifiers\t%lu (%.2f%%)\n",
           (unsigned long) nids, nids * 100.0 / nelts);
-  fprintf (stderr, "slots\t\t%lu\n",
-          (unsigned long) table->nslots);
-  fprintf (stderr, "deleted\t\t%lu\n",
+  fprintf (stderr, "\tentries\t\t%lu (%.2f%%)\n",
+          (unsigned long) nelts, nelts * 100.0 / table->nslots);
+  fprintf (stderr, "\tdeleted\t\t%lu\n",
           (unsigned long) deleted);
-  fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
+  fprintf (stderr, "\tslots\t\t%lu\n",
+          (unsigned long) table->nslots);
+  fprintf (stderr, "\tstring bytes\t%lu%c (%lu%c obstack_memory_used)\n",
           SCALE (total_bytes), LABEL (total_bytes),
-          SCALE (overhead), LABEL (overhead));
-  fprintf (stderr, "table size\t%lu%c\n",
+          SCALE (obmem), LABEL (obmem));
+  fprintf (stderr, "\ttable size\t%lu%c\n",
           SCALE (headers), LABEL (headers));
 
   exp_len = (double)total_bytes / (double)nelts;
   exp2_len = exp_len * exp_len;
   exp_len2 = (double) sum_of_squares / (double) nelts;
 
-  fprintf (stderr, "coll/search\t%.4f\n",
+  fprintf (stderr, "\tsearches\t%lu\n",
+          (unsigned long) table->searches);
+  fprintf (stderr, "\tcollisions\t%lu\n",
+          (unsigned long) table->collisions);
+  fprintf (stderr, "\tcoll/search\t%.4f\n",
           (double) table->collisions / (double) table->searches);
-  fprintf (stderr, "ins/search\t%.4f\n",
+  fprintf (stderr, "\tins/search\t%.4f\n",
           (double) nelts / (double) table->searches);
-  fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n",
+  fprintf (stderr, "\tavg. entry\t%.2f bytes (+/- %.2f)\n",
           exp_len, approx_sqrt (exp_len2 - exp2_len));
-  fprintf (stderr, "longest entry\t%lu\n",
+  fprintf (stderr, "\tlongest entry\t%lu\n",
           (unsigned long) longest);
 #undef SCALE
 #undef LABEL

=== modified file 'libiberty/hashtab.c'
--- libiberty/hashtab.c 2011-08-09 02:39:45 +0000
+++ libiberty/hashtab.c 2011-08-09 03:24:09 +0000
@@ -58,6 +58,7 @@ Boston, MA 02110-1301, USA.  */
 #endif
 
 #include <stdio.h>
+#include <assert.h>
 
 #include "libiberty.h"
 #include "ansidecl.h"
@@ -813,6 +814,90 @@ htab_collisions (htab_t htab)
   return (double) htab->collisions / (double) htab->searches;
 }
 
+/* Return the number of collisions */
+
+unsigned int
+htab_collisions_num (htab_t htab)
+{
+  return htab->collisions;
+}
+
+/* Return the number of searches */
+
+unsigned int
+htab_searches_num (htab_t htab)
+{
+  return htab->searches;
+}
+
+/* Dump allocation statistics to stderr. If elem_size > 0 display total memory
+ * usage of hash table too. */
+
+void
+htab_dump_statistics (htab_t table, size_t elem_size)
+{
+  size_t n_valid, headers, contents, empties, deleted;
+  void **p, **limit;
+
+#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
+                 ? (x) \
+                 : ((x) < 1024*1024*10 \
+                    ? (x) / 1024 \
+                    : (x) / (1024*1024))))
+#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
+
+  deleted = n_valid = empties = 0;
+  p = table->entries;
+  limit = p + table->size;
+  do
+    if (*p == HTAB_DELETED_ENTRY)
+      ++deleted;
+    else if (*p == HTAB_EMPTY_ENTRY)
+      ++empties;
+    else
+      ++n_valid;
+  while (++p < limit);
+
+  assert (deleted == table->n_deleted);
+  assert (empties == table->size - table->n_elements);
+  assert (n_valid + deleted == table->n_elements);
+
+  headers = table->size * sizeof (*(table->entries));
+  contents = n_valid * elem_size;
+
+  fprintf (stderr, "\tslots\t\t%lu\n",
+          (unsigned long) table->size);
+  fprintf (stderr, "\tidentifiers\t%lu\n",
+          (unsigned long) n_valid);
+  fprintf (stderr, "\tentries\t\t%lu (%.2f%%)\n",
+          (unsigned long) table->n_elements,
+          table->n_elements * 100.0 / table->size);
+  fprintf (stderr, "\tdeleted\t\t%lu\n",
+          (unsigned long) table->n_deleted);
+  fprintf (stderr, "\tstruct htab\t%u  B\n",
+          sizeof (*table));
+  fprintf (stderr, "\ttable size\t%lu %cB\n",
+          SCALE (headers), LABEL (headers));
+  if (elem_size > 0)
+    {
+      fprintf (stderr, "\telement\t\t%lu  B\n",
+              (unsigned long) elem_size);
+      fprintf (stderr, "\ttotal contents\t%lu %cB\n",
+              SCALE (contents), LABEL (contents));
+    }
+
+  fprintf (stderr, "\tsearches\t%lu\n",
+          (unsigned long) table->searches);
+  fprintf (stderr, "\tcollisions\t%lu\n",
+          (unsigned long) table->collisions);
+  fprintf (stderr, "\tcoll/search\t%.4f\n",
+          (double) table->collisions / (double) table->searches);
+
+#undef SCALE
+#undef LABEL
+}
+
+
 /* Hash P as a null-terminated string.
 
    Copied from gcc/hashtable.c.  Zack had the following to say with respect

Reply via email to