/* Calculate branch probabilities, and basic block execution counts.
- Copyright (C) 1990-2019 Free Software Foundation, Inc.
+ Copyright (C) 1990-2021 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.
switch (hist->type)
{
case HIST_TYPE_INTERVAL:
- gimple_gen_interval_profiler (hist, t, 0);
+ gimple_gen_interval_profiler (hist, t);
break;
case HIST_TYPE_POW2:
- gimple_gen_pow2_profiler (hist, t, 0);
+ gimple_gen_pow2_profiler (hist, t);
break;
- case HIST_TYPE_SINGLE_VALUE:
- gimple_gen_one_value_profiler (hist, t, 0);
+ case HIST_TYPE_TOPN_VALUES:
+ gimple_gen_topn_values_profiler (hist, t);
break;
case HIST_TYPE_INDIR_CALL:
- case HIST_TYPE_INDIR_CALL_TOPN:
- gimple_gen_ic_profiler (hist, t, 0);
+ gimple_gen_ic_profiler (hist, t);
break;
case HIST_TYPE_AVERAGE:
- gimple_gen_average_profiler (hist, t, 0);
+ gimple_gen_average_profiler (hist, t);
break;
case HIST_TYPE_IOR:
- gimple_gen_ior_profiler (hist, t, 0);
+ gimple_gen_ior_profiler (hist, t);
break;
case HIST_TYPE_TIME_PROFILE:
- gimple_gen_time_profiler (t, 0);
+ gimple_gen_time_profiler (t);
break;
default:
return;
}
- bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun));
+ bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun), true);
edge_gcov_counts = new hash_map<edge,gcov_type>;
/* Attach extra info block to each bb. */
}
if (bb_gcov_count (bb))
{
+ bool set_to_guessed = false;
FOR_EACH_EDGE (e, ei, bb->succs)
- e->probability = profile_probability::probability_in_gcov_type
- (edge_gcov_count (e), bb_gcov_count (bb));
+ {
+ bool prev_never = e->probability == profile_probability::never ();
+ e->probability = profile_probability::probability_in_gcov_type
+ (edge_gcov_count (e), bb_gcov_count (bb));
+ if (e->probability == profile_probability::never ()
+ && !prev_never
+ && flag_profile_partial_training)
+ set_to_guessed = true;
+ }
+ if (set_to_guessed)
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ e->probability = e->probability.guessed ();
if (bb->index >= NUM_FIXED_BLOCKS
&& block_ends_with_condjump_p (bb)
&& EDGE_COUNT (bb->succs) >= 2)
}
}
- if (exec_counts)
+ if (exec_counts
+ && (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun))
+ || !flag_profile_partial_training))
profile_status_for_fn (cfun) = PROFILE_READ;
/* 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 (bb_gcov_count (bb) || !flag_profile_partial_training)
+ bb->count = profile_count::from_gcov_type (bb_gcov_count (bb));
+ else
+ bb->count = profile_count::guessed_zero ();
/* If function was not trained, preserve local estimates including statically
determined zero counts. */
- else if (profile_status_for_fn (cfun) == PROFILE_READ)
+ else if (profile_status_for_fn (cfun) == PROFILE_READ
+ && !flag_profile_partial_training)
FOR_ALL_BB_FN (bb, cfun)
if (!(bb->count == profile_count::zero ()))
bb->count = bb->count.global0 ();
free_aux_for_blocks ();
}
+/* Sort the histogram value and count for TOPN and INDIR_CALL type. */
+
+static void
+sort_hist_values (histogram_value hist)
+{
+ gcc_assert (hist->type == HIST_TYPE_TOPN_VALUES
+ || hist->type == HIST_TYPE_INDIR_CALL);
+
+ int counters = hist->hvalue.counters[1];
+ for (int i = 0; i < counters - 1; i++)
+ /* Hist value is organized as:
+ [total_executions, N, value1, counter1, ..., valueN, counterN]
+ Use decrease bubble sort to rearrange it. The sort starts from <value1,
+ counter1> and compares counter first. If counter is same, compares the
+ value, exchange it if small to keep stable. */
+
+ {
+ bool swapped = false;
+ for (int j = 0; j < counters - 1 - i; j++)
+ {
+ gcov_type *p = &hist->hvalue.counters[2 * j + 2];
+ if (p[1] < p[3] || (p[1] == p[3] && p[0] < p[2]))
+ {
+ std::swap (p[0], p[2]);
+ std::swap (p[1], p[3]);
+ swapped = true;
+ }
+ }
+ if (!swapped)
+ break;
+ }
+}
/* Load value histograms values whose description is stored in VALUES array
from .gcda file.
gimple *stmt = hist->hvalue.stmt;
t = (int) hist->type;
+ bool topn_p = (hist->type == HIST_TYPE_TOPN_VALUES
+ || hist->type == HIST_TYPE_INDIR_CALL);
- aact_count = act_count[t];
+ /* TOP N counter uses variable number of counters. */
+ if (topn_p)
+ {
+ unsigned total_size;
+ if (act_count[t])
+ total_size = 2 + 2 * act_count[t][1];
+ else
+ total_size = 2;
+ gimple_add_histogram_value (cfun, stmt, hist);
+ hist->n_counters = total_size;
+ hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
+ for (j = 0; j < hist->n_counters; j++)
+ if (act_count[t])
+ hist->hvalue.counters[j] = act_count[t][j];
+ else
+ hist->hvalue.counters[j] = 0;
+ act_count[t] += hist->n_counters;
+ sort_hist_values (hist);
+ }
+ else
+ {
+ aact_count = act_count[t];
- if (act_count[t])
- act_count[t] += hist->n_counters;
+ if (act_count[t])
+ act_count[t] += hist->n_counters;
- gimple_add_histogram_value (cfun, stmt, hist);
- hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
- for (j = 0; j < hist->n_counters; j++)
- if (aact_count)
- hist->hvalue.counters[j] = aact_count[j];
- else
- hist->hvalue.counters[j] = 0;
+ gimple_add_histogram_value (cfun, stmt, hist);
+ hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
+ for (j = 0; j < hist->n_counters; j++)
+ if (aact_count)
+ hist->hvalue.counters[j] = aact_count[j];
+ else
+ hist->hvalue.counters[j] = 0;
+ }
/* Time profiler counter is not related to any statement,
so that we have to read the counter and set the value to
if (hist->type == HIST_TYPE_TIME_PROFILE)
{
node = cgraph_node::get (hist->fun->decl);
- node->tp_first_run = hist->hvalue.counters[0];
+ if (hist->hvalue.counters[0] >= 0
+ && hist->hvalue.counters[0] < INT_MAX / 2)
+ node->tp_first_run = hist->hvalue.counters[0];
+ else
+ {
+ if (flag_profile_correction)
+ error ("corrupted profile info: invalid time profile");
+ node->tp_first_run = 0;
+ }
+
+ /* Drop profile for -fprofile-reproducible=multithreaded. */
+ bool drop
+ = (flag_profile_reproducible == PROFILE_REPRODUCIBILITY_MULTITHREADED);
+ if (drop)
+ node->tp_first_run = 0;
- if (dump_file)
- fprintf (dump_file, "Read tp_first_run: %d\n", node->tp_first_run);
+ if (dump_file)
+ fprintf (dump_file, "Read tp_first_run: %d%s\n", node->tp_first_run,
+ drop ? "; ignored because profile reproducibility is "
+ "multi-threaded" : "");
}
}
ref.lineno = -1;
}
+ static const bool empty_zero_p = false;
+
static void
mark_empty (location_triplet &ref)
{
if (dump_file)
fprintf (dump_file, "%d instrumentation edges\n", num_instrumented);
+ /* Dump function body before it's instrumented.
+ It helps to debug gcov tool. */
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ dump_function_to_file (cfun->decl, dump_file, dump_flags);
+
/* Compute two different checksums. Note that we want to compute
the checksum in only once place, since it depends on the shape
of the control flow which can change during
various transformations. */
if (thunk)
{
- /* At stream in time we do not have CFG, so we can not do checksums. */
+ /* At stream in time we do not have CFG, so we cannot do checksums. */
cfg_checksum = 0;
lineno_checksum = 0;
}
seen_locations.add (loc);
expanded_location curr_location = expand_location (loc);
output_location (&streamed_locations, curr_location.file,
- curr_location.line, &offset, bb);
+ MAX (1, curr_location.line), &offset, bb);
}
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
seen_locations.add (loc);
output_location (&streamed_locations, gimple_filename (stmt),
- gimple_lineno (stmt), &offset, bb);
+ MAX (1, gimple_lineno (stmt)), &offset, bb);
}
}
{
expanded_location curr_location = expand_location (loc);
output_location (&streamed_locations, curr_location.file,
- curr_location.line, &offset, bb);
+ MAX (1, curr_location.line), &offset, bb);
}
if (offset)
if (flag_branch_probabilities
&& (profile_status_for_fn (cfun) == PROFILE_READ))
{
- struct loop *loop;
if (dump_file && (dump_flags & TDF_DETAILS))
report_predictor_hitrates ();
/* At this moment we have precise loop iteration count estimates.
Record them to loop structure before the profile gets out of date. */
- FOR_EACH_LOOP (loop, 0)
- if (loop->header->count > 0)
+ for (auto loop : loops_list (cfun, 0))
+ if (loop->header->count > 0 && loop->header->count.reliable_p ())
{
gcov_type nit = expected_loop_iterations_unbounded (loop);
widest_int bound = gcov_type_to_wide_int (nit);