diff options
author | Jan Hubicka <jh@suse.cz> | 2013-09-01 19:47:21 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2013-09-01 17:47:21 +0000 |
commit | 08f835dc74bccf078cb1cad4f3e20dda6d457d74 (patch) | |
tree | e2e4f83196fb64438ea666e999658cda183b0cf5 /gcc/ipa.c | |
parent | 0adad9c5b470715ead5e012b9114cc87198531fd (diff) | |
download | gcc-08f835dc74bccf078cb1cad4f3e20dda6d457d74.zip gcc-08f835dc74bccf078cb1cad4f3e20dda6d457d74.tar.gz gcc-08f835dc74bccf078cb1cad4f3e20dda6d457d74.tar.bz2 |
Makefile.in: Add ipa-profile.o
* Makefile.in: Add ipa-profile.o
(ipa.o, ipa-devrit.o, ipa-inline-analysis.o): Adjust dependencies.
* cgraph.c (struct cgraph_propagate_frequency_data,
cgraph_propagate_frequency_1, cgraph_propagate_frequency): Move to
ipa-profile.c; replace cgraph_ by ipa_ prefix.
* cgraph.h (cgraph_propagate_frequency): Remove.
* ipa-inline-analysis.c: Include ipa-utils.h; drop duplicated cfgloop.h.
(inline_update_callee_summaries): Update.
* ipa-profile.c: New file.
* ipa-utils.h (ipa_propagate_frequency): Declare.
* ipa.c: Do not include pointer-set.h, hash-table.h, lto-streamer.h,
data-streamer.h, value-prof.h
(symtab_remove_unreachable_nodes): Update profile.
(struct histogram_entry, histogram, histogram_pool, histogram_hash,
account_time_size, cmp_counts, dump_histogram,
ipa_profile_generate_summary, ipa_profile_write_summary,
ipa_profile_read_summary, ipa_profile, gate_ipa_profile,
pass_data_ipa_profile, pass_ipa_profile, make_pass_ipa_profile):
Move to ipa-profile.c
From-SVN: r202154
Diffstat (limited to 'gcc/ipa.c')
-rw-r--r-- | gcc/ipa.c | 508 |
1 files changed, 1 insertions, 507 deletions
@@ -30,15 +30,10 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "tree-iterator.h" #include "ipa-utils.h" -#include "pointer-set.h" #include "ipa-inline.h" -#include "hash-table.h" #include "tree-inline.h" #include "profile.h" #include "params.h" -#include "lto-streamer.h" -#include "data-streamer.h" -#include "value-prof.h" /* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ @@ -484,7 +479,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) /* If we removed something, perhaps profile could be improved. */ if (changed && optimize && inline_edge_summary_vec.exists ()) FOR_EACH_DEFINED_FUNCTION (node) - cgraph_propagate_frequency (node); + ipa_propagate_frequency (node); return changed; } @@ -1168,507 +1163,6 @@ make_pass_ipa_whole_program_visibility (gcc::context *ctxt) return new pass_ipa_whole_program_visibility (ctxt); } -/* Entry in the histogram. */ - -struct histogram_entry -{ - gcov_type count; - int time; - int size; -}; - -/* Histogram of profile values. - The histogram is represented as an ordered vector of entries allocated via - histogram_pool. During construction a separate hashtable is kept to lookup - duplicate entries. */ - -vec<histogram_entry *> histogram; -static alloc_pool histogram_pool; - -/* Hashtable support for storing SSA names hashed by their SSA_NAME_VAR. */ - -struct histogram_hash : typed_noop_remove <histogram_entry> -{ - typedef histogram_entry value_type; - typedef histogram_entry compare_type; - static inline hashval_t hash (const value_type *); - static inline int equal (const value_type *, const compare_type *); -}; - -inline hashval_t -histogram_hash::hash (const histogram_entry *val) -{ - return val->count; -} - -inline int -histogram_hash::equal (const histogram_entry *val, const histogram_entry *val2) -{ - return val->count == val2->count; -} - -/* Account TIME and SIZE executed COUNT times into HISTOGRAM. - HASHTABLE is the on-side hash kept to avoid duplicates. */ - -static void -account_time_size (hash_table <histogram_hash> hashtable, - vec<histogram_entry *> &histogram, - gcov_type count, int time, int size) -{ - histogram_entry key = {count, 0, 0}; - histogram_entry **val = hashtable.find_slot (&key, INSERT); - - if (!*val) - { - *val = (histogram_entry *) pool_alloc (histogram_pool); - **val = key; - histogram.safe_push (*val); - } - (*val)->time += time; - (*val)->size += size; -} - -int -cmp_counts (const void *v1, const void *v2) -{ - const histogram_entry *h1 = *(const histogram_entry * const *)v1; - const histogram_entry *h2 = *(const histogram_entry * const *)v2; - if (h1->count < h2->count) - return 1; - if (h1->count > h2->count) - return -1; - return 0; -} - -/* Dump HISTOGRAM to FILE. */ - -static void -dump_histogram (FILE *file, vec<histogram_entry *> histogram) -{ - unsigned int i; - gcov_type overall_time = 0, cumulated_time = 0, cumulated_size = 0, overall_size = 0; - - fprintf (dump_file, "Histogram:\n"); - for (i = 0; i < histogram.length (); i++) - { - overall_time += histogram[i]->count * histogram[i]->time; - overall_size += histogram[i]->size; - } - if (!overall_time) - overall_time = 1; - if (!overall_size) - overall_size = 1; - for (i = 0; i < histogram.length (); i++) - { - cumulated_time += histogram[i]->count * histogram[i]->time; - cumulated_size += histogram[i]->size; - fprintf (file, " "HOST_WIDEST_INT_PRINT_DEC": time:%i (%2.2f) size:%i (%2.2f)\n", - (HOST_WIDEST_INT) histogram[i]->count, - histogram[i]->time, - cumulated_time * 100.0 / overall_time, - histogram[i]->size, - cumulated_size * 100.0 / overall_size); - } -} - -/* Collect histogram from CFG profiles. */ - -static void -ipa_profile_generate_summary (void) -{ - struct cgraph_node *node; - gimple_stmt_iterator gsi; - hash_table <histogram_hash> hashtable; - basic_block bb; - - hashtable.create (10); - histogram_pool = create_alloc_pool ("IPA histogram", sizeof (struct histogram_entry), - 10); - - FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) - FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->symbol.decl)) - { - int time = 0; - int size = 0; - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple stmt = gsi_stmt (gsi); - if (gimple_code (stmt) == GIMPLE_CALL - && !gimple_call_fndecl (stmt)) - { - histogram_value h; - h = gimple_histogram_value_of_type - (DECL_STRUCT_FUNCTION (node->symbol.decl), - stmt, HIST_TYPE_INDIR_CALL); - /* No need to do sanity check: gimple_ic_transform already - takes away bad histograms. */ - if (h) - { - /* counter 0 is target, counter 1 is number of execution we called target, - counter 2 is total number of executions. */ - if (h->hvalue.counters[2]) - { - struct cgraph_edge * e = cgraph_edge (node, stmt); - e->indirect_info->common_target_id - = h->hvalue.counters [0]; - e->indirect_info->common_target_probability - = GCOV_COMPUTE_SCALE (h->hvalue.counters [1], h->hvalue.counters [2]); - if (e->indirect_info->common_target_probability > REG_BR_PROB_BASE) - { - if (dump_file) - fprintf (dump_file, "Probability capped to 1\n"); - e->indirect_info->common_target_probability = REG_BR_PROB_BASE; - } - } - gimple_remove_histogram_value (DECL_STRUCT_FUNCTION (node->symbol.decl), - stmt, h); - } - } - time += estimate_num_insns (stmt, &eni_time_weights); - size += estimate_num_insns (stmt, &eni_size_weights); - } - account_time_size (hashtable, histogram, bb->count, time, size); - } - hashtable.dispose (); - histogram.qsort (cmp_counts); -} - -/* Serialize the ipa info for lto. */ - -static void -ipa_profile_write_summary (void) -{ - struct lto_simple_output_block *ob - = lto_create_simple_output_block (LTO_section_ipa_profile); - unsigned int i; - - streamer_write_uhwi_stream (ob->main_stream, histogram.length()); - for (i = 0; i < histogram.length (); i++) - { - streamer_write_gcov_count_stream (ob->main_stream, histogram[i]->count); - streamer_write_uhwi_stream (ob->main_stream, histogram[i]->time); - streamer_write_uhwi_stream (ob->main_stream, histogram[i]->size); - } - lto_destroy_simple_output_block (ob); -} - -/* Deserialize the ipa info for lto. */ - -static void -ipa_profile_read_summary (void) -{ - struct lto_file_decl_data ** file_data_vec - = lto_get_file_decl_data (); - struct lto_file_decl_data * file_data; - hash_table <histogram_hash> hashtable; - int j = 0; - - hashtable.create (10); - histogram_pool = create_alloc_pool ("IPA histogram", sizeof (struct histogram_entry), - 10); - - while ((file_data = file_data_vec[j++])) - { - const char *data; - size_t len; - struct lto_input_block *ib - = lto_create_simple_input_block (file_data, - LTO_section_ipa_profile, - &data, &len); - if (ib) - { - unsigned int num = streamer_read_uhwi (ib); - unsigned int n; - for (n = 0; n < num; n++) - { - gcov_type count = streamer_read_gcov_count (ib); - int time = streamer_read_uhwi (ib); - int size = streamer_read_uhwi (ib); - account_time_size (hashtable, histogram, - count, time, size); - } - lto_destroy_simple_input_block (file_data, - LTO_section_ipa_profile, - ib, data, len); - } - } - hashtable.dispose (); - histogram.qsort (cmp_counts); -} - -/* Simple ipa profile pass propagating frequencies across the callgraph. */ - -static unsigned int -ipa_profile (void) -{ - struct cgraph_node **order; - struct cgraph_edge *e; - int order_pos; - bool something_changed = false; - int i; - gcov_type overall_time = 0, cutoff = 0, cumulated = 0, overall_size = 0; - struct cgraph_node *n,*n2; - int nindirect = 0, ncommon = 0, nunknown = 0, nuseless = 0, nconverted = 0; - bool node_map_initialized = false; - - if (dump_file) - dump_histogram (dump_file, histogram); - for (i = 0; i < (int)histogram.length (); i++) - { - overall_time += histogram[i]->count * histogram[i]->time; - overall_size += histogram[i]->size; - } - if (overall_time) - { - gcov_type threshold; - - gcc_assert (overall_size); - if (dump_file) - { - gcov_type min, cumulated_time = 0, cumulated_size = 0; - - fprintf (dump_file, "Overall time: "HOST_WIDEST_INT_PRINT_DEC"\n", - (HOST_WIDEST_INT)overall_time); - min = get_hot_bb_threshold (); - for (i = 0; i < (int)histogram.length () && histogram[i]->count >= min; - i++) - { - cumulated_time += histogram[i]->count * histogram[i]->time; - cumulated_size += histogram[i]->size; - } - fprintf (dump_file, "GCOV min count: "HOST_WIDEST_INT_PRINT_DEC - " Time:%3.2f%% Size:%3.2f%%\n", - (HOST_WIDEST_INT)min, - cumulated_time * 100.0 / overall_time, - cumulated_size * 100.0 / overall_size); - } - cutoff = (overall_time * PARAM_VALUE (HOT_BB_COUNT_WS_PERMILLE) + 500) / 1000; - threshold = 0; - for (i = 0; cumulated < cutoff; i++) - { - cumulated += histogram[i]->count * histogram[i]->time; - threshold = histogram[i]->count; - } - if (!threshold) - threshold = 1; - if (dump_file) - { - gcov_type cumulated_time = 0, cumulated_size = 0; - - for (i = 0; - i < (int)histogram.length () && histogram[i]->count >= threshold; - i++) - { - cumulated_time += histogram[i]->count * histogram[i]->time; - cumulated_size += histogram[i]->size; - } - fprintf (dump_file, "Determined min count: "HOST_WIDEST_INT_PRINT_DEC - " Time:%3.2f%% Size:%3.2f%%\n", - (HOST_WIDEST_INT)threshold, - cumulated_time * 100.0 / overall_time, - cumulated_size * 100.0 / overall_size); - } - if (threshold > get_hot_bb_threshold () - || in_lto_p) - { - if (dump_file) - fprintf (dump_file, "Threshold updated.\n"); - set_hot_bb_threshold (threshold); - } - } - histogram.release(); - free_alloc_pool (histogram_pool); - - /* Produce speculative calls: we saved common traget from porfiling into - e->common_target_id. Now, at link time, we can look up corresponding - function node and produce speculative call. */ - - FOR_EACH_DEFINED_FUNCTION (n) - { - bool update = false; - - for (e = n->indirect_calls; e; e = e->next_callee) - { - if (n->count) - nindirect++; - if (e->indirect_info->common_target_id) - { - if (!node_map_initialized) - init_node_map (false); - node_map_initialized = true; - ncommon++; - n2 = find_func_by_profile_id (e->indirect_info->common_target_id); - if (n2) - { - if (dump_file) - { - fprintf (dump_file, "Indirect call -> direct call from" - " other module %s/%i => %s/%i, prob %3.2f\n", - xstrdup (cgraph_node_name (n)), n->symbol.order, - xstrdup (cgraph_node_name (n2)), n2->symbol.order, - e->indirect_info->common_target_probability - / (float)REG_BR_PROB_BASE); - } - if (e->indirect_info->common_target_probability - < REG_BR_PROB_BASE / 2) - { - nuseless++; - if (dump_file) - fprintf (dump_file, - "Not speculating: probability is too low.\n"); - } - else if (!cgraph_maybe_hot_edge_p (e)) - { - nuseless++; - if (dump_file) - fprintf (dump_file, - "Not speculating: call is cold.\n"); - } - else if (cgraph_function_body_availability (n2) - <= AVAIL_OVERWRITABLE - && symtab_can_be_discarded ((symtab_node) n2)) - { - nuseless++; - if (dump_file) - fprintf (dump_file, - "Not speculating: target is overwritable " - "and can be discarded.\n"); - } - else - { - /* Target may be overwritable, but profile says that - control flow goes to this particular implementation - of N2. Speculate on the local alias to allow inlining. - */ - if (!symtab_can_be_discarded ((symtab_node) n2)) - n2 = cgraph (symtab_nonoverwritable_alias ((symtab_node)n2)); - nconverted++; - cgraph_turn_edge_to_speculative - (e, n2, - apply_scale (e->count, - e->indirect_info->common_target_probability), - apply_scale (e->frequency, - e->indirect_info->common_target_probability)); - update = true; - } - } - else - { - if (dump_file) - fprintf (dump_file, "Function with profile-id %i not found.\n", - e->indirect_info->common_target_id); - nunknown++; - } - } - } - if (update) - inline_update_overall_summary (n); - } - if (node_map_initialized) - del_node_map (); - if (dump_file && nindirect) - fprintf (dump_file, - "%i indirect calls trained.\n" - "%i (%3.2f%%) have common target.\n" - "%i (%3.2f%%) targets was not found.\n" - "%i (%3.2f%%) speculations seems useless.\n" - "%i (%3.2f%%) speculations produced.\n", - nindirect, - ncommon, ncommon * 100.0 / nindirect, - nunknown, nunknown * 100.0 / nindirect, - nuseless, nuseless * 100.0 / nindirect, - nconverted, nconverted * 100.0 / nindirect); - - order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); - order_pos = ipa_reverse_postorder (order); - for (i = order_pos - 1; i >= 0; i--) - { - if (order[i]->local.local && cgraph_propagate_frequency (order[i])) - { - for (e = order[i]->callees; e; e = e->next_callee) - if (e->callee->local.local && !e->callee->symbol.aux) - { - something_changed = true; - e->callee->symbol.aux = (void *)1; - } - } - order[i]->symbol.aux = NULL; - } - - while (something_changed) - { - something_changed = false; - for (i = order_pos - 1; i >= 0; i--) - { - if (order[i]->symbol.aux && cgraph_propagate_frequency (order[i])) - { - for (e = order[i]->callees; e; e = e->next_callee) - if (e->callee->local.local && !e->callee->symbol.aux) - { - something_changed = true; - e->callee->symbol.aux = (void *)1; - } - } - order[i]->symbol.aux = NULL; - } - } - free (order); - return 0; -} - -static bool -gate_ipa_profile (void) -{ - return flag_ipa_profile; -} - -namespace { - -const pass_data pass_data_ipa_profile = -{ - IPA_PASS, /* type */ - "profile_estimate", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - true, /* has_execute */ - TV_IPA_PROFILE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_ipa_profile : public ipa_opt_pass_d -{ -public: - pass_ipa_profile(gcc::context *ctxt) - : ipa_opt_pass_d(pass_data_ipa_profile, ctxt, - ipa_profile_generate_summary, /* generate_summary */ - ipa_profile_write_summary, /* write_summary */ - ipa_profile_read_summary, /* read_summary */ - NULL, /* write_optimization_summary */ - NULL, /* read_optimization_summary */ - NULL, /* stmt_fixup */ - 0, /* function_transform_todo_flags_start */ - NULL, /* function_transform */ - NULL) /* variable_transform */ - {} - - /* opt_pass methods: */ - bool gate () { return gate_ipa_profile (); } - unsigned int execute () { return ipa_profile (); } - -}; // class pass_ipa_profile - -} // anon namespace - -ipa_opt_pass_d * -make_pass_ipa_profile (gcc::context *ctxt) -{ - return new pass_ipa_profile (ctxt); -} - /* Generate and emit a static constructor or destructor. WHICH must be one of 'I' (for a constructor) or 'D' (for a destructor). BODY is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the |