Implement flat loop profile detection

This patch adds maybe_flat_loop_profile which can be used in loop profile udpate
to detect situation where the profile may be unrealistically flat and should
not be dwonscalled after vectorizing, unrolling and other transforms that
assume that loop has high iteration count even if the CFG profile says
otherwise.

Profile is flat if it was statically detected and at that time we had
no idea about actual number of iterations or we artificially capped them.
So the function considers flat all profiles that have guessed or lower
reliability in their count and there is no nb_iteration_bounds/estimate
which would prove that the profile iteration count is high enough.

gcc/ChangeLog:

	* cfgloop.h (maybe_flat_loop_profile): Declare
	* cfgloopanal.cc (maybe_flat_loop_profile): New function.
	* tree-cfg.cc (print_loop_info): Print info about flat profiles.
This commit is contained in:
Jan Hubicka 2023-07-21 17:34:31 +02:00
parent 3291f9e6cb
commit ea272814c2
3 changed files with 67 additions and 2 deletions

View file

@ -407,6 +407,7 @@ gcov_type expected_loop_iterations_unbounded (const class loop *,
extern bool expected_loop_iterations_by_profile (const class loop *loop,
sreal *ret,
bool *reliable = NULL);
extern bool maybe_flat_loop_profile (const class loop *);
extern unsigned expected_loop_iterations (class loop *);
extern rtx doloop_condition_get (rtx_insn *);

View file

@ -303,6 +303,67 @@ expected_loop_iterations_by_profile (const class loop *loop, sreal *ret,
return true;
}
/* Return true if loop CFG profile may be unrealistically flat.
This is a common case, since average loops iterate only about 5 times.
In the case we do not have profile feedback or do not know real number of
iterations during profile estimation, we are likely going to predict it with
similar low iteration count. For static loop profiles we also artificially
cap profile of loops with known large iteration count so they do not appear
significantly more hot than other loops with unknown iteration counts.
For loop optimization heuristics we ignore CFG profile and instead
use get_estimated_loop_iterations API which returns estimate
only when it is realistic. For unknown counts some optimizations,
like vectorizer or unroller make guess that iteration count will
be large. In this case we need to avoid scaling down the profile
after the loop transform. */
bool
maybe_flat_loop_profile (const class loop *loop)
{
bool reliable;
sreal ret;
if (!expected_loop_iterations_by_profile (loop, &ret, &reliable))
return true;
/* Reliable CFG estimates ought never be flat. Sanity check with
nb_iterations_estimate. If those differ, it is a but in profile
updating code */
if (reliable)
{
int64_t intret = ret.to_nearest_int ();
if (loop->any_estimate
&& (wi::ltu_p (intret * 2, loop->nb_iterations_estimate)
|| wi::gtu_p (intret, loop->nb_iterations_estimate * 2)))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"Loop %i has inconsistent iterations estimates: "
"reliable CFG based iteration estimate is %f "
"while nb_iterations_estimate is %i\n",
loop->num,
ret.to_double (),
(int)loop->nb_iterations_estimate.to_shwi ());
return true;
}
return false;
}
/* Allow some margin of error and see if we are close to known bounds.
sreal (9,-3) is 9/8 */
int64_t intret = (ret * sreal (9, -3)).to_nearest_int ();
if (loop->any_upper_bound && wi::geu_p (intret, loop->nb_iterations_upper_bound))
return false;
if (loop->any_likely_upper_bound
&& wi::geu_p (intret, loop->nb_iterations_likely_upper_bound))
return false;
if (loop->any_estimate
&& wi::geu_p (intret, loop->nb_iterations_estimate))
return false;
return true;
}
/* Returns expected number of iterations of LOOP, according to
measured or guessed profile.

View file

@ -8523,8 +8523,11 @@ print_loop_info (FILE *file, const class loop *loop, const char *prefix)
bool reliable;
sreal iterations;
if (loop->num && expected_loop_iterations_by_profile (loop, &iterations, &reliable))
fprintf (file, "\n%siterations by profile: %f %s", prefix,
iterations.to_double (), reliable ? "(reliable)" : "(unreliable)");
{
fprintf (file, "\n%siterations by profile: %f (%s%s)", prefix,
iterations.to_double (), reliable ? "reliable" : "unreliable",
maybe_flat_loop_profile (loop) ? ", maybe flat" : "");
}
}