Skip to content

Commit eb5c75e

Browse files
committed
Add an option to reduce pagefault when available
In Linux, `MAP_POPULATE` can populate page tables and pagefault in advance. This should improve some performance.
1 parent 076f815 commit eb5c75e

File tree

4 files changed

+15
-0
lines changed

4 files changed

+15
-0
lines changed

include/mimalloc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ typedef enum mi_option_e {
311311
mi_option_page_reset,
312312
mi_option_abandoned_page_reset,
313313
mi_option_segment_reset,
314+
mi_option_prefault,
314315
mi_option_eager_commit_delay,
315316
mi_option_reset_delay,
316317
mi_option_use_numa_nodes,

readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ or via environment variables:
302302
`MIMALLOC_EAGER_COMMIT_DELAY=N` (`N` is 1 by default) to delay the initial `N` segments (of 4MiB)
303303
of a thread to not allocate in the huge OS pages; this prevents threads that are short lived
304304
and allocate just a little to take up space in the huge OS page area (which cannot be reset).
305+
- `MIMALLOC_PREFAULT=1`: (Linux only) enable memory prefaulting when available. This option instructs the kernel to synchronously
306+
load the entire mapped region into active memory by specifying `MAP_POPULATE` in `mmap`. It will cause read-ahead on that memory,
307+
and then the subsequent accesses to the memory can proceed without page faults, improving some performance, but might also reduce
308+
some available memory. In `mimalloc_test_stress`, it is known to reduce about 95% page-faults.
305309

306310
Use caution when using `fork` in combination with either large or huge OS pages: on a fork, the OS uses copy-on-write
307311
for all pages in the original process including the huge OS pages. When any memory is now written in that area, the

src/options.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ static mi_option_desc_t options[_mi_option_last] =
8181
{ 1, UNINIT, MI_OPTION(page_reset) }, // reset page memory on free
8282
{ 0, UNINIT, MI_OPTION(abandoned_page_reset) },// reset free page memory when a thread terminates
8383
{ 0, UNINIT, MI_OPTION(segment_reset) }, // reset segment memory on free (needs eager commit)
84+
#if defined(__linux__)
85+
{ 0, UNINIT, MI_OPTION(prefault) },
86+
#endif
8487
#if defined(__NetBSD__)
8588
{ 0, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed
8689
#else

src/os.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
362362
#define MAP_NORESERVE 0
363363
#endif
364364
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
365+
#if defined(__linux__)
366+
if (mi_option_get(mi_option_prefault))
367+
flags = flags | MAP_POPULATE;
368+
#endif
365369
int fd = -1;
366370
#if defined(MAP_ALIGNED) // BSD
367371
if (try_alignment > 0) {
@@ -392,6 +396,9 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
392396
}
393397
else {
394398
int lflags = flags & ~MAP_NORESERVE; // using NORESERVE on huge pages seems to fail on Linux
399+
#if defined(__linux__)
400+
lflags = lflags & ~MAP_POPULATE; // don't use MAP_POPULATE on huge pages
401+
#endif
395402
int lfd = fd;
396403
#ifdef MAP_ALIGNED_SUPER
397404
lflags |= MAP_ALIGNED_SUPER;

0 commit comments

Comments
 (0)