]> gcc.gnu.org Git - gcc.git/commitdiff
profiling: fix streaming of TOPN counters
authorMartin Liska <mliska@suse.cz>
Tue, 16 Feb 2021 15:28:06 +0000 (16:28 +0100)
committerMartin Liska <mliska@suse.cz>
Thu, 4 Mar 2021 15:21:52 +0000 (16:21 +0100)
libgcc/ChangeLog:

PR gcov-profile/99105
* libgcov-driver.c (write_top_counters): Rename to ...
(write_topn_counters): ... this.
(write_one_data): Pre-allocate buffer for number of items
in the corresponding linked lists.
* libgcov.h (malloc_mmap): New function.
(allocate_gcov_kvp): Use it.

gcc/testsuite/ChangeLog:

PR gcov-profile/99105
* gcc.dg/tree-prof/indir-call-prof-malloc.c: Use profile
correction as the wrapped malloc is called one more time
from libgcov.
* gcc.dg/tree-prof/pr97461.c: Likewise.

gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-malloc.c
gcc/testsuite/gcc.dg/tree-prof/pr97461.c
libgcc/libgcov-driver.c
libgcc/libgcov.h

index 454e224c95fdc87fab954974050a9966535a94d3..7bda4aedfc89332c26a84ffac58b94678db685f3 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-options "-O2 -ldl" } */
+/* { dg-options "-O2 -ldl -fprofile-correction" } */
 
 #define _GNU_SOURCE
 #include <stdio.h>
index 213fac9af042203eb5509efdcc740f53cab62c45..f684be4d80f4b0d3207c0e80867f513e05d9ff37 100644 (file)
@@ -1,5 +1,5 @@
 /* PR gcov-profile/97461 */
-/* { dg-options "-O2 -ldl" } */
+/* { dg-options "-O2 -ldl -fprofile-correction" } */
 
 #define _GNU_SOURCE
 
index 914623501329420efaea9e0f475601a66c1c90e1..a1338b6e5255997e817a552718b02b6ebedc3a95 100644 (file)
@@ -42,6 +42,10 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
 #include <sys/stat.h>
 #endif
 
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
 #ifdef L_gcov
 
 /* A utility function for outputting errors.  */
@@ -334,30 +338,65 @@ read_error:
   return -1;
 }
 
+#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
+
 /* Store all TOP N counters where each has a dynamic length.  */
 
 static void
-write_top_counters (const struct gcov_ctr_info *ci_ptr,
-                   unsigned t_ix,
-                   gcov_unsigned_t n_counts)
+write_topn_counters (const struct gcov_ctr_info *ci_ptr,
+                    unsigned t_ix,
+                    gcov_unsigned_t n_counts)
 {
   unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
   gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
+
+  /* It can happen in a multi-threaded environment that number of counters is
+     different from the size of the corresponding linked lists.  */
+#define LIST_SIZE_MIN_LENGTH 4 * 1024
+
+  static unsigned *list_sizes = NULL;
+  static unsigned list_size_length = 0;
+
+  if (list_sizes == NULL || counters > list_size_length)
+    {
+      list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
+#if HAVE_SYS_MMAN_H
+      list_sizes
+       = (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
+#endif
+
+      /* Malloc fallback.  */
+      if (list_sizes == NULL)
+       list_sizes = (unsigned *)xmalloc (list_size_length * sizeof (unsigned));
+    }
+
+  memset (list_sizes, 0, counters * sizeof (unsigned));
   unsigned pair_total = 0;
+
   for (unsigned i = 0; i < counters; i++)
-    pair_total += ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 1];
+    {
+      gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
+      for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
+          node != NULL; node = node->next)
+       {
+         ++pair_total;
+         ++list_sizes[i];
+       }
+    }
+
   unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total;
   gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
                         GCOV_TAG_COUNTER_LENGTH (disk_size));
 
   for (unsigned i = 0; i < counters; i++)
     {
-      gcov_type pair_count = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 1];
       gcov_write_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i]);
-      gcov_write_counter (pair_count);
+      gcov_write_counter (list_sizes[i]);
       gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
+
+      unsigned j = 0;
       for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start;
-          node != NULL; node = node->next)
+          j < list_sizes[i]; node = node->next, j++)
        {
          gcov_write_counter (node->value);
          gcov_write_counter (node->count);
@@ -425,7 +464,7 @@ write_one_data (const struct gcov_info *gi_ptr,
          n_counts = ci_ptr->num;
 
          if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
-           write_top_counters (ci_ptr, t_ix, n_counts);
+           write_topn_counters (ci_ptr, t_ix, n_counts);
          else
            {
              /* Do not stream when all counters are zero.  */
index acdb7cd150071a9251db0805f07040bc17b9f602..2780cc098c86dd709a5b02cb07a5a7ba168411b6 100644 (file)
@@ -409,6 +409,19 @@ gcov_counter_add (gcov_type *counter, gcov_type value,
     *counter += value;
 }
 
+#if HAVE_SYS_MMAN_H
+
+/* Allocate LENGTH with mmap function.  */
+
+static inline void *
+malloc_mmap (size_t length)
+{
+  return mmap (NULL, length, PROT_READ | PROT_WRITE,
+              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+}
+
+#endif
+
 /* Allocate gcov_kvp from statically pre-allocated pool,
    or use heap otherwise.  */
 
@@ -424,9 +437,7 @@ allocate_gcov_kvp (void)
   if (__gcov_kvp_dynamic_pool == NULL
       || __gcov_kvp_dynamic_pool_index >= __gcov_kvp_dynamic_pool_size)
     {
-      void *ptr = mmap (NULL, MMAP_CHUNK_SIZE,
-                       PROT_READ | PROT_WRITE,
-                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      void *ptr = malloc_mmap (MMAP_CHUNK_SIZE);
       if (ptr != MAP_FAILED)
        {
          __gcov_kvp_dynamic_pool = ptr;
This page took 0.070529 seconds and 5 git commands to generate.