[PATCH v2] malloc: Don't call __get_thp_mode/__get_thp_size twice

H.J. Lu hjl.tools@gmail.com
Tue Jun 23 04:59:41 GMT 2026


On Tue, Jun 23, 2026 at 12:14 AM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
>
>
> On 22/06/26 10:15, H.J. Lu wrote:
> > This is identical to the first version.   Now it can be applied
> > to master branch since its prerequisite has been merged into
> > master branch.
> >
> > From ad568336b63148195af93cf7bd4adf6efa282deb Mon Sep 17 00:00:00 2001
> > From: "H.J. Lu" <hjl.tools@gmail.com>
> > Date: Sat, 18 Apr 2026 11:36:41 +0800
> > Subject: [PATCH v2] malloc: Don't call __get_thp_mode/__get_thp_size twice
> >
> > Both ld.so and malloc track kernel THP mode and THP page size when THP
> > in ld.so is enabled by
> >
> > GLIBC_TUNABLES=glibc.elf.thp=1
> >
> > and THP in malloc is enabled by
> >
> > GLIBC_TUNABLES=glibc.malloc.hugetlb=1
> >
> > But DL_MAP_DEFAULT_THP_PAGESIZE and MALLOC_DEFAULT_THP_PAGESIZE may be
> > different when they are defined in <hugepages.h>.
> >
> > If THP in ld.so is enabled, change malloc to use kernel THP mode from
> > ld.so, instead of calling __get_thp_mode, and use THP page size from
> > ld.so if it came from __get_thp_size.  This avoids calling __get_thp_mode
> > and __get_thp_size again, which are quite expensive:
> >
> > 1. Initialize mp_.thp_mode and GL(dl_thp_mode) to thp_mode_unknown.
> > 2. Set mp_.thp_mode to GL(dl_thp_mode) if GL(dl_thp_mode) isn't
> > thp_mode_unknown.  Otherwise call __get_thp_mode to set mp_.thp_mode.
> > 3. GL(dl_elf_thp_pagesize) is set to DL_MAP_DEFAULT_THP_PAGESIZE without
> > calling __get_thp_size and THP page size for malloc may be different from
> > THP page size for ld.so.  Set mp_.thp_pagesize to GL(dl_elf_thp_pagesize)
> > if DL_MAP_DEFAULT_THP_PAGESIZE is defined.  Otherwise call __get_thp_size
> > to set mp_.thp_pagesize.
> >
> > This fixes BZ #34083.
> >
> > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
>
> Looks good, some comments below.  I think Andreas will need to ack it now that
> we are in soft-freeze.
>
> > ---
> >  malloc/malloc.c             | 56 +++++++++++++++++++++++++++++++++----
> >  sysdeps/generic/hugepages.h |  3 +-
> >  2 files changed, 53 insertions(+), 6 deletions(-)
> >
> > diff --git a/malloc/malloc.c b/malloc/malloc.c
> > index a354576aca..f0ed95213f 100644
> > --- a/malloc/malloc.c
> > +++ b/malloc/malloc.c
> > @@ -1529,7 +1529,7 @@ static struct malloc_par mp_ =
> >    .mmap_threshold = DEFAULT_MMAP_THRESHOLD,
> >    .trim_threshold = DEFAULT_TRIM_THRESHOLD,
> >    .arena_test = sizeof (long) == 4 ? 2 : 8,
> > -  .thp_mode = thp_mode_not_supported
> > +  .thp_mode = thp_mode_unknown
> >  #if USE_TCACHE
> >    ,
> >    .tcache_count = TCACHE_FILL_COUNT,
> > @@ -4657,13 +4657,41 @@ do_set_mxfast (size_t value)
> >    return 1;
> >  }
> >
> > +#ifdef HAVE_THP
> > +static __always_inline enum thp_mode_t
> > +get_dl_thp_mode (void)
> > +{
> > +  return GL(dl_thp_mode);
> > +}
> > +
> > +static __always_inline unsigned long int
> > +get_dl_elf_thp_pagesize (void)
> > +{
> > +  return GL(dl_elf_thp_pagesize);
> > +}
> > +#else
> > +# define get_dl_thp_mode()           __get_thp_mode ()
> > +# define get_dl_elf_thp_pagesize()   __get_thp_size ()
> > +#endif
> > +
> >  static __always_inline int
> >  do_set_hugetlb (size_t value)
> >  {
> > +  /* If __get_thp_mode and __get_thp_size have been called during
> > +     startup, don't call them again here.  */
> > +  enum thp_mode_t thp_mode = get_dl_thp_mode ();
> > +
> >    /* Enable THP if MALLOC_DEFAULT_THP_PAGESIZE is non-zero.  */
> >    if (MALLOC_DEFAULT_THP_PAGESIZE > 0)
> >      {
> > -      mp_.thp_mode = thp_mode_madvise;
> > +      /* If thp_mode is unknown, THP segment load is disabled by
> > +      GLIBC_TUNABLES=glibc.elf.thp=0.  In this case, set
> > +      mp_.thp_mode to madvise.  Otherwise, set it to thp_mode to
> > +      keep mp_.thp_mode in sync with GL(dl_thp_mode).  */
> > +      if (thp_mode == thp_mode_unknown)
> > +     mp_.thp_mode = thp_mode_madvise;
> > +      else
> > +     mp_.thp_mode = thp_mode;
> >        mp_.thp_pagesize = MALLOC_DEFAULT_THP_PAGESIZE;
> >      }
> >
>
> When glibc.elf.thp=1, it now mirrors the real kernel mode instead of defaulting
> to thp_mode_madvise. The madvise_thp will then stops issuing MADV_HUGEPAGE, which
> I think benign/beneficial (kernel already covers always; never madvise was wasteful).
>
> But it means glibc.malloc.hugetlb behavior on aarch64 now depends on glibc.elf.thp;
> two previously independent tunables. The default is unchanged:
>
>   elf.thp unset -> disabled -> unknown -> old forced-madvise
>
> So it only matters when the tunable is set. Maybe add a note in the manual/NEWS
> about this change.

Done in the v3 patch.

> > @@ -4680,9 +4708,27 @@ do_set_hugetlb (size_t value)
> >        if (MALLOC_DEFAULT_THP_PAGESIZE > 0)
> >       return 0;
> >
> > -      mp_.thp_mode = __get_thp_mode ();
> > -      if (mp_.thp_mode == thp_mode_madvise || mp_.thp_mode == thp_mode_always)
> > -     mp_.thp_pagesize = __get_thp_size ();
> > +      if (thp_mode == thp_mode_unknown)
> > +     {
> > +       /* Call __get_thp_mode and __get_thp_size when THP segment load
> > +          is disabled.  */
> > +       mp_.thp_mode = __get_thp_mode ();
> > +       if (mp_.thp_mode == thp_mode_madvise
> > +           || mp_.thp_mode == thp_mode_always)
> > +         mp_.thp_pagesize = __get_thp_size ();
> > +     }
> > +      else
> > +     {
> > +       /* THP segment load is enabled.  GL(dl_elf_thp_pagesize) is
> > +          set to DL_MAP_DEFAULT_THP_PAGESIZE if it isn't zero .  In
>
> Stray space after 'zero'.

Removed.

> > +          this case, call __get_thp_size () instead of using
> > +          DL_MAP_DEFAULT_THP_PAGESIZE for malloc.  */
> > +       mp_.thp_mode = thp_mode;
> > +       if (DL_MAP_DEFAULT_THP_PAGESIZE != 0)
> > +         mp_.thp_pagesize = __get_thp_size ();
> > +       else
> > +         mp_.thp_pagesize = get_dl_elf_thp_pagesize ();
> > +     }
> >      }
> >    else if (value >= 2)
> >      __get_hugepage_config (value == 2 ? 0 : value, &mp_.hp_pagesize,
>
> When elf.thp=1, malloc uses GL(dl_elf_thp_pagesize), which ld.so caps at
> MAX_THP_PAGESIZE; when elf.thp=0/unset, malloc uses the uncapped __get_thp_size().
>
> I think we should not matter for current supported ABIs, but maybe we should
> consolidate the logic.

Changed in the v3 patch.

> > diff --git a/sysdeps/generic/hugepages.h b/sysdeps/generic/hugepages.h
> > index 8e54661527..49251d94ab 100644
> > --- a/sysdeps/generic/hugepages.h
> > +++ b/sysdeps/generic/hugepages.h
> > @@ -37,7 +37,8 @@ unsigned long int __get_thp_size (void) attribute_hidden;
> >
> >  enum thp_mode_t
> >  {
> > -  thp_mode_not_supported = 0,
> > +  thp_mode_unknown = 0,
> > +  thp_mode_not_supported,
> >    thp_mode_always,
> >    thp_mode_madvise,
> >    thp_mode_never
> > --
> > 2.54.0
> >
>


-- 
H.J.


More information about the Libc-alpha mailing list