Home | History | Annotate | Line # | Download | only in gcc
      1  1.1  mrg /* Optimization statistics functions.
      2  1.1  mrg    Copyright (C) 2008-2022 Free Software Foundation, Inc.
      3  1.1  mrg    Contributed by Richard Guenther  <rguenther (at) suse.de>
      4  1.1  mrg 
      5  1.1  mrg This file is part of GCC.
      6  1.1  mrg 
      7  1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      8  1.1  mrg the terms of the GNU General Public License as published by the Free
      9  1.1  mrg Software Foundation; either version 3, or (at your option) any later
     10  1.1  mrg version.
     11  1.1  mrg 
     12  1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     13  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  1.1  mrg for more details.
     16  1.1  mrg 
     17  1.1  mrg You should have received a copy of the GNU General Public License
     18  1.1  mrg along with GCC; see the file COPYING3.  If not see
     19  1.1  mrg <http://www.gnu.org/licenses/>.  */
     20  1.1  mrg 
     21  1.1  mrg #include "config.h"
     22  1.1  mrg #include "system.h"
     23  1.1  mrg #include "coretypes.h"
     24  1.1  mrg #include "function.h"
     25  1.1  mrg #include "tree-pass.h"
     26  1.1  mrg #include "context.h"
     27  1.1  mrg #include "pass_manager.h"
     28  1.1  mrg 
     29  1.1  mrg static int statistics_dump_nr;
     30  1.1  mrg static dump_flags_t statistics_dump_flags;
     31  1.1  mrg static FILE *statistics_dump_file;
     32  1.1  mrg 
     33  1.1  mrg /* Statistics entry.  A integer counter associated to a string ID
     34  1.1  mrg    and value.  */
     35  1.1  mrg 
     36  1.1  mrg struct statistics_counter {
     37  1.1  mrg   const char *id;
     38  1.1  mrg   int val;
     39  1.1  mrg   bool histogram_p;
     40  1.1  mrg   unsigned HOST_WIDE_INT count;
     41  1.1  mrg   unsigned HOST_WIDE_INT prev_dumped_count;
     42  1.1  mrg };
     43  1.1  mrg 
     44  1.1  mrg /* Hashtable helpers.  */
     45  1.1  mrg 
     46  1.1  mrg struct stats_counter_hasher : pointer_hash <statistics_counter>
     47  1.1  mrg {
     48  1.1  mrg   static inline hashval_t hash (const statistics_counter *);
     49  1.1  mrg   static inline bool equal (const statistics_counter *,
     50  1.1  mrg 			    const statistics_counter *);
     51  1.1  mrg   static inline void remove (statistics_counter *);
     52  1.1  mrg };
     53  1.1  mrg 
     54  1.1  mrg /* Hash a statistic counter by its string ID.  */
     55  1.1  mrg 
     56  1.1  mrg inline hashval_t
     57  1.1  mrg stats_counter_hasher::hash (const statistics_counter *c)
     58  1.1  mrg {
     59  1.1  mrg   return htab_hash_string (c->id) + c->val;
     60  1.1  mrg }
     61  1.1  mrg 
     62  1.1  mrg /* Compare two statistic counters by their string IDs.  */
     63  1.1  mrg 
     64  1.1  mrg inline bool
     65  1.1  mrg stats_counter_hasher::equal (const statistics_counter *c1,
     66  1.1  mrg 			     const statistics_counter *c2)
     67  1.1  mrg {
     68  1.1  mrg   return c1->val == c2->val && strcmp (c1->id, c2->id) == 0;
     69  1.1  mrg }
     70  1.1  mrg 
     71  1.1  mrg /* Free a statistics entry.  */
     72  1.1  mrg 
     73  1.1  mrg inline void
     74  1.1  mrg stats_counter_hasher::remove (statistics_counter *v)
     75  1.1  mrg {
     76  1.1  mrg   free (CONST_CAST (char *, v->id));
     77  1.1  mrg   free (v);
     78  1.1  mrg }
     79  1.1  mrg 
     80  1.1  mrg typedef hash_table<stats_counter_hasher> stats_counter_table_type;
     81  1.1  mrg 
     82  1.1  mrg /* Array of statistic hashes, indexed by pass id.  */
     83  1.1  mrg static stats_counter_table_type **statistics_hashes;
     84  1.1  mrg static unsigned nr_statistics_hashes;
     85  1.1  mrg 
     86  1.1  mrg /* Return the current hashtable to be used for recording or printing
     87  1.1  mrg    statistics.  */
     88  1.1  mrg 
     89  1.1  mrg static stats_counter_table_type *
     90  1.1  mrg curr_statistics_hash (void)
     91  1.1  mrg {
     92  1.1  mrg   unsigned idx;
     93  1.1  mrg 
     94  1.1  mrg   gcc_assert (current_pass->static_pass_number >= 0);
     95  1.1  mrg   idx = current_pass->static_pass_number;
     96  1.1  mrg 
     97  1.1  mrg   if (idx < nr_statistics_hashes
     98  1.1  mrg       && statistics_hashes[idx])
     99  1.1  mrg     return statistics_hashes[idx];
    100  1.1  mrg 
    101  1.1  mrg   if (idx >= nr_statistics_hashes)
    102  1.1  mrg     {
    103  1.1  mrg       statistics_hashes = XRESIZEVEC (stats_counter_table_type *,
    104  1.1  mrg 				      statistics_hashes, idx+1);
    105  1.1  mrg       memset (statistics_hashes + nr_statistics_hashes, 0,
    106  1.1  mrg 	      (idx + 1 - nr_statistics_hashes)
    107  1.1  mrg 	      * sizeof (stats_counter_table_type *));
    108  1.1  mrg       nr_statistics_hashes = idx + 1;
    109  1.1  mrg     }
    110  1.1  mrg 
    111  1.1  mrg   statistics_hashes[idx] = new stats_counter_table_type (15);
    112  1.1  mrg 
    113  1.1  mrg   return statistics_hashes[idx];
    114  1.1  mrg }
    115  1.1  mrg 
    116  1.1  mrg /* Helper for statistics_fini_pass.  Print the counter difference
    117  1.1  mrg    since the last dump for the pass dump files.  */
    118  1.1  mrg 
    119  1.1  mrg int
    120  1.1  mrg statistics_fini_pass_1 (statistics_counter **slot,
    121  1.1  mrg 			void *data ATTRIBUTE_UNUSED)
    122  1.1  mrg {
    123  1.1  mrg   statistics_counter *counter = *slot;
    124  1.1  mrg   unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
    125  1.1  mrg   if (count == 0)
    126  1.1  mrg     return 1;
    127  1.1  mrg   if (counter->histogram_p)
    128  1.1  mrg     fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
    129  1.1  mrg 	     counter->id, counter->val, count);
    130  1.1  mrg   else
    131  1.1  mrg     fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
    132  1.1  mrg 	     counter->id, count);
    133  1.1  mrg   counter->prev_dumped_count = counter->count;
    134  1.1  mrg   return 1;
    135  1.1  mrg }
    136  1.1  mrg 
    137  1.1  mrg /* Helper for statistics_fini_pass.  Print the counter difference
    138  1.1  mrg    since the last dump for the statistics dump.  */
    139  1.1  mrg 
    140  1.1  mrg int
    141  1.1  mrg statistics_fini_pass_2 (statistics_counter **slot,
    142  1.1  mrg 			void *data ATTRIBUTE_UNUSED)
    143  1.1  mrg {
    144  1.1  mrg   statistics_counter *counter = *slot;
    145  1.1  mrg   unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
    146  1.1  mrg   if (count == 0)
    147  1.1  mrg     return 1;
    148  1.1  mrg   counter->prev_dumped_count = counter->count;
    149  1.1  mrg   if (counter->histogram_p)
    150  1.1  mrg     fprintf (statistics_dump_file,
    151  1.1  mrg 	     "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
    152  1.1  mrg 	     current_pass->static_pass_number,
    153  1.1  mrg 	     current_pass->name,
    154  1.1  mrg 	     counter->id, counter->val,
    155  1.1  mrg 	     current_function_name (),
    156  1.1  mrg 	     count);
    157  1.1  mrg   else
    158  1.1  mrg     fprintf (statistics_dump_file,
    159  1.1  mrg 	     "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
    160  1.1  mrg 	     current_pass->static_pass_number,
    161  1.1  mrg 	     current_pass->name,
    162  1.1  mrg 	     counter->id,
    163  1.1  mrg 	     current_function_name (),
    164  1.1  mrg 	     count);
    165  1.1  mrg   counter->prev_dumped_count = counter->count;
    166  1.1  mrg   return 1;
    167  1.1  mrg }
    168  1.1  mrg 
    169  1.1  mrg /* Helper for statistics_fini_pass, reset the counters.  */
    170  1.1  mrg 
    171  1.1  mrg int
    172  1.1  mrg statistics_fini_pass_3 (statistics_counter **slot,
    173  1.1  mrg 			void *data ATTRIBUTE_UNUSED)
    174  1.1  mrg {
    175  1.1  mrg   statistics_counter *counter = *slot;
    176  1.1  mrg   counter->prev_dumped_count = counter->count;
    177  1.1  mrg   return 1;
    178  1.1  mrg }
    179  1.1  mrg 
    180  1.1  mrg /* Dump the current statistics incrementally.  */
    181  1.1  mrg 
    182  1.1  mrg void
    183  1.1  mrg statistics_fini_pass (void)
    184  1.1  mrg {
    185  1.1  mrg   if (current_pass->static_pass_number == -1)
    186  1.1  mrg     return;
    187  1.1  mrg 
    188  1.1  mrg   if (dump_file
    189  1.1  mrg       && dump_flags & TDF_STATS)
    190  1.1  mrg     {
    191  1.1  mrg       fprintf (dump_file, "\n");
    192  1.1  mrg       fprintf (dump_file, "Pass statistics of \"%s\": ", current_pass->name);
    193  1.1  mrg       fprintf (dump_file, "----------------\n");
    194  1.1  mrg       curr_statistics_hash ()
    195  1.1  mrg 	->traverse_noresize <void *, statistics_fini_pass_1> (NULL);
    196  1.1  mrg       fprintf (dump_file, "\n");
    197  1.1  mrg     }
    198  1.1  mrg   if (statistics_dump_file
    199  1.1  mrg       && !(statistics_dump_flags & TDF_STATS
    200  1.1  mrg 	   || statistics_dump_flags & TDF_DETAILS))
    201  1.1  mrg     curr_statistics_hash ()
    202  1.1  mrg       ->traverse_noresize <void *, statistics_fini_pass_2> (NULL);
    203  1.1  mrg   curr_statistics_hash ()
    204  1.1  mrg     ->traverse_noresize <void *, statistics_fini_pass_3> (NULL);
    205  1.1  mrg }
    206  1.1  mrg 
    207  1.1  mrg /* Helper for printing summary information.  */
    208  1.1  mrg 
    209  1.1  mrg int
    210  1.1  mrg statistics_fini_1 (statistics_counter **slot, opt_pass *pass)
    211  1.1  mrg {
    212  1.1  mrg   statistics_counter *counter = *slot;
    213  1.1  mrg   if (counter->count == 0)
    214  1.1  mrg     return 1;
    215  1.1  mrg   if (counter->histogram_p)
    216  1.1  mrg     fprintf (statistics_dump_file,
    217  1.1  mrg 	     "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n",
    218  1.1  mrg 	     pass->static_pass_number,
    219  1.1  mrg 	     pass->name,
    220  1.1  mrg 	     counter->id, counter->val,
    221  1.1  mrg 	     counter->count);
    222  1.1  mrg   else
    223  1.1  mrg     fprintf (statistics_dump_file,
    224  1.1  mrg 	     "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
    225  1.1  mrg 	     pass->static_pass_number,
    226  1.1  mrg 	     pass->name,
    227  1.1  mrg 	     counter->id,
    228  1.1  mrg 	     counter->count);
    229  1.1  mrg   return 1;
    230  1.1  mrg }
    231  1.1  mrg 
    232  1.1  mrg /* Finish the statistics and dump summary information.  */
    233  1.1  mrg 
    234  1.1  mrg void
    235  1.1  mrg statistics_fini (void)
    236  1.1  mrg {
    237  1.1  mrg   gcc::pass_manager *passes = g->get_passes ();
    238  1.1  mrg   if (!statistics_dump_file)
    239  1.1  mrg     return;
    240  1.1  mrg 
    241  1.1  mrg   if (statistics_dump_flags & TDF_STATS)
    242  1.1  mrg     {
    243  1.1  mrg       unsigned i;
    244  1.1  mrg       for (i = 0; i < nr_statistics_hashes; ++i)
    245  1.1  mrg 	if (statistics_hashes[i]
    246  1.1  mrg 	    && passes->get_pass_for_id (i) != NULL)
    247  1.1  mrg 	  statistics_hashes[i]
    248  1.1  mrg 	    ->traverse_noresize <opt_pass *, statistics_fini_1>
    249  1.1  mrg 	    (passes->get_pass_for_id (i));
    250  1.1  mrg     }
    251  1.1  mrg 
    252  1.1  mrg   dump_end (statistics_dump_nr, statistics_dump_file);
    253  1.1  mrg }
    254  1.1  mrg 
    255  1.1  mrg /* Register the statistics dump file.  */
    256  1.1  mrg 
    257  1.1  mrg void
    258  1.1  mrg statistics_early_init (void)
    259  1.1  mrg {
    260  1.1  mrg   gcc::dump_manager *dumps = g->get_dumps ();
    261  1.1  mrg   statistics_dump_nr = dumps->dump_register (".statistics", "statistics",
    262  1.1  mrg 					     "statistics", DK_tree,
    263  1.1  mrg 					     OPTGROUP_NONE,
    264  1.1  mrg 					     false);
    265  1.1  mrg }
    266  1.1  mrg 
    267  1.1  mrg /* Init the statistics.  */
    268  1.1  mrg 
    269  1.1  mrg void
    270  1.1  mrg statistics_init (void)
    271  1.1  mrg {
    272  1.1  mrg   gcc::dump_manager *dumps = g->get_dumps ();
    273  1.1  mrg   statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
    274  1.1  mrg   statistics_dump_flags = dumps->get_dump_file_info (statistics_dump_nr)->pflags;
    275  1.1  mrg }
    276  1.1  mrg 
    277  1.1  mrg /* Lookup or add a statistics counter in the hashtable HASH with ID, VAL
    278  1.1  mrg    and HISTOGRAM_P.  */
    279  1.1  mrg 
    280  1.1  mrg static statistics_counter *
    281  1.1  mrg lookup_or_add_counter (stats_counter_table_type *hash, const char *id, int val,
    282  1.1  mrg 		       bool histogram_p)
    283  1.1  mrg {
    284  1.1  mrg   statistics_counter **counter;
    285  1.1  mrg   statistics_counter c;
    286  1.1  mrg   c.id = id;
    287  1.1  mrg   c.val = val;
    288  1.1  mrg   counter = hash->find_slot (&c, INSERT);
    289  1.1  mrg   if (!*counter)
    290  1.1  mrg     {
    291  1.1  mrg       *counter = XNEW (statistics_counter);
    292  1.1  mrg       (*counter)->id = xstrdup (id);
    293  1.1  mrg       (*counter)->val = val;
    294  1.1  mrg       (*counter)->histogram_p = histogram_p;
    295  1.1  mrg       (*counter)->prev_dumped_count = 0;
    296  1.1  mrg       (*counter)->count = 0;
    297  1.1  mrg     }
    298  1.1  mrg   return *counter;
    299  1.1  mrg }
    300  1.1  mrg 
    301  1.1  mrg /* Add statistics information about event ID in function FN.
    302  1.1  mrg    This will increment the counter associated with ID by INCR.
    303  1.1  mrg    It will also dump the event to the global statistics file if requested.  */
    304  1.1  mrg 
    305  1.1  mrg void
    306  1.1  mrg statistics_counter_event (struct function *fn, const char *id, int incr)
    307  1.1  mrg {
    308  1.1  mrg   statistics_counter *counter;
    309  1.1  mrg 
    310  1.1  mrg   if ((!(dump_flags & TDF_STATS)
    311  1.1  mrg        && !statistics_dump_file)
    312  1.1  mrg       || incr == 0)
    313  1.1  mrg     return;
    314  1.1  mrg 
    315  1.1  mrg   if (current_pass
    316  1.1  mrg       && current_pass->static_pass_number != -1)
    317  1.1  mrg     {
    318  1.1  mrg       counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
    319  1.1  mrg       gcc_assert (!counter->histogram_p);
    320  1.1  mrg       counter->count += incr;
    321  1.1  mrg     }
    322  1.1  mrg 
    323  1.1  mrg   if (!statistics_dump_file
    324  1.1  mrg       || !(statistics_dump_flags & TDF_DETAILS))
    325  1.1  mrg     return;
    326  1.1  mrg 
    327  1.1  mrg   fprintf (statistics_dump_file,
    328  1.1  mrg 	   "%d %s \"%s\" \"%s\" %d\n",
    329  1.1  mrg 	   current_pass ? current_pass->static_pass_number : -1,
    330  1.1  mrg 	   current_pass ? current_pass->name : "none",
    331  1.1  mrg 	   id,
    332  1.1  mrg 	   function_name (fn),
    333  1.1  mrg 	   incr);
    334  1.1  mrg }
    335  1.1  mrg 
    336  1.1  mrg /* Add statistics information about event ID in function FN with the
    337  1.1  mrg    histogram value VAL.
    338  1.1  mrg    It will dump the event to the global statistics file if requested.  */
    339  1.1  mrg 
    340  1.1  mrg void
    341  1.1  mrg statistics_histogram_event (struct function *fn, const char *id, int val)
    342  1.1  mrg {
    343  1.1  mrg   statistics_counter *counter;
    344  1.1  mrg 
    345  1.1  mrg   if (!(dump_flags & TDF_STATS)
    346  1.1  mrg       && !statistics_dump_file)
    347  1.1  mrg     return;
    348  1.1  mrg 
    349  1.1  mrg   counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
    350  1.1  mrg   gcc_assert (counter->histogram_p);
    351  1.1  mrg   counter->count += 1;
    352  1.1  mrg 
    353  1.1  mrg   if (!statistics_dump_file
    354  1.1  mrg       || !(statistics_dump_flags & TDF_DETAILS))
    355  1.1  mrg     return;
    356  1.1  mrg 
    357  1.1  mrg   fprintf (statistics_dump_file,
    358  1.1  mrg 	   "%d %s \"%s == %d\" \"%s\" 1\n",
    359  1.1  mrg 	   current_pass->static_pass_number,
    360  1.1  mrg 	   current_pass->name,
    361  1.1  mrg 	   id, val,
    362  1.1  mrg 	   function_name (fn));
    363  1.1  mrg }
    364