From b08264b3446104587a0b11e9f857bd1068771dd0 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 30 May 2016 12:09:12 -0700 Subject: [PATCH 3/4] Rework shortfall laundering. - Redefine the shortfall threshold using the vm_laundering_needed() predicate. Now, we are in shortfall when the inactive queue is below its target and the free page count is below the pagedaemon wakeup threshold. In this state we attempt to launder enough pages to meet the inactive and free page targets. This improves behaviour in the case where almost all of the system's non-wired memory is active, but there is little memory pressure. In particular, there's no need to launder aggressively if v_inact_count < v_inact_target and v_free_count is above the pagedaemon wakeup threshold. - The performance is unchanged when the system is persistently in shortfall, for example when many threads are writing sequentially to large memory-mapped files. - Add some comments which hopefully make the logic easier to follow. --- sys/sys/vmmeter.h | 11 +++++++++++ sys/vm/vm_pageout.c | 44 ++++++++++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/sys/sys/vmmeter.h b/sys/sys/vmmeter.h index eae9fce..13ce84e 100644 --- a/sys/sys/vmmeter.h +++ b/sys/sys/vmmeter.h @@ -198,6 +198,17 @@ vm_laundry_target(void) } /* + * Return true if we are in shortfall and must being laundering dirty memory. + */ +static inline int +vm_laundering_needed(void) +{ + + return (vm_cnt.v_inactive_count < vm_cnt.v_inactive_target && + vm_paging_needed()); +} + +/* * Obtain the value of a per-CPU counter. */ #define VM_METER_PCPU_CNT(member) \ diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 0229ea2..fde8026 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -1144,30 +1144,38 @@ vm_pageout_laundry_worker(void *arg) launder = 0; /* - * First determine whether we're in shortfall. If so, there's - * an impending need for clean pages. We attempt to launder the - * target within one pagedaemon sleep period. + * First determine whether we need to launder pages to meet a + * shortage of free pages. */ - shortfall = vm_laundry_target() + vm_pageout_deficit; - if (shortfall > 0) { + if (vm_laundering_needed()) { + shortfall = vm_laundry_target() + vm_pageout_deficit; /* - * If the shortfall has grown since the last cycle or - * we're still in shortfall despite a previous - * laundering run, start a new run. + * If we're in shortfall and we haven't yet started a + * laundering cycle to get us out of it, begin a run. + * If we're still in shortfall despite a previous + * laundering run, start a new one. */ - if (shortfall > prev_shortfall || cycle == tcycle) { + if (prev_shortfall == 0 || cycle == tcycle) { target = shortfall; cycle = 0; tcycle = VM_LAUNDER_RATE; } prev_shortfall = shortfall; - launder = target / (tcycle - (cycle % tcycle)); - goto launder; - } else { - if (prev_shortfall > 0) - /* We're out of shortfall; the target is met. */ - target = 0; - shortfall = prev_shortfall = 0; + } + if (prev_shortfall > 0) { + /* + * We entered shortfall at some point in the recent + * past. If we have reached our target, or the + * laundering run is finished and we're not currently in + * shortfall, we have no immediate need to launder + * pages. Otherwise keep laundering. + */ + if (vm_laundry_target() <= 0 || cycle == tcycle) { + shortfall = prev_shortfall = target = 0; + } else { + launder = target / (tcycle - cycle); + goto dolaundry; + } } /* @@ -1187,7 +1195,7 @@ vm_pageout_laundry_worker(void *arg) if (target > 0 && cycle != tcycle) { /* Continue an ongoing background run. */ launder = target / (tcycle - (cycle % tcycle)); - goto launder; + goto dolaundry; } ninact = vm_cnt.v_inactive_count; @@ -1212,7 +1220,7 @@ vm_pageout_laundry_worker(void *arg) launder = target / (tcycle - (cycle % tcycle)); } -launder: +dolaundry: if (launder > 0) { laundered = vm_pageout_launder(domain, launder); target -= min(laundered, target); -- 2.8.1