summaryrefslogtreecommitdiff
path: root/libgcc/libgcov-profiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgcc/libgcov-profiler.c')
-rw-r--r--libgcc/libgcov-profiler.c103
1 files changed, 98 insertions, 5 deletions
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index a99d93bb412..70a821dc625 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -46,6 +46,26 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value,
}
#endif
+#ifdef L_gcov_interval_profiler_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, MEMMODEL_RELAXED);
+ else if (delta >= steps)
+ __atomic_fetch_add (&counters[steps], 1, MEMMODEL_RELAXED);
+ else
+ __atomic_fetch_add (&counters[delta], 1, MEMMODEL_RELAXED);
+}
+#endif
+
#ifdef L_gcov_pow2_profiler
/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
COUNTERS[0] is incremented. */
@@ -60,6 +80,21 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
}
#endif
+#ifdef L_gcov_pow2_profiler_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, MEMMODEL_RELAXED);
+ else
+ __atomic_fetch_add (&counters[1], 1, MEMMODEL_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 +103,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 +119,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, MEMMODEL_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
+
+#ifdef L_gcov_one_value_profiler_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
@@ -265,7 +324,7 @@ __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
@@ -282,8 +341,19 @@ __gcov_time_profiler (gcov_type* counters)
if (!counters[0])
counters[0] = ++function_counter;
}
+
+/* Sets corresponding COUNTERS if there is no value.
+ Function is thread-safe. */
+
+void
+__gcov_time_profiler_atomic (gcov_type* counters)
+{
+ if (!counters[0])
+ counters[0] = __atomic_add_fetch (&function_counter, 1, MEMMODEL_RELAXED);
+}
#endif
+
#ifdef L_gcov_average_profiler
/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
to saturate up. */
@@ -296,6 +366,18 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value)
}
#endif
+#ifdef L_gcov_average_profiler_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, MEMMODEL_RELAXED);
+ __atomic_fetch_add (&counters[1], 1, MEMMODEL_RELAXED);
+}
+#endif
+
#ifdef L_gcov_ior_profiler
/* Bitwise-OR VALUE into COUNTER. */
@@ -306,4 +388,15 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value)
}
#endif
+#ifdef L_gcov_ior_profiler_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, MEMMODEL_RELAXED);
+}
+#endif
+
+
#endif /* inhibit_libc */