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