diff options
Diffstat (limited to 'gcc/statistics.cc')
-rw-r--r-- | gcc/statistics.cc | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/gcc/statistics.cc b/gcc/statistics.cc new file mode 100644 index 0000000..0d596e3 --- /dev/null +++ b/gcc/statistics.cc @@ -0,0 +1,363 @@ +/* Optimization statistics functions. + Copyright (C) 2008-2022 Free Software Foundation, Inc. + Contributed by Richard Guenther <rguenther@suse.de> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "function.h" +#include "tree-pass.h" +#include "context.h" +#include "pass_manager.h" + +static int statistics_dump_nr; +static dump_flags_t statistics_dump_flags; +static FILE *statistics_dump_file; + +/* Statistics entry. A integer counter associated to a string ID + and value. */ + +struct statistics_counter { + const char *id; + int val; + bool histogram_p; + unsigned HOST_WIDE_INT count; + unsigned HOST_WIDE_INT prev_dumped_count; +}; + +/* Hashtable helpers. */ + +struct stats_counter_hasher : pointer_hash <statistics_counter> +{ + static inline hashval_t hash (const statistics_counter *); + static inline bool equal (const statistics_counter *, + const statistics_counter *); + static inline void remove (statistics_counter *); +}; + +/* Hash a statistic counter by its string ID. */ + +inline hashval_t +stats_counter_hasher::hash (const statistics_counter *c) +{ + return htab_hash_string (c->id) + c->val; +} + +/* Compare two statistic counters by their string IDs. */ + +inline bool +stats_counter_hasher::equal (const statistics_counter *c1, + const statistics_counter *c2) +{ + return c1->val == c2->val && strcmp (c1->id, c2->id) == 0; +} + +/* Free a statistics entry. */ + +inline void +stats_counter_hasher::remove (statistics_counter *v) +{ + free (CONST_CAST (char *, v->id)); + free (v); +} + +typedef hash_table<stats_counter_hasher> stats_counter_table_type; + +/* Array of statistic hashes, indexed by pass id. */ +static stats_counter_table_type **statistics_hashes; +static unsigned nr_statistics_hashes; + +/* Return the current hashtable to be used for recording or printing + statistics. */ + +static stats_counter_table_type * +curr_statistics_hash (void) +{ + unsigned idx; + + gcc_assert (current_pass->static_pass_number >= 0); + idx = current_pass->static_pass_number; + + if (idx < nr_statistics_hashes + && statistics_hashes[idx]) + return statistics_hashes[idx]; + + if (idx >= nr_statistics_hashes) + { + statistics_hashes = XRESIZEVEC (stats_counter_table_type *, + statistics_hashes, idx+1); + memset (statistics_hashes + nr_statistics_hashes, 0, + (idx + 1 - nr_statistics_hashes) + * sizeof (stats_counter_table_type *)); + nr_statistics_hashes = idx + 1; + } + + statistics_hashes[idx] = new stats_counter_table_type (15); + + return statistics_hashes[idx]; +} + +/* Helper for statistics_fini_pass. Print the counter difference + since the last dump for the pass dump files. */ + +int +statistics_fini_pass_1 (statistics_counter **slot, + void *data ATTRIBUTE_UNUSED) +{ + statistics_counter *counter = *slot; + unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count; + if (count == 0) + return 1; + if (counter->histogram_p) + fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n", + counter->id, counter->val, count); + else + fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n", + counter->id, count); + counter->prev_dumped_count = counter->count; + return 1; +} + +/* Helper for statistics_fini_pass. Print the counter difference + since the last dump for the statistics dump. */ + +int +statistics_fini_pass_2 (statistics_counter **slot, + void *data ATTRIBUTE_UNUSED) +{ + statistics_counter *counter = *slot; + unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count; + if (count == 0) + return 1; + counter->prev_dumped_count = counter->count; + if (counter->histogram_p) + fprintf (statistics_dump_file, + "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n", + current_pass->static_pass_number, + current_pass->name, + counter->id, counter->val, + current_function_name (), + count); + else + fprintf (statistics_dump_file, + "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n", + current_pass->static_pass_number, + current_pass->name, + counter->id, + current_function_name (), + count); + counter->prev_dumped_count = counter->count; + return 1; +} + +/* Helper for statistics_fini_pass, reset the counters. */ + +int +statistics_fini_pass_3 (statistics_counter **slot, + void *data ATTRIBUTE_UNUSED) +{ + statistics_counter *counter = *slot; + counter->prev_dumped_count = counter->count; + return 1; +} + +/* Dump the current statistics incrementally. */ + +void +statistics_fini_pass (void) +{ + if (current_pass->static_pass_number == -1) + return; + + if (dump_file + && dump_flags & TDF_STATS) + { + fprintf (dump_file, "\n"); + fprintf (dump_file, "Pass statistics of \"%s\": ", current_pass->name); + fprintf (dump_file, "----------------\n"); + curr_statistics_hash () + ->traverse_noresize <void *, statistics_fini_pass_1> (NULL); + fprintf (dump_file, "\n"); + } + if (statistics_dump_file + && !(statistics_dump_flags & TDF_STATS + || statistics_dump_flags & TDF_DETAILS)) + curr_statistics_hash () + ->traverse_noresize <void *, statistics_fini_pass_2> (NULL); + curr_statistics_hash () + ->traverse_noresize <void *, statistics_fini_pass_3> (NULL); +} + +/* Helper for printing summary information. */ + +int +statistics_fini_1 (statistics_counter **slot, opt_pass *pass) +{ + statistics_counter *counter = *slot; + if (counter->count == 0) + return 1; + if (counter->histogram_p) + fprintf (statistics_dump_file, + "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n", + pass->static_pass_number, + pass->name, + counter->id, counter->val, + counter->count); + else + fprintf (statistics_dump_file, + "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n", + pass->static_pass_number, + pass->name, + counter->id, + counter->count); + return 1; +} + +/* Finish the statistics and dump summary information. */ + +void +statistics_fini (void) +{ + gcc::pass_manager *passes = g->get_passes (); + if (!statistics_dump_file) + return; + + if (statistics_dump_flags & TDF_STATS) + { + unsigned i; + for (i = 0; i < nr_statistics_hashes; ++i) + if (statistics_hashes[i] + && passes->get_pass_for_id (i) != NULL) + statistics_hashes[i] + ->traverse_noresize <opt_pass *, statistics_fini_1> + (passes->get_pass_for_id (i)); + } + + dump_end (statistics_dump_nr, statistics_dump_file); +} + +/* Register the statistics dump file. */ + +void +statistics_early_init (void) +{ + gcc::dump_manager *dumps = g->get_dumps (); + statistics_dump_nr = dumps->dump_register (".statistics", "statistics", + "statistics", DK_tree, + OPTGROUP_NONE, + false); +} + +/* Init the statistics. */ + +void +statistics_init (void) +{ + gcc::dump_manager *dumps = g->get_dumps (); + statistics_dump_file = dump_begin (statistics_dump_nr, NULL); + statistics_dump_flags = dumps->get_dump_file_info (statistics_dump_nr)->pflags; +} + +/* Lookup or add a statistics counter in the hashtable HASH with ID, VAL + and HISTOGRAM_P. */ + +static statistics_counter * +lookup_or_add_counter (stats_counter_table_type *hash, const char *id, int val, + bool histogram_p) +{ + statistics_counter **counter; + statistics_counter c; + c.id = id; + c.val = val; + counter = hash->find_slot (&c, INSERT); + if (!*counter) + { + *counter = XNEW (statistics_counter); + (*counter)->id = xstrdup (id); + (*counter)->val = val; + (*counter)->histogram_p = histogram_p; + (*counter)->prev_dumped_count = 0; + (*counter)->count = 0; + } + return *counter; +} + +/* Add statistics information about event ID in function FN. + This will increment the counter associated with ID by INCR. + It will also dump the event to the global statistics file if requested. */ + +void +statistics_counter_event (struct function *fn, const char *id, int incr) +{ + statistics_counter *counter; + + if ((!(dump_flags & TDF_STATS) + && !statistics_dump_file) + || incr == 0) + return; + + if (current_pass + && current_pass->static_pass_number != -1) + { + counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false); + gcc_assert (!counter->histogram_p); + counter->count += incr; + } + + if (!statistics_dump_file + || !(statistics_dump_flags & TDF_DETAILS)) + return; + + fprintf (statistics_dump_file, + "%d %s \"%s\" \"%s\" %d\n", + current_pass ? current_pass->static_pass_number : -1, + current_pass ? current_pass->name : "none", + id, + function_name (fn), + incr); +} + +/* Add statistics information about event ID in function FN with the + histogram value VAL. + It will dump the event to the global statistics file if requested. */ + +void +statistics_histogram_event (struct function *fn, const char *id, int val) +{ + statistics_counter *counter; + + if (!(dump_flags & TDF_STATS) + && !statistics_dump_file) + return; + + counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true); + gcc_assert (counter->histogram_p); + counter->count += 1; + + if (!statistics_dump_file + || !(statistics_dump_flags & TDF_DETAILS)) + return; + + fprintf (statistics_dump_file, + "%d %s \"%s == %d\" \"%s\" 1\n", + current_pass->static_pass_number, + current_pass->name, + id, val, + function_name (fn)); +} |