split checksum into cfg checksum and line checksum
From-SVN: r173147
This commit is contained in:
parent
112cee354d
commit
10adac5108
13 changed files with 264 additions and 82 deletions
|
@ -1,3 +1,29 @@
|
|||
2011-04-28 David Li <davidxl@google.com>
|
||||
|
||||
* tree.c (crc32_string): Use crc32_byte.
|
||||
(crc32_byte): New function.
|
||||
* tree.h (crc32_byte): New function.
|
||||
* gcov.c (read_graph_file): Handle new cfg_cksum.
|
||||
(read_count_file): Ditto.
|
||||
* profile.c (instrument_values): Ditto.
|
||||
(get_exec_counts): Ditto.
|
||||
(read_profile_edge_counts): Ditto.
|
||||
(compute_branch_probabilities): Ditto.
|
||||
(compute_value_histograms): Ditto.
|
||||
(branch_prob): Ditto.
|
||||
(end_branch_prob): Ditto.
|
||||
* coverage.c (read_counts_file): Ditto.
|
||||
(get_coverage_counts): Ditto.
|
||||
(tree_coverage_counter_addr): Ditto.
|
||||
(coverage_checksum_string): Ditto.
|
||||
(coverage_begin_output): Ditto.
|
||||
(coverage_end_function): Ditto.
|
||||
(build_fn_info_type): Ditto.
|
||||
(build_fn_info_value): Ditto.
|
||||
* libgcov.c (gcov_exit): Ditto.
|
||||
* gcov-dump.c (tag_function): Ditto.
|
||||
(compute_checksum): Remove.
|
||||
|
||||
2011-04-29 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* config/rs6000/rs6000.c (rs6000_delegitimize_address): Handle
|
||||
|
|
128
gcc/coverage.c
128
gcc/coverage.c
|
@ -51,13 +51,15 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "intl.h"
|
||||
#include "filenames.h"
|
||||
|
||||
#include "gcov-io.h"
|
||||
#include "gcov-io.c"
|
||||
|
||||
struct function_list
|
||||
{
|
||||
struct function_list *next; /* next function */
|
||||
unsigned ident; /* function ident */
|
||||
unsigned checksum; /* function checksum */
|
||||
unsigned lineno_checksum; /* function lineno checksum */
|
||||
unsigned cfg_checksum; /* function cfg checksum */
|
||||
unsigned n_ctrs[GCOV_COUNTERS];/* number of counters. */
|
||||
};
|
||||
|
||||
|
@ -69,7 +71,8 @@ typedef struct counts_entry
|
|||
unsigned ctr;
|
||||
|
||||
/* Store */
|
||||
unsigned checksum;
|
||||
unsigned lineno_checksum;
|
||||
unsigned cfg_checksum;
|
||||
gcov_type *counts;
|
||||
struct gcov_ctr_summary summary;
|
||||
|
||||
|
@ -114,8 +117,6 @@ static hashval_t htab_counts_entry_hash (const void *);
|
|||
static int htab_counts_entry_eq (const void *, const void *);
|
||||
static void htab_counts_entry_del (void *);
|
||||
static void read_counts_file (void);
|
||||
static unsigned compute_checksum (void);
|
||||
static unsigned coverage_checksum_string (unsigned, const char *);
|
||||
static tree build_fn_info_type (unsigned);
|
||||
static tree build_fn_info_value (const struct function_list *, tree);
|
||||
static tree build_ctr_info_type (void);
|
||||
|
@ -171,11 +172,12 @@ static void
|
|||
read_counts_file (void)
|
||||
{
|
||||
gcov_unsigned_t fn_ident = 0;
|
||||
gcov_unsigned_t checksum = -1;
|
||||
counts_entry_t *summaried = NULL;
|
||||
unsigned seen_summary = 0;
|
||||
gcov_unsigned_t tag;
|
||||
int is_error = 0;
|
||||
unsigned lineno_checksum = 0;
|
||||
unsigned cfg_checksum = 0;
|
||||
|
||||
if (!gcov_open (da_file_name, 1))
|
||||
return;
|
||||
|
@ -215,7 +217,8 @@ read_counts_file (void)
|
|||
if (tag == GCOV_TAG_FUNCTION)
|
||||
{
|
||||
fn_ident = gcov_read_unsigned ();
|
||||
checksum = gcov_read_unsigned ();
|
||||
lineno_checksum = gcov_read_unsigned ();
|
||||
cfg_checksum = gcov_read_unsigned ();
|
||||
if (seen_summary)
|
||||
{
|
||||
/* We have already seen a summary, this means that this
|
||||
|
@ -265,24 +268,26 @@ read_counts_file (void)
|
|||
if (!entry)
|
||||
{
|
||||
*slot = entry = XCNEW (counts_entry_t);
|
||||
entry->ident = elt.ident;
|
||||
entry->ident = fn_ident;
|
||||
entry->ctr = elt.ctr;
|
||||
entry->checksum = checksum;
|
||||
entry->lineno_checksum = lineno_checksum;
|
||||
entry->cfg_checksum = cfg_checksum;
|
||||
entry->summary.num = n_counts;
|
||||
entry->counts = XCNEWVEC (gcov_type, n_counts);
|
||||
}
|
||||
else if (entry->checksum != checksum)
|
||||
else if (entry->lineno_checksum != lineno_checksum
|
||||
|| entry->cfg_checksum != cfg_checksum)
|
||||
{
|
||||
error ("coverage mismatch for function %u while reading execution counters",
|
||||
fn_ident);
|
||||
error ("checksum is %x instead of %x", entry->checksum, checksum);
|
||||
error ("Profile data for function %u is corrupted", fn_ident);
|
||||
error ("checksum is (%x,%x) instead of (%x,%x)",
|
||||
entry->lineno_checksum, entry->cfg_checksum,
|
||||
lineno_checksum, cfg_checksum);
|
||||
htab_delete (counts_hash);
|
||||
break;
|
||||
}
|
||||
else if (entry->summary.num != n_counts)
|
||||
{
|
||||
error ("coverage mismatch for function %u while reading execution counters",
|
||||
fn_ident);
|
||||
error ("Profile data for function %u is corrupted", fn_ident);
|
||||
error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
|
||||
htab_delete (counts_hash);
|
||||
break;
|
||||
|
@ -324,10 +329,10 @@ read_counts_file (void)
|
|||
|
||||
gcov_type *
|
||||
get_coverage_counts (unsigned counter, unsigned expected,
|
||||
unsigned cfg_checksum, unsigned lineno_checksum,
|
||||
const struct gcov_ctr_summary **summary)
|
||||
{
|
||||
counts_entry_t *entry, elt;
|
||||
gcov_unsigned_t checksum = -1;
|
||||
|
||||
/* No hash table, no counts. */
|
||||
if (!counts_hash)
|
||||
|
@ -352,26 +357,21 @@ get_coverage_counts (unsigned counter, unsigned expected,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
checksum = compute_checksum ();
|
||||
if (entry->checksum != checksum
|
||||
if (entry->cfg_checksum != cfg_checksum
|
||||
|| entry->summary.num != expected)
|
||||
{
|
||||
static int warned = 0;
|
||||
bool warning_printed = false;
|
||||
tree id = DECL_ASSEMBLER_NAME (current_function_decl);
|
||||
|
||||
warning_printed =
|
||||
warning_at (input_location, OPT_Wcoverage_mismatch,
|
||||
"coverage mismatch for function "
|
||||
"%qE while reading counter %qs", id, ctr_names[counter]);
|
||||
warning_printed =
|
||||
warning_at (input_location, OPT_Wcoverage_mismatch,
|
||||
"The control flow of function %qE does not match "
|
||||
"its profile data (counter %qs)", id, ctr_names[counter]);
|
||||
if (warning_printed)
|
||||
{
|
||||
if (entry->checksum != checksum)
|
||||
inform (input_location, "checksum is %x instead of %x",
|
||||
entry->checksum, checksum);
|
||||
else
|
||||
inform (input_location, "number of counters is %d instead of %d",
|
||||
entry->summary.num, expected);
|
||||
inform (input_location, "Use -Wno-error=coverage-mismatch to tolerate "
|
||||
"the mismatch but performance may drop if the function is hot");
|
||||
|
||||
if (!seen_error ()
|
||||
&& !warned++)
|
||||
|
@ -388,6 +388,12 @@ get_coverage_counts (unsigned counter, unsigned expected,
|
|||
|
||||
return NULL;
|
||||
}
|
||||
else if (entry->lineno_checksum != lineno_checksum)
|
||||
{
|
||||
warning (0, "Source location for function %qE have changed,"
|
||||
" the profile data may be out of date",
|
||||
DECL_ASSEMBLER_NAME (current_function_decl));
|
||||
}
|
||||
|
||||
if (summary)
|
||||
*summary = &entry->summary;
|
||||
|
@ -467,6 +473,7 @@ tree_coverage_counter_addr (unsigned counter, unsigned no)
|
|||
NULL, NULL));
|
||||
}
|
||||
|
||||
|
||||
/* Generate a checksum for a string. CHKSUM is the current
|
||||
checksum. */
|
||||
|
||||
|
@ -529,8 +536,8 @@ coverage_checksum_string (unsigned chksum, const char *string)
|
|||
|
||||
/* Compute checksum for the current function. We generate a CRC32. */
|
||||
|
||||
static unsigned
|
||||
compute_checksum (void)
|
||||
unsigned
|
||||
coverage_compute_lineno_checksum (void)
|
||||
{
|
||||
expanded_location xloc
|
||||
= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
|
||||
|
@ -542,6 +549,36 @@ compute_checksum (void)
|
|||
|
||||
return chksum;
|
||||
}
|
||||
|
||||
/* Compute cfg checksum for the current function.
|
||||
The checksum is calculated carefully so that
|
||||
source code changes that doesn't affect the control flow graph
|
||||
won't change the checksum.
|
||||
This is to make the profile data useable across source code change.
|
||||
The downside of this is that the compiler may use potentially
|
||||
wrong profile data - that the source code change has non-trivial impact
|
||||
on the validity of profile data (e.g. the reversed condition)
|
||||
but the compiler won't detect the change and use the wrong profile data. */
|
||||
|
||||
unsigned
|
||||
coverage_compute_cfg_checksum (void)
|
||||
{
|
||||
basic_block bb;
|
||||
unsigned chksum = n_basic_blocks;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
chksum = crc32_byte (chksum, bb->index);
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
chksum = crc32_byte (chksum, e->dest->index);
|
||||
}
|
||||
}
|
||||
|
||||
return chksum;
|
||||
}
|
||||
|
||||
/* Begin output to the graph file for the current function.
|
||||
Opens the output file, if not already done. Writes the
|
||||
|
@ -549,7 +586,7 @@ compute_checksum (void)
|
|||
should be output. */
|
||||
|
||||
int
|
||||
coverage_begin_output (void)
|
||||
coverage_begin_output (unsigned lineno_checksum, unsigned cfg_checksum)
|
||||
{
|
||||
/* We don't need to output .gcno file unless we're under -ftest-coverage
|
||||
(e.g. -fprofile-arcs/generate/use don't need .gcno to work). */
|
||||
|
@ -575,12 +612,14 @@ coverage_begin_output (void)
|
|||
bbg_file_opened = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Announce function */
|
||||
offset = gcov_write_tag (GCOV_TAG_FUNCTION);
|
||||
gcov_write_unsigned (current_function_funcdef_no + 1);
|
||||
gcov_write_unsigned (compute_checksum ());
|
||||
gcov_write_unsigned (lineno_checksum);
|
||||
gcov_write_unsigned (cfg_checksum);
|
||||
gcov_write_string (IDENTIFIER_POINTER
|
||||
(DECL_ASSEMBLER_NAME (current_function_decl)));
|
||||
(DECL_ASSEMBLER_NAME (current_function_decl)));
|
||||
gcov_write_string (xloc.file);
|
||||
gcov_write_unsigned (xloc.line);
|
||||
gcov_write_length (offset);
|
||||
|
@ -594,7 +633,7 @@ coverage_begin_output (void)
|
|||
error has occurred. Save function coverage counts. */
|
||||
|
||||
void
|
||||
coverage_end_function (void)
|
||||
coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
|
@ -613,9 +652,11 @@ coverage_end_function (void)
|
|||
*functions_tail = item;
|
||||
functions_tail = &item->next;
|
||||
|
||||
|
||||
item->next = 0;
|
||||
item->ident = current_function_funcdef_no + 1;
|
||||
item->checksum = compute_checksum ();
|
||||
item->lineno_checksum = lineno_checksum;
|
||||
item->cfg_checksum = cfg_checksum;
|
||||
for (i = 0; i != GCOV_COUNTERS; i++)
|
||||
{
|
||||
item->n_ctrs[i] = fn_n_ctrs[i];
|
||||
|
@ -640,13 +681,18 @@ build_fn_info_type (unsigned int counters)
|
|||
/* ident */
|
||||
fields = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
|
||||
/* checksum */
|
||||
/* lineno_checksum */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* cfg checksum */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
array_type = build_int_cst (NULL_TREE, counters - 1);
|
||||
array_type = build_index_type (array_type);
|
||||
array_type = build_array_type (get_gcov_unsigned_t (), array_type);
|
||||
|
@ -680,10 +726,16 @@ build_fn_info_value (const struct function_list *function, tree type)
|
|||
function->ident));
|
||||
fields = DECL_CHAIN (fields);
|
||||
|
||||
/* checksum */
|
||||
/* lineno_checksum */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, fields,
|
||||
build_int_cstu (get_gcov_unsigned_t (),
|
||||
function->checksum));
|
||||
function->lineno_checksum));
|
||||
fields = DECL_CHAIN (fields);
|
||||
|
||||
/* cfg_checksum */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, fields,
|
||||
build_int_cstu (get_gcov_unsigned_t (),
|
||||
function->cfg_checksum));
|
||||
fields = DECL_CHAIN (fields);
|
||||
|
||||
/* counters */
|
||||
|
|
|
@ -28,11 +28,17 @@ extern void coverage_finish (void);
|
|||
|
||||
/* Complete the coverage information for the current function. Once
|
||||
per function. */
|
||||
extern void coverage_end_function (void);
|
||||
extern void coverage_end_function (unsigned, unsigned);
|
||||
|
||||
/* Start outputting coverage information for the current
|
||||
function. Repeatable per function. */
|
||||
extern int coverage_begin_output (void);
|
||||
extern int coverage_begin_output (unsigned, unsigned);
|
||||
|
||||
/* Compute the control flow checksum for the current function. */
|
||||
extern unsigned coverage_compute_cfg_checksum (void);
|
||||
|
||||
/* Compute the line number checksum for the current function. */
|
||||
extern unsigned coverage_compute_lineno_checksum (void);
|
||||
|
||||
/* Allocate some counters. Repeatable per function. */
|
||||
extern int coverage_counter_alloc (unsigned /*counter*/, unsigned/*num*/);
|
||||
|
@ -44,6 +50,8 @@ extern tree tree_coverage_counter_addr (unsigned /*counter*/, unsigned/*num*/);
|
|||
/* Get all the counters for the current function. */
|
||||
extern gcov_type *get_coverage_counts (unsigned /*counter*/,
|
||||
unsigned /*expected*/,
|
||||
unsigned /*cfg_checksum*/,
|
||||
unsigned /*lineno_checksum*/,
|
||||
const struct gcov_ctr_summary **);
|
||||
|
||||
extern tree get_gcov_type (void);
|
||||
|
|
|
@ -267,7 +267,8 @@ tag_function (const char *filename ATTRIBUTE_UNUSED,
|
|||
unsigned long pos = gcov_position ();
|
||||
|
||||
printf (" ident=%u", gcov_read_unsigned ());
|
||||
printf (", checksum=0x%08x", gcov_read_unsigned ());
|
||||
printf (", lineno_checksum=0x%08x", gcov_read_unsigned ());
|
||||
printf (", cfg_checksum_checksum=0x%08x", gcov_read_unsigned ());
|
||||
|
||||
if (gcov_position () - pos < length)
|
||||
{
|
||||
|
|
|
@ -103,7 +103,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|||
note: unit function-graph*
|
||||
unit: header int32:checksum string:source
|
||||
function-graph: announce_function basic_blocks {arcs | lines}*
|
||||
announce_function: header int32:ident int32:checksum
|
||||
announce_function: header int32:ident
|
||||
int32:lineno_checksum int32:cfg_checksum
|
||||
string:name string:source int32:lineno
|
||||
basic_block: header int32:flags*
|
||||
arcs: header int32:block_no arc*
|
||||
|
@ -132,7 +133,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|||
data: {unit function-data* summary:object summary:program*}*
|
||||
unit: header int32:checksum
|
||||
function-data: announce_function arc_counts
|
||||
announce_function: header int32:ident int32:checksum
|
||||
announce_function: header int32:ident
|
||||
int32:lineno_checksum int32:cfg_checksum
|
||||
arc_counts: header int64:count*
|
||||
summary: int32:checksum {count-summary}GCOV_COUNTERS
|
||||
count-summary: int32:num int32:runs int64:sum
|
||||
|
@ -294,7 +296,7 @@ typedef HOST_WIDEST_INT gcov_type;
|
|||
file marker -- it is not required to be present. */
|
||||
|
||||
#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000)
|
||||
#define GCOV_TAG_FUNCTION_LENGTH (2)
|
||||
#define GCOV_TAG_FUNCTION_LENGTH (3)
|
||||
#define GCOV_TAG_BLOCKS ((gcov_unsigned_t)0x01410000)
|
||||
#define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM)
|
||||
#define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH)
|
||||
|
@ -412,10 +414,12 @@ struct gcov_summary
|
|||
idiom. The number of counters is determined from the counter_mask
|
||||
in gcov_info. We hold an array of function info, so have to
|
||||
explicitly calculate the correct array stride. */
|
||||
|
||||
struct gcov_fn_info
|
||||
{
|
||||
gcov_unsigned_t ident; /* unique ident of function */
|
||||
gcov_unsigned_t checksum; /* function checksum */
|
||||
gcov_unsigned_t lineno_checksum; /* function lineo_checksum */
|
||||
gcov_unsigned_t cfg_checksum; /* function cfg checksum */
|
||||
unsigned n_ctrs[0]; /* instrumented counters */
|
||||
};
|
||||
|
||||
|
|
22
gcc/gcov.c
22
gcc/gcov.c
|
@ -54,6 +54,13 @@ along with Gcov; see the file COPYING3. If not see
|
|||
some places we make use of the knowledge of how profile.c works to
|
||||
select particular algorithms here. */
|
||||
|
||||
/* The code validates that the profile information read in corresponds
|
||||
to the code currently being compiled. Rather than checking for
|
||||
identical files, the code below computes a checksum on the CFG
|
||||
(based on the order of basic blocks and the arcs in the CFG). If
|
||||
the CFG checksum in the gcda file match the CFG checksum for the
|
||||
code currently being compiled, the profile data will be used. */
|
||||
|
||||
/* This is the size of the buffer used to read in source file lines. */
|
||||
|
||||
#define STRING_SIZE 200
|
||||
|
@ -161,7 +168,8 @@ typedef struct function_info
|
|||
/* Name of function. */
|
||||
char *name;
|
||||
unsigned ident;
|
||||
unsigned checksum;
|
||||
unsigned lineno_checksum;
|
||||
unsigned cfg_checksum;
|
||||
|
||||
/* Array of basic blocks. */
|
||||
block_t *blocks;
|
||||
|
@ -807,12 +815,14 @@ read_graph_file (void)
|
|||
if (tag == GCOV_TAG_FUNCTION)
|
||||
{
|
||||
char *function_name;
|
||||
unsigned ident, checksum, lineno;
|
||||
unsigned ident, lineno;
|
||||
unsigned lineno_checksum, cfg_checksum;
|
||||
source_t *src;
|
||||
function_t *probe, *prev;
|
||||
|
||||
ident = gcov_read_unsigned ();
|
||||
checksum = gcov_read_unsigned ();
|
||||
lineno_checksum = gcov_read_unsigned ();
|
||||
cfg_checksum = gcov_read_unsigned ();
|
||||
function_name = xstrdup (gcov_read_string ());
|
||||
src = find_source (gcov_read_string ());
|
||||
lineno = gcov_read_unsigned ();
|
||||
|
@ -820,7 +830,8 @@ read_graph_file (void)
|
|||
fn = XCNEW (function_t);
|
||||
fn->name = function_name;
|
||||
fn->ident = ident;
|
||||
fn->checksum = checksum;
|
||||
fn->lineno_checksum = lineno_checksum;
|
||||
fn->cfg_checksum = cfg_checksum;
|
||||
fn->src = src;
|
||||
fn->line = lineno;
|
||||
|
||||
|
@ -1107,7 +1118,8 @@ read_count_file (void)
|
|||
|
||||
if (!fn)
|
||||
;
|
||||
else if (gcov_read_unsigned () != fn->checksum)
|
||||
else if (gcov_read_unsigned () != fn->lineno_checksum
|
||||
|| gcov_read_unsigned () != fn->cfg_checksum)
|
||||
{
|
||||
mismatch:;
|
||||
fnotice (stderr, "%s:profile mismatch for '%s'\n",
|
||||
|
|
|
@ -372,9 +372,10 @@ gcov_exit (void)
|
|||
|
||||
/* Check function. */
|
||||
if (tag != GCOV_TAG_FUNCTION
|
||||
|| length != GCOV_TAG_FUNCTION_LENGTH
|
||||
|| length != GCOV_TAG_FUNCTION_LENGTH
|
||||
|| gcov_read_unsigned () != fi_ptr->ident
|
||||
|| gcov_read_unsigned () != fi_ptr->checksum)
|
||||
|| gcov_read_unsigned () != fi_ptr->lineno_checksum
|
||||
|| gcov_read_unsigned () != fi_ptr->cfg_checksum)
|
||||
{
|
||||
read_mismatch:;
|
||||
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
|
||||
|
@ -517,7 +518,8 @@ gcov_exit (void)
|
|||
/* Announce function. */
|
||||
gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
|
||||
gcov_write_unsigned (fi_ptr->ident);
|
||||
gcov_write_unsigned (fi_ptr->checksum);
|
||||
gcov_write_unsigned (fi_ptr->lineno_checksum);
|
||||
gcov_write_unsigned (fi_ptr->cfg_checksum);
|
||||
|
||||
c_ix = 0;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
|
||||
|
|
|
@ -102,13 +102,6 @@ static int total_num_branches;
|
|||
|
||||
/* Forward declarations. */
|
||||
static void find_spanning_tree (struct edge_list *);
|
||||
static unsigned instrument_edges (struct edge_list *);
|
||||
static void instrument_values (histogram_values);
|
||||
static void compute_branch_probabilities (void);
|
||||
static void compute_value_histograms (histogram_values);
|
||||
static gcov_type * get_exec_counts (void);
|
||||
static basic_block find_group (basic_block);
|
||||
static void union_groups (basic_block, basic_block);
|
||||
|
||||
/* Add edge instrumentation code to the entire insn chain.
|
||||
|
||||
|
@ -233,10 +226,12 @@ instrument_values (histogram_values values)
|
|||
}
|
||||
|
||||
|
||||
/* Computes hybrid profile for all matching entries in da_file. */
|
||||
/* Computes hybrid profile for all matching entries in da_file.
|
||||
|
||||
CFG_CHECKSUM is the precomputed checksum for the CFG. */
|
||||
|
||||
static gcov_type *
|
||||
get_exec_counts (void)
|
||||
get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum)
|
||||
{
|
||||
unsigned num_edges = 0;
|
||||
basic_block bb;
|
||||
|
@ -253,7 +248,8 @@ get_exec_counts (void)
|
|||
num_edges++;
|
||||
}
|
||||
|
||||
counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, &profile_info);
|
||||
counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum,
|
||||
lineno_checksum, &profile_info);
|
||||
if (!counts)
|
||||
return NULL;
|
||||
|
||||
|
@ -442,10 +438,12 @@ read_profile_edge_counts (gcov_type *exec_counts)
|
|||
}
|
||||
|
||||
/* Compute the branch probabilities for the various branches.
|
||||
Annotate them accordingly. */
|
||||
Annotate them accordingly.
|
||||
|
||||
CFG_CHECKSUM is the precomputed checksum for the CFG. */
|
||||
|
||||
static void
|
||||
compute_branch_probabilities (void)
|
||||
compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
|
||||
{
|
||||
basic_block bb;
|
||||
int i;
|
||||
|
@ -454,7 +452,7 @@ compute_branch_probabilities (void)
|
|||
int passes;
|
||||
int hist_br_prob[20];
|
||||
int num_branches;
|
||||
gcov_type *exec_counts = get_exec_counts ();
|
||||
gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum);
|
||||
int inconsistent = 0;
|
||||
|
||||
/* Very simple sanity checks so we catch bugs in our profiling code. */
|
||||
|
@ -772,10 +770,13 @@ compute_branch_probabilities (void)
|
|||
}
|
||||
|
||||
/* Load value histograms values whose description is stored in VALUES array
|
||||
from .gcda file. */
|
||||
from .gcda file.
|
||||
|
||||
CFG_CHECKSUM is the precomputed checksum for the CFG. */
|
||||
|
||||
static void
|
||||
compute_value_histograms (histogram_values values)
|
||||
compute_value_histograms (histogram_values values, unsigned cfg_checksum,
|
||||
unsigned lineno_checksum)
|
||||
{
|
||||
unsigned i, j, t, any;
|
||||
unsigned n_histogram_counters[GCOV_N_VALUE_COUNTERS];
|
||||
|
@ -803,7 +804,8 @@ compute_value_histograms (histogram_values values)
|
|||
|
||||
histogram_counts[t] =
|
||||
get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
|
||||
n_histogram_counters[t], NULL);
|
||||
n_histogram_counters[t], cfg_checksum,
|
||||
lineno_checksum, NULL);
|
||||
if (histogram_counts[t])
|
||||
any = 1;
|
||||
act_count[t] = histogram_counts[t];
|
||||
|
@ -905,6 +907,7 @@ branch_prob (void)
|
|||
unsigned num_instrumented;
|
||||
struct edge_list *el;
|
||||
histogram_values values = NULL;
|
||||
unsigned cfg_checksum, lineno_checksum;
|
||||
|
||||
total_num_times_called++;
|
||||
|
||||
|
@ -1058,11 +1061,19 @@ branch_prob (void)
|
|||
if (dump_file)
|
||||
fprintf (dump_file, "%d ignored edges\n", ignored_edges);
|
||||
|
||||
|
||||
/* Compute two different checksums. Note that we want to compute
|
||||
the checksum in only once place, since it depends on the shape
|
||||
of the control flow which can change during
|
||||
various transformations. */
|
||||
cfg_checksum = coverage_compute_cfg_checksum ();
|
||||
lineno_checksum = coverage_compute_lineno_checksum ();
|
||||
|
||||
/* Write the data from which gcov can reconstruct the basic block
|
||||
graph. */
|
||||
|
||||
/* Basic block flags */
|
||||
if (coverage_begin_output ())
|
||||
if (coverage_begin_output (lineno_checksum, cfg_checksum))
|
||||
{
|
||||
gcov_position_t offset;
|
||||
|
||||
|
@ -1079,7 +1090,7 @@ branch_prob (void)
|
|||
EXIT_BLOCK_PTR->index = last_basic_block;
|
||||
|
||||
/* Arcs */
|
||||
if (coverage_begin_output ())
|
||||
if (coverage_begin_output (lineno_checksum, cfg_checksum))
|
||||
{
|
||||
gcov_position_t offset;
|
||||
|
||||
|
@ -1120,7 +1131,7 @@ branch_prob (void)
|
|||
}
|
||||
|
||||
/* Line numbers. */
|
||||
if (coverage_begin_output ())
|
||||
if (coverage_begin_output (lineno_checksum, cfg_checksum))
|
||||
{
|
||||
/* Initialize the output. */
|
||||
output_location (NULL, 0, NULL, NULL);
|
||||
|
@ -1175,9 +1186,9 @@ branch_prob (void)
|
|||
|
||||
if (flag_branch_probabilities)
|
||||
{
|
||||
compute_branch_probabilities ();
|
||||
compute_branch_probabilities (cfg_checksum, lineno_checksum);
|
||||
if (flag_profile_values)
|
||||
compute_value_histograms (values);
|
||||
compute_value_histograms (values, cfg_checksum, lineno_checksum);
|
||||
}
|
||||
|
||||
remove_fake_edges ();
|
||||
|
@ -1205,7 +1216,7 @@ branch_prob (void)
|
|||
|
||||
VEC_free (histogram_value, heap, values);
|
||||
free_edge_list (el);
|
||||
coverage_end_function ();
|
||||
coverage_end_function (lineno_checksum, cfg_checksum);
|
||||
}
|
||||
|
||||
/* Union find algorithm implementation for the basic blocks using
|
||||
|
@ -1372,4 +1383,3 @@ end_branch_prob (void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2011-04-28 Xinliang David Li <davidxl@google.com>
|
||||
|
||||
* testsuite/gcc.dg/tree-prof/prof-robust-1.c: New test.
|
||||
* testsuite/g++.dg/prof-robust-1.C: New test.
|
||||
|
||||
2011-04-28 Ira Rosen <ira.rosen@linaro.org>
|
||||
|
||||
PR tree-optimization/48765
|
||||
|
|
24
gcc/testsuite/g++.dg/prof-robust-1.C
Normal file
24
gcc/testsuite/g++.dg/prof-robust-1.C
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* { dg-options "-O2 -fno-weak" } */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace {
|
||||
namespace {
|
||||
|
||||
class MyClass {
|
||||
public:
|
||||
void foo() const;
|
||||
~MyClass() { foo(); }
|
||||
};
|
||||
|
||||
void MyClass::foo() const { printf("Goodbye World\n"); }
|
||||
|
||||
}
|
||||
|
||||
static MyClass variable;
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
25
gcc/testsuite/gcc.dg/tree-prof/prof-robust-1.c
Normal file
25
gcc/testsuite/gcc.dg/tree-prof/prof-robust-1.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* { dg-options "-O2 -w" } */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _PROFILE_USE
|
||||
int foo(int x) {
|
||||
return 3 * x;
|
||||
}
|
||||
#else
|
||||
int foo(int x) {
|
||||
return 3 * x;
|
||||
}
|
||||
#endif
|
||||
|
||||
int x = 1000;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
int sum = 0;
|
||||
for (i = 0; i < x; i++)
|
||||
sum += i;
|
||||
printf("%d\n", sum);
|
||||
return 0;
|
||||
}
|
24
gcc/tree.c
24
gcc/tree.c
|
@ -8510,14 +8510,12 @@ dump_tree_statistics (void)
|
|||
|
||||
#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
|
||||
|
||||
/* Generate a crc32 of a string. */
|
||||
/* Generate a crc32 of a byte. */
|
||||
|
||||
unsigned
|
||||
crc32_string (unsigned chksum, const char *string)
|
||||
crc32_byte (unsigned chksum, char byte)
|
||||
{
|
||||
do
|
||||
{
|
||||
unsigned value = *string << 24;
|
||||
unsigned value = (unsigned) byte << 24;
|
||||
unsigned ix;
|
||||
|
||||
for (ix = 8; ix--; value <<= 1)
|
||||
|
@ -8528,6 +8526,18 @@ crc32_string (unsigned chksum, const char *string)
|
|||
chksum <<= 1;
|
||||
chksum ^= feedback;
|
||||
}
|
||||
return chksum;
|
||||
}
|
||||
|
||||
|
||||
/* Generate a crc32 of a string. */
|
||||
|
||||
unsigned
|
||||
crc32_string (unsigned chksum, const char *string)
|
||||
{
|
||||
do
|
||||
{
|
||||
chksum = crc32_byte (chksum, *string);
|
||||
}
|
||||
while (*string++);
|
||||
return chksum;
|
||||
|
@ -8551,8 +8561,10 @@ clean_symbol_name (char *p)
|
|||
*p = '_';
|
||||
}
|
||||
|
||||
/* Generate a name for a special-purpose function function.
|
||||
/* Generate a name for a special-purpose function.
|
||||
The generated name may need to be unique across the whole link.
|
||||
Changes to this function may also require corresponding changes to
|
||||
xstrdup_mask_random.
|
||||
TYPE is some string to identify the purpose of this function to the
|
||||
linker or collect2; it must start with an uppercase letter,
|
||||
one of:
|
||||
|
|
|
@ -5001,6 +5001,7 @@ inlined_function_outer_scope_p (const_tree block)
|
|||
|
||||
/* In tree.c */
|
||||
extern unsigned crc32_string (unsigned, const char *);
|
||||
extern unsigned crc32_byte (unsigned, char);
|
||||
extern void clean_symbol_name (char *);
|
||||
extern tree get_file_function_name (const char *);
|
||||
extern tree get_callee_fndecl (const_tree);
|
||||
|
|
Loading…
Add table
Reference in a new issue