1 /* Optimization statistics functions.
2    Copyright (C) 2008-2013 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 "tree-pass.h"
25 #include "tree-dump.h"
26 #include "statistics.h"
27 #include "hashtab.h"
28 #include "function.h"
29 
30 static int statistics_dump_nr;
31 static int statistics_dump_flags;
32 static FILE *statistics_dump_file;
33 
34 /* Statistics entry.  A integer counter associated to a string ID
35    and value.  */
36 
37 typedef struct statistics_counter_s {
38   const char *id;
39   int val;
40   bool histogram_p;
41   unsigned HOST_WIDE_INT count;
42   unsigned HOST_WIDE_INT prev_dumped_count;
43 } statistics_counter_t;
44 
45 /* Array of statistic hashes, indexed by pass id.  */
46 static htab_t *statistics_hashes;
47 static unsigned nr_statistics_hashes;
48 
49 /* Hash a statistic counter by its string ID.  */
50 
51 static hashval_t
hash_statistics_hash(const void * p)52 hash_statistics_hash (const void *p)
53 {
54   const statistics_counter_t *const c = (const statistics_counter_t *)p;
55   return htab_hash_string (c->id) + c->val;
56 }
57 
58 /* Compare two statistic counters by their string IDs.  */
59 
60 static int
hash_statistics_eq(const void * p,const void * q)61 hash_statistics_eq (const void *p, const void *q)
62 {
63   const statistics_counter_t *const c1 = (const statistics_counter_t *)p;
64   const statistics_counter_t *const c2 = (const statistics_counter_t *)q;
65   return c1->val == c2->val && strcmp (c1->id, c2->id) == 0;
66 }
67 
68 /* Free a statistics entry.  */
69 
70 static void
hash_statistics_free(void * p)71 hash_statistics_free (void *p)
72 {
73   free (CONST_CAST(char *, ((statistics_counter_t *)p)->id));
74   free (p);
75 }
76 
77 /* Return the current hashtable to be used for recording or printing
78    statistics.  */
79 
80 static htab_t
curr_statistics_hash(void)81 curr_statistics_hash (void)
82 {
83   unsigned idx;
84 
85   gcc_assert (current_pass->static_pass_number >= 0);
86   idx = current_pass->static_pass_number;
87 
88   if (idx < nr_statistics_hashes
89       && statistics_hashes[idx] != NULL)
90     return statistics_hashes[idx];
91 
92   if (idx >= nr_statistics_hashes)
93     {
94       statistics_hashes = XRESIZEVEC (struct htab *, statistics_hashes, idx+1);
95       memset (statistics_hashes + nr_statistics_hashes, 0,
96 	      (idx + 1 - nr_statistics_hashes) * sizeof (htab_t));
97       nr_statistics_hashes = idx + 1;
98     }
99 
100   statistics_hashes[idx] = htab_create (15, hash_statistics_hash,
101 					hash_statistics_eq,
102 					hash_statistics_free);
103 
104   return statistics_hashes[idx];
105 }
106 
107 /* Helper for statistics_fini_pass.  Print the counter difference
108    since the last dump for the pass dump files.  */
109 
110 static int
statistics_fini_pass_1(void ** slot,void * data ATTRIBUTE_UNUSED)111 statistics_fini_pass_1 (void **slot, void *data ATTRIBUTE_UNUSED)
112 {
113   statistics_counter_t *counter = (statistics_counter_t *)*slot;
114   unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
115   if (count == 0)
116     return 1;
117   if (counter->histogram_p)
118     fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
119 	     counter->id, counter->val, count);
120   else
121     fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
122 	     counter->id, count);
123   counter->prev_dumped_count = counter->count;
124   return 1;
125 }
126 
127 /* Helper for statistics_fini_pass.  Print the counter difference
128    since the last dump for the statistics dump.  */
129 
130 static int
statistics_fini_pass_2(void ** slot,void * data ATTRIBUTE_UNUSED)131 statistics_fini_pass_2 (void **slot, void *data ATTRIBUTE_UNUSED)
132 {
133   statistics_counter_t *counter = (statistics_counter_t *)*slot;
134   unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
135   if (count == 0)
136     return 1;
137   counter->prev_dumped_count = counter->count;
138   if (counter->histogram_p)
139     fprintf (statistics_dump_file,
140 	     "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
141 	     current_pass->static_pass_number,
142 	     current_pass->name,
143 	     counter->id, counter->val,
144 	     current_function_name (),
145 	     count);
146   else
147     fprintf (statistics_dump_file,
148 	     "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
149 	     current_pass->static_pass_number,
150 	     current_pass->name,
151 	     counter->id,
152 	     current_function_name (),
153 	     count);
154   counter->prev_dumped_count = counter->count;
155   return 1;
156 }
157 
158 /* Helper for statistics_fini_pass, reset the counters.  */
159 
160 static int
statistics_fini_pass_3(void ** slot,void * data ATTRIBUTE_UNUSED)161 statistics_fini_pass_3 (void **slot, void *data ATTRIBUTE_UNUSED)
162 {
163   statistics_counter_t *counter = (statistics_counter_t *)*slot;
164   counter->prev_dumped_count = counter->count;
165   return 1;
166 }
167 
168 /* Dump the current statistics incrementally.  */
169 
170 void
statistics_fini_pass(void)171 statistics_fini_pass (void)
172 {
173   if (current_pass->static_pass_number == -1)
174     return;
175 
176   if (dump_file
177       && dump_flags & TDF_STATS)
178     {
179       fprintf (dump_file, "\n");
180       fprintf (dump_file, "Pass statistics:\n");
181       fprintf (dump_file, "----------------\n");
182       htab_traverse_noresize (curr_statistics_hash (),
183 			      statistics_fini_pass_1, NULL);
184       fprintf (dump_file, "\n");
185     }
186   if (statistics_dump_file
187       && !(statistics_dump_flags & TDF_STATS
188 	   || statistics_dump_flags & TDF_DETAILS))
189     htab_traverse_noresize (curr_statistics_hash (),
190 			    statistics_fini_pass_2, NULL);
191   htab_traverse_noresize (curr_statistics_hash (),
192 			  statistics_fini_pass_3, NULL);
193 }
194 
195 /* Helper for printing summary information.  */
196 
197 static int
statistics_fini_1(void ** slot,void * data)198 statistics_fini_1 (void **slot, void *data)
199 {
200   struct opt_pass *pass = (struct opt_pass *)data;
201   statistics_counter_t *counter = (statistics_counter_t *)*slot;
202   if (counter->count == 0)
203     return 1;
204   if (counter->histogram_p)
205     fprintf (statistics_dump_file,
206 	     "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n",
207 	     pass->static_pass_number,
208 	     pass->name,
209 	     counter->id, counter->val,
210 	     counter->count);
211   else
212     fprintf (statistics_dump_file,
213 	     "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
214 	     pass->static_pass_number,
215 	     pass->name,
216 	     counter->id,
217 	     counter->count);
218   return 1;
219 }
220 
221 /* Finish the statistics and dump summary information.  */
222 
223 void
statistics_fini(void)224 statistics_fini (void)
225 {
226   if (!statistics_dump_file)
227     return;
228 
229   if (statistics_dump_flags & TDF_STATS)
230     {
231       unsigned i;
232       for (i = 0; i < nr_statistics_hashes; ++i)
233 	if (statistics_hashes[i] != NULL
234 	    && get_pass_for_id (i) != NULL)
235 	  htab_traverse_noresize (statistics_hashes[i],
236 				  statistics_fini_1, get_pass_for_id (i));
237     }
238 
239   dump_end (statistics_dump_nr, statistics_dump_file);
240 }
241 
242 /* Register the statistics dump file.  */
243 
244 void
statistics_early_init(void)245 statistics_early_init (void)
246 {
247   statistics_dump_nr = dump_register (".statistics", "statistics",
248 				      "statistics", TDF_TREE, OPTGROUP_NONE);
249 }
250 
251 /* Init the statistics.  */
252 
253 void
statistics_init(void)254 statistics_init (void)
255 {
256   statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
257   statistics_dump_flags = get_dump_file_info (statistics_dump_nr)->pflags;
258 }
259 
260 /* Lookup or add a statistics counter in the hashtable HASH with ID, VAL
261    and HISTOGRAM_P.  */
262 
263 static statistics_counter_t *
lookup_or_add_counter(htab_t hash,const char * id,int val,bool histogram_p)264 lookup_or_add_counter (htab_t hash, const char *id, int val,
265 		       bool histogram_p)
266 {
267   statistics_counter_t **counter;
268   statistics_counter_t c;
269   c.id = id;
270   c.val = val;
271   counter = (statistics_counter_t **) htab_find_slot (hash, &c, INSERT);
272   if (!*counter)
273     {
274       *counter = XNEW (struct statistics_counter_s);
275       (*counter)->id = xstrdup (id);
276       (*counter)->val = val;
277       (*counter)->histogram_p = histogram_p;
278       (*counter)->prev_dumped_count = 0;
279       (*counter)->count = 0;
280     }
281   return *counter;
282 }
283 
284 /* Add statistics information about event ID in function FN.
285    This will increment the counter associated with ID by INCR.
286    It will also dump the event to the global statistics file if requested.  */
287 
288 void
statistics_counter_event(struct function * fn,const char * id,int incr)289 statistics_counter_event (struct function *fn, const char *id, int incr)
290 {
291   statistics_counter_t *counter;
292 
293   if ((!(dump_flags & TDF_STATS)
294        && !statistics_dump_file)
295       || incr == 0)
296     return;
297 
298   if (current_pass->static_pass_number != -1)
299     {
300       counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
301       gcc_assert (!counter->histogram_p);
302       counter->count += incr;
303     }
304 
305   if (!statistics_dump_file
306       || !(statistics_dump_flags & TDF_DETAILS))
307     return;
308 
309   fprintf (statistics_dump_file,
310 	   "%d %s \"%s\" \"%s\" %d\n",
311 	   current_pass->static_pass_number,
312 	   current_pass->name,
313 	   id,
314 	   function_name (fn),
315 	   incr);
316 }
317 
318 /* Add statistics information about event ID in function FN with the
319    histogram value VAL.
320    It will dump the event to the global statistics file if requested.  */
321 
322 void
statistics_histogram_event(struct function * fn,const char * id,int val)323 statistics_histogram_event (struct function *fn, const char *id, int val)
324 {
325   statistics_counter_t *counter;
326 
327   if (!(dump_flags & TDF_STATS)
328       && !statistics_dump_file)
329     return;
330 
331   counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
332   gcc_assert (counter->histogram_p);
333   counter->count += 1;
334 
335   if (!statistics_dump_file
336       || !(statistics_dump_flags & TDF_DETAILS))
337     return;
338 
339   fprintf (statistics_dump_file,
340 	   "%d %s \"%s == %d\" \"%s\" 1\n",
341 	   current_pass->static_pass_number,
342 	   current_pass->name,
343 	   id, val,
344 	   function_name (fn));
345 }
346