real.c (real_to_decimal, [...]): Distinguish QNaN & SNaN.
[gcc.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 statistics_counter_t *c = (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 statistics_counter_t *c1 = (statistics_counter_t *)p;
66 statistics_counter_t *c2 = (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 ((void *)((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 = current_pass->static_pass_number;
86
87 if (idx < nr_statistics_hashes
88 && statistics_hashes[idx] != NULL)
89 return statistics_hashes[idx];
90
91 if (idx >= nr_statistics_hashes)
92 {
93 statistics_hashes = xrealloc (statistics_hashes,
94 (idx + 1) * sizeof (htab_t));
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
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
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 cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
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 cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
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
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
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
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
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
245 statistics_early_init (void)
246 {
247 statistics_dump_nr = dump_register (".statistics", "statistics",
248 "statistics", TDF_TREE);
249 }
250
251 /* Init the statistics. */
252
253 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)->flags;
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 *
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
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 counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
299 gcc_assert (!counter->histogram_p);
300 counter->count += incr;
301
302 if (!statistics_dump_file
303 || !(statistics_dump_flags & TDF_DETAILS))
304 return;
305
306 fprintf (statistics_dump_file,
307 "%d %s \"%s\" \"%s\" %d\n",
308 current_pass->static_pass_number,
309 current_pass->name,
310 id,
311 fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)",
312 incr);
313 }
314
315 /* Add statistics information about event ID in function FN with the
316 histogram value VAL.
317 It will dump the event to the global statistics file if requested. */
318
319 void
320 statistics_histogram_event (struct function *fn, const char *id, int val)
321 {
322 statistics_counter_t *counter;
323
324 if (!(dump_flags & TDF_STATS)
325 && !statistics_dump_file)
326 return;
327
328 counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
329 gcc_assert (counter->histogram_p);
330 counter->count += 1;
331
332 if (!statistics_dump_file
333 || !(statistics_dump_flags & TDF_DETAILS))
334 return;
335
336 fprintf (statistics_dump_file,
337 "%d %s \"%s == %d\" \"%s\" 1\n",
338 current_pass->static_pass_number,
339 current_pass->name,
340 id, val,
341 fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)");
342 }