* basic-block. (profile_record): New struct, moved from passes.c.

* cfghooks.h (struct cfg_hooks) <account_profile_record>: New hook.
	(account_profile_record): New prototype.
	* cfghooks.c (account_profile_record): New function.
	* tree-cfg.c (gimple_account_profile_record): New function
	(gimple_cfg_hooks): Add it.
	* cfgrtl.c (rtl_account_profile_record): New function
	(rtl_cfg_hooks, cfg_layout_rtl_cfg_hooks): Add it.
	* passes.c (check_profile_consistency): Simplify.  Move IR-dependent
	code around using cfghooks machinery.

From-SVN: r192271
This commit is contained in:
Steven Bosscher 2012-10-09 20:37:11 +00:00
parent ca4277584f
commit aa4723d7f5
7 changed files with 158 additions and 92 deletions

View File

@ -1,3 +1,16 @@
2012-10-09 Steven Bosscher <steven@gcc.gnu.org>
* basic-block. (profile_record): New struct, moved from passes.c.
* cfghooks.h (struct cfg_hooks) <account_profile_record>: New hook.
(account_profile_record): New prototype.
* cfghooks.c (account_profile_record): New function.
* tree-cfg.c (gimple_account_profile_record): New function
(gimple_cfg_hooks): Add it.
* cfgrtl.c (rtl_account_profile_record): New function
(rtl_cfg_hooks, cfg_layout_rtl_cfg_hooks): Add it.
* passes.c (check_profile_consistency): Simplify. Move IR-dependent
code around using cfghooks machinery.
2012-10-09 Oleg Endo <olegendo@gcc.gnu.org>
PR target/54760

View File

@ -101,6 +101,37 @@ typedef struct gcov_working_set_info
gcov_type min_counter;
} gcov_working_set_t;
/* Structure to gather statistic about profile consistency, per pass.
An array of this structure, indexed by pass static number, is allocated
in passes.c. The structure is defined here so that different CFG modes
can do their book-keeping via CFG hooks.
For every field[2], field[0] is the count before the pass runs, and
field[1] is the post-pass count. This allows us to monitor the effect
of each individual pass on the profile consistency.
This structure is not supposed to be used by anything other than passes.c
and one CFG hook per CFG mode. */
struct profile_record
{
/* The number of basic blocks where sum(freq) of the block's predecessors
doesn't match reasonably well with the incoming frequency. */
int num_mismatched_freq_in[2];
/* Likewise for a basic block's successors. */
int num_mismatched_freq_out[2];
/* The number of basic blocks where sum(count) of the block's predecessors
doesn't match reasonably well with the incoming frequency. */
int num_mismatched_count_in[2];
/* Likewise for a basic block's successors. */
int num_mismatched_count_out[2];
/* A weighted cost of the run-time of the function body. */
gcov_type time[2];
/* A weighted cost of the size of the function body. */
int size[2];
/* True iff this pass actually was run. */
bool run;
};
/* Declared in cfgloop.h. */
struct loop;

View File

@ -1324,3 +1324,57 @@ split_block_before_cond_jump (basic_block bb)
return cfg_hooks->split_block_before_cond_jump (bb);
}
/* Work-horse for passes.c:check_profile_consistency.
Do book-keeping of the CFG for the profile consistency checker.
If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1
then do post-pass accounting. Store the counting in RECORD. */
void
account_profile_record (struct profile_record *record, int after_pass)
{
basic_block bb;
edge_iterator ei;
edge e;
int sum;
gcov_type lsum;
FOR_ALL_BB (bb)
{
if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (cfun)
&& profile_status != PROFILE_ABSENT)
{
sum = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
sum += e->probability;
if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100)
record->num_mismatched_freq_out[after_pass]++;
lsum = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
lsum += e->count;
if (EDGE_COUNT (bb->succs)
&& (lsum - bb->count > 100 || lsum - bb->count < -100))
record->num_mismatched_count_out[after_pass]++;
}
if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
&& profile_status != PROFILE_ABSENT)
{
sum = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
sum += EDGE_FREQUENCY (e);
if (abs (sum - bb->frequency) > 100
|| (MAX (sum, bb->frequency) > 10
&& abs ((sum - bb->frequency) * 100 / (MAX (sum, bb->frequency) + 1)) > 10))
record->num_mismatched_freq_in[after_pass]++;
lsum = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
lsum += e->count;
if (lsum - bb->count > 100 || lsum - bb->count < -100)
record->num_mismatched_count_in[after_pass]++;
}
if (bb == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
|| bb == EXIT_BLOCK_PTR_FOR_FUNCTION (cfun))
continue;
gcc_assert (cfg_hooks->account_profile_record);
cfg_hooks->account_profile_record(bb, after_pass, record);
}
}

View File

@ -145,6 +145,9 @@ struct cfg_hooks
/* Split a basic block if it ends with a conditional branch and if
the other part of the block is not empty. */
basic_block (*split_block_before_cond_jump) (basic_block);
/* Do book-keeping of a basic block for the profile consistency checker. */
void (*account_profile_record) (basic_block, int, struct profile_record *);
};
extern void verify_flow_info (void);
@ -198,6 +201,8 @@ extern void copy_bbs (basic_block *, unsigned, basic_block *,
edge *, unsigned, edge *, struct loop *,
basic_block);
void account_profile_record (struct profile_record *, int);
extern void cfg_layout_initialize (unsigned int);
extern void cfg_layout_finalize (void);

View File

@ -4452,6 +4452,28 @@ rtl_duplicate_bb (basic_block bb)
return bb;
}
/* Do book-keeping of basic block BB for the profile consistency checker.
If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1
then do post-pass accounting. Store the counting in RECORD. */
static void
rtl_account_profile_record (basic_block bb, int after_pass,
struct profile_record *record)
{
rtx insn;
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
{
record->size[after_pass]
+= insn_rtx_cost (PATTERN (insn), false);
if (profile_status == PROFILE_READ)
record->time[after_pass]
+= insn_rtx_cost (PATTERN (insn), true) * bb->count;
else if (profile_status == PROFILE_GUESSED)
record->time[after_pass]
+= insn_rtx_cost (PATTERN (insn), true) * bb->frequency;
}
}
/* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = {
"rtl",
@ -4486,6 +4508,7 @@ struct cfg_hooks rtl_cfg_hooks = {
NULL, /* flush_pending_stmts */
rtl_block_empty_p, /* block_empty_p */
rtl_split_block_before_cond_jump, /* split_block_before_cond_jump */
rtl_account_profile_record,
};
/* Implementation of CFG manipulation for cfg layout RTL, where
@ -4526,6 +4549,7 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
NULL, /* flush_pending_stmts */
rtl_block_empty_p, /* block_empty_p */
rtl_split_block_before_cond_jump, /* split_block_before_cond_jump */
rtl_account_profile_record,
};
#include "gt-cfgrtl.h"

View File

@ -1778,30 +1778,16 @@ execute_function_dump (void *data ATTRIBUTE_UNUSED)
}
}
/* Make statistic about profile consistency. */
struct profile_record
{
int num_mismatched_freq_in[2];
int num_mismatched_freq_out[2];
int num_mismatched_count_in[2];
int num_mismatched_count_out[2];
bool run;
gcov_type time[2];
int size[2];
};
static struct profile_record *profile_record;
/* Do profile consistency book-keeping for the pass with static number INDEX.
If SUBPASS is zero, we run _before_ the pass, and if SUBPASS is one, then
we run _after_ the pass. RUN is true if the pass really runs, or FALSE
if we are only book-keeping on passes that may have selectively disabled
themselves on a given function. */
static void
check_profile_consistency (int index, int subpass, bool run)
{
basic_block bb;
edge_iterator ei;
edge e;
int sum;
gcov_type lsum;
if (index == -1)
return;
if (!profile_record)
@ -1810,79 +1796,7 @@ check_profile_consistency (int index, int subpass, bool run)
gcc_assert (index < passes_by_id_size && index >= 0);
gcc_assert (subpass < 2);
profile_record[index].run |= run;
FOR_ALL_BB (bb)
{
if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (cfun)
&& profile_status != PROFILE_ABSENT)
{
sum = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
sum += e->probability;
if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100)
profile_record[index].num_mismatched_freq_out[subpass]++;
lsum = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
lsum += e->count;
if (EDGE_COUNT (bb->succs)
&& (lsum - bb->count > 100 || lsum - bb->count < -100))
profile_record[index].num_mismatched_count_out[subpass]++;
}
if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
&& profile_status != PROFILE_ABSENT)
{
sum = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
sum += EDGE_FREQUENCY (e);
if (abs (sum - bb->frequency) > 100
|| (MAX (sum, bb->frequency) > 10
&& abs ((sum - bb->frequency) * 100 / (MAX (sum, bb->frequency) + 1)) > 10))
profile_record[index].num_mismatched_freq_in[subpass]++;
lsum = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
lsum += e->count;
if (lsum - bb->count > 100 || lsum - bb->count < -100)
profile_record[index].num_mismatched_count_in[subpass]++;
}
if (bb == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
|| bb == EXIT_BLOCK_PTR_FOR_FUNCTION (cfun))
continue;
if ((cfun && (cfun->curr_properties & PROP_trees)))
{
gimple_stmt_iterator i;
for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
profile_record[index].size[subpass]
+= estimate_num_insns (gsi_stmt (i), &eni_size_weights);
if (profile_status == PROFILE_READ)
profile_record[index].time[subpass]
+= estimate_num_insns (gsi_stmt (i),
&eni_time_weights) * bb->count;
else if (profile_status == PROFILE_GUESSED)
profile_record[index].time[subpass]
+= estimate_num_insns (gsi_stmt (i),
&eni_time_weights) * bb->frequency;
}
}
else if (cfun && (cfun->curr_properties & PROP_rtl))
{
rtx insn;
for (insn = NEXT_INSN (BB_HEAD (bb)); insn && insn != NEXT_INSN (BB_END (bb));
insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
profile_record[index].size[subpass]
+= insn_rtx_cost (PATTERN (insn), false);
if (profile_status == PROFILE_READ)
profile_record[index].time[subpass]
+= insn_rtx_cost (PATTERN (insn), true) * bb->count;
else if (profile_status == PROFILE_GUESSED)
profile_record[index].time[subpass]
+= insn_rtx_cost (PATTERN (insn), true) * bb->frequency;
}
}
}
account_profile_record (&profile_record[index], subpass);
}
/* Output profile consistency. */

View File

@ -7591,6 +7591,30 @@ gimple_lv_add_condition_to_bb (basic_block first_head ATTRIBUTE_UNUSED,
e0->flags |= EDGE_FALSE_VALUE;
}
/* Do book-keeping of basic block BB for the profile consistency checker.
If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1
then do post-pass accounting. Store the counting in RECORD. */
static void
gimple_account_profile_record (basic_block bb, int after_pass,
struct profile_record *record)
{
gimple_stmt_iterator i;
for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
record->size[after_pass]
+= estimate_num_insns (gsi_stmt (i), &eni_size_weights);
if (profile_status == PROFILE_READ)
record->time[after_pass]
+= estimate_num_insns (gsi_stmt (i),
&eni_time_weights) * bb->count;
else if (profile_status == PROFILE_GUESSED)
record->time[after_pass]
+= estimate_num_insns (gsi_stmt (i),
&eni_time_weights) * bb->frequency;
}
}
struct cfg_hooks gimple_cfg_hooks = {
"gimple",
gimple_verify_flow_info,
@ -7624,6 +7648,7 @@ struct cfg_hooks gimple_cfg_hooks = {
flush_pending_stmts, /* flush_pending_stmts */
gimple_empty_block_p, /* block_empty_p */
gimple_split_block_before_cond_jump, /* split_block_before_cond_jump */
gimple_account_profile_record,
};