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