From 5089df534b85b795bfcdca8f4f1957ad15a60558 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 22 Jan 2021 11:27:16 +0100 Subject: [PATCH] Restore profile reproducibility. gcc/ChangeLog: PR gcov-profile/98739 * common.opt: Add missing sign symbol. * value-prof.c (get_nth_most_common_value): Restore handling of PROFILE_REPRODUCIBILITY_PARALLEL_RUNS and PROFILE_REPRODUCIBILITY_MULTITHREADED. libgcc/ChangeLog: PR gcov-profile/98739 * libgcov-merge.c (__gcov_merge_topn): Mark when merging ends with a dropped counter. * libgcov.h (gcov_topn_add_value): Add return value. --- gcc/common.opt | 2 +- gcc/value-prof.c | 26 ++++++++++++++++++++------ libgcc/libgcov-merge.c | 14 +++++++++++--- libgcc/libgcov.h | 13 +++++++++---- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/gcc/common.opt b/gcc/common.opt index bde1711870d..a8a2b67a99d 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2248,7 +2248,7 @@ Enum(profile_reproducibility) String(parallel-runs) Value(PROFILE_REPRODUCIBILIT EnumValue Enum(profile_reproducibility) String(multithreaded) Value(PROFILE_REPRODUCIBILITY_MULTITHREADED) -fprofile-reproducible +fprofile-reproducible= Common Joined RejectNegative Var(flag_profile_reproducible) Enum(profile_reproducibility) Init(PROFILE_REPRODUCIBILITY_SERIAL) -fprofile-reproducible=[serial|parallel-runs|multithreaded] Control level of reproducibility of profile gathered by -fprofile-generate. diff --git a/gcc/value-prof.c b/gcc/value-prof.c index 4c916f4994f..3e899a39b84 100644 --- a/gcc/value-prof.c +++ b/gcc/value-prof.c @@ -747,8 +747,8 @@ gimple_divmod_fixed_value (gassign *stmt, tree value, profile_probability prob, abs (counters[0]) is the number of executions for i in 0 ... TOPN-1 - counters[2 * i + 1] is target - abs (counters[2 * i + 2]) is corresponding hitrate counter. + counters[2 * i + 2] is target + counters[2 * i + 3] is corresponding hitrate counter. Value of counters[0] negative when counter became full during merging and some values are lost. */ @@ -766,15 +766,29 @@ get_nth_most_common_value (gimple *stmt, const char *counter_type, *value = 0; gcov_type read_all = abs_hwi (hist->hvalue.counters[0]); + gcov_type covered = 0; + for (unsigned i = 0; i < counters; ++i) + covered += hist->hvalue.counters[2 * i + 3]; gcov_type v = hist->hvalue.counters[2 * n + 2]; gcov_type c = hist->hvalue.counters[2 * n + 3]; if (hist->hvalue.counters[0] < 0 - && (flag_profile_reproducible == PROFILE_REPRODUCIBILITY_PARALLEL_RUNS - || (flag_profile_reproducible - == PROFILE_REPRODUCIBILITY_MULTITHREADED))) - return false; + && flag_profile_reproducible == PROFILE_REPRODUCIBILITY_PARALLEL_RUNS) + { + if (dump_file) + fprintf (dump_file, "Histogram value dropped in %qs mode", + "-fprofile-reproducible=parallel-runs"); + return false; + } + else if (covered != read_all + && flag_profile_reproducible == PROFILE_REPRODUCIBILITY_MULTITHREADED) + { + if (dump_file) + fprintf (dump_file, "Histogram value dropped in %qs mode", + "-fprofile-reproducible=multithreaded"); + return false; + } /* Indirect calls can't be verified. */ if (stmt diff --git a/libgcc/libgcov-merge.c b/libgcc/libgcov-merge.c index 9306e8d688c..7db188a4f4c 100644 --- a/libgcc/libgcov-merge.c +++ b/libgcc/libgcov-merge.c @@ -94,6 +94,9 @@ __gcov_merge_time_profile (gcov_type *counters, unsigned n_counters) -- the stored candidate on the most common value of the measured entity -- counter + + We use -TOTAL for situation when merging dropped some values. + The information is used for -fprofile-reproducible flag. */ void @@ -107,7 +110,9 @@ __gcov_merge_topn (gcov_type *counters, unsigned n_counters) gcov_type all = gcov_get_counter_ignore_scaling (-1); gcov_type n = gcov_get_counter_ignore_scaling (-1); - counters[GCOV_TOPN_MEM_COUNTERS * i] += all; + unsigned full = all < 0; + gcov_type *total = &counters[GCOV_TOPN_MEM_COUNTERS * i]; + *total += full ? -all : all; for (unsigned j = 0; j < n; j++) { @@ -115,9 +120,12 @@ __gcov_merge_topn (gcov_type *counters, unsigned n_counters) gcov_type count = gcov_get_counter_ignore_scaling (-1); // TODO: we should use atomic here - gcov_topn_add_value (counters + GCOV_TOPN_MEM_COUNTERS * i, value, - count, 0, 0); + full |= gcov_topn_add_value (counters + GCOV_TOPN_MEM_COUNTERS * i, + value, count, 0, 0); } + + if (full) + *total = -(*total); } } #endif /* L_gcov_merge_topn */ diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h index b4a7e942a7e..df08e882dd7 100644 --- a/libgcc/libgcov.h +++ b/libgcc/libgcov.h @@ -435,9 +435,10 @@ allocate_gcov_kvp (void) /* Add key value pair VALUE:COUNT to a top N COUNTERS. When INCREMENT_TOTAL is true, add COUNT to total of the TOP counter. If USE_ATOMIC is true, - do it in atomic way. */ + do it in atomic way. Return true when the counter is full, otherwise + return false. */ -static inline void +static inline unsigned gcov_topn_add_value (gcov_type *counters, gcov_type value, gcov_type count, int use_atomic, int increment_total) { @@ -453,7 +454,7 @@ gcov_topn_add_value (gcov_type *counters, gcov_type value, gcov_type count, if (current_node->value == value) { gcov_counter_add (¤t_node->count, count, use_atomic); - return; + return 0; } if (minimal_node == NULL @@ -471,12 +472,14 @@ gcov_topn_add_value (gcov_type *counters, gcov_type value, gcov_type count, minimal_node->value = value; minimal_node->count = count; } + + return 1; } else { struct gcov_kvp *new_node = allocate_gcov_kvp (); if (new_node == NULL) - return; + return 0; new_node->value = value; new_node->count = count; @@ -515,6 +518,8 @@ gcov_topn_add_value (gcov_type *counters, gcov_type value, gcov_type count, if (success) gcov_counter_add (&counters[1], 1, use_atomic); } + + return 0; } #endif /* !inhibit_libc */ -- 2.30.2