/* Routines required for instrumenting a program. */
/* Compile this one with gcc. */
-/* Copyright (C) 1989-2019 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
This file is part of GCC.
#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
}
#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,
- 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. */
+/* Tries to determine N most commons value among its inputs. */
static inline void
-__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value,
- int use_atomic)
+__gcov_topn_values_profiler_body (gcov_type *counters, gcov_type value,
+ int use_atomic)
{
- if (use_atomic)
- __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED);
- else
- counters[0]++;
-
- ++counters;
-
- /* We have GCOV_DISK_SINGLE_VALUES as we can keep multiple values
- next to each other. */
- unsigned sindex = 0;
-
- for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++)
- {
- if (value == counters[2 * i])
- {
- if (use_atomic)
- __atomic_fetch_add (&counters[2 * i + 1], 1, __ATOMIC_RELAXED);
- else
- counters[2 * i + 1]++;
- return;
- }
- else if (counters[2 * i + 1] == 0)
- {
- /* We found an empty slot. */
- counters[2 * i] = value;
- counters[2 * i + 1] = 1;
- return;
- }
-
- if (counters[2 * i + 1] < counters[2 * sindex + 1])
- sindex = i;
- }
-
- /* We haven't found an empty slot, then decrement the smallest. */
- if (use_atomic)
- __atomic_fetch_sub (&counters[2 * sindex + 1], 1, __ATOMIC_RELAXED);
- else
- counters[2 * sindex + 1]--;
+ gcov_topn_add_value (counters, value, 1, use_atomic, 1);
}
-#ifdef L_gcov_one_value_profiler_v2
+#ifdef L_gcov_topn_values_profiler
void
-__gcov_one_value_profiler_v2 (gcov_type *counters, gcov_type value)
+__gcov_topn_values_profiler (gcov_type *counters, gcov_type value)
{
- __gcov_one_value_profiler_body (counters, value, 0);
+ __gcov_topn_values_profiler_body (counters, value, 0);
}
#endif
-#if defined(L_gcov_one_value_profiler_v2_atomic) && GCOV_SUPPORTS_ATOMIC
+#if defined(L_gcov_topn_values_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
/* Update one value profilers (COUNTERS) for a given VALUE.
https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */
void
-__gcov_one_value_profiler_v2_atomic (gcov_type *counters, gcov_type value)
+__gcov_topn_values_profiler_atomic (gcov_type *counters, gcov_type value)
{
- __gcov_one_value_profiler_body (counters, value, 1);
+ __gcov_topn_values_profiler_body (counters, value, 1);
}
#endif
as a pointer to a function. */
/* Tries to determine the most common value among its inputs. */
-void
-__gcov_indirect_call_profiler_v4 (gcov_type value, void* cur_func)
+static inline void
+__gcov_indirect_call_profiler_body (gcov_type value, void *cur_func,
+ int use_atomic)
{
/* If the C++ virtual tables contain function descriptors then one
function may have multiple descriptors and we need to dereference
if (cur_func == __gcov_indirect_call.callee
|| (__LIBGCC_VTABLE_USES_DESCRIPTORS__
&& *(void **) cur_func == *(void **) __gcov_indirect_call.callee))
- __gcov_one_value_profiler_body (__gcov_indirect_call.counters, value, 0);
+ __gcov_topn_values_profiler_body (__gcov_indirect_call.counters, value,
+ use_atomic);
__gcov_indirect_call.callee = NULL;
}
+
+void
+__gcov_indirect_call_profiler_v4 (gcov_type value, void *cur_func)
+{
+ __gcov_indirect_call_profiler_body (value, cur_func, 0);
+}
+
+#if GCOV_SUPPORTS_ATOMIC
+void
+__gcov_indirect_call_profiler_v4_atomic (gcov_type value, void *cur_func)
+{
+ __gcov_indirect_call_profiler_body (value, cur_func, 1);
+}
+#endif
+
#endif
#ifdef L_gcov_time_profiler