Mercurial > hg > CbC > CbC_gcc
diff gcc/profile.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/profile.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/profile.c Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ /* Calculate branch probabilities, and basic block execution counts. - Copyright (C) 1990-2017 Free Software Foundation, Inc. + Copyright (C) 1990-2018 Free Software Foundation, Inc. Contributed by James E. Wilson, UC Berkeley/Cygnus Support; based on some ideas from Dain Samples of UC Berkeley. Further mangling by Bob Manson, Cygnus Support. @@ -84,11 +84,7 @@ /* Counter summary from the last set of coverage counts read. */ -const struct gcov_ctr_summary *profile_info; - -/* Counter working set information computed from the current counter - summary. Not initialized unless profile_info summary is non-NULL. */ -static gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS]; +gcov_summary *profile_info; /* Collect statistics on the performance of this pass for the entire source file. */ @@ -103,14 +99,6 @@ static int total_hist_br_prob[20]; static int total_num_branches; -/* Helper function to update gcov_working_sets. */ - -void add_working_set (gcov_working_set_t *set) { - int i = 0; - for (; i < NUM_GCOV_WORKING_SETS; i++) - gcov_working_sets[i] = set[i]; -} - /* Forward declarations. */ static void find_spanning_tree (struct edge_list *); @@ -207,60 +195,6 @@ } -/* Fill the working set information into the profile_info structure. */ - -void -get_working_sets (void) -{ - unsigned ws_ix, pctinc, pct; - gcov_working_set_t *ws_info; - - if (!profile_info) - return; - - compute_working_sets (profile_info, gcov_working_sets); - - if (dump_file) - { - fprintf (dump_file, "Counter working sets:\n"); - /* Multiply the percentage by 100 to avoid float. */ - pctinc = 100 * 100 / NUM_GCOV_WORKING_SETS; - for (ws_ix = 0, pct = pctinc; ws_ix < NUM_GCOV_WORKING_SETS; - ws_ix++, pct += pctinc) - { - if (ws_ix == NUM_GCOV_WORKING_SETS - 1) - pct = 9990; - ws_info = &gcov_working_sets[ws_ix]; - /* Print out the percentage using int arithmatic to avoid float. */ - fprintf (dump_file, "\t\t%u.%02u%%: num counts=%u, min counter=" - "%" PRId64 "\n", - pct / 100, pct - (pct / 100 * 100), - ws_info->num_counters, - (int64_t)ws_info->min_counter); - } - } -} - -/* Given a the desired percentage of the full profile (sum_all from the - summary), multiplied by 10 to avoid float in PCT_TIMES_10, returns - the corresponding working set information. If an exact match for - the percentage isn't found, the closest value is used. */ - -gcov_working_set_t * -find_working_set (unsigned pct_times_10) -{ - unsigned i; - if (!profile_info) - return NULL; - gcc_assert (pct_times_10 <= 1000); - if (pct_times_10 >= 999) - return &gcov_working_sets[NUM_GCOV_WORKING_SETS - 1]; - i = pct_times_10 * NUM_GCOV_WORKING_SETS / 1000; - if (!i) - return &gcov_working_sets[0]; - return &gcov_working_sets[i - 1]; -} - /* Computes hybrid profile for all matching entries in da_file. CFG_CHECKSUM is the precomputed checksum for the CFG. */ @@ -283,21 +217,14 @@ num_edges++; } - counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum, - lineno_checksum, &profile_info); + counts = get_coverage_counts (GCOV_COUNTER_ARCS, cfg_checksum, + lineno_checksum); if (!counts) return NULL; - get_working_sets (); - - if (dump_file && profile_info) - fprintf (dump_file, "Merged %u profiles with maximal count %u.\n", - profile_info->runs, (unsigned) profile_info->sum_max); - return counts; } - static bool is_edge_inconsistent (vec<edge, va_gc> *edges) { @@ -439,24 +366,7 @@ { num_edges++; if (exec_counts) - { - edge_gcov_count (e) = exec_counts[exec_counts_pos++]; - if (edge_gcov_count (e) > profile_info->sum_max) - { - if (flag_profile_correction) - { - static bool informed = 0; - if (dump_enabled_p () && !informed) - dump_printf_loc (MSG_NOTE, input_location, - "corrupted profile info: edge count" - " exceeds maximal count\n"); - informed = 1; - } - else - error ("corrupted profile info: edge from %i to %i exceeds maximal count", - bb->index, e->dest->index); - } - } + edge_gcov_count (e) = exec_counts[exec_counts_pos++]; else edge_gcov_count (e) = 0; @@ -476,38 +386,6 @@ return num_edges; } -#define OVERLAP_BASE 10000 - -/* Compare the static estimated profile to the actual profile, and - return the "degree of overlap" measure between them. - - Degree of overlap is a number between 0 and OVERLAP_BASE. It is - the sum of each basic block's minimum relative weights between - two profiles. And overlap of OVERLAP_BASE means two profiles are - identical. */ - -static int -compute_frequency_overlap (void) -{ - gcov_type count_total = 0, freq_total = 0; - int overlap = 0; - basic_block bb; - - FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) - { - count_total += bb_gcov_count (bb); - freq_total += bb->frequency; - } - - if (count_total == 0 || freq_total == 0) - return 0; - - FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) - overlap += MIN (bb_gcov_count (bb) * OVERLAP_BASE / count_total, - bb->frequency * OVERLAP_BASE / freq_total); - - return overlap; -} /* Compute the branch probabilities for the various branches. Annotate them accordingly. @@ -529,17 +407,15 @@ /* Very simple sanity checks so we catch bugs in our profiling code. */ if (!profile_info) - return; + { + if (dump_file) + fprintf (dump_file, "Profile info is missing; giving up\n"); + return; + } bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun)); edge_gcov_counts = new hash_map<edge,gcov_type>; - if (profile_info->sum_all < profile_info->sum_max) - { - error ("corrupted profile info: sum_all is smaller than sum_max"); - exec_counts = NULL; - } - /* Attach extra info block to each bb. */ alloc_aux_for_blocks (sizeof (struct bb_profile_info)); FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) @@ -676,14 +552,6 @@ } } } - if (dump_file) - { - int overlap = compute_frequency_overlap (); - gimple_dump_cfg (dump_file, dump_flags); - fprintf (dump_file, "Static profile overlap: %d.%d%%\n", - overlap / (OVERLAP_BASE / 100), - overlap % (OVERLAP_BASE / 100)); - } total_num_passes += passes; if (dump_file) @@ -708,7 +576,8 @@ if (dump_enabled_p () && informed == 0) { informed = 1; - dump_printf_loc (MSG_NOTE, input_location, + dump_printf_loc (MSG_NOTE, + dump_location_t::from_location_t (input_location), "correcting inconsistent profile data\n"); } correct_negative_edge_counts (); @@ -829,15 +698,23 @@ } } - FOR_ALL_BB_FN (bb, cfun) - { + /* If we have real data, use them! */ + if (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun)) + || !flag_guess_branch_prob) + FOR_ALL_BB_FN (bb, cfun) bb->count = profile_count::from_gcov_type (bb_gcov_count (bb)); - } + /* If function was not trained, preserve local estimates including statically + determined zero counts. */ + else + FOR_ALL_BB_FN (bb, cfun) + if (!(bb->count == profile_count::zero ())) + bb->count = bb->count.global0 (); + bb_gcov_counts.release (); delete edge_gcov_counts; edge_gcov_counts = NULL; - counts_to_freqs (); + update_max_bb_count (); if (dump_file) { @@ -893,10 +770,9 @@ continue; } - histogram_counts[t] = - get_coverage_counts (COUNTER_FOR_HIST_TYPE (t), - n_histogram_counters[t], cfg_checksum, - lineno_checksum, NULL); + histogram_counts[t] = get_coverage_counts (COUNTER_FOR_HIST_TYPE (t), + cfg_checksum, + lineno_checksum); if (histogram_counts[t]) any = 1; act_count[t] = histogram_counts[t]; @@ -941,17 +817,90 @@ free (histogram_counts[t]); } +/* Location triplet which records a location. */ +struct location_triplet +{ + const char *filename; + int lineno; + int bb_index; +}; + +/* Traits class for streamed_locations hash set below. */ + +struct location_triplet_hash : typed_noop_remove <location_triplet> +{ + typedef location_triplet value_type; + typedef location_triplet compare_type; + + static hashval_t + hash (const location_triplet &ref) + { + inchash::hash hstate (0); + if (ref.filename) + hstate.add_int (strlen (ref.filename)); + hstate.add_int (ref.lineno); + hstate.add_int (ref.bb_index); + return hstate.end (); + } + + static bool + equal (const location_triplet &ref1, const location_triplet &ref2) + { + return ref1.lineno == ref2.lineno + && ref1.bb_index == ref2.bb_index + && ref1.filename != NULL + && ref2.filename != NULL + && strcmp (ref1.filename, ref2.filename) == 0; + } + + static void + mark_deleted (location_triplet &ref) + { + ref.lineno = -1; + } + + static void + mark_empty (location_triplet &ref) + { + ref.lineno = -2; + } + + static bool + is_deleted (const location_triplet &ref) + { + return ref.lineno == -1; + } + + static bool + is_empty (const location_triplet &ref) + { + return ref.lineno == -2; + } +}; + + + + /* When passed NULL as file_name, initialize. When passed something else, output the necessary commands to change line to LINE and offset to FILE_NAME. */ static void -output_location (char const *file_name, int line, +output_location (hash_set<location_triplet_hash> *streamed_locations, + char const *file_name, int line, gcov_position_t *offset, basic_block bb) { static char const *prev_file_name; static int prev_line; bool name_differs, line_differs; + location_triplet triplet; + triplet.filename = file_name; + triplet.lineno = line; + triplet.bb_index = bb ? bb->index : 0; + + if (streamed_locations->add (triplet)) + return; + if (!file_name) { prev_file_name = NULL; @@ -1040,6 +989,8 @@ flow_call_edges_add (NULL); add_noreturn_fake_exit_edges (); + hash_set <location_triplet_hash> streamed_locations; + /* We can't handle cyclic regions constructed using abnormal edges. To avoid these we replace every source of abnormal edge by a fake edge from entry node and every destination by fake edge to exit. @@ -1276,7 +1227,9 @@ /* Line numbers. */ /* Initialize the output. */ - output_location (NULL, 0, NULL, NULL); + output_location (&streamed_locations, NULL, 0, NULL, NULL); + + hash_set<int_hash <location_t, 0, 2> > seen_locations; FOR_EACH_BB_FN (bb, cfun) { @@ -1285,28 +1238,37 @@ if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) { - expanded_location curr_location = - expand_location (DECL_SOURCE_LOCATION (current_function_decl)); - output_location (curr_location.file, curr_location.line, - &offset, bb); + location_t loc = DECL_SOURCE_LOCATION (current_function_decl); + seen_locations.add (loc); + expanded_location curr_location = expand_location (loc); + output_location (&streamed_locations, curr_location.file, + curr_location.line, &offset, bb); } for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); - if (!RESERVED_LOCATION_P (gimple_location (stmt))) - output_location (gimple_filename (stmt), gimple_lineno (stmt), - &offset, bb); + location_t loc = gimple_location (stmt); + if (!RESERVED_LOCATION_P (loc)) + { + seen_locations.add (loc); + output_location (&streamed_locations, gimple_filename (stmt), + gimple_lineno (stmt), &offset, bb); + } } - /* Notice GOTO expressions eliminated while constructing the CFG. */ + /* Notice GOTO expressions eliminated while constructing the CFG. + It's hard to distinguish such expression, but goto_locus should + not be any of already seen location. */ + location_t loc; if (single_succ_p (bb) - && !RESERVED_LOCATION_P (single_succ_edge (bb)->goto_locus)) + && (loc = single_succ_edge (bb)->goto_locus) + && !RESERVED_LOCATION_P (loc) + && !seen_locations.contains (loc)) { - expanded_location curr_location - = expand_location (single_succ_edge (bb)->goto_locus); - output_location (curr_location.file, curr_location.line, - &offset, bb); + expanded_location curr_location = expand_location (loc); + output_location (&streamed_locations, curr_location.file, + curr_location.line, &offset, bb); } if (offset)