Branch data Line data Source code
1 : : /* Optimization statistics functions.
2 : : Copyright (C) 2008-2024 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 : 160681 : stats_counter_hasher::hash (const statistics_counter *c)
59 : : {
60 : 160681 : return htab_hash_string (c->id) + c->val;
61 : : }
62 : :
63 : : /* Compare two statistic counters by their string IDs. */
64 : :
65 : : inline bool
66 : 160249 : stats_counter_hasher::equal (const statistics_counter *c1,
67 : : const statistics_counter *c2)
68 : : {
69 : 160249 : 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 : 544317109 : curr_statistics_hash (bool alloc = true)
92 : : {
93 : 544317109 : unsigned idx;
94 : :
95 : 544317109 : gcc_assert (current_pass->static_pass_number >= 0);
96 : 544317109 : idx = current_pass->static_pass_number;
97 : :
98 : 544317109 : if (idx < nr_statistics_hashes
99 : 657102 : && statistics_hashes[idx])
100 : : return statistics_hashes[idx];
101 : :
102 : 544184628 : if (!alloc)
103 : : return nullptr;
104 : :
105 : 679 : if (idx >= nr_statistics_hashes)
106 : : {
107 : 610 : statistics_hashes = XRESIZEVEC (stats_counter_table_type *,
108 : : statistics_hashes, idx+1);
109 : 610 : memset (statistics_hashes + nr_statistics_hashes, 0,
110 : 610 : (idx + 1 - nr_statistics_hashes)
111 : : * sizeof (stats_counter_table_type *));
112 : 610 : nr_statistics_hashes = idx + 1;
113 : : }
114 : :
115 : 679 : statistics_hashes[idx] = new stats_counter_table_type (15);
116 : :
117 : 679 : 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 : 38293 : get_function_name (struct function *fn)
125 : : {
126 : 38293 : if ((statistics_dump_flags & TDF_ASMNAME)
127 : 38293 : && 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 : 38293 : 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 : 2211 : statistics_fini_pass_1 (statistics_counter **slot,
141 : : void *data ATTRIBUTE_UNUSED)
142 : : {
143 : 2211 : statistics_counter *counter = *slot;
144 : 2211 : unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
145 : 2211 : if (count == 0)
146 : : return 1;
147 : 1689 : if (counter->histogram_p)
148 : 666 : fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
149 : : counter->id, counter->val, count);
150 : : else
151 : 1023 : fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
152 : : counter->id, count);
153 : 1689 : counter->prev_dumped_count = counter->count;
154 : 1689 : 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 : 497221 : statistics_fini_pass_2 (statistics_counter **slot,
162 : : void *data ATTRIBUTE_UNUSED)
163 : : {
164 : 497221 : statistics_counter *counter = *slot;
165 : 497221 : unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
166 : 497221 : if (count == 0)
167 : : return 1;
168 : 38293 : counter->prev_dumped_count = counter->count;
169 : 38293 : if (counter->histogram_p)
170 : 19489 : 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 : 18804 : 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 : 38293 : counter->prev_dumped_count = counter->count;
186 : 38293 : return 1;
187 : : }
188 : :
189 : : /* Helper for statistics_fini_pass, reset the counters. */
190 : :
191 : : int
192 : 624103 : statistics_fini_pass_3 (statistics_counter **slot,
193 : : void *data ATTRIBUTE_UNUSED)
194 : : {
195 : 624103 : statistics_counter *counter = *slot;
196 : 624103 : counter->prev_dumped_count = counter->count;
197 : 624103 : return 1;
198 : : }
199 : :
200 : : /* Dump the current statistics incrementally. */
201 : :
202 : : void
203 : 599837680 : statistics_fini_pass (void)
204 : : {
205 : 599837680 : if (current_pass->static_pass_number == -1)
206 : : return;
207 : :
208 : 544272534 : stats_counter_table_type *stat_hash = curr_statistics_hash (false);
209 : :
210 : 544272534 : if (dump_file
211 : 544272534 : && dump_flags & TDF_STATS)
212 : : {
213 : 1798 : fprintf (dump_file, "\n");
214 : 1798 : fprintf (dump_file, "Pass statistics of \"%s\": ", current_pass->name);
215 : 1798 : fprintf (dump_file, "----------------\n");
216 : 1798 : if (stat_hash)
217 : 2772 : stat_hash->traverse_noresize <void *, statistics_fini_pass_1> (NULL);
218 : 1798 : fprintf (dump_file, "\n");
219 : : }
220 : :
221 : 544272534 : if (!stat_hash)
222 : : return;
223 : :
224 : 88585 : if (statistics_dump_file
225 : 88585 : && !(statistics_dump_flags & TDF_STATS
226 : 65229 : || statistics_dump_flags & TDF_DETAILS))
227 : 562450 : stat_hash->traverse_noresize <void *, statistics_fini_pass_2> (NULL);
228 : 712688 : 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 : 269314 : statistics_fini (void)
260 : : {
261 : 269314 : gcc::pass_manager *passes = g->get_passes ();
262 : 269314 : if (!statistics_dump_file)
263 : : return;
264 : :
265 : 63 : if (statistics_dump_flags & TDF_STATS)
266 : : {
267 : : unsigned i;
268 : 312 : for (i = 0; i < nr_statistics_hashes; ++i)
269 : 309 : if (statistics_hashes[i]
270 : 309 : && 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 : 63 : dump_end (statistics_dump_nr, statistics_dump_file);
277 : : }
278 : :
279 : : /* Register the statistics dump file. */
280 : :
281 : : void
282 : 277256 : statistics_early_init (void)
283 : : {
284 : 277256 : gcc::dump_manager *dumps = g->get_dumps ();
285 : 277256 : statistics_dump_nr = dumps->dump_register (".statistics", "statistics",
286 : : "statistics", DK_tree,
287 : : OPTGROUP_NONE,
288 : : false);
289 : 277256 : }
290 : :
291 : : /* Init the statistics. */
292 : :
293 : : void
294 : 270959 : statistics_init (void)
295 : : {
296 : 270959 : gcc::dump_manager *dumps = g->get_dumps ();
297 : 270959 : statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
298 : 270959 : statistics_dump_flags = dumps->get_dump_file_info (statistics_dump_nr)->pflags;
299 : 270959 : }
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 : 44575 : lookup_or_add_counter (stats_counter_table_type *hash, const char *id, int val,
306 : : bool histogram_p)
307 : : {
308 : 44575 : statistics_counter **counter;
309 : 44575 : statistics_counter c;
310 : 44575 : c.id = id;
311 : 44575 : c.val = val;
312 : 44575 : counter = hash->find_slot (&c, INSERT);
313 : 44575 : if (!*counter)
314 : : {
315 : 3341 : *counter = XNEW (statistics_counter);
316 : 3341 : (*counter)->id = xstrdup (id);
317 : 3341 : (*counter)->val = val;
318 : 3341 : (*counter)->histogram_p = histogram_p;
319 : 3341 : (*counter)->prev_dumped_count = 0;
320 : 3341 : (*counter)->count = 0;
321 : : }
322 : 44575 : 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 : 211865198 : statistics_counter_event (struct function *fn, const char *id, int incr)
331 : : {
332 : 211865198 : statistics_counter *counter;
333 : :
334 : 211865198 : if ((!(dump_flags & TDF_STATS)
335 : 211863359 : && !statistics_dump_file)
336 : 212001457 : || incr == 0)
337 : : return;
338 : :
339 : 20880 : if (current_pass
340 : 20876 : && current_pass->static_pass_number != -1)
341 : : {
342 : 20876 : counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
343 : 20876 : gcc_assert (!counter->histogram_p);
344 : 20876 : counter->count += incr;
345 : : }
346 : :
347 : 20880 : if (!statistics_dump_file
348 : 20880 : || !(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 : 71451663 : statistics_histogram_event (struct function *fn, const char *id, int val)
366 : : {
367 : 71451663 : statistics_counter *counter;
368 : :
369 : 71451663 : if (!(dump_flags & TDF_STATS)
370 : 71451663 : && !statistics_dump_file)
371 : : return;
372 : :
373 : 23699 : counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
374 : 23699 : gcc_assert (counter->histogram_p);
375 : 23699 : counter->count += 1;
376 : :
377 : 23699 : if (!statistics_dump_file
378 : 23699 : || !(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 : : }
|