mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-25 17:51:10 +08:00
gcov: make profile merging smarter
Support merging of profiles that are built from a different .o files but belong to the same source file. Moreover, a checksum is verified during profile merging and so we can safely combine such profile. PR gcov-profile/90364 gcc/ChangeLog: * coverage.c (build_info): Emit checksum to the global variable. (build_info_type): Add new field for checksum. (coverage_obj_finish): Pass object_checksum. (coverage_init): Use 0 as checksum for .gcno files. * gcov-dump.c (dump_gcov_file): Dump also new checksum field. * gcov.c (read_graph_file): Read also checksum. * doc/invoke.texi: Document the behaviour change. libgcc/ChangeLog: * libgcov-driver.c (merge_one_data): Skip timestamp and verify checksums. (write_one_data): Write also checksum. * libgcov-util.c (read_gcda_file): Read also checksum field. * libgcov.h (struct gcov_info): Add new field.
This commit is contained in:
parent
489c8f2729
commit
72e0c742bd
@ -129,16 +129,7 @@ static const char *const ctr_names[GCOV_COUNTERS] = {
|
||||
#undef DEF_GCOV_COUNTER
|
||||
|
||||
/* Forward declarations. */
|
||||
static void read_counts_file (void);
|
||||
static tree build_var (tree, tree, int);
|
||||
static void build_fn_info_type (tree, unsigned, tree);
|
||||
static void build_info_type (tree, tree);
|
||||
static tree build_fn_info (const struct coverage_data *, tree, tree);
|
||||
static tree build_info (tree, tree);
|
||||
static bool coverage_obj_init (void);
|
||||
static vec<constructor_elt, va_gc> *coverage_obj_fn
|
||||
(vec<constructor_elt, va_gc> *, tree, struct coverage_data const *);
|
||||
static void coverage_obj_finish (vec<constructor_elt, va_gc> *);
|
||||
|
||||
/* Return the type node for gcov_type. */
|
||||
|
||||
@ -218,6 +209,9 @@ read_counts_file (void)
|
||||
tag = gcov_read_unsigned ();
|
||||
bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
|
||||
|
||||
/* Read checksum. */
|
||||
gcov_read_unsigned ();
|
||||
|
||||
counts_hash = new hash_table<counts_entry> (10);
|
||||
while ((tag = gcov_read_unsigned ()))
|
||||
{
|
||||
@ -935,6 +929,12 @@ build_info_type (tree type, tree fn_info_ptr_type)
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* Checksum. */
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* Filename */
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
build_pointer_type (build_qualified_type
|
||||
@ -977,7 +977,7 @@ build_info_type (tree type, tree fn_info_ptr_type)
|
||||
function info objects. */
|
||||
|
||||
static tree
|
||||
build_info (tree info_type, tree fn_ary)
|
||||
build_info (tree info_type, tree fn_ary, unsigned object_checksum)
|
||||
{
|
||||
tree info_fields = TYPE_FIELDS (info_type);
|
||||
tree merge_fn_type, n_funcs;
|
||||
@ -1003,6 +1003,12 @@ build_info (tree info_type, tree fn_ary)
|
||||
bbg_file_stamp));
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
/* Checksum. */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
|
||||
build_int_cstu (TREE_TYPE (info_fields),
|
||||
object_checksum));
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
/* Filename */
|
||||
da_file_name_len = strlen (da_file_name);
|
||||
filename_string = build_string (da_file_name_len + 1, da_file_name);
|
||||
@ -1214,7 +1220,8 @@ coverage_obj_fn (vec<constructor_elt, va_gc> *ctor, tree fn,
|
||||
function objects from CTOR. Generate the gcov_info initializer. */
|
||||
|
||||
static void
|
||||
coverage_obj_finish (vec<constructor_elt, va_gc> *ctor)
|
||||
coverage_obj_finish (vec<constructor_elt, va_gc> *ctor,
|
||||
unsigned object_checksum)
|
||||
{
|
||||
unsigned n_functions = vec_safe_length (ctor);
|
||||
tree fn_info_ary_type = build_array_type
|
||||
@ -1231,7 +1238,7 @@ coverage_obj_finish (vec<constructor_elt, va_gc> *ctor)
|
||||
varpool_node::finalize_decl (fn_info_ary);
|
||||
|
||||
DECL_INITIAL (gcov_info_var)
|
||||
= build_info (TREE_TYPE (gcov_info_var), fn_info_ary);
|
||||
= build_info (TREE_TYPE (gcov_info_var), fn_info_ary, object_checksum);
|
||||
varpool_node::finalize_decl (gcov_info_var);
|
||||
}
|
||||
|
||||
@ -1300,7 +1307,6 @@ coverage_init (const char *filename)
|
||||
strcpy (da_file_name + prefix_len + len, GCOV_DATA_SUFFIX);
|
||||
|
||||
bbg_file_stamp = local_tick;
|
||||
|
||||
if (flag_auto_profile)
|
||||
read_autofdo_file ();
|
||||
else if (flag_branch_probabilities)
|
||||
@ -1328,6 +1334,8 @@ coverage_init (const char *filename)
|
||||
gcov_write_unsigned (GCOV_NOTE_MAGIC);
|
||||
gcov_write_unsigned (GCOV_VERSION);
|
||||
gcov_write_unsigned (bbg_file_stamp);
|
||||
/* Use an arbitrary checksum */
|
||||
gcov_write_unsigned (0);
|
||||
gcov_write_string (getpwd ());
|
||||
|
||||
/* Do not support has_unexecuted_blocks for Ada. */
|
||||
@ -1353,14 +1361,24 @@ coverage_finish (void)
|
||||
cannot uniquely stamp it. If we can stamp it, libgcov will DTRT. */
|
||||
unlink (da_file_name);
|
||||
|
||||
/* Global GCDA checksum that aggregates all functions. */
|
||||
unsigned object_checksum = 0;
|
||||
|
||||
if (coverage_obj_init ())
|
||||
{
|
||||
vec<constructor_elt, va_gc> *fn_ctor = NULL;
|
||||
struct coverage_data *fn;
|
||||
|
||||
for (fn = functions_head; fn; fn = fn->next)
|
||||
fn_ctor = coverage_obj_fn (fn_ctor, fn->fn_decl, fn);
|
||||
coverage_obj_finish (fn_ctor);
|
||||
{
|
||||
fn_ctor = coverage_obj_fn (fn_ctor, fn->fn_decl, fn);
|
||||
|
||||
object_checksum = crc32_unsigned (object_checksum, fn->ident);
|
||||
object_checksum = crc32_unsigned (object_checksum,
|
||||
fn->lineno_checksum);
|
||||
object_checksum = crc32_unsigned (object_checksum, fn->cfg_checksum);
|
||||
}
|
||||
coverage_obj_finish (fn_ctor, object_checksum);
|
||||
}
|
||||
|
||||
XDELETEVEC (da_file_name);
|
||||
|
@ -14882,6 +14882,10 @@ supports locking, the data files will be correctly updated. Unless
|
||||
a strict ISO C dialect option is in effect, @code{fork} calls are
|
||||
detected and correctly handled without double counting.
|
||||
|
||||
Moreover, an object file can be recompiled multiple times
|
||||
and the corresponding @file{.gcda} file merges as long as
|
||||
the source file and the compiler options are unchanged.
|
||||
|
||||
@item
|
||||
For profile-directed optimizations, compile the source files again with
|
||||
the same optimization and code generation options plus
|
||||
|
@ -206,11 +206,12 @@ dump_gcov_file (const char *filename)
|
||||
}
|
||||
|
||||
/* stamp */
|
||||
{
|
||||
unsigned stamp = gcov_read_unsigned ();
|
||||
unsigned stamp = gcov_read_unsigned ();
|
||||
printf ("%s:stamp %lu\n", filename, (unsigned long)stamp);
|
||||
|
||||
printf ("%s:stamp %lu\n", filename, (unsigned long)stamp);
|
||||
}
|
||||
/* Checksum */
|
||||
unsigned checksum = gcov_read_unsigned ();
|
||||
printf ("%s:checksum %lu\n", filename, (unsigned long)checksum);
|
||||
|
||||
if (!is_data_type)
|
||||
{
|
||||
|
@ -1814,6 +1814,8 @@ read_graph_file (void)
|
||||
bbg_file_name, v, e);
|
||||
}
|
||||
bbg_stamp = gcov_read_unsigned ();
|
||||
/* Read checksum. */
|
||||
gcov_read_unsigned ();
|
||||
bbg_cwd = xstrdup (gcov_read_string ());
|
||||
bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
|
||||
|
||||
@ -2031,6 +2033,9 @@ read_count_file (void)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Read checksum. */
|
||||
gcov_read_unsigned ();
|
||||
|
||||
while ((tag = gcov_read_unsigned ()))
|
||||
{
|
||||
unsigned length = gcov_read_unsigned ();
|
||||
|
@ -260,12 +260,15 @@ merge_one_data (const char *filename,
|
||||
if (!gcov_version (gi_ptr, length, filename))
|
||||
return -1;
|
||||
|
||||
/* Skip timestamp. */
|
||||
gcov_read_unsigned ();
|
||||
|
||||
length = gcov_read_unsigned ();
|
||||
if (length != gi_ptr->stamp)
|
||||
if (length != gi_ptr->checksum)
|
||||
{
|
||||
/* Read from a different compilation. Overwrite the file. */
|
||||
gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
|
||||
"with a different timestamp\n", filename);
|
||||
"with a different checksum\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -495,6 +498,7 @@ write_one_data (const struct gcov_info *gi_ptr,
|
||||
dump_unsigned (GCOV_DATA_MAGIC, dump_fn, arg);
|
||||
dump_unsigned (GCOV_VERSION, dump_fn, arg);
|
||||
dump_unsigned (gi_ptr->stamp, dump_fn, arg);
|
||||
dump_unsigned (gi_ptr->checksum, dump_fn, arg);
|
||||
|
||||
#ifdef NEED_L_GCOV
|
||||
/* Generate whole program statistics. */
|
||||
|
@ -310,6 +310,9 @@ read_gcda_file (const char *filename)
|
||||
/* Read stamp. */
|
||||
obj_info->stamp = gcov_read_unsigned ();
|
||||
|
||||
/* Read checksum. */
|
||||
obj_info->checksum = gcov_read_unsigned ();
|
||||
|
||||
while (1)
|
||||
{
|
||||
gcov_position_t base;
|
||||
|
@ -230,6 +230,7 @@ struct gcov_info
|
||||
struct gcov_info *next; /* link to next, used by libgcov */
|
||||
|
||||
gcov_unsigned_t stamp; /* uniquifying time stamp */
|
||||
gcov_unsigned_t checksum; /* unique object checksum */
|
||||
const char *filename; /* output file name */
|
||||
|
||||
gcov_merge_fn merge[GCOV_COUNTERS]; /* merge functions (null for
|
||||
|
Loading…
x
Reference in New Issue
Block a user