gcov-dump: add --stable option

Message ID 2b638b91-a9e3-8d69-f1f6-1eaf222552fe@suse.cz
State New, archived
Headers
Series gcov-dump: add --stable option |

Commit Message

Martin Liška Aug. 2, 2022, 8:02 a.m. UTC
  The option prints TOP N counters in a stable format
usage for comparison (diff).

Will install the patch if there are no objections.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Martin

gcc/ChangeLog:

	* doc/gcov-dump.texi: Document the new option.
	* gcov-dump.cc (main): Parse the new option.
	(print_usage): Show the option.
	(tag_counters): Sort key:value pairs of TOP N counter.
---
 gcc/doc/gcov-dump.texi |  5 ++++
 gcc/gcov-dump.cc       | 61 +++++++++++++++++++++++++++++++++++++-----
 2 files changed, 59 insertions(+), 7 deletions(-)
  

Patch

diff --git a/gcc/doc/gcov-dump.texi b/gcc/doc/gcov-dump.texi
index 4f4e355dd28..0491ab17bc1 100644
--- a/gcc/doc/gcov-dump.texi
+++ b/gcc/doc/gcov-dump.texi
@@ -62,6 +62,7 @@  gcov-dump [@option{-v}|@option{--version}]
      [@option{-l}|@option{--long}]
      [@option{-p}|@option{--positions}]
      [@option{-r}|@option{--raw}]
+     [@option{-s}|@option{--stable}]
      @var{gcovfiles}
 @c man end
 @end ignore
@@ -85,6 +86,10 @@  Dump positions of records.
 @itemx --raw
 Print content records in raw format.
 
+@item -s
+@itemx --stable
+Print content in stable format usable for comparison.
+
 @item -v
 @itemx --version
 Display the @command{gcov-dump} version number (on the standard output),
diff --git a/gcc/gcov-dump.cc b/gcc/gcov-dump.cc
index 0804c794e9e..85b1be8859e 100644
--- a/gcc/gcov-dump.cc
+++ b/gcc/gcov-dump.cc
@@ -28,6 +28,10 @@  along with Gcov; see the file COPYING3.  If not see
 #include "gcov-io.h"
 #include "gcov-io.cc"
 
+#include <vector>
+
+using namespace std;
+
 static void dump_gcov_file (const char *);
 static void print_prefix (const char *, unsigned, gcov_position_t);
 static void print_usage (void);
@@ -50,6 +54,7 @@  typedef struct tag_format
 static int flag_dump_contents = 0;
 static int flag_dump_positions = 0;
 static int flag_dump_raw = 0;
+static int flag_dump_stable = 0;
 
 static const struct option options[] =
 {
@@ -57,7 +62,9 @@  static const struct option options[] =
   { "version",              no_argument,       NULL, 'v' },
   { "long",                 no_argument,       NULL, 'l' },
   { "positions",	    no_argument,       NULL, 'o' },
-  { 0, 0, 0, 0 }
+  { "raw",		    no_argument,       NULL, 'r' },
+  { "stable",		    no_argument,       NULL, 's' },
+  {}
 };
 
 #define VALUE_PADDING_PREFIX "              "
@@ -96,7 +103,7 @@  main (int argc ATTRIBUTE_UNUSED, char **argv)
 
   diagnostic_initialize (global_dc, 0);
 
-  while ((opt = getopt_long (argc, argv, "hlprvw", options, NULL)) != -1)
+  while ((opt = getopt_long (argc, argv, "hlprsvw", options, NULL)) != -1)
     {
       switch (opt)
 	{
@@ -115,6 +122,9 @@  main (int argc ATTRIBUTE_UNUSED, char **argv)
 	case 'r':
 	  flag_dump_raw = 1;
 	  break;
+	case 's':
+	  flag_dump_stable = 1;
+	  break;
 	default:
 	  fprintf (stderr, "unknown flag `%c'\n", opt);
 	}
@@ -134,6 +144,8 @@  print_usage (void)
   printf ("  -l, --long           Dump record contents too\n");
   printf ("  -p, --positions      Dump record positions\n");
   printf ("  -r, --raw            Print content records in raw format\n");
+  printf ("  -s, --stable         Print content in stable "
+	  "format usable for comparison\n");
   printf ("  -v, --version        Print version number\n");
   printf ("\nFor bug reporting instructions, please see:\n%s.\n",
 	   bug_report_url);
@@ -439,16 +451,52 @@  tag_counters (const char *filename ATTRIBUTE_UNUSED,
   int n_counts = GCOV_TAG_COUNTER_NUM (length);
   bool has_zeros = n_counts < 0;
   n_counts = abs (n_counts);
+  unsigned counter_idx = GCOV_COUNTER_FOR_TAG (tag);
 
   printf (" %s %u counts%s",
-	  counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts,
+	  counter_names[counter_idx], n_counts,
 	  has_zeros ? " (all zero)" : "");
   if (flag_dump_contents)
     {
+      vector<gcov_type> counters;
       for (int ix = 0; ix != n_counts; ix++)
+	counters.push_back (has_zeros ? 0 : gcov_read_counter ());
+
+      /* Make stable sort for TOP N counters.  */
+      if (flag_dump_stable)
+	if (counter_idx == GCOV_COUNTER_V_INDIR
+	    || counter_idx == GCOV_COUNTER_V_TOPN)
+	  {
+	    unsigned start = 0;
+	    while (start < counters.size ())
+	      {
+		unsigned n = counters[start + 1];
+
+		/* Use bubble sort.  */
+		for (unsigned i = 1; i <= n; ++i)
+		  for (unsigned j = i; j <= n; ++j)
+		    {
+		      gcov_type key1 = counters[start + 2 * i];
+		      gcov_type value1 = counters[start + 2 * i + 1];
+		      gcov_type key2 = counters[start + 2 * j];
+		      gcov_type value2 = counters[start + 2 * j + 1];
+
+		      if (value1 < value2 || (value1 == value2 && key1 < key2))
+			{
+			  std::swap (counters[start + 2 * i],
+				     counters[start + 2 * j]);
+			  std::swap (counters[start + 2 * i + 1],
+				     counters[start + 2 * j + 1]);
+			}
+		    }
+		start += 2 * (n + 1);
+	      }
+	    if (start != counters.size ())
+	      abort ();
+	  }
+
+      for (unsigned ix = 0; ix < counters.size (); ++ix)
 	{
-	  gcov_type count;
-
 	  if (flag_dump_raw)
 	    {
 	      if (ix == 0)
@@ -461,8 +509,7 @@  tag_counters (const char *filename ATTRIBUTE_UNUSED,
 	      printf (VALUE_PADDING_PREFIX VALUE_PREFIX, ix);
 	    }
 
-	  count = has_zeros ? 0 : gcov_read_counter ();
-	  printf ("%" PRId64 " ", count);
+	  printf ("%" PRId64 " ", counters[ix]);
 	}
     }
 }