aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2021-02-16 16:28:06 +0100
committerMartin Liska <mliska@suse.cz>2021-03-04 16:21:52 +0100
commit6a8fc0c31a9ae759fe9bf59b5418abf2af938f91 (patch)
treed0f65e009207e8142f7e5882e2c9e059c3e1b6b8
parentc9816196328a4f4b927f08cf2f66cf255849da0b (diff)
downloadgcc-6a8fc0c31a9ae759fe9bf59b5418abf2af938f91.zip
gcc-6a8fc0c31a9ae759fe9bf59b5418abf2af938f91.tar.gz
gcc-6a8fc0c31a9ae759fe9bf59b5418abf2af938f91.tar.bz2
profiling: fix streaming of TOPN counters
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.
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-malloc.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/pr97461.c2
-rw-r--r--libgcc/libgcov-driver.c55
-rw-r--r--libgcc/libgcov.h17
4 files changed, 63 insertions, 13 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-malloc.c b/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-malloc.c
index 454e224..7bda4ae 100644
--- a/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-malloc.c
+++ b/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-malloc.c
@@ -1,4 +1,4 @@
-/* { dg-options "-O2 -ldl" } */
+/* { dg-options "-O2 -ldl -fprofile-correction" } */
#define _GNU_SOURCE
#include <stdio.h>
diff --git a/gcc/testsuite/gcc.dg/tree-prof/pr97461.c b/gcc/testsuite/gcc.dg/tree-prof/pr97461.c
index 213fac9..f684be4d 100644
--- a/gcc/testsuite/gcc.dg/tree-prof/pr97461.c
+++ b/gcc/testsuite/gcc.dg/tree-prof/pr97461.c
@@ -1,5 +1,5 @@
/* PR gcov-profile/97461 */
-/* { dg-options "-O2 -ldl" } */
+/* { dg-options "-O2 -ldl -fprofile-correction" } */
#define _GNU_SOURCE
diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c
index 9146235..a1338b6 100644
--- a/libgcc/libgcov-driver.c
+++ b/libgcc/libgcov-driver.c
@@ -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. */
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index acdb7cd..2780cc0 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -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;