> Hello. > > AS mentioned here, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97461#c25, I > like > what Richard suggested. So instead of usage of malloc, we should use mmap > memory > chunks that serve as a memory pool for struct gcov_kvp. > > Malloc is used as a fallback when mmap is not available. I also drop > statically > pre-allocated static pool, mmap solves the root problem. > > Patch can bootstrap on x86_64-linux-gnu and survives regression tests. > > Ready to be installed? > Thanks, > Martin > > gcc/ChangeLog: > > PR gcov-profile/97461 > * gcov-io.h (GCOV_PREALLOCATED_KVP): Remove. > > libgcc/ChangeLog: > > PR gcov-profile/97461 > * config.in: Regenerate. > * configure: Likewise. > * configure.ac: Check sys/mman.h header file > * libgcov-driver.c (struct gcov_kvp): Remove static > pre-allocated pool and use a dynamic one. > * libgcov.h (MMAP_CHUNK_SIZE): New. > (gcov_counter_add): Use mmap to allocate pool for struct > gcov_kvp. OK, thanks. We should be ready to add support for non-mmap targets (especially mingw).
Honza > --- > gcc/gcov-io.h | 3 --- > libgcc/config.in | 3 +++ > libgcc/configure | 4 ++-- > libgcc/configure.ac | 2 +- > libgcc/libgcov-driver.c | 11 +++++++---- > libgcc/libgcov.h | 42 ++++++++++++++++++++++++++++++++--------- > 6 files changed, 46 insertions(+), 19 deletions(-) > > diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h > index baed67609e2..75f16a274c7 100644 > --- a/gcc/gcov-io.h > +++ b/gcc/gcov-io.h > @@ -292,9 +292,6 @@ GCOV_COUNTERS > /* Maximum number of tracked TOP N value profiles. */ > #define GCOV_TOPN_MAXIMUM_TRACKED_VALUES 32 > -/* Number of pre-allocated gcov_kvp structures. */ > -#define GCOV_PREALLOCATED_KVP 64 > - > /* Convert a counter index to a tag. */ > #define GCOV_TAG_FOR_COUNTER(COUNT) \ > (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t)(COUNT) << 17)) > diff --git a/libgcc/config.in b/libgcc/config.in > index 5be5321d258..f93c64a00c3 100644 > --- a/libgcc/config.in > +++ b/libgcc/config.in > @@ -49,6 +49,9 @@ > /* Define to 1 if you have the <sys/auxv.h> header file. */ > #undef HAVE_SYS_AUXV_H > +/* Define to 1 if you have the <sys/mman.h> header file. */ > +#undef HAVE_SYS_MMAN_H > + > /* Define to 1 if you have the <sys/stat.h> header file. */ > #undef HAVE_SYS_STAT_H > diff --git a/libgcc/configure b/libgcc/configure > index 78fc22a5784..dd3afb2c957 100755 > --- a/libgcc/configure > +++ b/libgcc/configure > @@ -4458,7 +4458,7 @@ as_fn_arith $ac_cv_sizeof_long_double \* 8 && > long_double_type_size=$as_val > for ac_header in inttypes.h stdint.h stdlib.h ftw.h \ > unistd.h sys/stat.h sys/types.h \ > - string.h strings.h memory.h sys/auxv.h > + string.h strings.h memory.h sys/auxv.h sys/mman.h > do : > as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` > ac_fn_c_check_header_preproc "$LINENO" "$ac_header" "$as_ac_Header" > @@ -4913,7 +4913,7 @@ case "$host" in > case "$enable_cet" in > auto) > # Check if target supports multi-byte NOPs > - # and if assembler supports CET insn. > + # and if compiler and assembler support CET insn. > cet_save_CFLAGS="$CFLAGS" > CFLAGS="$CFLAGS -fcf-protection" > cat confdefs.h - <<_ACEOF >conftest.$ac_ext > diff --git a/libgcc/configure.ac b/libgcc/configure.ac > index ed50c0e9b49..10ffb046415 100644 > --- a/libgcc/configure.ac > +++ b/libgcc/configure.ac > @@ -224,7 +224,7 @@ AC_SUBST(long_double_type_size) > AC_CHECK_HEADERS(inttypes.h stdint.h stdlib.h ftw.h \ > unistd.h sys/stat.h sys/types.h \ > - string.h strings.h memory.h sys/auxv.h) > + string.h strings.h memory.h sys/auxv.h sys/mman.h) > AC_HEADER_STDC > # Check for decimal float support. > diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c > index e474e032b54..91462350132 100644 > --- a/libgcc/libgcov-driver.c > +++ b/libgcc/libgcov-driver.c > @@ -588,11 +588,14 @@ struct gcov_root __gcov_root; > struct gcov_master __gcov_master = > {GCOV_VERSION, 0}; > -/* Pool of pre-allocated gcov_kvp strutures. */ > -struct gcov_kvp __gcov_kvp_pool[GCOV_PREALLOCATED_KVP]; > +/* Dynamic pool for gcov_kvp structures. */ > +struct gcov_kvp *__gcov_kvp_dynamic_pool; > -/* Index to first free gcov_kvp in the pool. */ > -unsigned __gcov_kvp_pool_index; > +/* Index into __gcov_kvp_dynamic_pool array. */ > +unsigned __gcov_kvp_dynamic_pool_index; > + > +/* Size of _gcov_kvp_dynamic_pool array. */ > +unsigned __gcov_kvp_dynamic_pool_size; > void > __gcov_exit (void) > diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h > index b4a7e942a7e..e848811d89d 100644 > --- a/libgcc/libgcov.h > +++ b/libgcc/libgcov.h > @@ -45,6 +45,10 @@ > #include "libgcc_tm.h" > #include "gcov.h" > +#if HAVE_SYS_MMAN_H > +#include <sys/mman.h> > +#endif > + > #if __CHAR_BIT__ == 8 > typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI))); > typedef unsigned gcov_position_t __attribute__ ((mode (SI))); > @@ -250,8 +254,9 @@ struct indirect_call_tuple > /* Exactly one of these will be active in the process. */ > extern struct gcov_master __gcov_master; > -extern struct gcov_kvp __gcov_kvp_pool[GCOV_PREALLOCATED_KVP]; > -extern unsigned __gcov_kvp_pool_index; > +extern struct gcov_kvp *__gcov_kvp_dynamic_pool; > +extern unsigned __gcov_kvp_dynamic_pool_index; > +extern unsigned __gcov_kvp_dynamic_pool_size; > /* Dump a set of gcov objects. */ > extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN; > @@ -410,25 +415,44 @@ gcov_counter_add (gcov_type *counter, gcov_type value, > static inline struct gcov_kvp * > allocate_gcov_kvp (void) > { > +#define MMAP_CHUNK_SIZE (128 * 1024) > struct gcov_kvp *new_node = NULL; > + unsigned kvp_sizeof = sizeof(struct gcov_kvp); > + > + /* Try mmaped pool if available. */ > +#if !defined(IN_GCOV_TOOL) && !defined(L_gcov_merge_topn) && HAVE_SYS_MMAN_H > + 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, 0, 0); > + if (ptr != MAP_FAILED) > + { > + __gcov_kvp_dynamic_pool = ptr; > + __gcov_kvp_dynamic_pool_size = MMAP_CHUNK_SIZE / kvp_sizeof; > + __gcov_kvp_dynamic_pool_index = 0; > + } > + } > -#if !defined(IN_GCOV_TOOL) && !defined(L_gcov_merge_topn) > - if (__gcov_kvp_pool_index < GCOV_PREALLOCATED_KVP) > + if (__gcov_kvp_dynamic_pool != NULL) > { > unsigned index; > #if GCOV_SUPPORTS_ATOMIC > index > - = __atomic_fetch_add (&__gcov_kvp_pool_index, 1, __ATOMIC_RELAXED); > + = __atomic_fetch_add (&__gcov_kvp_dynamic_pool_index, 1, > + __ATOMIC_RELAXED); > #else > - index = __gcov_kvp_pool_index++; > + index = __gcov_kvp_dynamic_pool_index++; > #endif > - if (index < GCOV_PREALLOCATED_KVP) > - new_node = &__gcov_kvp_pool[index]; > + if (index < __gcov_kvp_dynamic_pool_size) > + new_node = __gcov_kvp_dynamic_pool + index; > } > #endif > + /* Fallback to malloc. */ > if (new_node == NULL) > - new_node = (struct gcov_kvp *)xcalloc (1, sizeof (struct gcov_kvp)); > + new_node = (struct gcov_kvp *)xcalloc (1, kvp_sizeof); > return new_node; > } > -- > 2.30.0 >