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