From ece21ff6ea9d969d3b6aae82136622a7126eefc1 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 2 Jun 2020 10:11:07 +0200 Subject: [PATCH] Do not stream all zeros for gcda files. 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 | 9 +++++--- gcc/gcov-dump.c | 51 ++++++++++++++++++++++------------------- gcc/gcov.c | 9 ++++++-- libgcc/libgcov-driver.c | 44 ++++++++++++++++++++++++----------- libgcc/libgcov-util.c | 41 ++++++++++++++++++--------------- 5 files changed, 92 insertions(+), 62 deletions(-) diff --git a/gcc/coverage.c b/gcc/coverage.c index 1dcda4353cd..f353c9c5022 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -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 ())) diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c index cfa771e4a25..97ff27861c6 100644 --- a/gcc/gcov-dump.c +++ b/gcc/gcov-dump.c @@ -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; diff --git a/gcc/gcov.c b/gcc/gcov.c index b2d2fda4563..b302e2197dd 100644 --- a/gcc/gcov.c +++ b/gcc/gcov.c @@ -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 ())) diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c index 871b87b867b..2590593a58a 100644 --- a/libgcc/libgcov-driver.c +++ b/libgcc/libgcov-driver.c @@ -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); } diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c index 09e34f0a33a..1ada1fecb58 100644 --- a/libgcc/libgcov-util.c +++ b/libgcc/libgcov-util.c @@ -57,12 +57,12 @@ void gcov_set_verbose (void) #include #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)