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 343831 : stats_counter_hasher::hash (const statistics_counter *c)
59 : {
60 343831 : return htab_hash_string (c->id) + c->val;
61 : }
62 :
63 : /* Compare two statistic counters by their string IDs. */
64 :
65 : inline bool
66 345825 : stats_counter_hasher::equal (const statistics_counter *c1,
67 : const statistics_counter *c2)
68 : {
69 345825 : 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 582289108 : curr_statistics_hash (bool alloc = true)
92 : {
93 582289108 : unsigned idx;
94 :
95 582289108 : gcc_assert (current_pass->static_pass_number >= 0);
96 582289108 : idx = current_pass->static_pass_number;
97 :
98 582289108 : if (idx < nr_statistics_hashes
99 844102 : && statistics_hashes[idx])
100 : return statistics_hashes[idx];
101 :
102 582059153 : if (!alloc)
103 : return nullptr;
104 :
105 689 : if (idx >= nr_statistics_hashes)
106 : {
107 609 : statistics_hashes = XRESIZEVEC (stats_counter_table_type *,
108 : statistics_hashes, idx+1);
109 609 : memset (statistics_hashes + nr_statistics_hashes, 0,
110 609 : (idx + 1 - nr_statistics_hashes)
111 : * sizeof (stats_counter_table_type *));
112 609 : nr_statistics_hashes = idx + 1;
113 : }
114 :
115 689 : statistics_hashes[idx] = new stats_counter_table_type (15);
116 :
117 689 : 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 74479 : get_function_name (struct function *fn)
125 : {
126 74479 : if ((statistics_dump_flags & TDF_ASMNAME)
127 74479 : && 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 74479 : 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 2222 : statistics_fini_pass_1 (statistics_counter **slot,
141 : void *data ATTRIBUTE_UNUSED)
142 : {
143 2222 : statistics_counter *counter = *slot;
144 2222 : unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
145 2222 : if (count == 0)
146 : return 1;
147 1700 : if (counter->histogram_p)
148 671 : fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
149 : counter->id, counter->val, count);
150 : else
151 1029 : fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
152 : counter->id, count);
153 1700 : counter->prev_dumped_count = counter->count;
154 1700 : 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 1088301 : statistics_fini_pass_2 (statistics_counter **slot,
162 : void *data ATTRIBUTE_UNUSED)
163 : {
164 1088301 : statistics_counter *counter = *slot;
165 1088301 : unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
166 1088301 : if (count == 0)
167 : return 1;
168 74479 : counter->prev_dumped_count = counter->count;
169 74479 : if (counter->histogram_p)
170 38139 : 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 36340 : 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 74479 : counter->prev_dumped_count = counter->count;
186 74479 : return 1;
187 : }
188 :
189 : /* Helper for statistics_fini_pass, reset the counters. */
190 :
191 : int
192 1140040 : statistics_fini_pass_3 (statistics_counter **slot,
193 : void *data ATTRIBUTE_UNUSED)
194 : {
195 1140040 : statistics_counter *counter = *slot;
196 1140040 : counter->prev_dumped_count = counter->count;
197 1140040 : return 1;
198 : }
199 :
200 : /* Dump the current statistics incrementally. */
201 :
202 : void
203 641315261 : statistics_fini_pass (void)
204 : {
205 641315261 : if (current_pass->static_pass_number == -1)
206 : return;
207 :
208 582204781 : stats_counter_table_type *stat_hash = curr_statistics_hash (false);
209 :
210 582204781 : if (dump_file
211 582204781 : && 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 2788 : stat_hash->traverse_noresize <void *, statistics_fini_pass_1> (NULL);
218 1880 : fprintf (dump_file, "\n");
219 : }
220 :
221 582204781 : if (!stat_hash)
222 : return;
223 :
224 146317 : if (statistics_dump_file
225 146317 : && !(statistics_dump_flags & TDF_STATS
226 136668 : || statistics_dump_flags & TDF_DETAILS))
227 1224969 : stat_hash->traverse_noresize <void *, statistics_fini_pass_2> (NULL);
228 1286357 : 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 289376 : statistics_fini (void)
260 : {
261 289376 : gcc::pass_manager *passes = g->get_passes ();
262 289376 : if (!statistics_dump_file)
263 : return;
264 :
265 71 : 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 71 : dump_end (statistics_dump_nr, statistics_dump_file);
277 : }
278 :
279 : /* Register the statistics dump file. */
280 :
281 : void
282 298828 : statistics_early_init (void)
283 : {
284 298828 : gcc::dump_manager *dumps = g->get_dumps ();
285 298828 : statistics_dump_nr = dumps->dump_register (".statistics", "statistics",
286 : "statistics", DK_tree,
287 : OPTGROUP_NONE,
288 : false);
289 298828 : }
290 :
291 : /* Init the statistics. */
292 :
293 : void
294 291268 : statistics_init (void)
295 : {
296 291268 : gcc::dump_manager *dumps = g->get_dumps ();
297 291268 : statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
298 291268 : statistics_dump_flags = dumps->get_dump_file_info (statistics_dump_nr)->pflags;
299 291268 : }
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 84327 : lookup_or_add_counter (stats_counter_table_type *hash, const char *id, int val,
306 : bool histogram_p)
307 : {
308 84327 : statistics_counter **counter;
309 84327 : statistics_counter c;
310 84327 : c.id = id;
311 84327 : c.val = val;
312 84327 : counter = hash->find_slot (&c, INSERT);
313 84327 : if (!*counter)
314 : {
315 3355 : *counter = XNEW (statistics_counter);
316 3355 : (*counter)->id = xstrdup (id);
317 3355 : (*counter)->val = val;
318 3355 : (*counter)->histogram_p = histogram_p;
319 3355 : (*counter)->prev_dumped_count = 0;
320 3355 : (*counter)->count = 0;
321 : }
322 84327 : 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 229601002 : statistics_counter_event (struct function *fn, const char *id, int incr)
331 : {
332 229601002 : statistics_counter *counter;
333 :
334 229601002 : if ((!(dump_flags & TDF_STATS)
335 229599143 : && !statistics_dump_file)
336 229872662 : || incr == 0)
337 : return;
338 :
339 39242 : if (current_pass
340 39238 : && current_pass->static_pass_number != -1)
341 : {
342 39238 : counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
343 39238 : gcc_assert (!counter->histogram_p);
344 39238 : counter->count += incr;
345 : }
346 :
347 39242 : if (!statistics_dump_file
348 39242 : || !(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 76105982 : statistics_histogram_event (struct function *fn, const char *id, int val)
366 : {
367 76105982 : statistics_counter *counter;
368 :
369 76105982 : if (!(dump_flags & TDF_STATS)
370 76105982 : && !statistics_dump_file)
371 : return;
372 :
373 45089 : counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
374 45089 : gcc_assert (counter->histogram_p);
375 45089 : counter->count += 1;
376 :
377 45089 : if (!statistics_dump_file
378 45089 : || !(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 : }
|