Line data Source code
1 : /* Optimization statistics functions.
2 : Copyright (C) 2008-2026 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 "function.h"
25 : #include "tree-pass.h"
26 : #include "context.h"
27 : #include "pass_manager.h"
28 : #include "tree.h"
29 :
30 : static int statistics_dump_nr;
31 : static dump_flags_t 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 : struct statistics_counter {
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 : };
44 :
45 : /* Hashtable helpers. */
46 :
47 : struct stats_counter_hasher : pointer_hash <statistics_counter>
48 : {
49 : static inline hashval_t hash (const statistics_counter *);
50 : static inline bool equal (const statistics_counter *,
51 : const statistics_counter *);
52 : static inline void remove (statistics_counter *);
53 : };
54 :
55 : /* Hash a statistic counter by its string ID. */
56 :
57 : inline hashval_t
58 176459 : stats_counter_hasher::hash (const statistics_counter *c)
59 : {
60 176459 : return htab_hash_string (c->id) + c->val;
61 : }
62 :
63 : /* Compare two statistic counters by their string IDs. */
64 :
65 : inline bool
66 175510 : stats_counter_hasher::equal (const statistics_counter *c1,
67 : const statistics_counter *c2)
68 : {
69 175510 : return c1->val == c2->val && strcmp (c1->id, c2->id) == 0;
70 : }
71 :
72 : /* Free a statistics entry. */
73 :
74 : inline void
75 : stats_counter_hasher::remove (statistics_counter *v)
76 : {
77 : free (const_cast<char *> (v->id));
78 : free (v);
79 : }
80 :
81 : typedef hash_table<stats_counter_hasher> stats_counter_table_type;
82 :
83 : /* Array of statistic hashes, indexed by pass id. */
84 : static stats_counter_table_type **statistics_hashes;
85 : static unsigned nr_statistics_hashes;
86 :
87 : /* Return the current hashtable to be used for recording or printing
88 : statistics. */
89 :
90 : static stats_counter_table_type *
91 581350970 : curr_statistics_hash (bool alloc = true)
92 : {
93 581350970 : unsigned idx;
94 :
95 581350970 : gcc_assert (current_pass->static_pass_number >= 0);
96 581350970 : idx = current_pass->static_pass_number;
97 :
98 581350970 : if (idx < nr_statistics_hashes
99 666975 : && statistics_hashes[idx])
100 : return statistics_hashes[idx];
101 :
102 581216652 : if (!alloc)
103 : return nullptr;
104 :
105 694 : if (idx >= nr_statistics_hashes)
106 : {
107 624 : statistics_hashes = XRESIZEVEC (stats_counter_table_type *,
108 : statistics_hashes, idx+1);
109 624 : memset (statistics_hashes + nr_statistics_hashes, 0,
110 624 : (idx + 1 - nr_statistics_hashes)
111 : * sizeof (stats_counter_table_type *));
112 624 : nr_statistics_hashes = idx + 1;
113 : }
114 :
115 694 : statistics_hashes[idx] = new stats_counter_table_type (15);
116 :
117 694 : return statistics_hashes[idx];
118 : }
119 :
120 : /* Helper function to return asmname or name of FN
121 : depending on whether asmname option is set. */
122 :
123 : static const char *
124 38833 : get_function_name (struct function *fn)
125 : {
126 38833 : if ((statistics_dump_flags & TDF_ASMNAME)
127 38833 : && fn && DECL_ASSEMBLER_NAME_SET_P (fn->decl))
128 : {
129 0 : tree asmname = decl_assembler_name (fn->decl);
130 0 : if (asmname)
131 0 : return IDENTIFIER_POINTER (asmname);
132 : }
133 38833 : return function_name (fn);
134 : }
135 :
136 : /* Helper for statistics_fini_pass. Print the counter difference
137 : since the last dump for the pass dump files. */
138 :
139 : int
140 2252 : statistics_fini_pass_1 (statistics_counter **slot,
141 : void *data ATTRIBUTE_UNUSED)
142 : {
143 2252 : statistics_counter *counter = *slot;
144 2252 : unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
145 2252 : if (count == 0)
146 : return 1;
147 1730 : if (counter->histogram_p)
148 686 : fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
149 : counter->id, counter->val, count);
150 : else
151 1044 : fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
152 : counter->id, count);
153 1730 : counter->prev_dumped_count = counter->count;
154 1730 : return 1;
155 : }
156 :
157 : /* Helper for statistics_fini_pass. Print the counter difference
158 : since the last dump for the statistics dump. */
159 :
160 : int
161 518664 : statistics_fini_pass_2 (statistics_counter **slot,
162 : void *data ATTRIBUTE_UNUSED)
163 : {
164 518664 : statistics_counter *counter = *slot;
165 518664 : unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
166 518664 : if (count == 0)
167 : return 1;
168 38833 : counter->prev_dumped_count = counter->count;
169 38833 : if (counter->histogram_p)
170 19824 : fprintf (statistics_dump_file,
171 : "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
172 : current_pass->static_pass_number,
173 : current_pass->name,
174 : counter->id, counter->val,
175 : get_function_name (cfun),
176 : count);
177 : else
178 19009 : fprintf (statistics_dump_file,
179 : "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
180 : current_pass->static_pass_number,
181 : current_pass->name,
182 : counter->id,
183 : get_function_name (cfun),
184 : count);
185 38833 : counter->prev_dumped_count = counter->count;
186 38833 : return 1;
187 : }
188 :
189 : /* Helper for statistics_fini_pass, reset the counters. */
190 :
191 : int
192 643823 : statistics_fini_pass_3 (statistics_counter **slot,
193 : void *data ATTRIBUTE_UNUSED)
194 : {
195 643823 : statistics_counter *counter = *slot;
196 643823 : counter->prev_dumped_count = counter->count;
197 643823 : return 1;
198 : }
199 :
200 : /* Dump the current statistics incrementally. */
201 :
202 : void
203 640083722 : statistics_fini_pass (void)
204 : {
205 640083722 : if (current_pass->static_pass_number == -1)
206 : return;
207 :
208 581305808 : stats_counter_table_type *stat_hash = curr_statistics_hash (false);
209 :
210 581305808 : if (dump_file
211 581305808 : && dump_flags & TDF_STATS)
212 : {
213 1880 : fprintf (dump_file, "\n");
214 1880 : fprintf (dump_file, "Pass statistics of \"%s\": ", current_pass->name);
215 1880 : fprintf (dump_file, "----------------\n");
216 1880 : if (stat_hash)
217 2821 : stat_hash->traverse_noresize <void *, statistics_fini_pass_1> (NULL);
218 1880 : fprintf (dump_file, "\n");
219 : }
220 :
221 581305808 : if (!stat_hash)
222 : return;
223 :
224 89850 : if (statistics_dump_file
225 89850 : && !(statistics_dump_flags & TDF_STATS
226 66758 : || statistics_dump_flags & TDF_DETAILS))
227 585422 : stat_hash->traverse_noresize <void *, statistics_fini_pass_2> (NULL);
228 733673 : stat_hash->traverse_noresize <void *, statistics_fini_pass_3> (NULL);
229 : }
230 :
231 : /* Helper for printing summary information. */
232 :
233 : int
234 43 : statistics_fini_1 (statistics_counter **slot, opt_pass *pass)
235 : {
236 43 : statistics_counter *counter = *slot;
237 43 : if (counter->count == 0)
238 : return 1;
239 43 : if (counter->histogram_p)
240 22 : fprintf (statistics_dump_file,
241 : "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n",
242 : pass->static_pass_number,
243 : pass->name,
244 : counter->id, counter->val,
245 : counter->count);
246 : else
247 21 : fprintf (statistics_dump_file,
248 : "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
249 : pass->static_pass_number,
250 : pass->name,
251 : counter->id,
252 : counter->count);
253 : return 1;
254 : }
255 :
256 : /* Finish the statistics and dump summary information. */
257 :
258 : void
259 276762 : statistics_fini (void)
260 : {
261 276762 : gcc::pass_manager *passes = g->get_passes ();
262 276762 : if (!statistics_dump_file)
263 : return;
264 :
265 66 : if (statistics_dump_flags & TDF_STATS)
266 : {
267 : unsigned i;
268 317 : for (i = 0; i < nr_statistics_hashes; ++i)
269 314 : if (statistics_hashes[i]
270 314 : && passes->get_pass_for_id (i) != NULL)
271 7 : statistics_hashes[i]
272 : ->traverse_noresize <opt_pass *, statistics_fini_1>
273 50 : (passes->get_pass_for_id (i));
274 : }
275 :
276 66 : dump_end (statistics_dump_nr, statistics_dump_file);
277 : }
278 :
279 : /* Register the statistics dump file. */
280 :
281 : void
282 285722 : statistics_early_init (void)
283 : {
284 285722 : gcc::dump_manager *dumps = g->get_dumps ();
285 285722 : statistics_dump_nr = dumps->dump_register (".statistics", "statistics",
286 : "statistics", DK_tree,
287 : OPTGROUP_NONE,
288 : false);
289 285722 : }
290 :
291 : /* Init the statistics. */
292 :
293 : void
294 278638 : statistics_init (void)
295 : {
296 278638 : gcc::dump_manager *dumps = g->get_dumps ();
297 278638 : statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
298 278638 : statistics_dump_flags = dumps->get_dump_file_info (statistics_dump_nr)->pflags;
299 278638 : }
300 :
301 : /* Lookup or add a statistics counter in the hashtable HASH with ID, VAL
302 : and HISTOGRAM_P. */
303 :
304 : static statistics_counter *
305 45162 : lookup_or_add_counter (stats_counter_table_type *hash, const char *id, int val,
306 : bool histogram_p)
307 : {
308 45162 : statistics_counter **counter;
309 45162 : statistics_counter c;
310 45162 : c.id = id;
311 45162 : c.val = val;
312 45162 : counter = hash->find_slot (&c, INSERT);
313 45162 : if (!*counter)
314 : {
315 3396 : *counter = XNEW (statistics_counter);
316 3396 : (*counter)->id = xstrdup (id);
317 3396 : (*counter)->val = val;
318 3396 : (*counter)->histogram_p = histogram_p;
319 3396 : (*counter)->prev_dumped_count = 0;
320 3396 : (*counter)->count = 0;
321 : }
322 45162 : return *counter;
323 : }
324 :
325 : /* Add statistics information about event ID in function FN.
326 : This will increment the counter associated with ID by INCR.
327 : It will also dump the event to the global statistics file if requested. */
328 :
329 : void
330 229968722 : statistics_counter_event (struct function *fn, const char *id, int incr)
331 : {
332 229968722 : statistics_counter *counter;
333 :
334 229968722 : if ((!(dump_flags & TDF_STATS)
335 229966845 : && !statistics_dump_file)
336 230110087 : || incr == 0)
337 : return;
338 :
339 21106 : if (current_pass
340 21102 : && current_pass->static_pass_number != -1)
341 : {
342 21102 : counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
343 21102 : gcc_assert (!counter->histogram_p);
344 21102 : counter->count += incr;
345 : }
346 :
347 21106 : if (!statistics_dump_file
348 21106 : || !(statistics_dump_flags & TDF_DETAILS))
349 : return;
350 :
351 0 : fprintf (statistics_dump_file,
352 : "%d %s \"%s\" \"%s\" %d\n",
353 : current_pass ? current_pass->static_pass_number : -1,
354 0 : current_pass ? current_pass->name : "none",
355 : id,
356 : get_function_name (fn),
357 : incr);
358 : }
359 :
360 : /* Add statistics information about event ID in function FN with the
361 : histogram value VAL.
362 : It will dump the event to the global statistics file if requested. */
363 :
364 : void
365 76664670 : statistics_histogram_event (struct function *fn, const char *id, int val)
366 : {
367 76664670 : statistics_counter *counter;
368 :
369 76664670 : if (!(dump_flags & TDF_STATS)
370 76664670 : && !statistics_dump_file)
371 : return;
372 :
373 24060 : counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
374 24060 : gcc_assert (counter->histogram_p);
375 24060 : counter->count += 1;
376 :
377 24060 : if (!statistics_dump_file
378 24060 : || !(statistics_dump_flags & TDF_DETAILS))
379 : return;
380 :
381 0 : fprintf (statistics_dump_file,
382 : "%d %s \"%s == %d\" \"%s\" 1\n",
383 : current_pass->static_pass_number,
384 : current_pass->name,
385 : id, val,
386 : get_function_name (fn));
387 : }
|