On 6/19/19 10:56 AM, Martin Liška wrote:
> Thank you very much for the numbers. Today, I'm going to prepare the 
> generalization of single-value counter to track N values.

Ok, here's a patch candidate that does tracking of most common N values. For 
your test-case I can see:

pr69678.gcda:    01a90000:  18:COUNTERS indirect_call 9 counts
pr69678.gcda:                   0: 350000000 1868707024 175000000 969338501 
175000000 0 0 0 
pr69678.gcda:                   8: 0 

So for now, you'll need to generalize get_most_common_single_value to return
N most common values.

Eventually we'll need to renamed the counter as it won't be tracking just a 
single value
any longer. I can take care of it.

Can you please verify that the patch candidate works for you?
Thanks,
Martin
>From 93175b20aa794baf1795ff1ccb3ac0391c326ada Mon Sep 17 00:00:00 2001
From: Martin Liska <mli...@suse.cz>
Date: Wed, 19 Jun 2019 14:15:14 +0200
Subject: [PATCH] Support N values in libgcov for single value counter type.

---
 libgcc/libgcov-merge.c    | 48 +++++++++++++++++++++------------------
 libgcc/libgcov-profiler.c | 38 +++++++++++++++++++++++--------
 2 files changed, 54 insertions(+), 32 deletions(-)

diff --git a/libgcc/libgcov-merge.c b/libgcc/libgcov-merge.c
index f778cc4b6b7..84367005663 100644
--- a/libgcc/libgcov-merge.c
+++ b/libgcc/libgcov-merge.c
@@ -89,49 +89,53 @@ __gcov_merge_time_profile (gcov_type *counters, unsigned n_counters)
 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;
 
+  /* Read all part values.  */
+  gcov_type read_counters[2 * GCOV_DISK_SINGLE_VALUES];
+
   for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++)
     {
-      value = gcov_get_counter_target ();
-      counter = gcov_get_counter_ignore_scaling (-1);
+      read_counters[2 * i] = gcov_get_counter_target ();
+      read_counters[2 * i + 1] = 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;
-	}
+  if (read_counters[1] == -1)
+    {
+      counters[1] = -1;
+      return;
+    }
+
+  for (unsigned i = 0; i < GCOV_DISK_SINGLE_VALUES; i++)
+    {
+      if (read_counters[2 * i + 1] == 0)
+	return;
 
+      unsigned j;
       for (j = 0; j < GCOV_DISK_SINGLE_VALUES; j++)
 	{
-	  if (counters[2 * j] == value)
+	  if (counters[2 * j] == read_counters[2 * i])
 	    {
-	      counters[2 * j + 1] += counter;
+	      counters[2 * j + 1] += read_counters[2 * i + 1];
 	      break;
 	    }
 	  else if (counters[2 * j + 1] == 0)
 	    {
-	      counters[2 * j] = value;
-	      counters[2 * j + 1] = counter;
+	      counters[2 * j] += read_counters[2 * i];
+	      counters[2 * j + 1] += read_counters[2 * i + 1];
 	      break;
 	    }
 	}
 
-      /* We haven't found a free slot for the value, mark overflow.  */
+      /* We haven't found a slot, bail out.  */
       if (j == GCOV_DISK_SINGLE_VALUES)
-	counters[1] = -1;
+	{
+	  counters[1] = -1;
+	  return;
+	}
     }
 }
 
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index 9ba65b90df3..0ef400bdda7 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -118,20 +118,38 @@ static inline void
 __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value,
 				int use_atomic)
 {
-  if (value == counters[1])
-    counters[2]++;
-  else if (counters[2] == 0)
-    {
-      counters[2] = 1;
-      counters[1] = value;
-    }
-  else
-    counters[2]--;
-
   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])
+	{
+	  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.  */
+  counters[2 * sindex + 1]--;
 }
 
 #ifdef L_gcov_one_value_profiler_v2
-- 
2.21.0

Reply via email to