Dump profile-based number of iterations
authorMartin Liska <mliska@suse.cz>
Fri, 24 Jun 2016 16:22:44 +0000 (18:22 +0200)
committerMartin Liska <marxin@gcc.gnu.org>
Fri, 24 Jun 2016 16:22:44 +0000 (16:22 +0000)
* analyze_brprob.py: Parse and display average number
of loop iterations.
* cfgloop.c (flow_loop_dump): Dump average number of loop iterations.
* cfgloop.h: Change 'struct loop' to 'const struct loop' for a
few functions.
* cfgloopanal.c (expected_loop_iterations_unbounded): Set a new
argument to true if the expected number of iterations is
loop-based.

From-SVN: r237762

contrib/ChangeLog
contrib/analyze_brprob.py
gcc/ChangeLog
gcc/cfgloop.c
gcc/cfgloop.h
gcc/cfgloopanal.c

index 07019c2ccbe9b8940a5c3dc4d8361c55dc94501d..d5f194af4d3c066148c6b7861626f23edfe1f1b1 100644 (file)
@@ -1,3 +1,8 @@
+2016-06-24  Martin Liska  <mliska@suse.cz>
+
+       * analyze_brprob.py: Parse and display average number
+       of loop iterations.
+
 2016-06-23  Andi Kleen  <ak@linux.intel.com>
 
        * gen_autofdo_event.py: New file to regenerate
index 2526623ff55075624c6accbf4c944a018f491be8..c276d810a4f6ddd2ed948b169dbdd21a0a1efe82 100755 (executable)
@@ -67,9 +67,26 @@ import os
 import re
 import argparse
 
+from math import *
+
 def percentage(a, b):
     return 100.0 * a / b
 
+def average(values):
+    return 1.0 * sum(values) / len(values)
+
+def average_cutoff(values, cut):
+    l = len(values)
+    skip = floor(l * cut / 2)
+    if skip > 0:
+        values.sort()
+        values = values[skip:-skip]
+    return average(values)
+
+def median(values):
+    values.sort()
+    return values[int(len(values) / 2)]
+
 class Summary:
     def __init__(self, name):
         self.name = name
@@ -93,6 +110,7 @@ class Profile:
     def __init__(self, filename):
         self.filename = filename
         self.heuristics = {}
+        self.niter_vector = []
 
     def add(self, name, prediction, count, hits):
         if not name in self.heuristics:
@@ -106,6 +124,10 @@ class Profile:
         s.hits += hits
         s.fits += max(hits, count - hits)
 
+    def add_loop_niter(self, niter):
+        if niter > 0:
+            self.niter_vector.append(niter)
+
     def branches_max(self):
         return max([v.branches for k, v in self.heuristics.items()])
 
@@ -127,6 +149,13 @@ class Profile:
              percentage(v.hits, v.count), percentage(v.fits, v.count),
              v.count, v.count_formatted(), percentage(v.count, self.count_max()) ))
 
+        print ('\nLoop count: %d' % len(self.niter_vector)),
+        print('  avg. # of iter: %.2f' % average(self.niter_vector))
+        print('  median # of iter: %.2f' % median(self.niter_vector))
+        for v in [1, 5, 10, 20, 30]:
+            cut = 0.01 * v
+            print('  avg. (%d%% cutoff) # of iter: %.2f' % (v, average_cutoff(self.niter_vector, cut)))
+
 parser = argparse.ArgumentParser()
 parser.add_argument('dump_file', metavar = 'dump_file', help = 'IPA profile dump file')
 parser.add_argument('-s', '--sorting', dest = 'sorting', choices = ['branches', 'hitrate', 'coverage'], default = 'branches')
@@ -135,6 +164,7 @@ args = parser.parse_args()
 
 profile = Profile(sys.argv[1])
 r = re.compile('  (.*) heuristics( of edge [0-9]*->[0-9]*)?( \\(.*\\))?: (.*)%.*exec ([0-9]*) hit ([0-9]*)')
+loop_niter_str = ';;  profile-based iteration count: '
 for l in open(args.dump_file).readlines():
     m = r.match(l)
     if m != None and m.group(3) == None:
@@ -144,5 +174,8 @@ for l in open(args.dump_file).readlines():
         hits = int(m.group(6))
 
         profile.add(name, prediction, count, hits)
+    elif l.startswith(loop_niter_str):
+        v = int(l[len(loop_niter_str):])
+        profile.add_loop_niter(v)
 
 profile.dump(args.sorting)
index 01c7807e873540ff84872e31b5d37fe136accb73..80048f15a664f194fc8ae0a2e4da84eae382d332 100644 (file)
@@ -1,3 +1,12 @@
+2016-06-24  Martin Liska  <mliska@suse.cz>
+
+       * cfgloop.c (flow_loop_dump): Dump average number of loop iterations.
+       * cfgloop.h: Change 'struct loop' to 'const struct loop' for a
+       few functions.
+       * cfgloopanal.c (expected_loop_iterations_unbounded): Set a new
+       argument to true if the expected number of iterations is
+       loop-based.
+
 2016-06-24  Uros Bizjak  <ubizjak@gmail.com>
 
        * configure.ac (HAVE_AS_GOTOF_IN_DATA): Use $as_ix86_gas_32_opt to
index 5650f0d92c573eb76cb493a8adc7b03d336c6501..e6174bd2191b3a8cc0dd4d65ad8f71188ceec370 100644 (file)
@@ -136,6 +136,14 @@ flow_loop_dump (const struct loop *loop, FILE *file,
           loop_depth (loop), (long) (loop_outer (loop)
                                      ? loop_outer (loop)->num : -1));
 
+  if (loop->latch)
+    {
+      bool read_profile_p;
+      gcov_type nit = expected_loop_iterations_unbounded (loop, &read_profile_p);
+      if (read_profile_p && !loop->any_estimate)
+       fprintf (file, ";;  profile-based iteration count: %lu\n", nit);
+    }
+
   fprintf (file, ";;  nodes:");
   bbs = get_loop_body (loop);
   for (i = 0; i < loop->num_nodes; i++)
@@ -1913,7 +1921,7 @@ get_estimated_loop_iterations (struct loop *loop, widest_int *nit)
    false, otherwise returns true.  */
 
 bool
-get_max_loop_iterations (struct loop *loop, widest_int *nit)
+get_max_loop_iterations (const struct loop *loop, widest_int *nit)
 {
   if (!loop->any_upper_bound)
     return false;
@@ -1927,7 +1935,7 @@ get_max_loop_iterations (struct loop *loop, widest_int *nit)
    on the number of iterations of LOOP could not be derived, returns -1.  */
 
 HOST_WIDE_INT
-get_max_loop_iterations_int (struct loop *loop)
+get_max_loop_iterations_int (const struct loop *loop)
 {
   widest_int nit;
   HOST_WIDE_INT hwi_nit;
index aba2988c99e3d83d282f6583ce6ae2de6a4ca5c5..dfc7525dcad5ca6bcc06df1495dc748ac92473f4 100644 (file)
@@ -319,7 +319,8 @@ extern void verify_loop_structure (void);
 
 /* Loop analysis.  */
 extern bool just_once_each_iteration_p (const struct loop *, const_basic_block);
-gcov_type expected_loop_iterations_unbounded (struct loop *);
+gcov_type expected_loop_iterations_unbounded (const struct loop *,
+                                             bool *read_profile_p = NULL);
 extern unsigned expected_loop_iterations (struct loop *);
 extern rtx doloop_condition_get (rtx);
 
@@ -778,10 +779,10 @@ loop_outermost (struct loop *loop)
 
 extern void record_niter_bound (struct loop *, const widest_int &, bool, bool);
 extern HOST_WIDE_INT get_estimated_loop_iterations_int (struct loop *);
-extern HOST_WIDE_INT get_max_loop_iterations_int (struct loop *);
+extern HOST_WIDE_INT get_max_loop_iterations_int (const struct loop *);
 extern HOST_WIDE_INT get_likely_max_loop_iterations_int (struct loop *);
 extern bool get_estimated_loop_iterations (struct loop *loop, widest_int *nit);
-extern bool get_max_loop_iterations (struct loop *loop, widest_int *nit);
+extern bool get_max_loop_iterations (const struct loop *loop, widest_int *nit);
 extern bool get_likely_max_loop_iterations (struct loop *loop, widest_int *nit);
 extern int bb_loop_depth (const_basic_block);
 
index 938ac43879a530a61b7b077f774ec2fb0755958b..c16398692788b0407a45e91756bc515db40dd1b5 100644 (file)
@@ -231,12 +231,15 @@ average_num_loop_insns (const struct loop *loop)
    value.  */
 
 gcov_type
-expected_loop_iterations_unbounded (struct loop *loop)
+expected_loop_iterations_unbounded (const struct loop *loop,
+                                   bool *read_profile_p)
 {
   edge e;
   edge_iterator ei;
   gcov_type expected;
   
+  if (read_profile_p)
+    *read_profile_p = false;
 
   /* Average loop rolls about 3 times. If we have no profile at all, it is
      best we can do.  */
@@ -258,7 +261,11 @@ expected_loop_iterations_unbounded (struct loop *loop)
       if (count_in == 0)
        expected = count_latch * 2;
       else
-       expected = (count_latch + count_in - 1) / count_in;
+       {
+         expected = (count_latch + count_in - 1) / count_in;
+         if (read_profile_p)
+           *read_profile_p = true;
+       }
     }
   else
     {