aboutsummaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2019-06-10 09:38:59 +0200
committerMartin Liska <marxin@gcc.gnu.org>2019-06-10 07:38:59 +0000
commit92d417175b9f7b41d5ebe3ceb723f808917ed964 (patch)
tree68db0aeb3fb07bf5bb068e205d5a3cb895a45a01 /libgcc
parentb076a52602320955ca7f4b8b54a5451f9f3c7658 (diff)
downloadgcc-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/ChangeLog24
-rw-r--r--libgcc/Makefile.in6
-rw-r--r--libgcc/libgcov-merge.c83
-rw-r--r--libgcc/libgcov-profiler.c33
-rw-r--r--libgcc/libgcov.h29
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. */