From patchwork Tue Jan 9 11:23:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Martin_Li=C5=A1ka?= X-Patchwork-Id: 857393 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-470518-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="G1i6zGac"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zG8sj08PRz9sBZ for ; Tue, 9 Jan 2018 22:23:52 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :subject:from:to:cc:references:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=CS30GmNed8cyIcSUU jo4dFeyauSl8Vinka0MBPFV2waoP41zuMfydqBSnGa/aU+5bypzj5IWnfHCEQGqe dgXzRhy5gSiOdsQS8Aaj9kJwqxRCDSFsphThX3JyESlmwXWYKLSjrXCUjaPd5p6v p4vpJLh1pQxl2deBu7uBqXPXEQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :subject:from:to:cc:references:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=nlvsw9Vd3PuT37AVk0wWep/ jKeA=; b=G1i6zGacGW5PRb9lFXOK+/xpHkwZnn0Oh9eqh5Z0jFPOUrobW+EpvTA zK6PpaDl9jLXA0hJlYnKwUNh5Vh32kik8v2759/xGg4Za6BmiLmID8d/QaqLypPg Uw6MUnuOd6cIfIMeqKuJTTFJNnmhr8qez8/bFSfSy4BhWDafFx7w= Received: (qmail 43197 invoked by alias); 9 Jan 2018 11:23:46 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 43187 invoked by uid 89); 9 Jan 2018 11:23:45 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.2 spammy=separated, 1000.0, 00f, 12s X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 09 Jan 2018 11:23:43 +0000 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 67EC4AAAD; Tue, 9 Jan 2018 11:23:41 +0000 (UTC) Subject: [PATCH 1/5] Fix usage of analyze_brprob.py script. From: =?utf-8?q?Martin_Li=C5=A1ka?= To: GCC Patches Cc: Jan Hubicka References: <95e8e2f2-9d42-9ab0-c0d9-43dff5dcc891@suse.cz> Message-ID: Date: Tue, 9 Jan 2018 12:23:39 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.4.0 MIME-Version: 1.0 In-Reply-To: <95e8e2f2-9d42-9ab0-c0d9-43dff5dcc891@suse.cz> X-IsSubscribed: yes First patch from the series simplifies how we dump and post-process statistics. I switched to use ';' separated values instead of a complex human language. Changes to analyze_brprob.py add possibility to filter out dominant edges. Having that one can see how predictor values change if a dominant edge is ignored. Martin From ef3c162961f3599ee65e87ecde5138d9f37f0221 Mon Sep 17 00:00:00 2001 From: marxin Date: Thu, 21 Dec 2017 17:19:13 +0100 Subject: [PATCH 1/5] Fix usage of analyze_brprob.py script. contrib/ChangeLog: 2017-12-21 Martin Liska * analyze_brprob.py: Support new format that can be easily parsed. Add new column to report. gcc/ChangeLog: 2017-12-21 Martin Liska * 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. --- contrib/analyze_brprob.py | 103 ++++++++++++++++++++++++++++++++-------------- gcc/predict.c | 13 ++++++ gcc/profile-count.h | 5 +++ 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/contrib/analyze_brprob.py b/contrib/analyze_brprob.py index e03d1da1cde..de5f474d629 100755 --- a/contrib/analyze_brprob.py +++ b/contrib/analyze_brprob.py @@ -71,6 +71,7 @@ from math import * counter_aggregates = set(['combined', 'first match', 'DS theory', 'no prediction']) +hot_threshold = 10 def percentage(a, b): return 100.0 * a / b @@ -131,47 +132,87 @@ class PredictDefFile: with open(self.path, 'w+') as f: for l in modified_lines: f.write(l + '\n') +class Heuristics: + def __init__(self, count, hits, fits): + self.count = count + self.hits = hits + self.fits = fits class Summary: def __init__(self, name): self.name = name - self.branches = 0 - self.successfull_branches = 0 - self.count = 0 - self.hits = 0 - self.fits = 0 + self.edges= [] + + def branches(self): + return len(self.edges) + + 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): - return 100.0 * self.hits / self.count + return 100.0 * self.hits() / self.count() 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): - v = self.count + v = self.count() for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']: if v < 1000: return "%3.2f%s" % (v, unit) v /= 1000.0 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): + # 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 if predict_def != None and self.name in predict_def.predictors: predicted_as = predict_def.predictors[self.name] print('%-40s %8i %5.1f%% %11.2f%% %7.2f%% / %6.2f%% %14i %8s %5.1f%%' % - (self.name, self.branches, - percentage(self.branches, branches_max), + (self.name, self.branches(), + percentage(self.branches(), branches_max), self.get_branch_hitrate(), self.get_hitrate(), - percentage(self.fits, self.count), - self.count, self.count_formatted(), - percentage(self.count, count_max)), end = '') + percentage(self.fits(), self.count()), + self.count(), self.count_formatted(), + percentage(self.count(), count_max)), end = '') if predicted_as != None: print('%12i%% %5.1f%%' % (predicted_as, 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() class Profile: @@ -185,33 +226,29 @@ class Profile: self.heuristics[name] = Summary(name) s = self.heuristics[name] - s.branches += 1 - s.count += count if prediction < 50: hits = count - hits remaining = count - hits - if hits >= remaining: - s.successfull_branches += 1 + fits = max(hits, remaining) - s.hits += hits - s.fits += max(hits, remaining) + s.edges.append(Heuristics(count, hits, fits)) 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()]) + return max([v.branches() for k, v in self.heuristics.items()]) 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): count_max = self.count_max() branches_max = self.branches_max() - sorter = lambda x: x.branches + sorter = lambda x: x.branches() if sorting == 'branch-hitrate': sorter = lambda x: x.get_branch_hitrate() elif sorting == 'hitrate': @@ -221,10 +258,10 @@ class Profile: elif sorting == 'name': 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)', 'BR. HITRATE', 'HITRATE', 'COVERAGE', 'COVERAGE', '(REL)', - 'predict.def', '(REL)')) + 'predict.def', '(REL)', 'HOT branches (>%d%%)' % hot_threshold)) for h in sorted(heuristics, key = sorter): h.print(branches_max, count_max, predict_def) @@ -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('-w', '--write-def-file', action = 'store_true', 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() 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: ' + for l in open(args.dump_file): - m = r.match(l) - if m != None and m.group(3) == None: - name = m.group(1) - prediction = float(m.group(4)) - count = int(m.group(5)) - hits = int(m.group(6)) + if l.startswith(';;heuristics;'): + parts = l.strip().split(';') + assert len(parts) == 8 + name = parts[3] + prediction = float(parts[6]) + count = int(parts[4]) + hits = int(parts[5]) profile.add(name, prediction, count, hits) elif l.startswith(loop_niter_str): diff --git a/gcc/predict.c b/gcc/predict.c index 9cea90d1063..3ac18a2c5f2 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -747,6 +747,19 @@ dump_prediction (FILE *file, enum br_predictor predictor, int probability, } 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. */ diff --git a/gcc/profile-count.h b/gcc/profile-count.h index 3c5f720ee81..3a37b1293e5 100644 --- a/gcc/profile-count.h +++ b/gcc/profile-count.h @@ -689,6 +689,11 @@ public: { 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. Return true if this can be done without losing info about profile. -- 2.14.3