Skip to content

Commit 2b4b669

Browse files
committed
Add an option to reduce pagefault when available
In Linux, This option instructs the kernel to synchronously load the entire mapped region into active memory by specifying `MAP_POPULATE` in `mmap`. It will cause read-ahead on that memory, and then the subsequent accesses to the memory can proceed without page faults, improving some performance.
1 parent 076f815 commit 2b4b669

File tree

4 files changed

+17
-0
lines changed

4 files changed

+17
-0
lines changed

include/mimalloc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ typedef enum mi_option_e {
311311
mi_option_page_reset,
312312
mi_option_abandoned_page_reset,
313313
mi_option_segment_reset,
314+
#if defined(__linux__)
315+
mi_option_prefault,
316+
#endif
314317
mi_option_eager_commit_delay,
315318
mi_option_reset_delay,
316319
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)