diff libgcc/libgcov-profiler.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/libgcc/libgcov-profiler.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/libgcc/libgcov-profiler.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,6 +1,6 @@
 /* Routines required for instrumenting a program.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -106,46 +106,61 @@
 #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.
-
-   In any case, COUNTERS[2] is incremented.  If USE_ATOMIC is set to 1,
-   COUNTERS[2] is updated with an atomic instruction.  */
+/* 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 (value == counters[0])
-    counters[1]++;
-  else if (counters[1] == 0)
+  if (use_atomic)
+    __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED);
+  else
+    counters[0]++;
+
+  ++counters;
+
+  /* First try to find an existing value.  */
+  int empty_counter = -1;
+
+  for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
+    if (value == counters[2 * i])
+      {
+	if (use_atomic)
+	  __atomic_fetch_add (&counters[2 * i + 1], GCOV_TOPN_VALUES,
+			      __ATOMIC_RELAXED);
+	else
+	  counters[2 * i + 1] += GCOV_TOPN_VALUES;
+	return;
+      }
+    else if (counters[2 * i + 1] <= 0)
+      empty_counter = i;
+
+  /* Find an empty slot for a new value.  */
+  if (empty_counter != -1)
     {
-      counters[1] = 1;
-      counters[0] = value;
+      counters[2 * empty_counter] = value;
+      counters[2 * empty_counter + 1] = GCOV_TOPN_VALUES;
+      return;
     }
-  else
-    counters[1]--;
 
-  if (use_atomic)
-    __atomic_fetch_add (&counters[2], 1, __ATOMIC_RELAXED);
-  else
-    counters[2]++;
+  /* We haven't found an empty slot, then decrement all
+     counter values by one.  */
+  for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
+    if (use_atomic)
+      __atomic_fetch_sub (&counters[2 * i + 1], 1, __ATOMIC_RELAXED);
+    else
+      counters[2 * i + 1]--;
 }
 
-#ifdef L_gcov_one_value_profiler
+#ifdef L_gcov_topn_values_profiler
 void
-__gcov_one_value_profiler (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_atomic) && GCOV_SUPPORTS_ATOMIC
+#if defined(L_gcov_topn_values_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
 
 /* Update one value profilers (COUNTERS) for a given VALUE.
 
@@ -157,146 +172,13 @@
    https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html.  */
 
 void
-__gcov_one_value_profiler_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
 
-#ifdef L_gcov_indirect_call_topn_profiler
-/* Tries to keep track the most frequent N values in the counters where
-   N is specified by parameter TOPN_VAL. To track top N values, 2*N counter
-   entries are used.
-   counter[0] --- the accumative count of the number of times one entry in
-                  in the counters gets evicted/replaced due to limited capacity.
-                  When this value reaches a threshold, the bottom N values are
-                  cleared.
-   counter[1] through counter[2*N] records the top 2*N values collected so far.
-   Each value is represented by two entries: count[2*i+1] is the ith value, and
-   count[2*i+2] is the number of times the value is seen.  */
-
-static void
-__gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value)
-{
-   unsigned i, found = 0, have_zero_count = 0;
-   gcov_type *entry;
-   gcov_type *lfu_entry = &counters[1];
-   gcov_type *value_array = &counters[1];
-   gcov_type *num_eviction = &counters[0];
-   gcov_unsigned_t topn_val = GCOV_ICALL_TOPN_VAL;
-
-   /* There are 2*topn_val values tracked, each value takes two slots in the
-      counter array.  */
-   for (i = 0; i < (topn_val << 2); i += 2)
-     {
-       entry = &value_array[i];
-       if (entry[0] == value)
-         {
-           entry[1]++ ;
-           found = 1;
-           break;
-         }
-       else if (entry[1] == 0)
-         {
-           lfu_entry = entry;
-           have_zero_count = 1;
-         }
-      else if (entry[1] < lfu_entry[1])
-        lfu_entry = entry;
-     }
-
-   if (found)
-     return;
-
-   /* lfu_entry is either an empty entry or an entry
-      with lowest count, which will be evicted.  */
-   lfu_entry[0] = value;
-   lfu_entry[1] = 1;
-
-#define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000
-
-   /* Too many evictions -- time to clear bottom entries to
-      avoid hot values bumping each other out.  */
-   if (!have_zero_count
-       && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD)
-     {
-       unsigned i, j;
-       gcov_type *p, minv;
-       gcov_type* tmp_cnts
-           = (gcov_type *)alloca (topn_val * sizeof (gcov_type));
-
-       *num_eviction = 0;
-
-       for (i = 0; i < topn_val; i++)
-         tmp_cnts[i] = 0;
-
-       /* Find the largest topn_val values from the group of
-          2*topn_val values and put them into tmp_cnts.  */
-
-       for (i = 0; i < 2 * topn_val; i += 2)
-         {
-           p = 0;
-           for (j = 0; j < topn_val; j++)
-             {
-               if (!p || tmp_cnts[j] < *p)
-                  p = &tmp_cnts[j];
-             }
-            if (value_array[i + 1] > *p)
-              *p = value_array[i + 1];
-         }
-
-       minv = tmp_cnts[0];
-       for (j = 1; j < topn_val; j++)
-         {
-           if (tmp_cnts[j] < minv)
-             minv = tmp_cnts[j];
-         }
-       /* Zero out low value entries.  */
-       for (i = 0; i < 2 * topn_val; i += 2)
-         {
-           if (value_array[i + 1] < minv)
-             {
-               value_array[i] = 0;
-               value_array[i + 1] = 0;
-             }
-         }
-     }
-}
-
-/* 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).
-   The variables are set directly by GCC instrumented code, so declaration
-   here must match one in tree-profile.c.  */
-
-#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
-__thread
-#endif
-struct indirect_call_tuple __gcov_indirect_call_topn;
-
-#ifdef TARGET_VTABLE_USES_DESCRIPTORS
-#define VTABLE_USES_DESCRIPTORS 1
-#else
-#define VTABLE_USES_DESCRIPTORS 0
-#endif
-
-/* This fucntion is instrumented at function entry to track topn indirect
-   calls to CUR_FUNC.  */
- 
-void
-__gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func)
-{
-  void *callee_func = __gcov_indirect_call_topn.callee;
-  /* 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
-      || (VTABLE_USES_DESCRIPTORS && callee_func
-	  && *(void **) cur_func == *(void **) callee_func))
-    __gcov_topn_value_profiler_body (__gcov_indirect_call_topn.counters, value);
-}
-#endif
-
-#ifdef L_gcov_indirect_call_profiler_v2
+#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).
@@ -317,8 +199,9 @@
    as a pointer to a function.  */
 
 /* Tries to determine the most common value among its inputs. */
-void
-__gcov_indirect_call_profiler_v2 (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
@@ -326,16 +209,32 @@
   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
 
 /* Counter for first visit of each function.  */
-gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN = 1;
+gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN;
 
 #endif