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