[PATCH 2/2] LoongArch64: Align large code segments to 32MB for THP
WANG Rui
wangrui@loongson.cn
Tue Feb 24 07:48:29 GMT 2026
On LoongArch64, using 16K normal pages means the PMD huge page size is
32M. Mapping code segments that are 32M or larger to 32M-aligned address
helps make them eligible for THP.
This patch changes the segment mapping logic for segments with a zero
vaddr and a zero offset. When running on LP64 with a 16K page size, if
an executable segment's size is greater than or equal to 32M, we
explicitly set its alignment to 32M. This optimization improves TLB
usage and execution performance for large objects.
* sysdeps/unix/sysv/linux/loongarch/dl-map-segments.h
(_dl_map_segment): Align large executable segments to 32MB when
using 16K pages on LP64.
Signed-off-by: WANG Rui <wangrui@loongson.cn>
---
.../sysv/linux/loongarch/dl-map-segments.h | 25 ++++++++++++++-----
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/loongarch/dl-map-segments.h b/sysdeps/unix/sysv/linux/loongarch/dl-map-segments.h
index 139004ae2f..913c44c996 100644
--- a/sysdeps/unix/sysv/linux/loongarch/dl-map-segments.h
+++ b/sysdeps/unix/sysv/linux/loongarch/dl-map-segments.h
@@ -1,4 +1,4 @@
-/* Map in a shared object's segments. Generic version.
+/* Map in a shared object's segments. LoongArch version.
Copyright (C) 1995-2026 Free Software Foundation, Inc.
Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
@@ -26,15 +26,28 @@ static __always_inline ElfW(Addr)
_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
const size_t maplength, int fd)
{
- if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize)))
+ ElfW(Addr) mapalign = c->mapalign;
+
+#ifdef __LP64__
+ /* On LoongArch64, using 16K normal pages means we get 32M PMD huge
+ * pages. So, if we align code segments of 32M or more to 32M address,
+ * it really helps with THP eligibility. */
+ if (__glibc_likely (GLRO(dl_pagesize) == 16384)
+ && c->mapstart == 0 && c->mapoff == 0
+ && (c->mapend - c->mapstart) >= 32 * 1024 * 1024
+ && mapalign < 32 * 1024 * 1024 && c->prot & PROT_EXEC)
+ mapalign = 32 * 1024 * 1024;
+#endif
+
+ if (__glibc_likely (mapalign <= GLRO(dl_pagesize)))
return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot,
MAP_COPY|MAP_FILE, fd, c->mapoff);
/* If the segment alignment > the page size, allocate enough space to
ensure that the segment can be properly aligned. */
- ElfW(Addr) maplen = (maplength >= c->mapalign
- ? (maplength + c->mapalign)
- : (2 * c->mapalign));
+ ElfW(Addr) maplen = (maplength >= mapalign
+ ? (maplength + mapalign)
+ : (2 * mapalign));
ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen,
PROT_NONE,
MAP_ANONYMOUS|MAP_COPY,
@@ -42,7 +55,7 @@ _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
if (__glibc_unlikely ((void *) map_start == MAP_FAILED))
return map_start;
- ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign);
+ ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, mapalign);
map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned,
maplength, c->prot,
MAP_COPY|MAP_FILE|MAP_FIXED,
--
2.53.0
More information about the Libc-alpha
mailing list