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.
This commit is contained in:
parent
c981619632
commit
6a8fc0c31a
|
@ -1,4 +1,4 @@
|
|||
/* { dg-options "-O2 -ldl" } */
|
||||
/* { dg-options "-O2 -ldl -fprofile-correction" } */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* PR gcov-profile/97461 */
|
||||
/* { dg-options "-O2 -ldl" } */
|
||||
/* { dg-options "-O2 -ldl -fprofile-correction" } */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue