You can preload a library that remaps all executable mappings to huge pages like this:
- Call the remapping function from the constructor of your preload library, since at that point all other libraries and the executable is already loaded and thus mapped.
- Iterate over all
r-xp
mappings in /proc/self/smaps
.
- Ignore the mapping of your preload library.
- Make sure that you don't call any function from a library that is being re-mapped from you core remapping code. For example, this could even exclude libc functions.
- For each mapping, select a sub-range that is huge-page size aligned. NB: The end address can be aligned-up if there is a gap to the next mapping.
- Copy that range to a temporary mapping
- Re-map that sub-range using hugepages (e.g. via
mmap(..., PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_FIXED |MAP_HUGETLB | MAP_HUGE_2MB, ...)
)
- Copy the saved range back
- unmap the temporary range
- Remove write permission of the re-mapped range via
mprotect(..., PROT_READ | PROT_EXEC)
All this can be accomplished in 500 lines of code or so.
Intel's iodlr project includes a preload library that works similar to the above approach.
Example usage:
LD_PRELOAD=/path/to/liblppreload.so IODLR_USE_EXPLICIT_HP=1 /path/to/your/executable
In contrast to the above approach iodlr iterates over ELF headers, thus, in some cases the first and last pages may end up not being remapped.
On Linux, code mappings aren't aligned to - say - 2 MiB hugepage sizes, by default.
Thus, with the above remapping schemes you may end up with a head and tail of each mapping that isn't remapped. Also, a code mapping that is only somewhat larger than 2 MiB may very well not being remapped due to its non-alignment.
However, since the applications where this optimization is feasible usually have much larger code mappings, such a scheme is likely good enough, as is.
However, one can also relink the executable and some libraries with -Wl,-zcommon-page-size=2097152 -Wl,-zmax-page-size=2097152
such that code mappings can be completely remapped. (as of 2023, this isn't recommended for iodlr, though, as it can even lead to effectively less code being remapped)