diff libgcc/libgcov-driver.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-driver.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/libgcc/libgcov-driver.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.
 
@@ -53,6 +53,8 @@
 
 #include "gcov-io.c"
 
+#define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
+
 struct gcov_fn_buffer
 {
   struct gcov_fn_buffer *next;
@@ -151,12 +153,33 @@
   return &fn_buffer->next;
 
 fail:
-  gcov_error ("profiling:%s:Function %u %s %u \n", filename, fn_ix,
+  gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
               len ? "cannot allocate" : "counter mismatch", len ? len : ix);
 
   return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
 }
 
+/* Convert VERSION into a string description and return the it.
+   BUFFER is used for storage of the string.  The code should be
+   aligned wit gcov-iov.c.  */
+
+static char *
+gcov_version_string (char *buffer, char version[4])
+{
+  if (version[0] < 'A' || version[0] > 'Z'
+      || version[1] < '0' || version[1] > '9'
+      || version[2] < '0' || version[2] > '9')
+    sprintf (buffer, "(unknown)");
+  else
+    {
+      unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
+      unsigned minor = version[2] - '0';
+      sprintf (buffer, "%u.%u (%s)", major, minor,
+	       version[3] == '*' ? "release" : "experimental");
+    }
+  return buffer;
+}
+
 /* Check if VERSION of the info block PTR matches libgcov one.
    Return 1 on success, or zero in case of versions mismatch.
    If FILENAME is not NULL, its value used for reporting purposes
@@ -169,12 +192,16 @@
   if (version != GCOV_VERSION)
     {
       char v[4], e[4];
+      char version_string[128], expected_string[128];
 
       GCOV_UNSIGNED2STRING (v, version);
       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
 
-      gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n",
-                  filename? filename : ptr->filename, e, v);
+      gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
+		  "got %s (%.4s)\n",
+		  filename? filename : ptr->filename,
+		  gcov_version_string (expected_string, e), e,
+		  gcov_version_string (version_string, v), v);
       return 0;
     }
   return 1;
@@ -186,6 +213,51 @@
 /* Including system dependent components. */
 #include "libgcov-driver-system.c"
 
+/* Prune TOP N value COUNTERS.  It's needed in order to preserve
+   reproducibility of builds.  */
+
+static void
+prune_topn_counter (gcov_type *counters, gcov_type all)
+{
+  for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
+    if (counters[2 * i + 1] < all)
+      {
+	counters[2 * i] = 0;
+	counters[2 * i + 1] = 0;
+      }
+}
+
+/* Prune counters so that they are ready to store or merge.  */
+
+static void
+prune_counters (struct gcov_info *gi)
+{
+  for (unsigned i = 0; i < gi->n_functions; i++)
+    {
+      const struct gcov_fn_info *gfi = gi->functions[i];
+      const struct gcov_ctr_info *ci = gfi->ctrs;
+
+      for (unsigned j = 0; j < GCOV_COUNTERS; j++)
+	{
+	  if (gi->merge[j] == NULL)
+	    continue;
+
+	  if (gi->merge[j] == __gcov_merge_topn)
+	    {
+	      gcc_assert (!(ci->num % GCOV_TOPN_VALUES_COUNTERS));
+	      for (unsigned k = 0; k < (ci->num / GCOV_TOPN_VALUES_COUNTERS);
+		   k++)
+		{
+		  gcov_type *counters
+		    = ci->values + (k * GCOV_TOPN_VALUES_COUNTERS);
+		  prune_topn_counter (counters + 1, *counters);
+		}
+	    }
+	  ci++;
+	}
+    }
+}
+
 /* This function merges counters in GI_PTR to an existing gcda file.
    Return 0 on success.
    Return -1 on error. In this case, caller will goto read_fatal.  */
@@ -209,7 +281,7 @@
   if (length != gi_ptr->stamp)
     {
       /* Read from a different compilation.  Overwrite the file.  */
-      gcov_error ("profiling:%s:overwriting an existing profile data "
+      gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
 		  "with a different timestamp\n", filename);
       return 0;
     }
@@ -289,7 +361,7 @@
   if (tag)
     {
     read_mismatch:;
-      gcov_error ("profiling:%s:Merge mismatch for %s %u\n",
+      gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
                   filename, f_ix >= 0 ? "function" : "summary",
                   f_ix < 0 ? -1 - f_ix : f_ix);
       return -1;
@@ -297,7 +369,7 @@
   return 0;
 
 read_error:
-  gcov_error ("profiling:%s:%s merging\n", filename,
+  gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
               error < 0 ? "Overflow": "Error");
   return -1;
 }
@@ -388,84 +460,6 @@
     }
 }
 
-/* Sort N entries in VALUE_ARRAY in descending order.
-   Each entry in VALUE_ARRAY has two values. The sorting
-   is based on the second value.  */
-
-GCOV_LINKAGE  void
-gcov_sort_n_vals (gcov_type *value_array, int n)
-{
-  int j, k;
-
-  for (j = 2; j < n; j += 2)
-    {
-      gcov_type cur_ent[2];
-
-      cur_ent[0] = value_array[j];
-      cur_ent[1] = value_array[j + 1];
-      k = j - 2;
-      while (k >= 0 && value_array[k + 1] < cur_ent[1])
-        {
-          value_array[k + 2] = value_array[k];
-          value_array[k + 3] = value_array[k+1];
-          k -= 2;
-        }
-      value_array[k + 2] = cur_ent[0];
-      value_array[k + 3] = cur_ent[1];
-    }
-}
-
-/* Sort the profile counters for all indirect call sites. Counters
-   for each call site are allocated in array COUNTERS.  */
-
-static void
-gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
-{
-  int i;
-  gcov_type *values;
-  int n = counters->num;
-
-  gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
-  values = counters->values;
-
-  for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
-    {
-      gcov_type *value_array = &values[i + 1];
-      gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
-    }
-}
-
-/* Sort topn indirect_call profile counters in GI_PTR.  */
-
-static void
-gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
-{
-  unsigned int i;
-  int f_ix;
-  const struct gcov_fn_info *gfi_ptr;
-  const struct gcov_ctr_info *ci_ptr;
-
-  if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV]) 
-    return;
-
-  for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
-    {
-      gfi_ptr = gi_ptr->functions[f_ix];
-      ci_ptr = gfi_ptr->ctrs;
-      for (i = 0; i < GCOV_COUNTERS; i++)
-        {
-          if (!gi_ptr->merge[i])
-            continue;
-          if (i == GCOV_COUNTER_ICALL_TOPNV)
-            {
-              gcov_sort_icall_topn_counter (ci_ptr);
-              break;
-            }
-          ci_ptr++;
-        }
-    }
-}
-
 /* Dump the coverage counts for one gcov_info object. We merge with existing
    counts when possible, to avoid growing the .da files ad infinitum. We use
    this program's checksum to make sure we only accumulate whole program
@@ -480,10 +474,10 @@
   struct gcov_summary summary = {};
   int error;
   gcov_unsigned_t tag;
-
   fn_buffer = 0;
 
-  gcov_sort_topn_counter_arrays (gi_ptr);
+  /* Prune current counters before we merge them.  */
+  prune_counters (gi_ptr);
 
   error = gcov_exit_open_gcda_file (gi_ptr, gf);
   if (error == -1)
@@ -495,7 +489,8 @@
       /* Merge data from file.  */
       if (tag != GCOV_DATA_MAGIC)
         {
-          gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename);
+	  gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
+		      gf->filename);
           goto read_fatal;
         }
       error = merge_one_data (gf->filename, gi_ptr, &summary);
@@ -516,8 +511,8 @@
 
   if ((error = gcov_close ()))
     gcov_error (error  < 0 ?
-                "profiling:%s:Overflow writing\n" :
-                "profiling:%s:Error writing\n",
+		GCOV_PROF_PREFIX "Overflow writing\n" :
+		GCOV_PROF_PREFIX "Error writing\n",
                 gf->filename);
 }