1/* Optimization statistics functions.
2 Copyright (C) 2008-2017 Free Software Foundation, Inc.
3 Contributed by Richard Guenther <rguenther@suse.de>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
29static int statistics_dump_nr;
30static dump_flags_t statistics_dump_flags;
31static FILE *statistics_dump_file;
32
33/* Statistics entry. A integer counter associated to a string ID
34 and value. */
35
36struct statistics_counter {
37 const char *id;
38 int val;
39 bool histogram_p;
40 unsigned HOST_WIDE_INT count;
41 unsigned HOST_WIDE_INT prev_dumped_count;
42};
43
44/* Hashtable helpers. */
45
46struct stats_counter_hasher : pointer_hash <statistics_counter>
47{
48 static inline hashval_t hash (const statistics_counter *);
49 static inline bool equal (const statistics_counter *,
50 const statistics_counter *);
51 static inline void remove (statistics_counter *);
52};
53
54/* Hash a statistic counter by its string ID. */
55
56inline hashval_t
57stats_counter_hasher::hash (const statistics_counter *c)
58{
59 return htab_hash_string (c->id) + c->val;
60}
61
62/* Compare two statistic counters by their string IDs. */
63
64inline bool
65stats_counter_hasher::equal (const statistics_counter *c1,
66 const statistics_counter *c2)
67{
68 return c1->val == c2->val && strcmp (c1->id, c2->id) == 0;
69}
70
71/* Free a statistics entry. */
72
73inline void
74stats_counter_hasher::remove (statistics_counter *v)
75{
76 free (CONST_CAST (char *, v->id));
77 free (v);
78}
79
80typedef hash_table<stats_counter_hasher> stats_counter_table_type;
81
82/* Array of statistic hashes, indexed by pass id. */
83static stats_counter_table_type **statistics_hashes;
84static unsigned nr_statistics_hashes;
85
86/* Return the current hashtable to be used for recording or printing
87 statistics. */
88
89static stats_counter_table_type *
90curr_statistics_hash (void)
91{
92 unsigned idx;
93
94 gcc_assert (current_pass->static_pass_number >= 0);
95 idx = current_pass->static_pass_number;
96
97 if (idx < nr_statistics_hashes
98 && statistics_hashes[idx])
99 return statistics_hashes[idx];
100
101 if (idx >= nr_statistics_hashes)
102 {
103 statistics_hashes = XRESIZEVEC (stats_counter_table_type *,
104 statistics_hashes, idx+1);
105 memset (statistics_hashes + nr_statistics_hashes, 0,
106 (idx + 1 - nr_statistics_hashes)
107 * sizeof (stats_counter_table_type *));
108 nr_statistics_hashes = idx + 1;
109 }
110
111 statistics_hashes[idx] = new stats_counter_table_type (15);
112
113 return statistics_hashes[idx];
114}
115
116/* Helper for statistics_fini_pass. Print the counter difference
117 since the last dump for the pass dump files. */
118
119int
120statistics_fini_pass_1 (statistics_counter **slot,
121 void *data ATTRIBUTE_UNUSED)
122{
123 statistics_counter *counter = *slot;
124 unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
125 if (count == 0)
126 return 1;
127 if (counter->histogram_p)
128 fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
129 counter->id, counter->val, count);
130 else
131 fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
132 counter->id, count);
133 counter->prev_dumped_count = counter->count;
134 return 1;
135}
136
137/* Helper for statistics_fini_pass. Print the counter difference
138 since the last dump for the statistics dump. */
139
140int
141statistics_fini_pass_2 (statistics_counter **slot,
142 void *data ATTRIBUTE_UNUSED)
143{
144 statistics_counter *counter = *slot;
145 unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
146 if (count == 0)
147 return 1;
148 counter->prev_dumped_count = counter->count;
149 if (counter->histogram_p)
150 fprintf (statistics_dump_file,
151 "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
152 current_pass->static_pass_number,
153 current_pass->name,
154 counter->id, counter->val,
155 current_function_name (),
156 count);
157 else
158 fprintf (statistics_dump_file,
159 "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
160 current_pass->static_pass_number,
161 current_pass->name,
162 counter->id,
163 current_function_name (),
164 count);
165 counter->prev_dumped_count = counter->count;
166 return 1;
167}
168
169/* Helper for statistics_fini_pass, reset the counters. */
170
171int
172statistics_fini_pass_3 (statistics_counter **slot,
173 void *data ATTRIBUTE_UNUSED)
174{
175 statistics_counter *counter = *slot;
176 counter->prev_dumped_count = counter->count;
177 return 1;
178}
179
180/* Dump the current statistics incrementally. */
181
182void
183statistics_fini_pass (void)
184{
185 if (current_pass->static_pass_number == -1)
186 return;
187
188 if (dump_file
189 && dump_flags & TDF_STATS)
190 {
191 fprintf (dump_file, "\n");
192 fprintf (dump_file, "Pass statistics of \"%s\": ", current_pass->name);
193 fprintf (dump_file, "----------------\n");
194 curr_statistics_hash ()
195 ->traverse_noresize <void *, statistics_fini_pass_1> (NULL);
196 fprintf (dump_file, "\n");
197 }
198 if (statistics_dump_file
199 && !(statistics_dump_flags & TDF_STATS
200 || statistics_dump_flags & TDF_DETAILS))
201 curr_statistics_hash ()
202 ->traverse_noresize <void *, statistics_fini_pass_2> (NULL);
203 curr_statistics_hash ()
204 ->traverse_noresize <void *, statistics_fini_pass_3> (NULL);
205}
206
207/* Helper for printing summary information. */
208
209int
210statistics_fini_1 (statistics_counter **slot, opt_pass *pass)
211{
212 statistics_counter *counter = *slot;
213 if (counter->count == 0)
214 return 1;
215 if (counter->histogram_p)
216 fprintf (statistics_dump_file,
217 "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n",
218 pass->static_pass_number,
219 pass->name,
220 counter->id, counter->val,
221 counter->count);
222 else
223 fprintf (statistics_dump_file,
224 "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
225 pass->static_pass_number,
226 pass->name,
227 counter->id,
228 counter->count);
229 return 1;
230}
231
232/* Finish the statistics and dump summary information. */
233
234void
235statistics_fini (void)
236{
237 gcc::pass_manager *passes = g->get_passes ();
238 if (!statistics_dump_file)
239 return;
240
241 if (statistics_dump_flags & TDF_STATS)
242 {
243 unsigned i;
244 for (i = 0; i < nr_statistics_hashes; ++i)
245 if (statistics_hashes[i]
246 && passes->get_pass_for_id (i) != NULL)
247 statistics_hashes[i]
248 ->traverse_noresize <opt_pass *, statistics_fini_1>
249 (passes->get_pass_for_id (i));
250 }
251
252 dump_end (statistics_dump_nr, statistics_dump_file);
253}
254
255/* Register the statistics dump file. */
256
257void
258statistics_early_init (void)
259{
260 gcc::dump_manager *dumps = g->get_dumps ();
261 statistics_dump_nr = dumps->dump_register (".statistics", "statistics",
262 "statistics", DK_tree,
263 OPTGROUP_NONE,
264 false);
265}
266
267/* Init the statistics. */
268
269void
270statistics_init (void)
271{
272 gcc::dump_manager *dumps = g->get_dumps ();
273 statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
274 statistics_dump_flags = dumps->get_dump_file_info (statistics_dump_nr)->pflags;
275}
276
277/* Lookup or add a statistics counter in the hashtable HASH with ID, VAL
278 and HISTOGRAM_P. */
279
280static statistics_counter *
281lookup_or_add_counter (stats_counter_table_type *hash, const char *id, int val,
282 bool histogram_p)
283{
284 statistics_counter **counter;
285 statistics_counter c;
286 c.id = id;
287 c.val = val;
288 counter = hash->find_slot (&c, INSERT);
289 if (!*counter)
290 {
291 *counter = XNEW (statistics_counter);
292 (*counter)->id = xstrdup (id);
293 (*counter)->val = val;
294 (*counter)->histogram_p = histogram_p;
295 (*counter)->prev_dumped_count = 0;
296 (*counter)->count = 0;
297 }
298 return *counter;
299}
300
301/* Add statistics information about event ID in function FN.
302 This will increment the counter associated with ID by INCR.
303 It will also dump the event to the global statistics file if requested. */
304
305void
306statistics_counter_event (struct function *fn, const char *id, int incr)
307{
308 statistics_counter *counter;
309
310 if ((!(dump_flags & TDF_STATS)
311 && !statistics_dump_file)
312 || incr == 0)
313 return;
314
315 if (current_pass
316 && current_pass->static_pass_number != -1)
317 {
318 counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
319 gcc_assert (!counter->histogram_p);
320 counter->count += incr;
321 }
322
323 if (!statistics_dump_file
324 || !(statistics_dump_flags & TDF_DETAILS))
325 return;
326
327 fprintf (statistics_dump_file,
328 "%d %s \"%s\" \"%s\" %d\n",
329 current_pass ? current_pass->static_pass_number : -1,
330 current_pass ? current_pass->name : "none",
331 id,
332 function_name (fn),
333 incr);
334}
335
336/* Add statistics information about event ID in function FN with the
337 histogram value VAL.
338 It will dump the event to the global statistics file if requested. */
339
340void
341statistics_histogram_event (struct function *fn, const char *id, int val)
342{
343 statistics_counter *counter;
344
345 if (!(dump_flags & TDF_STATS)
346 && !statistics_dump_file)
347 return;
348
349 counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
350 gcc_assert (counter->histogram_p);
351 counter->count += 1;
352
353 if (!statistics_dump_file
354 || !(statistics_dump_flags & TDF_DETAILS))
355 return;
356
357 fprintf (statistics_dump_file,
358 "%d %s \"%s == %d\" \"%s\" 1\n",
359 current_pass->static_pass_number,
360 current_pass->name,
361 id, val,
362 function_name (fn));
363}
364