svn commit: r304577 - user/alc/PQ_LAUNDRY/sys/vm

Mark Johnston markj at FreeBSD.org
Mon Aug 22 01:41:05 UTC 2016


Author: markj
Date: Mon Aug 22 01:41:03 2016
New Revision: 304577
URL: https://svnweb.freebsd.org/changeset/base/304577

Log:
  Rework the background laundering target after r304442.
  
  Now that we launder less frequently and at a rate proportional to the
  ratio of dirty to clean inactive pages, we want to process more pages during
  each background laundering run. Launder a constant number of pages,
  derived from the amount of system memory. Cap the rate at which pages are
  laundered to 4MB/s and add a check to ensure we don't launder too much on
  larger-memory systems if page daemon wakeups are infrequent and the number
  of dirty pages is large.
  
  Discussed with:	alc

Modified:
  user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c

Modified: user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c
==============================================================================
--- user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c	Mon Aug 22 01:28:02 2016	(r304576)
+++ user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c	Mon Aug 22 01:41:03 2016	(r304577)
@@ -231,10 +231,15 @@ SYSCTL_INT(_vm, OID_AUTO, act_scan_laund
 	CTLFLAG_RW, &act_scan_laundry_weight, 0,
 	"weight given to clean vs. dirty pages in active queue scans");
 
-static u_int bkgrd_launder_max = 2048;
+static u_int bkgrd_launder_rate = 4096;
+SYSCTL_UINT(_vm, OID_AUTO, bkgrd_launder_rate,
+	CTLFLAG_RW, &bkgrd_launder_rate, 0,
+	"background laundering rate, in kilobytes per second");
+
+static u_int bkgrd_launder_max = 20 * 1024;
 SYSCTL_UINT(_vm, OID_AUTO, bkgrd_launder_max,
 	CTLFLAG_RW, &bkgrd_launder_max, 0,
-	"maximum background laundering rate, in pages per second");
+	"background laundering cap in kilobytes");
 
 #define VM_PAGEOUT_PAGE_COUNT 16
 int vm_pageout_page_count = VM_PAGEOUT_PAGE_COUNT;
@@ -1095,9 +1100,10 @@ static void
 vm_pageout_laundry_worker(void *arg)
 {
 	struct vm_domain *domain;
-	uint64_t nclean, nlaundry;
+	uint64_t nclean, ndirty;
 	u_int last_launder, wakeups;
-	int cycle, domidx, launder, prev_shortfall, shortfall, target;
+	int cycle, domidx, launder, prev_shortfall, shortfall;
+	int starting_target, target;
 
 	domidx = (uintptr_t)arg;
 	domain = &vm_dom[domidx];
@@ -1166,50 +1172,40 @@ vm_pageout_laundry_worker(void *arg)
 		 *
 		 * The background laundering threshold is not a constant.
 		 * Instead, it is a slowly growing function of the number of
-		 * page daemon wakeups since the last laundering.
+		 * page daemon wakeups since the last laundering.  Thus, as the
+		 * ratio of dirty to clean inactive pages grows, the amount of
+		 * memory pressure required to trigger laundering decreases.
 		 */
 		nclean = vm_cnt.v_inactive_count + vm_cnt.v_free_count;
-		nlaundry = vm_cnt.v_laundry_count;
+		ndirty = vm_cnt.v_laundry_count;
 		if (target == 0 && wakeups != last_launder &&
-		    nlaundry * isqrt(wakeups - last_launder) >= nclean) {
+		    ndirty * isqrt(wakeups - last_launder) >= nclean) {
 			last_launder = wakeups;
-
-			/*
-			 * The pagedaemon has woken up at least once since the
-			 * last background laundering run and we're above the
-			 * dirty page threshold.  Launder some pages to balance
-			 * the inactive and laundry queues.  We attempt to
-			 * finish within one second.
-			 */
-			cycle = VM_LAUNDER_INTERVAL;
-
-			/*
-			 * Set our target to that of the pagedaemon, scaled by
-			 * the relative lengths of the inactive and laundry
-			 * queues.  Divide by a fudge factor as well: we don't
-			 * want to reclaim dirty pages at the same rate as clean
-			 * pages.
-			 */
-			target = vm_cnt.v_free_target -
-			    vm_pageout_wakeup_thresh;
-			/* Avoid division by zero. */
-			if (nclean == 0)
-				nclean = 1;
-			target = nlaundry * (u_int)target / nclean / 10;
-			if (target == 0)
-				target = 1;
-
-			/*
-			 * Make sure we don't exceed the background laundering
-			 * threshold.
-			 */
-			target = min(target, bkgrd_launder_max);
+			target = starting_target =
+			    (vm_cnt.v_free_target - vm_cnt.v_free_min) / 10;
 		}
+		/*
+		 * We have a non-zero background laundering target.  If we've
+		 * laundered up to our maximum without observing a page daemon
+		 * wakeup, just stop.  This is a safety belt that ensures we
+		 * don't launder an excessive amount if memory pressure is low
+		 * and the ratio of dirty to clean pages is large.  Otherwise,
+		 * proceed at the background laundering rate.
+		 */
 		if (target > 0) {
-			if (cycle != 0)
-				launder = target / cycle--;
-			else
-				target = 0;
+			if (last_launder == wakeups) {
+				if (starting_target - target >=
+				    bkgrd_launder_max * PAGE_SIZE / 1024)
+					target = 0;
+			} else {
+				last_launder = wakeups;
+				starting_target = target;
+			}
+
+			launder = bkgrd_launder_rate * PAGE_SIZE / 1024 /
+			    VM_LAUNDER_INTERVAL;
+			if (launder < target)
+				launder = target;
 		}
 
 dolaundry:
@@ -1601,6 +1597,10 @@ drop_page:
 			if (page_shortage <= 0)
 				vm_page_deactivate(m);
 			else {
+				if (m->dirty == 0 &&
+				    m->object->ref_count != 0 &&
+				    pmap_is_modified(m))
+					vm_cnt.v_postponed_launderings++;
 				if (m->dirty == 0) {
 					vm_page_deactivate(m);
 					page_shortage -=


More information about the svn-src-user mailing list