> 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?
This looks like reasonable solution for Linux (i was thinking of it too) but I wonder what about setups w/o mmap support, like mingw32? I think we need some fallback there. I was wondering if simply disabling topn profiling until gcov_init time (where we seems to assume that malloc already works) would work in that case. We may lose some speculation during program construction, but that does not seem very bad... Honza > 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. > --- > 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 >