Commit d1b9a572 by Martin Liska Committed by Martin Liska

Fix usage of analyze_brprob.py script.

2018-01-19  Martin Liska  <mliska@suse.cz>

	* analyze_brprob.py: Support new format that can be easily
	parsed. Add new column to report.
2018-01-19  Martin Liska  <mliska@suse.cz>

	* predict.c (dump_prediction): Add new format for
	analyze_brprob.py script which is enabled with -details
	suboption.
	* profile-count.h (precise_p): New function.

From-SVN: r256886
parent 09a7858b
2018-01-19 Martin Liska <mliska@suse.cz>
* analyze_brprob.py: Support new format that can be easily
parsed. Add new column to report.
2018-01-03 Jakub Jelinek <jakub@redhat.com> 2018-01-03 Jakub Jelinek <jakub@redhat.com>
* update-copyright.py: Skip pdt-5.f03 in gfortran.dg subdir. * update-copyright.py: Skip pdt-5.f03 in gfortran.dg subdir.
......
...@@ -71,6 +71,7 @@ from math import * ...@@ -71,6 +71,7 @@ from math import *
counter_aggregates = set(['combined', 'first match', 'DS theory', counter_aggregates = set(['combined', 'first match', 'DS theory',
'no prediction']) 'no prediction'])
hot_threshold = 10
def percentage(a, b): def percentage(a, b):
return 100.0 * a / b return 100.0 * a / b
...@@ -131,47 +132,87 @@ class PredictDefFile: ...@@ -131,47 +132,87 @@ class PredictDefFile:
with open(self.path, 'w+') as f: with open(self.path, 'w+') as f:
for l in modified_lines: for l in modified_lines:
f.write(l + '\n') f.write(l + '\n')
class Heuristics:
def __init__(self, count, hits, fits):
self.count = count
self.hits = hits
self.fits = fits
class Summary: class Summary:
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.branches = 0 self.edges= []
self.successfull_branches = 0
self.count = 0 def branches(self):
self.hits = 0 return len(self.edges)
self.fits = 0
def hits(self):
return sum([x.hits for x in self.edges])
def fits(self):
return sum([x.fits for x in self.edges])
def count(self):
return sum([x.count for x in self.edges])
def successfull_branches(self):
return len([x for x in self.edges if 2 * x.hits >= x.count])
def get_hitrate(self): def get_hitrate(self):
return 100.0 * self.hits / self.count return 100.0 * self.hits() / self.count()
def get_branch_hitrate(self): def get_branch_hitrate(self):
return 100.0 * self.successfull_branches / self.branches return 100.0 * self.successfull_branches() / self.branches()
def count_formatted(self): def count_formatted(self):
v = self.count v = self.count()
for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']: for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']:
if v < 1000: if v < 1000:
return "%3.2f%s" % (v, unit) return "%3.2f%s" % (v, unit)
v /= 1000.0 v /= 1000.0
return "%.1f%s" % (v, 'Y') return "%.1f%s" % (v, 'Y')
def count(self):
return sum([x.count for x in self.edges])
def print(self, branches_max, count_max, predict_def): def print(self, branches_max, count_max, predict_def):
# filter out most hot edges (if requested)
self.edges = sorted(self.edges, reverse = True, key = lambda x: x.count)
if args.coverage_threshold != None:
threshold = args.coverage_threshold * self.count() / 100
edges = [x for x in self.edges if x.count < threshold]
if len(edges) != 0:
self.edges = edges
predicted_as = None predicted_as = None
if predict_def != None and self.name in predict_def.predictors: if predict_def != None and self.name in predict_def.predictors:
predicted_as = predict_def.predictors[self.name] predicted_as = predict_def.predictors[self.name]
print('%-40s %8i %5.1f%% %11.2f%% %7.2f%% / %6.2f%% %14i %8s %5.1f%%' % print('%-40s %8i %5.1f%% %11.2f%% %7.2f%% / %6.2f%% %14i %8s %5.1f%%' %
(self.name, self.branches, (self.name, self.branches(),
percentage(self.branches, branches_max), percentage(self.branches(), branches_max),
self.get_branch_hitrate(), self.get_branch_hitrate(),
self.get_hitrate(), self.get_hitrate(),
percentage(self.fits, self.count), percentage(self.fits(), self.count()),
self.count, self.count_formatted(), self.count(), self.count_formatted(),
percentage(self.count, count_max)), end = '') percentage(self.count(), count_max)), end = '')
if predicted_as != None: if predicted_as != None:
print('%12i%% %5.1f%%' % (predicted_as, print('%12i%% %5.1f%%' % (predicted_as,
self.get_hitrate() - predicted_as), end = '') self.get_hitrate() - predicted_as), end = '')
else:
print(' ' * 20, end = '')
# print details about the most important edges
if args.coverage_threshold == None:
edges = [x for x in self.edges[:100] if x.count * hot_threshold > self.count()]
if args.verbose:
for c in edges:
r = 100.0 * c.count / self.count()
print(' %.0f%%:%d' % (r, c.count), end = '')
elif len(edges) > 0:
print(' %0.0f%%:%d' % (100.0 * sum([x.count for x in edges]) / self.count(), len(edges)), end = '')
print() print()
class Profile: class Profile:
...@@ -185,33 +226,29 @@ class Profile: ...@@ -185,33 +226,29 @@ class Profile:
self.heuristics[name] = Summary(name) self.heuristics[name] = Summary(name)
s = self.heuristics[name] s = self.heuristics[name]
s.branches += 1
s.count += count
if prediction < 50: if prediction < 50:
hits = count - hits hits = count - hits
remaining = count - hits remaining = count - hits
if hits >= remaining: fits = max(hits, remaining)
s.successfull_branches += 1
s.hits += hits s.edges.append(Heuristics(count, hits, fits))
s.fits += max(hits, remaining)
def add_loop_niter(self, niter): def add_loop_niter(self, niter):
if niter > 0: if niter > 0:
self.niter_vector.append(niter) self.niter_vector.append(niter)
def branches_max(self): def branches_max(self):
return max([v.branches for k, v in self.heuristics.items()]) return max([v.branches() for k, v in self.heuristics.items()])
def count_max(self): def count_max(self):
return max([v.count for k, v in self.heuristics.items()]) return max([v.count() for k, v in self.heuristics.items()])
def print_group(self, sorting, group_name, heuristics, predict_def): def print_group(self, sorting, group_name, heuristics, predict_def):
count_max = self.count_max() count_max = self.count_max()
branches_max = self.branches_max() branches_max = self.branches_max()
sorter = lambda x: x.branches sorter = lambda x: x.branches()
if sorting == 'branch-hitrate': if sorting == 'branch-hitrate':
sorter = lambda x: x.get_branch_hitrate() sorter = lambda x: x.get_branch_hitrate()
elif sorting == 'hitrate': elif sorting == 'hitrate':
...@@ -221,10 +258,10 @@ class Profile: ...@@ -221,10 +258,10 @@ class Profile:
elif sorting == 'name': elif sorting == 'name':
sorter = lambda x: x.name.lower() sorter = lambda x: x.name.lower()
print('%-40s %8s %6s %12s %18s %14s %8s %6s %12s %6s' % print('%-40s %8s %6s %12s %18s %14s %8s %6s %12s %6s %s' %
('HEURISTICS', 'BRANCHES', '(REL)', ('HEURISTICS', 'BRANCHES', '(REL)',
'BR. HITRATE', 'HITRATE', 'COVERAGE', 'COVERAGE', '(REL)', 'BR. HITRATE', 'HITRATE', 'COVERAGE', 'COVERAGE', '(REL)',
'predict.def', '(REL)')) 'predict.def', '(REL)', 'HOT branches (>%d%%)' % hot_threshold))
for h in sorted(heuristics, key = sorter): for h in sorted(heuristics, key = sorter):
h.print(branches_max, count_max, predict_def) h.print(branches_max, count_max, predict_def)
...@@ -266,19 +303,23 @@ parser.add_argument('-s', '--sorting', dest = 'sorting', ...@@ -266,19 +303,23 @@ parser.add_argument('-s', '--sorting', dest = 'sorting',
parser.add_argument('-d', '--def-file', help = 'path to predict.def') parser.add_argument('-d', '--def-file', help = 'path to predict.def')
parser.add_argument('-w', '--write-def-file', action = 'store_true', parser.add_argument('-w', '--write-def-file', action = 'store_true',
help = 'Modify predict.def file in order to set new numbers') help = 'Modify predict.def file in order to set new numbers')
parser.add_argument('-c', '--coverage-threshold', type = int,
help = 'Ignore edges that have percentage coverage >= coverage-threshold')
parser.add_argument('-v', '--verbose', action = 'store_true', help = 'Print verbose informations')
args = parser.parse_args() args = parser.parse_args()
profile = Profile(args.dump_file) profile = Profile(args.dump_file)
r = re.compile(' (.*) heuristics( of edge [0-9]*->[0-9]*)?( \\(.*\\))?: (.*)%.*exec ([0-9]*) hit ([0-9]*)')
loop_niter_str = ';; profile-based iteration count: ' loop_niter_str = ';; profile-based iteration count: '
for l in open(args.dump_file): for l in open(args.dump_file):
m = r.match(l) if l.startswith(';;heuristics;'):
if m != None and m.group(3) == None: parts = l.strip().split(';')
name = m.group(1) assert len(parts) == 8
prediction = float(m.group(4)) name = parts[3]
count = int(m.group(5)) prediction = float(parts[6])
hits = int(m.group(6)) count = int(parts[4])
hits = int(parts[5])
profile.add(name, prediction, count, hits) profile.add(name, prediction, count, hits)
elif l.startswith(loop_niter_str): elif l.startswith(loop_niter_str):
......
2018-01-19 Martin Liska <mliska@suse.cz>
* predict.c (dump_prediction): Add new format for
analyze_brprob.py script which is enabled with -details
suboption.
* profile-count.h (precise_p): New function.
2018-01-19 Richard Sandiford <richard.sandiford@linaro.org> 2018-01-19 Richard Sandiford <richard.sandiford@linaro.org>
PR tree-optimization/83922 PR tree-optimization/83922
......
...@@ -747,6 +747,19 @@ dump_prediction (FILE *file, enum br_predictor predictor, int probability, ...@@ -747,6 +747,19 @@ dump_prediction (FILE *file, enum br_predictor predictor, int probability,
} }
fprintf (file, "\n"); fprintf (file, "\n");
/* Print output that be easily read by analyze_brprob.py script. We are
interested only in counts that are read from GCDA files. */
if (dump_file && (dump_flags & TDF_DETAILS)
&& bb->count.precise_p ()
&& reason == REASON_NONE)
{
gcc_assert (e->count ().precise_p ());
fprintf (file, ";;heuristics;%s;%" PRId64 ";%" PRId64 ";%.1f;\n",
predictor_info[predictor].name,
bb->count.to_gcov_type (), e->count ().to_gcov_type (),
probability * 100.0 / REG_BR_PROB_BASE);
}
} }
/* Return true if STMT is known to be unlikely executed. */ /* Return true if STMT is known to be unlikely executed. */
......
...@@ -691,6 +691,11 @@ public: ...@@ -691,6 +691,11 @@ public:
{ {
return !initialized_p () || m_quality >= profile_guessed_global0; return !initialized_p () || m_quality >= profile_guessed_global0;
} }
/* Return true if quality of profile is precise. */
bool precise_p () const
{
return m_quality == profile_precise;
}
/* When merging basic blocks, the two different profile counts are unified. /* When merging basic blocks, the two different profile counts are unified.
Return true if this can be done without losing info about profile. Return true if this can be done without losing info about profile.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment