[PATCH] hugepages: cache THP mode and page size [BZ #34083]
Shamil Abdulaev
ashamil435@gmail.com
Fri May 1 20:59:25 GMT 2026
__get_thp_mode and __get_thp_size read /sys files and are used by
both the dynamic linker and malloc. Cache their results in rtld_global
so the expensive THP probes are performed once per process.
Tested on x86_64-linux-gnu. No new test failures.
Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com>
---
elf/dl-support.c | 6 +++
sysdeps/generic/hugepages.h | 7 ++++
sysdeps/generic/ldsodefs.h | 6 +++
sysdeps/unix/sysv/linux/hugepages.c | 58 ++++++++++++++++++++++++-----
4 files changed, 68 insertions(+), 9 deletions(-)
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 0508d6113b..ec77cb3e7a 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -144,6 +144,12 @@ int _dl_inhibit_cache;
/* All known directories in sorted order. */
struct r_search_path_elem *_dl_all_dirs;
+/* Cached Transparent Huge Page mode and page size. */
+int _dl_thp_mode;
+unsigned long int _dl_thp_pagesize;
+int _dl_thp_mode_state;
+int _dl_thp_pagesize_state;
+
/* All directories after startup. */
struct r_search_path_elem *_dl_init_all_dirs;
diff --git a/sysdeps/generic/hugepages.h b/sysdeps/generic/hugepages.h
index 5fc9b5c8de..68be2ee242 100644
--- a/sysdeps/generic/hugepages.h
+++ b/sysdeps/generic/hugepages.h
@@ -32,6 +32,13 @@ enum thp_mode_t
thp_mode_not_supported
};
+enum thp_cache_state_t
+{
+ thp_cache_uninitialized,
+ thp_cache_initializing,
+ thp_cache_initialized
+};
+
enum thp_mode_t __get_thp_mode (void) attribute_hidden;
/* Return the supported huge page size from the REQUESTED sizes on PAGESIZE
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 15c4659853..4b2e337a81 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -395,6 +395,12 @@ struct rtld_global
/* List of search directories. */
EXTERN struct r_search_path_elem *_dl_all_dirs;
+ /* Cached Transparent Huge Page mode and page size. */
+ EXTERN int _dl_thp_mode;
+ EXTERN unsigned long int _dl_thp_pagesize;
+ EXTERN int _dl_thp_mode_state;
+ EXTERN int _dl_thp_pagesize_state;
+
/* Get architecture specific definitions. */
#define PROCINFO_DECL
#ifndef PROCINFO_CLASS
diff --git a/sysdeps/unix/sysv/linux/hugepages.c b/sysdeps/unix/sysv/linux/hugepages.c
index 46e05151a3..c32127f6a4 100644
--- a/sysdeps/unix/sysv/linux/hugepages.c
+++ b/sysdeps/unix/sysv/linux/hugepages.c
@@ -16,6 +16,8 @@
License along with the GNU C Library; see the file COPYING.LIB. If
not, see <https://www.gnu.org/licenses/>. */
+#include <atomic.h>
+#include <ldsodefs.h>
#include <intprops.h>
#include <dirent.h>
#include <hugepages.h>
@@ -25,18 +27,32 @@
unsigned long int
__get_thp_size (void)
{
+ if (atomic_load_acquire (&GL (dl_thp_pagesize_state))
+ == thp_cache_initialized)
+ return GL (dl_thp_pagesize);
+
+ int state = thp_cache_uninitialized;
+ if (!atomic_compare_exchange_acquire (&GL (dl_thp_pagesize_state),
+ &state, thp_cache_initializing))
+ {
+ while (atomic_load_acquire (&GL (dl_thp_pagesize_state))
+ != thp_cache_initialized)
+ atomic_spin_nop ();
+ return GL (dl_thp_pagesize);
+ }
+
+ unsigned long int r = 0;
int fd = __open64_nocancel (
"/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", O_RDONLY);
if (fd == -1)
- return 0;
+ goto out;
char str[INT_BUFSIZE_BOUND (unsigned long int)];
ssize_t s = __read_nocancel (fd, str, sizeof (str));
__close_nocancel (fd);
if (s < 0)
- return 0;
+ goto out;
- unsigned long int r = 0;
for (ssize_t i = 0; i < s; i++)
{
if (str[i] == '\n')
@@ -44,16 +60,36 @@ __get_thp_size (void)
r *= 10;
r += str[i] - '0';
}
+
+out:
+ GL (dl_thp_pagesize) = r;
+ atomic_store_release (&GL (dl_thp_pagesize_state),
+ thp_cache_initialized);
return r;
}
enum thp_mode_t
__get_thp_mode (void)
{
+ if (atomic_load_acquire (&GL (dl_thp_mode_state))
+ == thp_cache_initialized)
+ return (enum thp_mode_t) GL (dl_thp_mode);
+
+ int state = thp_cache_uninitialized;
+ if (!atomic_compare_exchange_acquire (&GL (dl_thp_mode_state),
+ &state, thp_cache_initializing))
+ {
+ while (atomic_load_acquire (&GL (dl_thp_mode_state))
+ != thp_cache_initialized)
+ atomic_spin_nop ();
+ return (enum thp_mode_t) GL (dl_thp_mode);
+ }
+
+ enum thp_mode_t mode = thp_mode_not_supported;
int fd = __open64_nocancel ("/sys/kernel/mm/transparent_hugepage/enabled",
O_RDONLY);
if (fd == -1)
- return thp_mode_not_supported;
+ goto out;
static const char mode_always[] = "[always] madvise never\n";
static const char mode_madvise[] = "always [madvise] never\n";
@@ -63,19 +99,23 @@ __get_thp_mode (void)
ssize_t s = __read_nocancel (fd, str, sizeof (str));
__close_nocancel (fd);
if (s >= sizeof str || s < 0)
- return thp_mode_not_supported;
+ goto out;
str[s] = '\0';
if (s == sizeof (mode_always) - 1)
{
if (strcmp (str, mode_always) == 0)
- return thp_mode_always;
+ mode = thp_mode_always;
else if (strcmp (str, mode_madvise) == 0)
- return thp_mode_madvise;
+ mode = thp_mode_madvise;
else if (strcmp (str, mode_never) == 0)
- return thp_mode_never;
+ mode = thp_mode_never;
}
- return thp_mode_not_supported;
+
+out:
+ GL (dl_thp_mode) = mode;
+ atomic_store_release (&GL (dl_thp_mode_state), thp_cache_initialized);
+ return mode;
}
#if !IS_IN (rtld)
--
2.54.0
More information about the Libc-alpha
mailing list