[RFC,07/11] malloc: make arena size configurable on startup

Message ID 0438c6b3f81ee46abef884de161dbb4b624655db.1568219400.git.isaku.yamahata@gmail.com
State Dropped
Headers

Commit Message

Isaku Yamahata Sept. 11, 2019, 9:04 p.m. UTC
  This patch is mainly to show the idea and to get feedback.
Probably there might be a better implementation.

This patch introduce tunable to makes heap allocator friendly
to LibOS.
It allows a way for the LibOS to adjust allocation size.
LibOS may have its own virtual address space layout (duto software
or hardware e.g. SGX) and as a result, it may have the limited heap.
If heap allocator tries to allocate too large memory, ENOMEM on
startup.

Signed-off-by: Isaku Yamahata <isaku.yamahata@gmail.com>
---
 elf/dl-tunables.list |  5 +++++
 malloc/arena.c       | 17 +++++++----------
 malloc/malloc.c      | 25 +++++++++++++++++++++++++
 malloc/malloc.h      |  1 +
 4 files changed, 38 insertions(+), 10 deletions(-)
  

Comments

Isaku Yamahata Sept. 12, 2019, 6:43 p.m. UTC | #1
Thanks for feedback.


On Wed, Sep 11, 2019 at 09:03:59PM -0400,
DJ Delorie <dj@redhat.com> wrote:

> 
> I have no fundamental problem with tuning the heap size, but...
> 
> 1. The heap size must always be a power of two; you need to enforce that
>    in the tunable callback.

sure.


> 2. Do you have any benchmarks that show that these changes don't affect
>    performance?  I don't mean differing size heaps, I mean changing a
>    constant to a variable in the code.

So far not yet. let me try bench-malloc-simple.c  bench-malloc-thread.c


> 3. I don't see the point of heap_max_specified.

ok. Let me fix it with the next spin.
  

Patch

diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 525c3767b5..31aaecd8bd 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -64,6 +64,11 @@  glibc {
       env_alias: MALLOC_MMAP_MAX_
       security_level: SXID_IGNORE
     }
+    heap_max {
+      type: INT_32
+      env_alias: MALLOC_HEAP_MAX_
+      security_level: SXID_IGNORE
+    }
     arena_max {
       type: SIZE_T
       env_alias: MALLOC_ARENA_MAX
diff --git a/malloc/arena.c b/malloc/arena.c
index a32eb403ec..acd03c53eb 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -26,14 +26,7 @@ 
 
 /* Compile-time constants.  */
 
-#define HEAP_MIN_SIZE (32 * 1024)
-#ifndef HEAP_MAX_SIZE
-# ifdef DEFAULT_MMAP_THRESHOLD_MAX
-#  define HEAP_MAX_SIZE (2 * DEFAULT_MMAP_THRESHOLD_MAX)
-# else
-#  define HEAP_MAX_SIZE (1024 * 1024) /* must be a power of two */
-# endif
-#endif
+#define HEAP_MAX_SIZE	(mp_.heap_max)
 
 /* HEAP_MIN_SIZE and HEAP_MAX_SIZE limit the size of mmap()ed heaps
    that are dynamically created for multi-threaded programs.  The
@@ -226,6 +219,7 @@  TUNABLE_CALLBACK (__name) (tunable_val_t *valp)				      \
 
 TUNABLE_CALLBACK_FNDECL (set_mmap_threshold, size_t)
 TUNABLE_CALLBACK_FNDECL (set_mmaps_max, int32_t)
+TUNABLE_CALLBACK_FNDECL (set_heap_max, int32_t)
 TUNABLE_CALLBACK_FNDECL (set_top_pad, size_t)
 TUNABLE_CALLBACK_FNDECL (set_perturb_byte, int32_t)
 TUNABLE_CALLBACK_FNDECL (set_trim_threshold, size_t)
@@ -316,6 +310,7 @@  ptmalloc_init (void)
   TUNABLE_GET (mmap_threshold, size_t, TUNABLE_CALLBACK (set_mmap_threshold));
   TUNABLE_GET (trim_threshold, size_t, TUNABLE_CALLBACK (set_trim_threshold));
   TUNABLE_GET (mmap_max, int32_t, TUNABLE_CALLBACK (set_mmaps_max));
+  TUNABLE_GET (heap_max, int32_t, TUNABLE_CALLBACK (set_heap_max));
   TUNABLE_GET (arena_max, size_t, TUNABLE_CALLBACK (set_arena_max));
   TUNABLE_GET (arena_test, size_t, TUNABLE_CALLBACK (set_arena_test));
 # if USE_TCACHE
@@ -365,6 +360,8 @@  ptmalloc_init (void)
                     __libc_mallopt (M_MMAP_MAX, atoi (&envline[10]));
                   else if (memcmp (envline, "ARENA_MAX", 9) == 0)
                     __libc_mallopt (M_ARENA_MAX, atoi (&envline[10]));
+                  else if (memcmp (envline, "HEAP_MAX_", 9) == 0)
+                    __libc_mallopt (M_HEAP_MAX, atoi (&envline[10]));
                 }
               break;
             case 10:
@@ -472,7 +469,7 @@  new_heap (size_t size, size_t top_pad)
      mapping (on Linux, this is the case for all non-writable mappings
      anyway). */
   p2 = MAP_FAILED;
-  if (aligned_heap_area)
+  if (aligned_heap_area && !mp_.heap_max_specified)
     {
       p2 = (char *) MMAP (aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,
                           MAP_NORESERVE);
@@ -493,7 +490,7 @@  new_heap (size_t size, size_t top_pad)
           ul = p2 - p1;
           if (ul)
             __munmap (p1, ul);
-          else
+          else if (!mp_.heap_max_specified)
             aligned_heap_area = p2 + HEAP_MAX_SIZE;
           __munmap (p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);
         }
diff --git a/malloc/malloc.c b/malloc/malloc.c
index fe973770a6..f776bb2452 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -981,6 +981,13 @@  int      __posix_memalign(void **, size_t, size_t);
 #define DEFAULT_MMAP_MAX       (65536)
 #endif
 
+#ifdef HEAP_MAX_SIZE
+# define DEFAULT_HEAP_MAX_SIZE	(2 * DEFAULT_MMAP_THREASHOLD_MAX)
+#else
+# define DEFAULT_HEAP_MAX_SIZE	(1024 * 1024)	/* must be power of two */
+#endif
+#define HEAP_MIN_SIZE		(32 * 1024)
+
 #include <malloc.h>
 
 #ifndef RETURN_ADDRESS
@@ -1713,6 +1720,8 @@  struct malloc_par
      it manually, at which point we need to disable any
      dynamic behavior. */
   int no_dyn_threshold;
+  int heap_max;
+  int heap_max_specified;
 
   /* Statistics */
   INTERNAL_SIZE_T mmapped_mem;
@@ -1766,6 +1775,8 @@  static struct malloc_par mp_ =
   .top_pad = DEFAULT_TOP_PAD,
   .n_mmaps_max = DEFAULT_MMAP_MAX,
   .mmap_threshold = DEFAULT_MMAP_THRESHOLD,
+  .heap_max = DEFAULT_HEAP_MAX_SIZE,
+  .heap_max_specified = 0,
   .trim_threshold = DEFAULT_TRIM_THRESHOLD,
 #define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))
   .arena_test = NARENAS_FROM_NCORES (1)
@@ -5052,6 +5063,16 @@  do_set_mmaps_max (int32_t value)
   return 1;
 }
 
+static __always_inline int
+do_set_heap_max (int32_t value)
+{
+  LIBC_PROBE (memory_mallopt_heap_max, 3, value, mp_.heap_max,
+	      mp_.no_dyn_threshold);
+  mp_.heap_max = value;
+  mp_.heap_max_specified = 1;
+  return 1;
+}
+
 static __always_inline int
 do_set_mallopt_check (int32_t value)
 {
@@ -5166,6 +5187,10 @@  __libc_mallopt (int param_number, int value)
       do_set_mmaps_max (value);
       break;
 
+    case M_HEAP_MAX:
+      do_set_heap_max (value);
+      break;
+
     case M_CHECK_ACTION:
       do_set_mallopt_check (value);
       break;
diff --git a/malloc/malloc.h b/malloc/malloc.h
index 70d8282bdc..30b93281aa 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -124,6 +124,7 @@  extern struct mallinfo mallinfo (void) __THROW;
 #define M_PERTURB           -6
 #define M_ARENA_TEST        -7
 #define M_ARENA_MAX         -8
+#define M_HEAP_MAX          -9
 
 /* General SVID/XPG interface to tunable parameters. */
 extern int mallopt (int __param, int __val) __THROW;