[PATCH] gcov: use mmap pools for KVP.

Martin Liška mliska@suse.cz
Fri Jan 22 13:31:58 GMT 2021


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.
---
  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



More information about the Gcc-patches mailing list