public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/marxin/heads/PR90364-improve-profile-merging-v2)] gcov: make profile merging smarter
@ 2021-09-10  9:09 Martin Liska
  0 siblings, 0 replies; 5+ messages in thread
From: Martin Liska @ 2021-09-10  9:09 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:40cfed232e06889f9f3197d9c8883b23d0d2234d

commit 40cfed232e06889f9f3197d9c8883b23d0d2234d
Author: Martin Liska <mliska@suse.cz>
Date:   Thu Sep 9 13:02:24 2021 +0200

    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.
    
    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.

Diff:
---
 gcc/coverage.c          | 47 +++++++++++++++++++++++++++++++----------------
 gcc/gcov-dump.c         |  9 +++++----
 gcc/gcov.c              |  2 ++
 libgcc/libgcov-driver.c |  8 ++++++--
 libgcc/libgcov-util.c   |  3 +++
 libgcc/libgcov.h        |  1 +
 6 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/gcc/coverage.c b/gcc/coverage.c
index 10d7f8366cb..60665591458 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -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> *);
 \f
 /* Return the type node for gcov_type.  */
 
@@ -935,6 +926,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 +974,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;
@@ -996,13 +993,19 @@ build_info (tree info_type, tree fn_ary)
   /* next -- NULL */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
   info_fields = DECL_CHAIN (info_fields);
-  
+
   /* stamp */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
 			  build_int_cstu (TREE_TYPE (info_fields),
 					  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 +1217,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 +1235,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 +1304,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 +1331,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 +1358,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);
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index f1489fe0214..bfaf735d2ff 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -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)
     {
diff --git a/gcc/gcov.c b/gcc/gcov.c
index cf0a49d8c30..60c59beadb1 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -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 ();
 
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 087f71e0107..7aa97bbb06a 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -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.  */
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index bc7416d99bf..766ca3559c4 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -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;
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index f6354a7a070..2a365c95759 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/marxin/heads/PR90364-improve-profile-merging-v2)] gcov: make profile merging smarter
@ 2021-10-11 14:03 Martin Liska
  0 siblings, 0 replies; 5+ messages in thread
From: Martin Liska @ 2021-10-11 14:03 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fdeb81a960faa19f75316e279a79c231da212f99

commit fdeb81a960faa19f75316e279a79c231da212f99
Author: Martin Liska <mliska@suse.cz>
Date:   Thu Sep 9 13:02:24 2021 +0200

    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.

Diff:
---
 gcc/coverage.c          | 50 +++++++++++++++++++++++++++++++++----------------
 gcc/doc/invoke.texi     |  4 ++++
 gcc/gcov-dump.c         |  9 +++++----
 gcc/gcov.c              |  5 +++++
 libgcc/libgcov-driver.c |  8 ++++++--
 libgcc/libgcov-util.c   |  3 +++
 libgcc/libgcov.h        |  1 +
 7 files changed, 58 insertions(+), 22 deletions(-)

diff --git a/gcc/coverage.c b/gcc/coverage.c
index 10d7f8366cb..4467f1eaa5c 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -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> *);
 \f
 /* 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;
@@ -996,13 +996,19 @@ build_info (tree info_type, tree fn_ary)
   /* next -- NULL */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
   info_fields = DECL_CHAIN (info_fields);
-  
+
   /* stamp */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
 			  build_int_cstu (TREE_TYPE (info_fields),
 					  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);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8b3ebcfbc4f..c37a320ba4f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index f1489fe0214..bfaf735d2ff 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -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)
     {
diff --git a/gcc/gcov.c b/gcc/gcov.c
index cf0a49d8c30..829e955a63b 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -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 ();
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 087f71e0107..7aa97bbb06a 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -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.  */
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index bc7416d99bf..766ca3559c4 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -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;
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index f6354a7a070..2a365c95759 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/marxin/heads/PR90364-improve-profile-merging-v2)] gcov: make profile merging smarter
@ 2021-10-01  9:29 Martin Liska
  0 siblings, 0 replies; 5+ messages in thread
From: Martin Liska @ 2021-10-01  9:29 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:8b2df3905773ab50ecfef4f9688332b7f06e77c7

commit 8b2df3905773ab50ecfef4f9688332b7f06e77c7
Author: Martin Liska <mliska@suse.cz>
Date:   Thu Sep 9 13:02:24 2021 +0200

    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.
    
    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.

Diff:
---
 gcc/coverage.c          | 50 +++++++++++++++++++++++++++++++++----------------
 gcc/gcov-dump.c         |  9 +++++----
 gcc/gcov.c              |  5 +++++
 libgcc/libgcov-driver.c |  8 ++++++--
 libgcc/libgcov-util.c   |  3 +++
 libgcc/libgcov.h        |  1 +
 6 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/gcc/coverage.c b/gcc/coverage.c
index 10d7f8366cb..4467f1eaa5c 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -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> *);
 \f
 /* 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;
@@ -996,13 +996,19 @@ build_info (tree info_type, tree fn_ary)
   /* next -- NULL */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
   info_fields = DECL_CHAIN (info_fields);
-  
+
   /* stamp */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
 			  build_int_cstu (TREE_TYPE (info_fields),
 					  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);
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index f1489fe0214..bfaf735d2ff 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -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)
     {
diff --git a/gcc/gcov.c b/gcc/gcov.c
index cf0a49d8c30..829e955a63b 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -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 ();
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 087f71e0107..7aa97bbb06a 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -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.  */
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index bc7416d99bf..766ca3559c4 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -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;
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index f6354a7a070..2a365c95759 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/marxin/heads/PR90364-improve-profile-merging-v2)] gcov: make profile merging smarter
@ 2021-09-10 11:29 Martin Liska
  0 siblings, 0 replies; 5+ messages in thread
From: Martin Liska @ 2021-09-10 11:29 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:5b2dbf67d2df620b2c2c973757a26f7dedfffdf0

commit 5b2dbf67d2df620b2c2c973757a26f7dedfffdf0
Author: Martin Liska <mliska@suse.cz>
Date:   Thu Sep 9 13:02:24 2021 +0200

    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.
    
    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.

Diff:
---
 gcc/coverage.c          | 50 +++++++++++++++++++++++++++++++++----------------
 gcc/gcov-dump.c         |  9 +++++----
 gcc/gcov.c              |  5 +++++
 libgcc/libgcov-driver.c |  8 ++++++--
 libgcc/libgcov-util.c   |  3 +++
 libgcc/libgcov.h        |  1 +
 6 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/gcc/coverage.c b/gcc/coverage.c
index 10d7f8366cb..4467f1eaa5c 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -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> *);
 \f
 /* 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;
@@ -996,13 +996,19 @@ build_info (tree info_type, tree fn_ary)
   /* next -- NULL */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
   info_fields = DECL_CHAIN (info_fields);
-  
+
   /* stamp */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
 			  build_int_cstu (TREE_TYPE (info_fields),
 					  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);
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index f1489fe0214..bfaf735d2ff 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -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)
     {
diff --git a/gcc/gcov.c b/gcc/gcov.c
index cf0a49d8c30..829e955a63b 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -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 ();
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 087f71e0107..7aa97bbb06a 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -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.  */
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index bc7416d99bf..766ca3559c4 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -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;
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index f6354a7a070..2a365c95759 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/marxin/heads/PR90364-improve-profile-merging-v2)] gcov: make profile merging smarter
@ 2021-09-10  9:06 Martin Liska
  0 siblings, 0 replies; 5+ messages in thread
From: Martin Liska @ 2021-09-10  9:06 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:f0d14ec287859857a32ea0347e527cf28b361019

commit f0d14ec287859857a32ea0347e527cf28b361019
Author: Martin Liska <mliska@suse.cz>
Date:   Thu Sep 9 13:02:24 2021 +0200

    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.
    
    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.

Diff:
---
 gcc/coverage.c          | 47 +++++++++++++++++++++++++++++++----------------
 gcc/gcov-dump.c         |  9 +++++----
 gcc/gcov.c              |  2 ++
 libgcc/libgcov-driver.c |  8 ++++++--
 libgcc/libgcov-util.c   |  3 +++
 libgcc/libgcov.h        |  1 +
 6 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/gcc/coverage.c b/gcc/coverage.c
index 10d7f8366cb..60665591458 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -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> *);
 \f
 /* Return the type node for gcov_type.  */
 
@@ -935,6 +926,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 +974,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;
@@ -996,13 +993,19 @@ build_info (tree info_type, tree fn_ary)
   /* next -- NULL */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
   info_fields = DECL_CHAIN (info_fields);
-  
+
   /* stamp */
   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
 			  build_int_cstu (TREE_TYPE (info_fields),
 					  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 +1217,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 +1235,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 +1304,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 +1331,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 +1358,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);
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index f1489fe0214..bfaf735d2ff 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -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)
     {
diff --git a/gcc/gcov.c b/gcc/gcov.c
index cf0a49d8c30..60c59beadb1 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -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 ();
 
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 087f71e0107..7aa97bbb06a 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -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.  */
diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index bc7416d99bf..766ca3559c4 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -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;
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index f6354a7a070..2a365c95759 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -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


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-10-11 14:03 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-10  9:09 [gcc(refs/users/marxin/heads/PR90364-improve-profile-merging-v2)] gcov: make profile merging smarter Martin Liska
  -- strict thread matches above, loose matches on Subject: below --
2021-10-11 14:03 Martin Liska
2021-10-01  9:29 Martin Liska
2021-09-10 11:29 Martin Liska
2021-09-10  9:06 Martin Liska

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).