diff options
author | Martin Liska <mliska@suse.cz> | 2019-06-10 09:38:59 +0200 |
---|---|---|
committer | Martin Liska <marxin@gcc.gnu.org> | 2019-06-10 07:38:59 +0000 |
commit | 92d417175b9f7b41d5ebe3ceb723f808917ed964 (patch) | |
tree | 68db0aeb3fb07bf5bb068e205d5a3cb895a45a01 /libgcc | |
parent | b076a52602320955ca7f4b8b54a5451f9f3c7658 (diff) | |
download | gcc-92d417175b9f7b41d5ebe3ceb723f808917ed964.zip gcc-92d417175b9f7b41d5ebe3ceb723f808917ed964.tar.gz gcc-92d417175b9f7b41d5ebe3ceb723f808917ed964.tar.bz2 |
Implement N disk counters for single value and indirect call counters.
2019-06-10 Martin Liska <mliska@suse.cz>
* gcov-io.h (GCOV_DISK_SINGLE_VALUES): New.
(GCOV_SINGLE_VALUE_COUNTERS): Likewise.
* ipa-profile.c (ipa_profile_generate_summary):
Use get_most_common_single_value.
* tree-profile.c (gimple_init_gcov_profiler):
Instrument with __gcov_one_value_profiler_v2
and __gcov_indirect_call_profiler_v4.
* value-prof.c (dump_histogram_value):
Print all values for HIST_TYPE_SINGLE_VALUE.
(stream_out_histogram_value): Update assert for
N values.
(stream_in_histogram_value): Set number of
counters for HIST_TYPE_SINGLE_VALUE.
(get_most_common_single_value): New.
(gimple_divmod_fixed_value_transform):
Use get_most_common_single_value.
(gimple_ic_transform): Likewise.
(gimple_stringops_transform): Likewise.
(gimple_find_values_to_profile): Set number
of counters for HIST_TYPE_SINGLE_VALUE.
* value-prof.h (get_most_common_single_value):
New.
2019-06-10 Martin Liska <mliska@suse.cz>
* Makefile.in: Add __gcov_one_value_profiler_v2,
__gcov_one_value_profiler_v2_atomic and
__gcov_indirect_call_profiler_v4.
* libgcov-merge.c (__gcov_merge_single): Change
function signature.
(merge_single_value_set): New.
* libgcov-profiler.c (__gcov_one_value_profiler_body):
Update functionality.
(__gcov_one_value_profiler): Remove.
(__gcov_one_value_profiler_v2): ... this.
(__gcov_one_value_profiler_atomic): Rename to ...
(__gcov_one_value_profiler_v2_atomic): this.
(__gcov_indirect_call_profiler_v3): Rename to ...
(__gcov_indirect_call_profiler_v4): ... this.
* libgcov.h (__gcov_one_value_profiler): Remove.
(__gcov_one_value_profiler_atomic): Remove.
(__gcov_one_value_profiler_v2_atomic): New.
(__gcov_indirect_call_profiler_v3): Remove.
(__gcov_one_value_profiler_v2): New.
(__gcov_indirect_call_profiler_v4): New.
(gcov_get_counter_ignore_scaling): New function.
From-SVN: r272106
Diffstat (limited to 'libgcc')
-rw-r--r-- | libgcc/ChangeLog | 24 | ||||
-rw-r--r-- | libgcc/Makefile.in | 6 | ||||
-rw-r--r-- | libgcc/libgcov-merge.c | 83 | ||||
-rw-r--r-- | libgcc/libgcov-profiler.c | 33 | ||||
-rw-r--r-- | libgcc/libgcov.h | 29 |
5 files changed, 126 insertions, 49 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 7ef347a..669041e 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,27 @@ +2019-06-10 Martin Liska <mliska@suse.cz> + + * Makefile.in: Add __gcov_one_value_profiler_v2, + __gcov_one_value_profiler_v2_atomic and + __gcov_indirect_call_profiler_v4. + * libgcov-merge.c (__gcov_merge_single): Change + function signature. + (merge_single_value_set): New. + * libgcov-profiler.c (__gcov_one_value_profiler_body): + Update functionality. + (__gcov_one_value_profiler): Remove. + (__gcov_one_value_profiler_v2): ... this. + (__gcov_one_value_profiler_atomic): Rename to ... + (__gcov_one_value_profiler_v2_atomic): this. + (__gcov_indirect_call_profiler_v3): Rename to ... + (__gcov_indirect_call_profiler_v4): ... this. + * libgcov.h (__gcov_one_value_profiler): Remove. + (__gcov_one_value_profiler_atomic): Remove. + (__gcov_one_value_profiler_v2_atomic): New. + (__gcov_indirect_call_profiler_v3): Remove. + (__gcov_one_value_profiler_v2): New. + (__gcov_indirect_call_profiler_v4): New. + (gcov_get_counter_ignore_scaling): New function. + 2019-06-07 Martin Liska <mliska@suse.cz> * Makefile.in: Remove usage of diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index fb77881..33b8380 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -893,13 +893,13 @@ LIBGCOV_PROFILER = _gcov_interval_profiler \ _gcov_interval_profiler_atomic \ _gcov_pow2_profiler \ _gcov_pow2_profiler_atomic \ - _gcov_one_value_profiler \ - _gcov_one_value_profiler_atomic \ + _gcov_one_value_profiler_v2 \ + _gcov_one_value_profiler_v2_atomic \ _gcov_average_profiler \ _gcov_average_profiler_atomic \ _gcov_ior_profiler \ _gcov_ior_profiler_atomic \ - _gcov_indirect_call_profiler_v3 \ + _gcov_indirect_call_profiler_v4 \ _gcov_time_profiler LIBGCOV_INTERFACE = _gcov_dump _gcov_flush _gcov_fork \ _gcov_execl _gcov_execlp \ diff --git a/libgcc/libgcov-merge.c b/libgcc/libgcov-merge.c index 702a69f..4241634 100644 --- a/libgcc/libgcov-merge.c +++ b/libgcc/libgcov-merge.c @@ -34,8 +34,9 @@ void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)), #endif #ifdef L_gcov_merge_single -void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)), - unsigned n_counters __attribute__ ((unused))) {} +void __gcov_merge_single (gcov_type *counters __attribute__ ((unused))) +{ +} #endif #else @@ -85,40 +86,72 @@ __gcov_merge_time_profile (gcov_type *counters, unsigned n_counters) #endif /* L_gcov_merge_time_profile */ #ifdef L_gcov_merge_single + +static void +merge_single_value_set (gcov_type *counters) +{ + unsigned j; + gcov_type value, counter; + + /* First value is number of total executions of the profiler. */ + gcov_type all = gcov_get_counter_ignore_scaling (-1); + counters[0] += all; + ++counters; + + for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++) + { + value = gcov_get_counter_target (); + counter = gcov_get_counter_ignore_scaling (-1); + + if (counter == -1) + { + counters[1] = -1; + /* We can't return as we need to read all counters. */ + continue; + } + else if (counter == 0 || counters[1] == -1) + { + /* We can't return as we need to read all counters. */ + continue; + } + + for (j = 0; j < GCOV_DISK_SINGLE_VALUES; j++) + { + if (counters[2 * j] == value) + { + counters[2 * j + 1] += counter; + break; + } + else if (counters[2 * j + 1] == 0) + { + counters[2 * j] = value; + counters[2 * j + 1] = counter; + break; + } + } + + /* We haven't found a free slot for the value, mark overflow. */ + if (j == GCOV_DISK_SINGLE_VALUES) + counters[1] = -1; + } +} + /* The profile merging function for choosing the most common value. It is given an array COUNTERS of N_COUNTERS old counters and it reads the same number of counters from the gcov file. The counters - are split into 3-tuples where the members of the tuple have + are split into pairs where the members of the tuple have meanings: -- the stored candidate on the most common value of the measured entity -- counter - -- total number of evaluations of the value */ + */ void __gcov_merge_single (gcov_type *counters, unsigned n_counters) { - unsigned i, n_measures; - gcov_type value, counter, all; + gcc_assert (!(n_counters % GCOV_SINGLE_VALUE_COUNTERS)); - gcc_assert (!(n_counters % 3)); - n_measures = n_counters / 3; - for (i = 0; i < n_measures; i++, counters += 3) - { - value = gcov_get_counter_target (); - counter = gcov_get_counter (); - all = gcov_get_counter (); - - if (counters[0] == value) - counters[1] += counter; - else if (counter > counters[1]) - { - counters[0] = value; - counters[1] = counter - counters[1]; - } - else - counters[1] -= counter; - counters[2] += all; - } + for (unsigned i = 0; i < (n_counters / GCOV_SINGLE_VALUE_COUNTERS); i++) + merge_single_value_set (counters + (i * GCOV_SINGLE_VALUE_COUNTERS)); } #endif /* L_gcov_merge_single */ diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c index 40f0858..9ba65b9 100644 --- a/libgcc/libgcov-profiler.c +++ b/libgcc/libgcov-profiler.c @@ -112,40 +112,37 @@ __gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value) COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this function is called more than 50% of the time with one value, this value - will be in COUNTERS[0] in the end. - - In any case, COUNTERS[2] is incremented. If USE_ATOMIC is set to 1, - COUNTERS[2] is updated with an atomic instruction. */ + will be in COUNTERS[0] in the end. */ static inline void __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value, int use_atomic) { - if (value == counters[0]) - counters[1]++; - else if (counters[1] == 0) + if (value == counters[1]) + counters[2]++; + else if (counters[2] == 0) { - counters[1] = 1; - counters[0] = value; + counters[2] = 1; + counters[1] = value; } else - counters[1]--; + counters[2]--; if (use_atomic) - __atomic_fetch_add (&counters[2], 1, __ATOMIC_RELAXED); + __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED); else - counters[2]++; + counters[0]++; } -#ifdef L_gcov_one_value_profiler +#ifdef L_gcov_one_value_profiler_v2 void -__gcov_one_value_profiler (gcov_type *counters, gcov_type value) +__gcov_one_value_profiler_v2 (gcov_type *counters, gcov_type value) { __gcov_one_value_profiler_body (counters, value, 0); } #endif -#if defined(L_gcov_one_value_profiler_atomic) && GCOV_SUPPORTS_ATOMIC +#if defined(L_gcov_one_value_profiler_v2_atomic) && GCOV_SUPPORTS_ATOMIC /* Update one value profilers (COUNTERS) for a given VALUE. @@ -157,13 +154,13 @@ __gcov_one_value_profiler (gcov_type *counters, gcov_type value) https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */ void -__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value) +__gcov_one_value_profiler_v2_atomic (gcov_type *counters, gcov_type value) { __gcov_one_value_profiler_body (counters, value, 1); } #endif -#ifdef L_gcov_indirect_call_profiler_v3 +#ifdef L_gcov_indirect_call_profiler_v4 /* These two variables are used to actually track caller and callee. Keep them in TLS memory so races are not common (they are written to often). @@ -185,7 +182,7 @@ struct indirect_call_tuple __gcov_indirect_call; /* Tries to determine the most common value among its inputs. */ void -__gcov_indirect_call_profiler_v3 (gcov_type value, void* cur_func) +__gcov_indirect_call_profiler_v4 (gcov_type value, void* cur_func) { /* If the C++ virtual tables contain function descriptors then one function may have multiple descriptors and we need to dereference diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h index b4f1ec5..144b481 100644 --- a/libgcc/libgcov.h +++ b/libgcc/libgcov.h @@ -271,9 +271,9 @@ extern void __gcov_interval_profiler_atomic (gcov_type *, gcov_type, int, unsigned); extern void __gcov_pow2_profiler (gcov_type *, gcov_type); extern void __gcov_pow2_profiler_atomic (gcov_type *, gcov_type); -extern void __gcov_one_value_profiler (gcov_type *, gcov_type); -extern void __gcov_one_value_profiler_atomic (gcov_type *, gcov_type); -extern void __gcov_indirect_call_profiler_v3 (gcov_type, void *); +extern void __gcov_one_value_profiler_v2 (gcov_type *, gcov_type); +extern void __gcov_one_value_profiler_v2_atomic (gcov_type *, gcov_type); +extern void __gcov_indirect_call_profiler_v4 (gcov_type, void *); extern void __gcov_time_profiler (gcov_type *); extern void __gcov_time_profiler_atomic (gcov_type *); extern void __gcov_average_profiler (gcov_type *, gcov_type); @@ -324,6 +324,29 @@ gcov_get_counter (void) #endif } +/* Similar function as gcov_get_counter(), but do not scale + when read value is equal to IGNORE_SCALING. */ + +static inline gcov_type +gcov_get_counter_ignore_scaling (gcov_type ignore_scaling) +{ +#ifndef IN_GCOV_TOOL + /* This version is for reading count values in libgcov runtime: + we read from gcda files. */ + + return gcov_read_counter (); +#else + /* This version is for gcov-tool. We read the value from memory and + multiply it by the merge weight. */ + + gcov_type v = gcov_read_counter_mem (); + if (v != ignore_scaling) + v *= gcov_get_merge_weight (); + + return v; +#endif +} + /* Similar function as gcov_get_counter(), but handles target address counters. */ |