This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][RFC] Statistics "infrastructure"


This is an attempt to provide (pass) statistics collection.  The
goal is to provide infrastructure to handle the current (pass specific)
statistics dumping that is done per function and per pass along the
regular tree/rtl dumps as well as to allow CU wide "fancy" analysis.

The most important aspect I think is simplicity to use it and especially
add new "counters".  Thus, we simply associate a counter with a string ID.

The patch is a rough implementation of the current features of
pass specific statistics plus a global "log" with statistics events.
In the end you can do any postprocessing / globbing / summing of
such global log.

A statistics event consists of a function (optional), a statement
(optional) and the counter ID.  I converted the counters from
tree-ssa-propagate.c as an example, instead of

		prop_stats.num_copy_prop++;

you now write

		statistics_add ("copy propagations");

(function and statement omitted, you might prefer #defines for strings
that you use multiple times).  In the .ccp1 dump file you then get

Pass statistics:
----------------
constant propagations: 15
copy propagations: 5

in stead of previously

Constants propagated:      15
Copies propagated:         5
Predicates folded:         0

and the 208t.statistics file will for example contain

33      ccp     "constant propagations" "sin_pif"       "(nostmt)"
33      ccp     "constant propagations" "sin_pif"       "(nostmt)"
38      copyprop        "copy propagations"     "sin_pif"       "(nostmt)"
38      copyprop        "copy propagations"     "sin_pif"       "(nostmt)"
38      copyprop        "copy propagations"     "sin_pif"       "(nostmt)"
38      copyprop        "copy propagations"     "sin_pif"       "(nostmt)"
38      copyprop        "copy propagations"     "sin_pif"       "(nostmt)"
33      ccp     "constant propagations" "__ieee754_lgammaf_r"   "(nostmt)"
33      ccp     "constant propagations" "__ieee754_lgammaf_r"   "(nostmt)"
33      ccp     "constant propagations" "__ieee754_lgammaf_r"   "(nostmt)"
...

(pass number, pass name, ID, function name, statement location 
(unimplemented)).

The backend implementation is of course not limited to be that simple,
but it is the interface that I am curious if it provides enough
information.

(please trim CC, use gcc@ for general discussion, gcc-patches@ for
implementation details of this hac^H^H^Hpatch)

Thanks,
Richard.

2008-03-15  Richard Guenther  <rguenther@suse.de>

	* tree-pass.h (statistics_add_fn_stmt): Declare.
	(statistics_add_stmt): New macro.
	(statistics_add): Likewise.
	* passes.c (statistics_dump_nr, statistics_dump_file): New globals.
	(init_optimization_passes): Register statistics dump.
	(execute_function_todo): Flush per function statistics.
	(execute_pass_list): Start statistics dump.
	(execute_ipa_pass_list): Likewise.
	(struct statistics_counter_s): New structure.
	(statistics_fini_pass): New function.
	(statistics_add_fn_stmt): Likewise.

	* tree-ssa-propagate.c: Use statistics infrastructure.

Index: trunk/gcc/passes.c
===================================================================
*** trunk.orig/gcc/passes.c	2008-03-15 17:26:59.000000000 +0100
--- trunk/gcc/passes.c	2008-03-15 19:09:30.000000000 +0100
*************** along with GCC; see the file COPYING3.  
*** 102,107 ****
--- 102,111 ----
  				   declarations for e.g. AIX 4.x.  */
  #endif
  
+ static void statistics_fini_pass (void);
+ static int statistics_dump_nr;
+ static FILE *statistics_dump_file;
+ 
  /* This is used for debugging.  It allows the current pass to printed
     from anywhere in compilation.  */
  struct tree_opt_pass *current_pass;
*************** init_optimization_passes (void)
*** 797,802 ****
--- 801,808 ----
    register_dump_files (all_passes, false,
  		       PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
  		       | PROP_cfg);
+   statistics_dump_nr = dump_register (".statistics", "statistics",
+ 				      "statistics", TDF_TREE, 0);
  }
  
  /* If we are in IPA mode (i.e., current_function_decl is NULL), call
*************** execute_function_todo (void *data)
*** 883,889 ****
    flags &= ~cfun->last_verified;
    if (!flags)
      return;
!   
    /* Always cleanup the CFG before trying to update SSA.  */
    if (flags & TODO_cleanup_cfg)
      {
--- 889,897 ----
    flags &= ~cfun->last_verified;
    if (!flags)
      return;
! 
!   statistics_fini_pass ();
! 
    /* Always cleanup the CFG before trying to update SSA.  */
    if (flags & TODO_cleanup_cfg)
      {
*************** execute_one_pass (struct tree_opt_pass *
*** 1171,1176 ****
--- 1179,1186 ----
  void
  execute_pass_list (struct tree_opt_pass *pass)
  {
+   if (statistics_dump_file == NULL)
+     statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
    do
      {
        if (execute_one_pass (pass) && pass->sub)
*************** execute_pass_list (struct tree_opt_pass 
*** 1185,1190 ****
--- 1195,1202 ----
  void
  execute_ipa_pass_list (struct tree_opt_pass *pass)
  {
+   if (statistics_dump_file == NULL)
+     statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
    do
      {
        gcc_assert (!current_function_decl);
*************** execute_ipa_pass_list (struct tree_opt_p
*** 1198,1201 ****
--- 1210,1311 ----
      }
    while (pass);
  }
+ 
+ /* Statistics entry.  A integer counter associated to a string ID.  */
+ 
+ typedef struct statistics_counter_s {
+   const char *id;
+   int count;
+ } statistics_counter_t;
+ 
+ static htab_t statistics_hash;
+ 
+ /* Hash a statistic counter by its string ID.  */
+ 
+ static hashval_t
+ hash_statistics_hash (const void *p)
+ {
+   return htab_hash_string (((statistics_counter_t *)p)->id);
+ }
+ 
+ /* Compare two statistic counters by their string IDs.  */
+ 
+ static int
+ hash_statistics_eq (const void *p, const void *q)
+ {
+   return !strcmp (((statistics_counter_t *)p)->id,
+ 		  ((statistics_counter_t *)q)->id);
+ }
+ 
+ /* Helper for statistics_fini_pass.  */
+ 
+ static int
+ statistics_fini_pass_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+ {
+   statistics_counter_t *counter = (statistics_counter_t *)*slot;
+   fprintf (dump_file, "%s: %d\n", counter->id, counter->count);
+   return 1;
+ }
+ 
+ /* Dump the current statistics state to the current pass dump file and
+    clear the statistics state.  */
+ 
+ static void
+ statistics_fini_pass (void)
+ {
+   if (!dump_file
+       || !(dump_flags & TDF_STATS)
+       || htab_elements (statistics_hash) == 0)
+     return;
+ 
+   fprintf (dump_file, "\n");
+   fprintf (dump_file, "Pass statistics:\n");
+   fprintf (dump_file, "----------------\n");
+   htab_traverse_noresize (statistics_hash, statistics_fini_pass_1, NULL);
+   fprintf (dump_file, "\n");
+ 
+   htab_empty (statistics_hash);
+ }
+ 
+ /* Add statistics information about event ID in function FN at statement
+    STMT.  This will increment a counter associated with ID.  It will also
+    dump the event to the global statistics file if requested.  */
+ 
+ void
+ statistics_add_fn_stmt (struct function *fn, tree stmt ATTRIBUTE_UNUSED,
+ 			const char *id)
+ {
+   static char statistics_print_buf[4096];
+ 
+   if (dump_flags & TDF_STATS)
+     {
+       statistics_counter_t **counter;
+       if (!statistics_hash)
+ 	statistics_hash = htab_create (15, hash_statistics_hash,
+ 				       hash_statistics_eq, free);
+       counter = (statistics_counter_t **)
+ 	htab_find_slot (statistics_hash, &id, INSERT);
+       if (!*counter)
+ 	{
+ 	  *counter = XNEW (struct statistics_counter_s);
+ 	  (*counter)->id = id;
+ 	  (*counter)->count = 0;
+ 	}
+       (*counter)->count++;
+     }
+ 
+   if (!statistics_dump_file)
+     return;
+ 
+   snprintf (statistics_print_buf, 4096,
+ 	    "%d\t%s\t\"%s\"\t\"%s\"\t\"%s\"\n",
+ 	    current_pass->static_pass_number,
+ 	    current_pass->name,
+ 	    id,
+ 	    fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)",
+ 	    "(nostmt)" /* FIXME */);
+ 
+   fputs (statistics_print_buf, statistics_dump_file);
+   fflush (statistics_dump_file);
+ }
  #include "gt-passes.h"
Index: trunk/gcc/tree-pass.h
===================================================================
*** trunk.orig/gcc/tree-pass.h	2008-03-15 17:22:27.000000000 +0100
--- trunk/gcc/tree-pass.h	2008-03-15 18:07:00.000000000 +0100
*************** extern void debug_pass (void);
*** 468,471 ****
--- 468,477 ----
     directly in jump threading, and avoid peeling them next time.  */
  extern bool first_pass_instance;
  
+ extern void statistics_add_fn_stmt (struct function *, tree, const char *);
+ #define statistics_add_stmt(stmt, id) \
+   do { statistics_add_fn_stmt (cfun, (stmt), (id)); } while (0)
+ #define statistics_add(id) \
+   do { statistics_add_fn_stmt (cfun, NULL_TREE, (id)); } while (0)
+ 
  #endif /* GCC_TREE_PASS_H */
Index: trunk/gcc/tree-ssa-propagate.c
===================================================================
*** trunk.orig/gcc/tree-ssa-propagate.c	2008-03-15 18:03:22.000000000 +0100
--- trunk/gcc/tree-ssa-propagate.c	2008-03-15 18:08:18.000000000 +0100
*************** replace_uses_in (tree stmt, bool *replac
*** 923,931 ****
  	continue;
  
        if (TREE_CODE (val) != SSA_NAME)
! 	prop_stats.num_const_prop++;
        else
! 	prop_stats.num_copy_prop++;
  
        propagate_value (use, val);
  
--- 923,931 ----
  	continue;
  
        if (TREE_CODE (val) != SSA_NAME)
! 	statistics_add ("constant propagations");
        else
! 	statistics_add ("copy propagations");
  
        propagate_value (use, val);
  
*************** replace_vuses_in (tree stmt, bool *repla
*** 1038,1046 ****
  	  GIMPLE_STMT_OPERAND (stmt, 1) = val->value;
  
  	  if (TREE_CODE (val->value) != SSA_NAME)
! 	    prop_stats.num_const_prop++;
  	  else
! 	    prop_stats.num_copy_prop++;
  
  	  /* Since we have replaced the whole RHS of STMT, there
  	     is no point in checking the other VUSEs, as they will
--- 1038,1046 ----
  	  GIMPLE_STMT_OPERAND (stmt, 1) = val->value;
  
  	  if (TREE_CODE (val->value) != SSA_NAME)
! 	    statistics_add ("constant propagations");
  	  else
! 	    statistics_add ("copy propagations");
  
  	  /* Since we have replaced the whole RHS of STMT, there
  	     is no point in checking the other VUSEs, as they will
*************** replace_vuses_in (tree stmt, bool *repla
*** 1066,1072 ****
  	continue;
  
        propagate_value (vuse, val);
!       prop_stats.num_copy_prop++;
        replaced = true;
      }
  
--- 1066,1072 ----
  	continue;
  
        propagate_value (vuse, val);
!       statistics_add ("copy propagations");
        replaced = true;
      }
  
*************** replace_phi_args_in (tree phi, prop_valu
*** 1098,1106 ****
  	  if (val && val != arg && may_propagate_copy (arg, val))
  	    {
  	      if (TREE_CODE (val) != SSA_NAME)
! 		prop_stats.num_const_prop++;
  	      else
! 		prop_stats.num_copy_prop++;
  
  	      propagate_value (PHI_ARG_DEF_PTR (phi, i), val);
  	      replaced = true;
--- 1098,1106 ----
  	  if (val && val != arg && may_propagate_copy (arg, val))
  	    {
  	      if (TREE_CODE (val) != SSA_NAME)
! 		statistics_add ("constant propagations");
  	      else
! 		statistics_add ("copy propagations");
  
  	      propagate_value (PHI_ARG_DEF_PTR (phi, i), val);
  	      replaced = true;
*************** fold_predicate_in (tree stmt)
*** 1163,1169 ****
  	  fprintf (dump_file, "\n");
  	}
  
!       prop_stats.num_pred_folded++;
        *pred_p = val;
        return true;
      }
--- 1163,1169 ----
  	  fprintf (dump_file, "\n");
  	}
  
!       statistics_add ("predicates folded");
        *pred_p = val;
        return true;
      }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]