Fix for PR39557
[official-gcc.git] / gcc / statistics.c
blobd2f665f3b20f7c468c35fe726381db35c78158a8
1 /* Optimization statistics functions.
2 Copyright (C) 2008
3 Free Software Foundation, Inc.
4 Contributed by Richard Guenther <rguenther@suse.de>
6 This file is part of GCC.
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.
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.
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/>. */
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"
32 static int statistics_dump_nr;
33 static int statistics_dump_flags;
34 static FILE *statistics_dump_file;
36 /* Statistics entry. A integer counter associated to a string ID
37 and value. */
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;
47 /* Array of statistic hashes, indexed by pass id. */
48 static htab_t *statistics_hashes;
49 static unsigned nr_statistics_hashes;
51 /* Hash a statistic counter by its string ID. */
53 static hashval_t
54 hash_statistics_hash (const void *p)
56 const statistics_counter_t *const c = (const statistics_counter_t *)p;
57 return htab_hash_string (c->id) + c->val;
60 /* Compare two statistic counters by their string IDs. */
62 static int
63 hash_statistics_eq (const void *p, const void *q)
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;
70 /* Free a statistics entry. */
72 static void
73 hash_statistics_free (void *p)
75 free (CONST_CAST(char *, ((statistics_counter_t *)p)->id));
76 free (p);
79 /* Return the current hashtable to be used for recording or printing
80 statistics. */
82 static htab_t
83 curr_statistics_hash (void)
85 unsigned idx = current_pass->static_pass_number;
87 if (idx < nr_statistics_hashes
88 && statistics_hashes[idx] != NULL)
89 return statistics_hashes[idx];
91 if (idx >= nr_statistics_hashes)
93 statistics_hashes = XRESIZEVEC (struct htab *, statistics_hashes, idx+1);
94 memset (statistics_hashes + nr_statistics_hashes, 0,
95 (idx + 1 - nr_statistics_hashes) * sizeof (htab_t));
96 nr_statistics_hashes = idx + 1;
99 statistics_hashes[idx] = htab_create (15, hash_statistics_hash,
100 hash_statistics_eq,
101 hash_statistics_free);
103 return statistics_hashes[idx];
106 /* Helper for statistics_fini_pass. Print the counter difference
107 since the last dump for the pass dump files. */
109 static int
110 statistics_fini_pass_1 (void **slot, void *data ATTRIBUTE_UNUSED)
112 statistics_counter_t *counter = (statistics_counter_t *)*slot;
113 unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
114 if (count == 0)
115 return 1;
116 if (counter->histogram_p)
117 fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
118 counter->id, counter->val, count);
119 else
120 fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
121 counter->id, count);
122 counter->prev_dumped_count = counter->count;
123 return 1;
126 /* Helper for statistics_fini_pass. Print the counter difference
127 since the last dump for the statistics dump. */
129 static int
130 statistics_fini_pass_2 (void **slot, void *data ATTRIBUTE_UNUSED)
132 statistics_counter_t *counter = (statistics_counter_t *)*slot;
133 unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
134 if (count == 0)
135 return 1;
136 counter->prev_dumped_count = counter->count;
137 if (counter->histogram_p)
138 fprintf (statistics_dump_file,
139 "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
140 current_pass->static_pass_number,
141 current_pass->name,
142 counter->id, counter->val,
143 cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
144 count);
145 else
146 fprintf (statistics_dump_file,
147 "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
148 current_pass->static_pass_number,
149 current_pass->name,
150 counter->id,
151 cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
152 count);
153 counter->prev_dumped_count = counter->count;
154 return 1;
157 /* Helper for statistics_fini_pass, reset the counters. */
159 static int
160 statistics_fini_pass_3 (void **slot, void *data ATTRIBUTE_UNUSED)
162 statistics_counter_t *counter = (statistics_counter_t *)*slot;
163 counter->prev_dumped_count = counter->count;
164 return 1;
167 /* Dump the current statistics incrementally. */
169 void
170 statistics_fini_pass (void)
172 if (current_pass->static_pass_number == -1)
173 return;
175 if (dump_file
176 && dump_flags & TDF_STATS)
178 fprintf (dump_file, "\n");
179 fprintf (dump_file, "Pass statistics:\n");
180 fprintf (dump_file, "----------------\n");
181 htab_traverse_noresize (curr_statistics_hash (),
182 statistics_fini_pass_1, NULL);
183 fprintf (dump_file, "\n");
185 if (statistics_dump_file
186 && !(statistics_dump_flags & TDF_STATS
187 || statistics_dump_flags & TDF_DETAILS))
188 htab_traverse_noresize (curr_statistics_hash (),
189 statistics_fini_pass_2, NULL);
190 htab_traverse_noresize (curr_statistics_hash (),
191 statistics_fini_pass_3, NULL);
194 /* Helper for printing summary information. */
196 static int
197 statistics_fini_1 (void **slot, void *data)
199 struct opt_pass *pass = (struct opt_pass *)data;
200 statistics_counter_t *counter = (statistics_counter_t *)*slot;
201 if (counter->count == 0)
202 return 1;
203 if (counter->histogram_p)
204 fprintf (statistics_dump_file,
205 "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n",
206 pass->static_pass_number,
207 pass->name,
208 counter->id, counter->val,
209 counter->count);
210 else
211 fprintf (statistics_dump_file,
212 "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
213 pass->static_pass_number,
214 pass->name,
215 counter->id,
216 counter->count);
217 return 1;
220 /* Finish the statistics and dump summary information. */
222 void
223 statistics_fini (void)
225 if (!statistics_dump_file)
226 return;
228 if (statistics_dump_flags & TDF_STATS)
230 unsigned i;
231 for (i = 0; i < nr_statistics_hashes; ++i)
232 if (statistics_hashes[i] != NULL
233 && get_pass_for_id (i) != NULL)
234 htab_traverse_noresize (statistics_hashes[i],
235 statistics_fini_1, get_pass_for_id (i));
238 dump_end (statistics_dump_nr, statistics_dump_file);
241 /* Register the statistics dump file. */
243 void
244 statistics_early_init (void)
246 statistics_dump_nr = dump_register (".statistics", "statistics",
247 "statistics", TDF_TREE);
250 /* Init the statistics. */
252 void
253 statistics_init (void)
255 statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
256 statistics_dump_flags = get_dump_file_info (statistics_dump_nr)->flags;
259 /* Lookup or add a statistics counter in the hashtable HASH with ID, VAL
260 and HISTOGRAM_P. */
262 static statistics_counter_t *
263 lookup_or_add_counter (htab_t hash, const char *id, int val,
264 bool histogram_p)
266 statistics_counter_t **counter;
267 statistics_counter_t c;
268 c.id = id;
269 c.val = val;
270 counter = (statistics_counter_t **) htab_find_slot (hash, &c, INSERT);
271 if (!*counter)
273 *counter = XNEW (struct statistics_counter_s);
274 (*counter)->id = xstrdup (id);
275 (*counter)->val = val;
276 (*counter)->histogram_p = histogram_p;
277 (*counter)->prev_dumped_count = 0;
278 (*counter)->count = 0;
280 return *counter;
283 /* Add statistics information about event ID in function FN.
284 This will increment the counter associated with ID by INCR.
285 It will also dump the event to the global statistics file if requested. */
287 void
288 statistics_counter_event (struct function *fn, const char *id, int incr)
290 statistics_counter_t *counter;
292 if ((!(dump_flags & TDF_STATS)
293 && !statistics_dump_file)
294 || incr == 0)
295 return;
297 counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
298 gcc_assert (!counter->histogram_p);
299 counter->count += incr;
301 if (!statistics_dump_file
302 || !(statistics_dump_flags & TDF_DETAILS))
303 return;
305 fprintf (statistics_dump_file,
306 "%d %s \"%s\" \"%s\" %d\n",
307 current_pass->static_pass_number,
308 current_pass->name,
310 fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)",
311 incr);
314 /* Add statistics information about event ID in function FN with the
315 histogram value VAL.
316 It will dump the event to the global statistics file if requested. */
318 void
319 statistics_histogram_event (struct function *fn, const char *id, int val)
321 statistics_counter_t *counter;
323 if (!(dump_flags & TDF_STATS)
324 && !statistics_dump_file)
325 return;
327 counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
328 gcc_assert (counter->histogram_p);
329 counter->count += 1;
331 if (!statistics_dump_file
332 || !(statistics_dump_flags & TDF_DETAILS))
333 return;
335 fprintf (statistics_dump_file,
336 "%d %s \"%s == %d\" \"%s\" 1\n",
337 current_pass->static_pass_number,
338 current_pass->name,
339 id, val,
340 fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)");