summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/users_guide/runtime_control.rst22
-rw-r--r--includes/rts/Flags.h6
-rw-r--r--libraries/base/GHC/RTS/Flags.hsc3
-rw-r--r--rts/RtsFlags.c6
-rw-r--r--rts/posix/OSMem.c50
5 files changed, 74 insertions, 13 deletions
diff --git a/docs/users_guide/runtime_control.rst b/docs/users_guide/runtime_control.rst
index 96b3d8aba3..7ebb9eb207 100644
--- a/docs/users_guide/runtime_control.rst
+++ b/docs/users_guide/runtime_control.rst
@@ -241,6 +241,28 @@ Miscellaneous RTS options
crashes if exception handling are enabled. In order to get more information
in compiled executables, C code or DLLs symbols need to be available.
+.. rts-flag:: --disable-delayed-os-memory-return
+
+ If given, uses ``MADV_DONTNEED`` instead of ``MADV_FREE`` on platforms where
+ this results in more accurate resident memory usage of the program as shown
+ in memory usage reporting tools (e.g. the ``RSS`` column in ``top`` and ``htop``).
+
+ Using this is expected to make the program slightly slower.
+
+ On Linux, MADV_FREE is newer and faster because it can avoid zeroing
+ pages if they are re-used by the process later (see ``man 2 madvise``),
+ but for the trade-off that memory inspection tools like ``top`` will
+ not immediately reflect the freeing in their display of resident memory
+ (RSS column): Only under memory pressure will Linux actually remove
+ the freed pages from the process and update its RSS statistics.
+ Until then, the pages show up as ``LazyFree`` in ``/proc/PID/smaps``
+ (see ``man 5 proc``).
+
+ The delayed RSS update can confuse programmers debugging memory issues,
+ production memory monitoring tools, and end users who may complain about
+ undue memory usage shown in reporting tools, so with this flag it can
+ be turned off.
+
.. rts-flag:: -xp
diff --git a/includes/rts/Flags.h b/includes/rts/Flags.h
index f27ce23b0b..4af19aa953 100644
--- a/includes/rts/Flags.h
+++ b/includes/rts/Flags.h
@@ -213,6 +213,12 @@ typedef struct _MISC_FLAGS {
bool generate_dump_file;
bool generate_stack_trace;
bool machineReadable;
+ bool disableDelayedOsMemoryReturn; /* See Note [MADV_FREE and MADV_DONTNEED].
+ It's in `MiscFlags` instead of
+ `GcFlags` because if GHC used madvise()
+ memory management for non-GC related
+ tasks in the future, we'd respect it
+ there as well. */
bool internalCounters; /* See Note [Internal Counter Stats] */
bool linkerAlwaysPic; /* Assume the object code is always PIC */
StgWord linkerMemBase; /* address to ask the OS for memory
diff --git a/libraries/base/GHC/RTS/Flags.hsc b/libraries/base/GHC/RTS/Flags.hsc
index 913344c166..abff8aa1f9 100644
--- a/libraries/base/GHC/RTS/Flags.hsc
+++ b/libraries/base/GHC/RTS/Flags.hsc
@@ -138,6 +138,7 @@ data MiscFlags = MiscFlags
, generateCrashDumpFile :: Bool
, generateStackTrace :: Bool
, machineReadable :: Bool
+ , disableDelayedOsMemoryReturn :: Bool
, internalCounters :: Bool
, linkerAlwaysPic :: Bool
, linkerMemBase :: Word
@@ -447,6 +448,8 @@ getMiscFlags = do
<*> (toBool <$>
(#{peek MISC_FLAGS, machineReadable} ptr :: IO CBool))
<*> (toBool <$>
+ (#{peek MISC_FLAGS, disableDelayedOsMemoryReturn} ptr :: IO CBool))
+ <*> (toBool <$>
(#{peek MISC_FLAGS, internalCounters} ptr :: IO CBool))
<*> (toBool <$>
(#{peek MISC_FLAGS, linkerAlwaysPic} ptr :: IO CBool))
diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c
index 0e28b980ac..7949d401db 100644
--- a/rts/RtsFlags.c
+++ b/rts/RtsFlags.c
@@ -243,6 +243,7 @@ void initRtsFlagsDefaults(void)
RtsFlags.MiscFlags.generate_stack_trace = true;
RtsFlags.MiscFlags.generate_dump_file = false;
RtsFlags.MiscFlags.machineReadable = false;
+ RtsFlags.MiscFlags.disableDelayedOsMemoryReturn = false;
RtsFlags.MiscFlags.internalCounters = false;
RtsFlags.MiscFlags.linkerAlwaysPic = DEFAULT_LINKER_ALWAYS_PIC;
RtsFlags.MiscFlags.linkerMemBase = 0;
@@ -914,6 +915,11 @@ error = true;
OPTION_UNSAFE;
RtsFlags.MiscFlags.machineReadable = true;
}
+ else if (strequal("disable-delayed-os-memory-return",
+ &rts_argv[arg][2])) {
+ OPTION_UNSAFE;
+ RtsFlags.MiscFlags.disableDelayedOsMemoryReturn = true;
+ }
else if (strequal("internal-counters",
&rts_argv[arg][2])) {
OPTION_SAFE;
diff --git a/rts/posix/OSMem.c b/rts/posix/OSMem.c
index dc8c4122f7..15f1b62dc9 100644
--- a/rts/posix/OSMem.c
+++ b/rts/posix/OSMem.c
@@ -602,6 +602,26 @@ void osCommitMemory(void *at, W_ size)
}
}
+/* Note [MADV_FREE and MADV_DONTNEED]
+ *
+ * madvise() provides flags with which one can release no longer needed pages
+ * back to the kernel without having to munmap() (which is expensive).
+ *
+ * On Linux, MADV_FREE is newer and faster because it can avoid zeroing
+ * pages if they are re-used by the process later (see `man 2 madvise`),
+ * but for the trade-off that memory inspection tools like `top` will
+ * not immediately reflect the freeing in their display of resident memory
+ * (RSS column): Only under memory pressure will Linux actually remove
+ * the freed pages from the process and update its RSS statistics.
+ * Until then, the pages show up as `LazyFree` in `/proc/PID/smaps`
+ * (see `man 5 proc`).
+ * The delayed RSS update can confuse programmers debugging memory issues,
+ * production memory monitoring tools, and end users who may complain about
+ * undue memory usage shown in reporting tools, so with
+ * `disableDelayedOsMemoryReturn` we provide an RTS flag that allows forcing
+ * usage of MADV_DONTNEED instead of MADV_FREE.
+ */
+
void osDecommitMemory(void *at, W_ size)
{
int r;
@@ -618,21 +638,25 @@ void osDecommitMemory(void *at, W_ size)
#endif
#if defined(MADV_FREE)
- // Try MADV_FREE first, FreeBSD has both and MADV_DONTNEED
- // just swaps memory out. Linux >= 4.5 has both DONTNEED and FREE; either
- // will work as they both allow the system to free anonymous pages.
- // It is important that we try both methods as the kernel which we were
- // built on may differ from the kernel we are now running on.
- r = madvise(at, size, MADV_FREE);
- if(r < 0) {
- if (errno == EINVAL) {
- // Perhaps the system doesn't support MADV_FREE; fall-through and
- // try MADV_DONTNEED.
+ // See Note [MADV_FREE and MADV_DONTNEED].
+ // If MADV_FREE is disabled, fall-through to MADV_DONTNEED.
+ if (!RtsFlags.MiscFlags.disableDelayedOsMemoryReturn) {
+ // Try MADV_FREE first, FreeBSD has both and MADV_DONTNEED
+ // just swaps memory out. Linux >= 4.5 has both DONTNEED and FREE; either
+ // will work as they both allow the system to free anonymous pages.
+ // It is important that we try both methods as the kernel which we were
+ // built on may differ from the kernel we are now running on.
+ r = madvise(at, size, MADV_FREE);
+ if(r < 0) {
+ if (errno == EINVAL) {
+ // Perhaps the system doesn't support MADV_FREE; fall-through and
+ // try MADV_DONTNEED.
+ } else {
+ sysErrorBelch("unable to decommit memory");
+ }
} else {
- sysErrorBelch("unable to decommit memory");
+ return;
}
- } else {
- return;
}
#endif