Do not stream all zeros for gcda files.
authorMartin Liska <mliska@suse.cz>
Tue, 2 Jun 2020 08:11:07 +0000 (10:11 +0200)
committerMartin Liska <mliska@suse.cz>
Thu, 2 Jul 2020 08:16:02 +0000 (10:16 +0200)
gcc/ChangeLog:

PR gcov-profile/95348
* coverage.c (read_counts_file): Read only COUNTERS that are
not all-zero.
* gcov-dump.c (tag_function): Change signature from unsigned to
signed integer.
(tag_blocks): Likewise.
(tag_arcs): Likewise.
(tag_lines): Likewise.
(tag_counters): Likewise.
(tag_summary): Likewise.
* gcov.c (read_count_file): Read all non-zero counters
sensitively.

libgcc/ChangeLog:

PR gcov-profile/95348
* libgcov-driver.c (merge_one_data): Merge only profiles
that are not of non-zero type.
(write_one_data): Write counters only if there's one non-zero
value.
* libgcov-util.c (tag_function): Change signature from unsigned
to int.
(tag_blocks): Likewise.
(tag_arcs): Likewise.
(tag_counters): Likewise.
(tag_summary): Likewise.
(tag_lines): Read only if COUNTERS is non-zero.
(read_gcda_file): Handle negative length for COUNTERS type.

gcc/coverage.c
gcc/gcov-dump.c
gcc/gcov.c
libgcc/libgcov-driver.c
libgcc/libgcov-util.c

index 1dcda4353cd4a0d6ee57301dce455344c4c370d6..f353c9c5022eb7aaf9b8008e68e3f4b1d52c4789 100644 (file)
@@ -245,7 +245,9 @@ read_counts_file (void)
       else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
        {
          counts_entry **slot, *entry, elt;
-         unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
+         int read_length = (int)length;
+         length = read_length > 0 ? read_length : 0;
+         unsigned n_counts = GCOV_TAG_COUNTER_NUM (abs (read_length));
          unsigned ix;
 
          elt.ident = fn_ident;
@@ -274,8 +276,9 @@ read_counts_file (void)
              counts_hash = NULL;
              break;
            }
-         for (ix = 0; ix != n_counts; ix++)
-           entry->counts[ix] += gcov_read_counter ();
+         if (read_length > 0)
+           for (ix = 0; ix != n_counts; ix++)
+             entry->counts[ix] = gcov_read_counter ();
        }
       gcov_sync (offset, length);
       if ((is_error = gcov_is_error ()))
index cfa771e4a25f03239d13766686eda9385d7f694f..97ff27861c6291a02aab38e3b43333114a0ed100 100644 (file)
@@ -32,19 +32,19 @@ static void dump_gcov_file (const char *);
 static void print_prefix (const char *, unsigned, gcov_position_t);
 static void print_usage (void);
 static void print_version (void);
-static void tag_function (const char *, unsigned, unsigned, unsigned);
-static void tag_blocks (const char *, unsigned, unsigned, unsigned);
-static void tag_arcs (const char *, unsigned, unsigned, unsigned);
-static void tag_lines (const char *, unsigned, unsigned, unsigned);
-static void tag_counters (const char *, unsigned, unsigned, unsigned);
-static void tag_summary (const char *, unsigned, unsigned, unsigned);
+static void tag_function (const char *, unsigned, int, unsigned);
+static void tag_blocks (const char *, unsigned, int, unsigned);
+static void tag_arcs (const char *, unsigned, int, unsigned);
+static void tag_lines (const char *, unsigned, int, unsigned);
+static void tag_counters (const char *, unsigned, int, unsigned);
+static void tag_summary (const char *, unsigned, int, unsigned);
 extern int main (int, char **);
 
 typedef struct tag_format
 {
   unsigned tag;
   char const *name;
-  void (*proc) (const char *, unsigned, unsigned, unsigned);
+  void (*proc) (const char *, unsigned, int, unsigned);
 } tag_format_t;
 
 static int flag_dump_contents = 0;
@@ -225,6 +225,7 @@ dump_gcov_file (const char *filename)
   while (1)
     {
       gcov_position_t base, position = gcov_position ();
+      int read_length;
       unsigned tag, length;
       tag_format_t const *format;
       unsigned tag_depth;
@@ -234,7 +235,8 @@ dump_gcov_file (const char *filename)
       tag = gcov_read_unsigned ();
       if (!tag)
        break;
-      length = gcov_read_unsigned ();
+      read_length = (int)gcov_read_unsigned ();
+      length = read_length > 0 ? read_length : 0;
       base = gcov_position ();
       mask = GCOV_TAG_MASK (tag) >> 1;
       for (tag_depth = 4; mask; mask >>= 8)
@@ -264,9 +266,9 @@ dump_gcov_file (const char *filename)
        }
 
       print_prefix (filename, tag_depth, position);
-      printf ("%08x:%4u:%s", tag, length, format->name);
+      printf ("%08x:%4u:%s", tag, abs (read_length), format->name);
       if (format->proc)
-       (*format->proc) (filename, tag, length, depth);
+       (*format->proc) (filename, tag, read_length, depth);
 
       printf ("\n");
       if (flag_dump_contents && format->proc)
@@ -294,10 +296,10 @@ dump_gcov_file (const char *filename)
 
 static void
 tag_function (const char *filename ATTRIBUTE_UNUSED,
-             unsigned tag ATTRIBUTE_UNUSED, unsigned length,
+             unsigned tag ATTRIBUTE_UNUSED, int length,
              unsigned depth ATTRIBUTE_UNUSED)
 {
-  unsigned long pos = gcov_position ();
+  long pos = gcov_position ();
 
   if (!length)
     printf (" placeholder");
@@ -330,7 +332,7 @@ tag_function (const char *filename ATTRIBUTE_UNUSED,
 
 static void
 tag_blocks (const char *filename ATTRIBUTE_UNUSED,
-           unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED,
+           unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED,
            unsigned depth ATTRIBUTE_UNUSED)
 {
   printf (" %u blocks", gcov_read_unsigned ());
@@ -338,7 +340,7 @@ tag_blocks (const char *filename ATTRIBUTE_UNUSED,
 
 static void
 tag_arcs (const char *filename ATTRIBUTE_UNUSED,
-         unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED,
+         unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED,
          unsigned depth)
 {
   unsigned n_arcs = GCOV_TAG_ARCS_NUM (length);
@@ -380,7 +382,7 @@ tag_arcs (const char *filename ATTRIBUTE_UNUSED,
 
 static void
 tag_lines (const char *filename ATTRIBUTE_UNUSED,
-          unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED,
+          unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED,
           unsigned depth)
 {
   if (flag_dump_contents)
@@ -425,7 +427,7 @@ tag_lines (const char *filename ATTRIBUTE_UNUSED,
 
 static void
 tag_counters (const char *filename ATTRIBUTE_UNUSED,
-             unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED,
+             unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED,
              unsigned depth)
 {
 #define DEF_GCOV_COUNTER(COUNTER, NAME, MERGE_FN) NAME,
@@ -433,15 +435,16 @@ tag_counters (const char *filename ATTRIBUTE_UNUSED,
 #include "gcov-counter.def"
 };
 #undef DEF_GCOV_COUNTER
-  unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
+  int n_counts = GCOV_TAG_COUNTER_NUM (length);
+  bool has_zeros = n_counts < 0;
+  n_counts = abs (n_counts);
 
-  printf (" %s %u counts",
-         counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts);
+  printf (" %s %u counts%s",
+         counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts,
+         has_zeros ? " (all zero)" : "");
   if (flag_dump_contents)
     {
-      unsigned ix;
-
-      for (ix = 0; ix != n_counts; ix++)
+      for (int ix = 0; ix != n_counts; ix++)
        {
          gcov_type count;
 
@@ -457,7 +460,7 @@ tag_counters (const char *filename ATTRIBUTE_UNUSED,
              printf (VALUE_PADDING_PREFIX VALUE_PREFIX, ix);
            }
 
-         count = gcov_read_counter ();
+         count = has_zeros ? 0 : gcov_read_counter ();
          printf ("%" PRId64 " ", count);
        }
     }
@@ -465,7 +468,7 @@ tag_counters (const char *filename ATTRIBUTE_UNUSED,
 
 static void
 tag_summary (const char *filename ATTRIBUTE_UNUSED,
-            unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED,
+            unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED,
             unsigned depth ATTRIBUTE_UNUSED)
 {
   gcov_summary summary;
index b2d2fda45632d767486afaadf42a658b8ad39dd1..b302e2197dd31b45eb9a4a01bdbcf84c395c0970 100644 (file)
@@ -1972,11 +1972,16 @@ read_count_file (void)
        }
       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
        {
+         int read_length = (int)length;
+         length = abs (read_length);
          if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
            goto mismatch;
 
-         for (ix = 0; ix != fn->counts.size (); ix++)
-           fn->counts[ix] += gcov_read_counter ();
+         if (read_length > 0)
+           for (ix = 0; ix != fn->counts.size (); ix++)
+             fn->counts[ix] += gcov_read_counter ();
+         else
+           length = 0;
        }
       gcov_sync (base, length);
       if ((error = gcov_is_error ()))
index 871b87b867bcece08a962d2eaca1d62b0a18fdc0..2590593a58abd40addbe54bc877c2fb21c1f489f 100644 (file)
@@ -302,13 +302,16 @@ merge_one_data (const char *filename,
             continue;
 
          tag = gcov_read_unsigned ();
-         length = gcov_read_unsigned ();
+         int read_length = (int)gcov_read_unsigned ();
+         length = abs (read_length);
          if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
              || (length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num)
                  && t_ix != GCOV_COUNTER_V_TOPN
                  && t_ix != GCOV_COUNTER_V_INDIR))
            goto read_mismatch;
-         (*merge) (ci_ptr->values, ci_ptr->num);
+         /* Merging with all zero counters does not make sense.  */
+         if (read_length > 0)
+           (*merge) (ci_ptr->values, ci_ptr->num);
          ci_ptr++;
        }
       if ((error = gcov_is_error ()))
@@ -414,27 +417,40 @@ write_one_data (const struct gcov_info *gi_ptr,
       ci_ptr = gfi_ptr->ctrs;
       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
         {
-          gcov_unsigned_t n_counts;
-          gcov_type *c_ptr;
+         gcov_position_t n_counts;
 
-          if (!gi_ptr->merge[t_ix])
-            continue;
+         if (!gi_ptr->merge[t_ix])
+           continue;
 
-          n_counts = ci_ptr->num;
+         n_counts = ci_ptr->num;
 
          if (gi_ptr->merge[t_ix] == __gcov_merge_topn)
            write_top_counters (ci_ptr, t_ix, n_counts);
          else
            {
-             gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
-                                    GCOV_TAG_COUNTER_LENGTH (n_counts));
-             c_ptr = ci_ptr->values;
-             while (n_counts--)
-               gcov_write_counter (*c_ptr++);
+             /* Do not stream when all counters are zero.  */
+             int all_zeros = 1;
+             for (unsigned i = 0; i < n_counts; i++)
+               if (ci_ptr->values[i] != 0)
+                 {
+                   all_zeros = 0;
+                   break;
+                 }
+
+             if (all_zeros)
+               gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
+                                      GCOV_TAG_COUNTER_LENGTH (-n_counts));
+             else
+               {
+                 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
+                                        GCOV_TAG_COUNTER_LENGTH (n_counts));
+                 for (unsigned i = 0; i < n_counts; i++)
+                   gcov_write_counter (ci_ptr->values[i]);
+               }
            }
 
-          ci_ptr++;
-        }
+         ci_ptr++;
+       }
       if (buffered)
         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
     }
index 09e34f0a33a3736b1ee9798efe214b80afa9443c..1ada1fecb5870ce954afc500ad58c9c48aa72ea1 100644 (file)
@@ -57,12 +57,12 @@ void gcov_set_verbose (void)
 #include <ftw.h>
 #endif
 
-static void tag_function (unsigned, unsigned);
-static void tag_blocks (unsigned, unsigned);
-static void tag_arcs (unsigned, unsigned);
-static void tag_lines (unsigned, unsigned);
-static void tag_counters (unsigned, unsigned);
-static void tag_summary (unsigned, unsigned);
+static void tag_function (unsigned, int);
+static void tag_blocks (unsigned, int);
+static void tag_arcs (unsigned, int);
+static void tag_lines (unsigned, int);
+static void tag_counters (unsigned, int);
+static void tag_summary (unsigned, int);
 
 /* The gcov_info for the first module.  */
 static struct gcov_info *curr_gcov_info;
@@ -117,7 +117,7 @@ typedef struct tag_format
 {
     unsigned tag;
     char const *name;
-    void (*proc) (unsigned, unsigned);
+    void (*proc) (unsigned, int);
 } tag_format_t;
 
 /* Handler table for various Tags.  */
@@ -138,7 +138,7 @@ static const tag_format_t tag_table[] =
 /* Handler for reading function tag.  */
 
 static void
-tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+tag_function (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
 {
   int i;
 
@@ -171,7 +171,7 @@ tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
 /* Handler for reading block tag.  */
 
 static void
-tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+tag_blocks (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
 {
   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
   gcc_unreachable ();
@@ -180,7 +180,7 @@ tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
 /* Handler for reading flow arc tag.  */
 
 static void
-tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+tag_arcs (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
 {
   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
   gcc_unreachable ();
@@ -189,7 +189,7 @@ tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
 /* Handler for reading line tag.  */
 
 static void
-tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+tag_lines (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
 {
   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
   gcc_unreachable ();
@@ -198,9 +198,9 @@ tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
 /* Handler for reading counters array tag with value as TAG and length of LENGTH.  */
 
 static void
-tag_counters (unsigned tag, unsigned length)
+tag_counters (unsigned tag, int length)
 {
-  unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
+  unsigned n_counts = GCOV_TAG_COUNTER_NUM (abs (length));
   gcov_type *values;
   unsigned ix;
   unsigned tag_ix;
@@ -211,17 +211,19 @@ tag_counters (unsigned tag, unsigned length)
   gcc_assert (k_ctrs[tag_ix].num == 0);
   k_ctrs[tag_ix].num = n_counts;
 
-  k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
+  k_ctrs[tag_ix].values = values = (gcov_type *) xcalloc (sizeof (gcov_type),
+                                                         n_counts);
   gcc_assert (values);
 
-  for (ix = 0; ix != n_counts; ix++)
-    values[ix] = gcov_read_counter ();
+  if (length > 0)
+    for (ix = 0; ix != n_counts; ix++)
+      values[ix] = gcov_read_counter ();
 }
 
 /* Handler for reading summary tag.  */
 
 static void
-tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+tag_summary (unsigned tag ATTRIBUTE_UNUSED, int ATTRIBUTE_UNUSED)
 {
   gcov_read_summary (&curr_gcov_info->summary);
 }
@@ -320,7 +322,8 @@ read_gcda_file (const char *filename)
       tag = gcov_read_unsigned ();
       if (!tag)
         break;
-      length = gcov_read_unsigned ();
+      int read_length = (int)gcov_read_unsigned ();
+      length = read_length > 0 ? read_length : 0;
       base = gcov_position ();
       mask = GCOV_TAG_MASK (tag) >> 1;
       for (tag_depth = 4; mask; mask >>= 8)
@@ -353,7 +356,7 @@ read_gcda_file (const char *filename)
         {
           unsigned long actual_length;
 
-          (*format->proc) (tag, length);
+         (*format->proc) (tag, read_length);
 
           actual_length = gcov_position () - base;
           if (actual_length > length)