From: "Martin Liška" <mliska@suse.cz>
To: Jan Hubicka <hubicka@ucw.cz>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH 2/2] Add edge predictions pruning
Date: Thu, 09 Jun 2016 11:24:00 -0000 [thread overview]
Message-ID: <94e15a58-4e9e-0957-111f-e80d57988717@suse.cz> (raw)
In-Reply-To: <20160608124133.GB14058@kam.mff.cuni.cz>
[-- Attachment #1: Type: text/plain, Size: 356 bytes --]
On 06/08/2016 02:41 PM, Jan Hubicka wrote:
> Adding hash for this prupose is bit of an overkill (there are
> definitly cheaper ways of solving so), but it will hardly affect compile
> time, so the pathc is OK.
>
> Thanks,
> Honza
Hi
Sending the final version where I added comments and I also changed
dump scanning to cover the new dump format.
Martin
[-- Attachment #2: 0002-Add-edge-predictions-pruning-v3.patch --]
[-- Type: text/x-patch, Size: 16828 bytes --]
From f83a515c952f3f17b45c757a3a84761d95959a39 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Tue, 31 May 2016 17:29:53 +0200
Subject: [PATCH 2/4] Add edge predictions pruning
contrib/ChangeLog:
2016-06-01 Martin Liska <mliska@suse.cz>
* analyze_brprob.py: Cover new dump output format.
gcc/ChangeLog:
2016-06-01 Martin Liska <mliska@suse.cz>
* predict.c (dump_prediction): Add new argument.
(enum predictor_reason): New enum.
(struct predictor_hash): New struct.
(predictor_hash::hash): New function.
(predictor_hash::equal): Likewise.
(not_removed_prediction_p): New function.
(prune_predictions_for_bb): Likewise.
(combine_predictions_for_bb): Prune predictions.
gcc/testsuite/ChangeLog:
2016-06-08 Martin Liska <mliska@suse.cz>
* g++.dg/predict-loop-exit-1.C: Scan for a new dump format.
* g++.dg/predict-loop-exit-2.C: Likewise.
* g++.dg/predict-loop-exit-3.C: Likewise.
* gcc.dg/predict-1.c: Likewise.
* gcc.dg/predict-2.c: Likewise.
* gcc.dg/predict-3.c: Likewise.
* gcc.dg/predict-4.c: Likewise.
* gcc.dg/predict-5.c: Likewise.
* gcc.dg/predict-6.c: Likewise.
* gcc.dg/predict-7.c: Likewise.
---
contrib/analyze_brprob.py | 10 +-
gcc/predict.c | 184 +++++++++++++++++++++++++----
gcc/testsuite/g++.dg/predict-loop-exit-1.C | 4 +-
gcc/testsuite/g++.dg/predict-loop-exit-2.C | 4 +-
gcc/testsuite/g++.dg/predict-loop-exit-3.C | 4 +-
gcc/testsuite/gcc.dg/predict-1.c | 2 +-
gcc/testsuite/gcc.dg/predict-2.c | 2 +-
gcc/testsuite/gcc.dg/predict-3.c | 2 +-
gcc/testsuite/gcc.dg/predict-4.c | 2 +-
gcc/testsuite/gcc.dg/predict-5.c | 2 +-
gcc/testsuite/gcc.dg/predict-6.c | 2 +-
gcc/testsuite/gcc.dg/predict-7.c | 2 +-
12 files changed, 182 insertions(+), 38 deletions(-)
diff --git a/contrib/analyze_brprob.py b/contrib/analyze_brprob.py
index 36371ff..9416eed 100755
--- a/contrib/analyze_brprob.py
+++ b/contrib/analyze_brprob.py
@@ -122,14 +122,14 @@ if len(sys.argv) != 2:
exit(1)
profile = Profile(sys.argv[1])
-r = re.compile(' (.*) heuristics: (.*)%.*exec ([0-9]*) hit ([0-9]*)')
+r = re.compile(' (.*) heuristics( of edge [0-9]*->[0-9]*)?( \\(.*\\))?: (.*)%.*exec ([0-9]*) hit ([0-9]*)')
for l in open(profile.filename).readlines():
m = r.match(l)
- if m != None:
+ if m != None and m.group(3) == None:
name = m.group(1)
- prediction = float(m.group(2))
- count = int(m.group(3))
- hits = int(m.group(4))
+ prediction = float(m.group(4))
+ count = int(m.group(5))
+ hits = int(m.group(6))
profile.add(name, prediction, count, hits)
diff --git a/gcc/predict.c b/gcc/predict.c
index e058793..a61e01c 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -55,13 +55,29 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-loop.h"
#include "tree-scalar-evolution.h"
+/* Enum with reasons why a predictor is ignored. */
+
+enum predictor_reason
+{
+ NONE,
+ IGNORED,
+ SINGLE_EDGE_DUPLICATE,
+ EDGE_PAIR_DUPLICATE
+};
+
+/* String messages for the aforementioned enum. */
+
+static const char *reason_messages[] = {"", " (ignored)",
+ " (single edge duplicate)", " (edge pair duplicate)"};
+
/* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX. */
static sreal real_almost_one, real_br_prob_base,
real_inv_br_prob_base, real_one_half, real_bb_freq_max;
static void combine_predictions_for_insn (rtx_insn *, basic_block);
-static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int);
+static void dump_prediction (FILE *, enum br_predictor, int, basic_block,
+ enum predictor_reason, edge);
static void predict_paths_leading_to (basic_block, enum br_predictor, enum prediction);
static void predict_paths_leading_to_edge (edge, enum br_predictor, enum prediction);
static bool can_predict_insn_p (const rtx_insn *);
@@ -723,21 +739,31 @@ invert_br_probabilities (rtx insn)
static void
dump_prediction (FILE *file, enum br_predictor predictor, int probability,
- basic_block bb, int used)
+ basic_block bb, enum predictor_reason reason = NONE,
+ edge ep_edge = NULL)
{
- edge e;
+ edge e = ep_edge;
edge_iterator ei;
if (!file)
return;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (! (e->flags & EDGE_FALLTHRU))
- break;
+ if (e == NULL)
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (! (e->flags & EDGE_FALLTHRU))
+ break;
+
+ char edge_info_str[128];
+ if (ep_edge)
+ sprintf (edge_info_str, " of edge %d->%d", ep_edge->src->index,
+ ep_edge->dest->index);
+ else
+ edge_info_str[0] = '\0';
- fprintf (file, " %s heuristics%s: %.1f%%",
+ fprintf (file, " %s heuristics%s%s: %.1f%%",
predictor_info[predictor].name,
- used ? "" : " (ignored)", probability * 100.0 / REG_BR_PROB_BASE);
+ edge_info_str, reason_messages[reason],
+ probability * 100.0 / REG_BR_PROB_BASE);
if (bb->count)
{
@@ -834,18 +860,18 @@ combine_predictions_for_insn (rtx_insn *insn, basic_block bb)
if (!found)
dump_prediction (dump_file, PRED_NO_PREDICTION,
- combined_probability, bb, true);
+ combined_probability, bb);
else
{
dump_prediction (dump_file, PRED_DS_THEORY, combined_probability,
- bb, !first_match);
+ bb, !first_match ? NONE : IGNORED);
dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability,
- bb, first_match);
+ bb, first_match ? NONE: IGNORED);
}
if (first_match)
combined_probability = best_probability;
- dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb, true);
+ dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb);
while (*pnote)
{
@@ -856,7 +882,8 @@ combine_predictions_for_insn (rtx_insn *insn, basic_block bb)
int probability = INTVAL (XEXP (XEXP (*pnote, 0), 1));
dump_prediction (dump_file, predictor, probability, bb,
- !first_match || best_predictor == predictor);
+ (!first_match || best_predictor == predictor)
+ ? NONE : IGNORED);
*pnote = XEXP (*pnote, 1);
}
else
@@ -887,6 +914,121 @@ combine_predictions_for_insn (rtx_insn *insn, basic_block bb)
single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
}
+/* Edge prediction hash traits. */
+
+struct predictor_hash: pointer_hash <edge_prediction>
+{
+
+ static inline hashval_t hash (const edge_prediction *);
+ static inline bool equal (const edge_prediction *, const edge_prediction *);
+};
+
+/* Calculate hash value of an edge prediction P based on predictor and
+ normalized probability. */
+
+inline hashval_t
+predictor_hash::hash (const edge_prediction *p)
+{
+ inchash::hash hstate;
+ hstate.add_int (p->ep_predictor);
+
+ int prob = p->ep_probability;
+ if (prob > REG_BR_PROB_BASE / 2)
+ prob = REG_BR_PROB_BASE - prob;
+
+ hstate.add_int (prob);
+
+ return hstate.end ();
+}
+
+/* Return true whether edge predictions P1 and P2 use the same predictor and
+ have equal (or opposed probability). */
+
+inline bool
+predictor_hash::equal (const edge_prediction *p1, const edge_prediction *p2)
+{
+ return (p1->ep_predictor == p2->ep_predictor
+ && (p1->ep_probability == p2->ep_probability
+ || p1->ep_probability == REG_BR_PROB_BASE - p2->ep_probability));
+}
+
+struct predictor_hash_traits: predictor_hash,
+ typed_noop_remove <edge_prediction *> {};
+
+/* Return true if edge prediction P is not in DATA hash set. */
+
+static bool
+not_removed_prediction_p (edge_prediction *p, void *data)
+{
+ hash_set<edge_prediction *> *remove = (hash_set<edge_prediction *> *) data;
+ return !remove->contains (p);
+}
+
+/* Prune predictions for a basic block BB. Currently we do following
+ clean-up steps:
+
+ 1) remove duplicate prediction that is guessed with the same probability
+ (different than 1/2) to both edge
+ 2) remove duplicates for a prediction that belongs with the same probability
+ to a single edge
+
+ */
+
+static void
+prune_predictions_for_bb (basic_block bb)
+{
+ edge_prediction **preds = bb_predictions->get (bb);
+
+ if (preds)
+ {
+ hash_table <predictor_hash_traits> s (13);
+ hash_set <edge_prediction *> remove;
+
+ /* Step 1: identify predictors that should be removed. */
+ for (edge_prediction *pred = *preds; pred; pred = pred->ep_next)
+ {
+ edge_prediction *existing = s.find (pred);
+ if (existing)
+ {
+ if (pred->ep_edge == existing->ep_edge
+ && pred->ep_probability == existing->ep_probability)
+ {
+ /* Remove a duplicate predictor. */
+ dump_prediction (dump_file, pred->ep_predictor,
+ pred->ep_probability, bb,
+ SINGLE_EDGE_DUPLICATE, pred->ep_edge);
+
+ remove.add (pred);
+ }
+ else if (pred->ep_edge != existing->ep_edge
+ && pred->ep_probability == existing->ep_probability
+ && pred->ep_probability != REG_BR_PROB_BASE / 2)
+ {
+ /* Remove both predictors as they predict the same
+ for both edges. */
+ dump_prediction (dump_file, existing->ep_predictor,
+ pred->ep_probability, bb,
+ EDGE_PAIR_DUPLICATE,
+ existing->ep_edge);
+ dump_prediction (dump_file, pred->ep_predictor,
+ pred->ep_probability, bb,
+ EDGE_PAIR_DUPLICATE,
+ pred->ep_edge);
+
+ remove.add (existing);
+ remove.add (pred);
+ }
+ }
+
+ edge_prediction **slot2 = s.find_slot (pred, INSERT);
+ *slot2 = pred;
+ }
+
+ /* Step 2: Remove predictors. */
+ filter_predictions (preds, not_removed_prediction_p, &remove);
+ }
+}
+
/* Combine predictions into single probability and store them into CFG.
Remove now useless prediction entries.
If DRY_RUN is set, only produce dumps and do not modify profile. */
@@ -935,7 +1077,10 @@ combine_predictions_for_bb (basic_block bb, bool dry_run)
if (dump_file)
fprintf (dump_file, "Predictions for bb %i\n", bb->index);
+ prune_predictions_for_bb (bb);
+
edge_prediction **preds = bb_predictions->get (bb);
+
if (preds)
{
/* We implement "first match" heuristics and use probability guessed
@@ -1001,18 +1146,18 @@ combine_predictions_for_bb (basic_block bb, bool dry_run)
first_match = true;
if (!found)
- dump_prediction (dump_file, PRED_NO_PREDICTION, combined_probability, bb, true);
+ dump_prediction (dump_file, PRED_NO_PREDICTION, combined_probability, bb);
else
{
dump_prediction (dump_file, PRED_DS_THEORY, combined_probability, bb,
- !first_match);
+ !first_match ? NONE : IGNORED);
dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability, bb,
- first_match);
+ first_match ? NONE : IGNORED);
}
if (first_match)
combined_probability = best_probability;
- dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb, true);
+ dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb);
if (preds)
{
@@ -1021,10 +1166,9 @@ combine_predictions_for_bb (basic_block bb, bool dry_run)
enum br_predictor predictor = pred->ep_predictor;
int probability = pred->ep_probability;
- if (pred->ep_edge != EDGE_SUCC (bb, 0))
- probability = REG_BR_PROB_BASE - probability;
dump_prediction (dump_file, predictor, probability, bb,
- !first_match || best_predictor == predictor);
+ (!first_match || best_predictor == predictor)
+ ? NONE : IGNORED, pred->ep_edge);
}
}
clear_bb_predictions (bb);
diff --git a/gcc/testsuite/g++.dg/predict-loop-exit-1.C b/gcc/testsuite/g++.dg/predict-loop-exit-1.C
index 357397f..88262eb 100644
--- a/gcc/testsuite/g++.dg/predict-loop-exit-1.C
+++ b/gcc/testsuite/g++.dg/predict-loop-exit-1.C
@@ -9,5 +9,5 @@ void test() {
return;
}
-/* { dg-final { scan-tree-dump-times "extra loop exit heuristics:" 2 "profile_estimate"} } */
-/* { dg-final { scan-tree-dump-times "loop exit heuristics:" 3 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "extra loop exit heuristics of edge\[^:\]*:" 2 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop exit heuristics of edge\[^:\]*:" 3 "profile_estimate"} } */
diff --git a/gcc/testsuite/g++.dg/predict-loop-exit-2.C b/gcc/testsuite/g++.dg/predict-loop-exit-2.C
index 172fab1..15e9866 100644
--- a/gcc/testsuite/g++.dg/predict-loop-exit-2.C
+++ b/gcc/testsuite/g++.dg/predict-loop-exit-2.C
@@ -9,5 +9,5 @@ void test() {
return;
}
-/* { dg-final { scan-tree-dump-times "extra loop exit heuristics:" 1 "profile_estimate"} } */
-/* { dg-final { scan-tree-dump-times "loop exit heuristics:" 2 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "extra loop exit heuristics of edge\[^:\]*:" 1 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop exit heuristics of edge\[^:\]*:" 2 "profile_estimate"} } */
diff --git a/gcc/testsuite/g++.dg/predict-loop-exit-3.C b/gcc/testsuite/g++.dg/predict-loop-exit-3.C
index e6ceec8..61af84b 100644
--- a/gcc/testsuite/g++.dg/predict-loop-exit-3.C
+++ b/gcc/testsuite/g++.dg/predict-loop-exit-3.C
@@ -9,5 +9,5 @@ void test() {
return;
}
-/* { dg-final { scan-tree-dump-times "extra loop exit heuristics:" 2 "profile_estimate"} } */
-/* { dg-final { scan-tree-dump-times "loop exit heuristics:" 3 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "extra loop exit heuristics of edge\[^:\]*:" 2 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop exit heuristics of edge\[^:\]*:" 3 "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-1.c b/gcc/testsuite/gcc.dg/predict-1.c
index 94f6b019..d0924f2 100644
--- a/gcc/testsuite/gcc.dg/predict-1.c
+++ b/gcc/testsuite/gcc.dg/predict-1.c
@@ -23,4 +23,4 @@ void foo (int bound)
}
}
-/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 2.0%" 5 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop iv compare heuristics of edge\[^:\]*: 2.0%" 5 "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-2.c b/gcc/testsuite/gcc.dg/predict-2.c
index f2fc49d..3011686 100644
--- a/gcc/testsuite/gcc.dg/predict-2.c
+++ b/gcc/testsuite/gcc.dg/predict-2.c
@@ -23,4 +23,4 @@ void foo (int base, int bound)
}
}
-/* { dg-final { scan-tree-dump-not "loop iv compare heuristics" "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-not "loop iv compare heuristics of edge\[^:\]*:" "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-3.c b/gcc/testsuite/gcc.dg/predict-3.c
index 08db59a..6768c36 100644
--- a/gcc/testsuite/gcc.dg/predict-3.c
+++ b/gcc/testsuite/gcc.dg/predict-3.c
@@ -25,4 +25,4 @@ void foo (int bound)
}
}
-/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 98.0%" 3 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop iv compare heuristics of edge\[^:\]*:: 98.0%" 3 "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-4.c b/gcc/testsuite/gcc.dg/predict-4.c
index 3e7fb74..5779da3 100644
--- a/gcc/testsuite/gcc.dg/predict-4.c
+++ b/gcc/testsuite/gcc.dg/predict-4.c
@@ -15,4 +15,4 @@ void foo (int bound)
}
}
-/* { dg-final { scan-tree-dump "loop iv compare heuristics: 50.0%" "profile_estimate"} } */
+/* { dg-final { scan-tree-dump "loop iv compare heuristics of edge\[^:\]*: 50.0%" "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-5.c b/gcc/testsuite/gcc.dg/predict-5.c
index 32178a8..56ada30 100644
--- a/gcc/testsuite/gcc.dg/predict-5.c
+++ b/gcc/testsuite/gcc.dg/predict-5.c
@@ -21,4 +21,4 @@ void foo (int base, int bound)
}
}
-/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 98.0%" 4 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop iv compare heuristics of edge\[^:\]*: 98.0%" 4 "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-6.c b/gcc/testsuite/gcc.dg/predict-6.c
index 16ad16f..9ed41ed 100644
--- a/gcc/testsuite/gcc.dg/predict-6.c
+++ b/gcc/testsuite/gcc.dg/predict-6.c
@@ -21,4 +21,4 @@ void foo (int base, int bound)
}
}
-/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 2.0%" 4 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop iv compare heuristics of edge\[^:\]*: 2.0%" 4 "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-7.c b/gcc/testsuite/gcc.dg/predict-7.c
index a0ea37b..fe34ca5 100644
--- a/gcc/testsuite/gcc.dg/predict-7.c
+++ b/gcc/testsuite/gcc.dg/predict-7.c
@@ -13,4 +13,4 @@ void foo (int base)
bar (i);
}
-/* { dg-final { scan-tree-dump-times "loop branch heuristics" 0 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop branch heuristics of edge\[^:\]*" 0 "profile_estimate"} } */
--
2.8.3
next prev parent reply other threads:[~2016-06-09 11:24 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-06-02 11:57 [PATCH 0/2] Deduplicate edge predictors marxin
2016-06-02 11:57 ` [PATCH 1/2] Introduce filtering for edge_predictions marxin
2016-06-02 11:57 ` [PATCH 2/2] Add edge predictions pruning marxin
2016-06-08 12:25 ` Martin Liška
2016-06-08 12:41 ` Jan Hubicka
2016-06-09 11:24 ` Martin Liška [this message]
2016-06-12 11:55 ` [BUILDROBOT] MPS430 build problem due to new enum (was: [PATCH 2/2] Add edge predictions pruning) Jan-Benedict Glaw
2016-06-13 7:25 ` [BUILDROBOT] MPS430 build problem due to new enum Martin Liška
2016-06-13 8:47 ` [BUILDROBOT] MPS430 build problem due to new enum (was: [PATCH 2/2] Add edge predictions pruning) Jan Hubicka
2016-06-13 10:01 ` [BUILDROBOT] MPS430 build problem due to new enum Martin Liška
2016-06-08 12:26 ` [PATCH 3/N] Add sorting support to analyze_brprob script Martin Liška
2016-06-08 15:02 ` Jan Hubicka
2016-06-08 12:29 ` [PATCH 4/N] Add new analyze_brprob_spec.py script Martin Liška
2016-06-08 15:12 ` Jan Hubicka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=94e15a58-4e9e-0957-111f-e80d57988717@suse.cz \
--to=mliska@suse.cz \
--cc=gcc-patches@gcc.gnu.org \
--cc=hubicka@ucw.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).