OSDN Git Service

2010-06-07 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / statistics.c
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 }