From: Adhemerval Zanella Date: Thu, 21 May 2026 16:55:41 +0000 (-0300) Subject: support: Skip malloc hugetlb={1,2} variants when kernel cannot honor them X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=b20b94006c79d65d75e5bd3a8d14fbcf9cd5bee6;p=thirdparty%2Fglibc.git support: Skip malloc hugetlb={1,2} variants when kernel cannot honor them The malloc test variants run with GLIBC_TUNABLES=glibc.malloc.hugetlb=1 exercise transparent huge pages via MADV_HUGEPAGE, which is only meaningful when /sys/kernel/mm/transparent_hugepage/enabled is set to 'madvise' ('always' makes the madvise redundant and 'never' makes it ineffective). The hugetlb=2 variants rely on MAP_HUGETLB, which requires a positive /proc/sys/vm/nr_hugepages. On systems that do not satisfy these prerequisites - including any non-Linux target - those runs only consume CPU time in this case. Add support/support_check_hugetlb.{c,h} exposing: - support_thp_is_madvise: true iff THP is in 'madvise' mode; - support_hugepages_reserved: true iff nr_hugepages > 0; - support_check_malloc_hugetlb: inspects GLIBC_TUNABLES and calls FAIL_UNSUPPORTED when the requested hugetlb mode cannot be honored. Gate the check at compile time so only the variant binaries pay for it. Reviewed-by: DJ Delorie --- diff --git a/Rules b/Rules index 64a337b265..385246f07d 100644 --- a/Rules +++ b/Rules @@ -288,7 +288,8 @@ $(addprefix $(objpfx),$(binaries-malloc-check-tests)): %-malloc-check: %.o \ endif ifneq "$(strip $(binaries-malloc-hugetlb1-tests))" "" -$(addprefix $(objpfx),$(binaries-malloc-hugetlb1-tests)): %-malloc-hugetlb1: %.o \ +$(addprefix $(objpfx),$(binaries-malloc-hugetlb1-tests)): \ +%-malloc-hugetlb1: %-malloc-hugetlb1.o \ $(link-extra-libs-tests) \ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) @@ -296,7 +297,8 @@ $(addprefix $(objpfx),$(binaries-malloc-hugetlb1-tests)): %-malloc-hugetlb1: %.o endif ifneq "$(strip $(binaries-malloc-hugetlb2-tests))" "" -$(addprefix $(objpfx),$(binaries-malloc-hugetlb2-tests)): %-malloc-hugetlb2: %.o \ +$(addprefix $(objpfx),$(binaries-malloc-hugetlb2-tests)): \ +%-malloc-hugetlb2: %-malloc-hugetlb2.o \ $(link-extra-libs-tests) \ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) diff --git a/malloc/Makefile b/malloc/Makefile index f95bca7f8f..72aa77af20 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -351,6 +351,19 @@ $(objpfx)%-threaded-worker.o: CPPFLAGS += -DTEST_IN_THREAD=TEST_THREAD_WORKER $(objpfx)%-threaded-worker.o: %.c $(before-compile) $(compile-command.c) +# Compile the hugetlb={1,2} test variants from their base sources with +# -DTEST_HUGETLB so support/test-driver.c gates them on kernel support. +$(foreach t,$(tests-malloc-hugetlb1),\ + $(eval libof-$(t)-malloc-hugetlb1 := testsuite)) +$(foreach t,$(tests-malloc-hugetlb2),\ + $(eval libof-$(t)-malloc-hugetlb2 := testsuite)) +$(objpfx)%-malloc-hugetlb1.o: CPPFLAGS += -DTEST_HUGETLB +$(objpfx)%-malloc-hugetlb1.o: %.c $(before-compile) + $(compile-command.c) +$(objpfx)%-malloc-hugetlb2.o: CPPFLAGS += -DTEST_HUGETLB +$(objpfx)%-malloc-hugetlb2.o: %.c $(before-compile) + $(compile-command.c) + # Include the cleanup handler. aux := set-freeres thread-freeres diff --git a/support/Makefile b/support/Makefile index 3f19a98bdc..87eeb8199f 100644 --- a/support/Makefile +++ b/support/Makefile @@ -55,6 +55,7 @@ libsupport-routines = \ support_can_chroot \ support_capture_subprocess \ support_capture_subprocess_check \ + support_check_hugetlb \ support_check_nss \ support_check_stat_fd \ support_check_stat_path \ diff --git a/support/support_check_hugetlb.c b/support/support_check_hugetlb.c new file mode 100644 index 0000000000..be7e10e80d --- /dev/null +++ b/support/support_check_hugetlb.c @@ -0,0 +1,79 @@ +/* Runtime detection of huge-page support for malloc tests. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +bool +support_thp_is_madvise (void) +{ + int fd = open ("/sys/kernel/mm/transparent_hugepage/enabled", O_RDONLY); + if (fd == -1) + return false; + +#define MODE_MADVISE "always [madvise] never\n" + + char str[sizeof(MODE_MADVISE)]; + ssize_t s = read (fd, str, sizeof (str)); + close (fd); + if (s != sizeof (str) - 1) + return false; + str[s] = '\0'; + return strcmp (str, MODE_MADVISE) == 0; +} + +bool +support_hugepages_reserved (void) +{ + int fd = open ("/proc/sys/vm/nr_hugepages", O_RDONLY); + if (fd == -1) + return false; + + char str[INT_BUFSIZE_BOUND(unsigned long int)]; + ssize_t s = read (fd, str, sizeof (str)); + close (fd); + if (s >= sizeof str || s < 0) + return false; + str[s] = '\0'; + unsigned long int n = 0; + return sscanf (str, "%lu", &n) == 1 && n > 0; +} + +void +support_check_malloc_hugetlb (void) +{ + if (!TUNABLE_IS_INITIALIZED (glibc, malloc, hugetlb)) + return; + + size_t hugetlb = TUNABLE_GET_FULL (glibc, malloc, hugetlb, size_t, NULL); + if (hugetlb == 1 && !support_thp_is_madvise ()) + FAIL_UNSUPPORTED ("glibc.malloc.hugetlb=1 requires" + " /sys/kernel/mm/transparent_hugepage/enabled" + " = madvise"); + if (hugetlb == 2 && !support_hugepages_reserved ()) + FAIL_UNSUPPORTED ("glibc.malloc.hugetlb=2 requires" + " /proc/sys/vm/nr_hugepages > 0"); +} diff --git a/support/support_check_hugetlb.h b/support/support_check_hugetlb.h new file mode 100644 index 0000000000..2c5f5cb80c --- /dev/null +++ b/support/support_check_hugetlb.h @@ -0,0 +1,48 @@ +/* Runtime detection of huge-page support for malloc tests. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_SUPPORT_CHECK_HUGETLB_H +#define SUPPORT_SUPPORT_CHECK_HUGETLB_H + +#include +#include + +__BEGIN_DECLS + +/* Returns true if /sys/kernel/mm/transparent_hugepage/enabled selects + `madvise' as the active mode (i.e. MADV_HUGEPAGE is honored, but + THP is not applied automatically). Returns false on any other + configuration, on read failure, or on non-Linux systems. */ +bool support_thp_is_madvise (void); + +/* Returns true if /proc/sys/vm/nr_hugepages reports a strictly + positive number of pre-allocated huge pages (the prerequisite for + MAP_HUGETLB allocations). Returns false on read failure or on + non-Linux systems. */ +bool support_hugepages_reserved (void); + +/* If the current process is running with GLIBC_TUNABLES requesting + glibc.malloc.hugetlb=1 or glibc.malloc.hugetlb=2, verifies that the + kernel can actually satisfy the requested mode. If not, terminates + the test with EXIT_UNSUPPORTED. No-op when no such tunable is set, + so it is safe to call unconditionally. */ +void support_check_malloc_hugetlb (void); + +__END_DECLS + +#endif /* SUPPORT_SUPPORT_CHECK_HUGETLB_H */ diff --git a/support/test-driver.c b/support/test-driver.c index 1455584667..a72c41e64c 100644 --- a/support/test-driver.c +++ b/support/test-driver.c @@ -103,9 +103,19 @@ #include +#ifdef TEST_HUGETLB +# include +#endif + int main (int argc, char **argv) { +#ifdef TEST_HUGETLB + /* For malloc hugetlb=1/=2 test variants: skip the test (UNSUPPORTED) + when the kernel cannot honor the requested mode. */ + support_check_malloc_hugetlb (); +#endif + struct test_config test_config; memset (&test_config, 0, sizeof (test_config));