summaryrefslogtreecommitdiff
path: root/libgcc/libgcov-profiler.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-05-02 14:43:35 +0000
commit34efdaf078b01a7387007c4e6bde6db86384c4b7 (patch)
treed503eaf41d085669d1481bb46ec038bc866fece6 /libgcc/libgcov-profiler.c
parentf733cf303bcdc952c92b81dd62199a40a1f555ec (diff)
downloadgcc-tarball-master.tar.gz
gcc-7.1.0gcc-7.1.0
Diffstat (limited to 'libgcc/libgcov-profiler.c')
-rw-r--r--libgcc/libgcov-profiler.c144
1 files changed, 101 insertions, 43 deletions
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index e94718834e..067d762c2a 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -1,6 +1,6 @@
/* Routines required for instrumenting a program. */
/* Compile this one with gcc. */
-/* Copyright (C) 1989-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2017 Free Software Foundation, Inc.
This file is part of GCC.
@@ -26,6 +26,17 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "libgcov.h"
#if !defined(inhibit_libc)
+/* Detect whether target can support atomic update of profilers. */
+#if __SIZEOF_LONG_LONG__ == 4 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+#define GCOV_SUPPORTS_ATOMIC 1
+#else
+#if __SIZEOF_LONG_LONG__ == 8 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+#define GCOV_SUPPORTS_ATOMIC 1
+#else
+#define GCOV_SUPPORTS_ATOMIC 0
+#endif
+#endif
+
#ifdef L_gcov_interval_profiler
/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
corresponding counter in COUNTERS. If the VALUE is above or below
@@ -46,6 +57,26 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value,
}
#endif
+#if defined(L_gcov_interval_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
+/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
+ corresponding counter in COUNTERS. If the VALUE is above or below
+ the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
+ instead. Function is thread-safe. */
+
+void
+__gcov_interval_profiler_atomic (gcov_type *counters, gcov_type value,
+ int start, unsigned steps)
+{
+ gcov_type delta = value - start;
+ if (delta < 0)
+ __atomic_fetch_add (&counters[steps + 1], 1, __ATOMIC_RELAXED);
+ else if (delta >= steps)
+ __atomic_fetch_add (&counters[steps], 1, __ATOMIC_RELAXED);
+ else
+ __atomic_fetch_add (&counters[delta], 1, __ATOMIC_RELAXED);
+}
+#endif
+
#ifdef L_gcov_pow2_profiler
/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
COUNTERS[0] is incremented. */
@@ -53,13 +84,28 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value,
void
__gcov_pow2_profiler (gcov_type *counters, gcov_type value)
{
- if (value & (value - 1))
+ if (value == 0 || (value & (value - 1)))
counters[0]++;
else
counters[1]++;
}
#endif
+#if defined(L_gcov_pow2_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
+/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
+ COUNTERS[0] is incremented. Function is thread-safe. */
+
+void
+__gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+ if (value == 0 || (value & (value - 1)))
+ __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED);
+ else
+ __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED);
+}
+#endif
+
+
/* Tries to determine the most common value among its inputs. Checks if the
value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
is incremented. If this is not the case and COUNTERS[1] is not zero,
@@ -68,10 +114,12 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
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. */
+ In any case, COUNTERS[2] is incremented. If USE_ATOMIC is set to 1,
+ COUNTERS[2] is updated with an atomic instruction. */
static inline void
-__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
+__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value,
+ int use_atomic)
{
if (value == counters[0])
counters[1]++;
@@ -82,14 +130,36 @@ __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
}
else
counters[1]--;
- counters[2]++;
+
+ if (use_atomic)
+ __atomic_fetch_add (&counters[2], 1, __ATOMIC_RELAXED);
+ else
+ counters[2]++;
}
#ifdef L_gcov_one_value_profiler
void
__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
{
- __gcov_one_value_profiler_body (counters, value);
+ __gcov_one_value_profiler_body (counters, value, 0);
+}
+#endif
+
+#if defined(L_gcov_one_value_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
+
+/* Update one value profilers (COUNTERS) for a given VALUE.
+
+ CAVEAT: Following function is not thread-safe, only total number
+ of executions (COUNTERS[2]) is update with an atomic instruction.
+ Problem is that one cannot atomically update two counters
+ (COUNTERS[0] and COUNTERS[1]), for more information please read
+ following email thread:
+ 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_body (counters, value, 1);
}
#endif
@@ -231,33 +301,6 @@ __gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func)
}
#endif
-#ifdef L_gcov_indirect_call_profiler
-/* This function exist only for workaround of binutils bug 14342.
- Once this compatibility hack is obsolette, it can be removed. */
-
-/* By default, the C++ compiler will use function addresses in the
- vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
- tells the compiler to use function descriptors instead. The value
- of this macro says how many words wide the descriptor is (normally 2).
-
- It is assumed that the address of a function descriptor may be treated
- as a pointer to a function. */
-
-/* Tries to determine the most common value among its inputs. */
-void
-__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
- void* cur_func, void* callee_func)
-{
- /* If the C++ virtual tables contain function descriptors then one
- function may have multiple descriptors and we need to dereference
- the descriptors to see if they point to the same function. */
- if (cur_func == callee_func
- || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && callee_func
- && *(void **) cur_func == *(void **) callee_func))
- __gcov_one_value_profiler_body (counter, value);
-}
-#endif
-
#ifdef L_gcov_indirect_call_profiler_v2
/* These two variables are used to actually track caller and callee. Keep
@@ -292,23 +335,15 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func)
if (cur_func == __gcov_indirect_call_callee
|| (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && __gcov_indirect_call_callee
&& *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
- __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value);
+ __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value, 0);
}
#endif
#ifdef L_gcov_time_profiler
/* Counter for first visit of each function. */
-static gcov_type function_counter;
+gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN;
-/* Sets corresponding COUNTERS if there is no value. */
-
-void
-__gcov_time_profiler (gcov_type* counters)
-{
- if (!counters[0])
- counters[0] = ++function_counter;
-}
#endif
#ifdef L_gcov_average_profiler
@@ -323,6 +358,18 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value)
}
#endif
+#if defined(L_gcov_average_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
+/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
+ to saturate up. Function is thread-safe. */
+
+void
+__gcov_average_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+ __atomic_fetch_add (&counters[0], value, __ATOMIC_RELAXED);
+ __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED);
+}
+#endif
+
#ifdef L_gcov_ior_profiler
/* Bitwise-OR VALUE into COUNTER. */
@@ -333,4 +380,15 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value)
}
#endif
+#if defined(L_gcov_ior_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
+/* Bitwise-OR VALUE into COUNTER. Function is thread-safe. */
+
+void
+__gcov_ior_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+ __atomic_fetch_or (&counters[0], value, __ATOMIC_RELAXED);
+}
+#endif
+
+
#endif /* inhibit_libc */