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