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