From 60684862588f8fbf35fa59e9994e350e4ef34dad Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 29 Mar 2018 14:27:40 +0000 Subject: [PATCH] Fix the background laundering mechanism after r329882. Rather than using the number of inactive queue scans as a metric for how many clean pages are being freed by the page daemon, have the page daemon keep a running counter of the number of pages it has freed, and have the laundry thread use that when computing the background laundering threshold. Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D14884 --- sys/vm/vm_pageout.c | 32 +++++++++++++++----------------- sys/vm/vm_pagequeue.h | 7 ++++--- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 5df8fc28b341..d7b3ef3a3d28 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -943,8 +943,7 @@ vm_pageout_laundry_worker(void *arg) { struct vm_domain *vmd; struct vm_pagequeue *pq; - uint64_t nclean, ndirty; - u_int inactq_scans, last_launder; + uint64_t nclean, ndirty, nfreed; int domain, last_target, launder, shortfall, shortfall_cycle, target; bool in_shortfall; @@ -958,8 +957,7 @@ vm_pageout_laundry_worker(void *arg) in_shortfall = false; shortfall_cycle = 0; target = 0; - inactq_scans = 0; - last_launder = 0; + nfreed = 0; /* * Calls to these handlers are serialized by the swap syscall lock. @@ -1000,7 +998,6 @@ vm_pageout_laundry_worker(void *arg) target = 0; goto trybackground; } - last_launder = inactq_scans; launder = target / shortfall_cycle--; goto dolaundry; @@ -1009,24 +1006,23 @@ vm_pageout_laundry_worker(void *arg) * meet the conditions to perform background laundering: * * 1. The ratio of dirty to clean inactive pages exceeds the - * background laundering threshold and the pagedaemon has - * been woken up to reclaim pages since our last - * laundering, or + * background laundering threshold, or * 2. we haven't yet reached the target of the current * background laundering run. * * The background laundering threshold is not a constant. * Instead, it is a slowly growing function of the number of - * page daemon scans 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. + * clean pages freed by the page daemon since the last + * background laundering. Thus, as the ratio of dirty to + * clean inactive pages grows, the amount of memory pressure + * required to trigger laundering decreases. */ trybackground: nclean = vmd->vmd_free_count + vmd->vmd_pagequeues[PQ_INACTIVE].pq_cnt; ndirty = vmd->vmd_pagequeues[PQ_LAUNDRY].pq_cnt; - if (target == 0 && inactq_scans != last_launder && - ndirty * isqrt(inactq_scans - last_launder) >= nclean) { + if (target == 0 && ndirty * isqrt(nfreed / + (vmd->vmd_free_target - vmd->vmd_free_min)) >= nclean) { target = vmd->vmd_background_launder_target; } @@ -1039,8 +1035,8 @@ vm_pageout_laundry_worker(void *arg) * proceed at the background laundering rate. */ if (target > 0) { - if (inactq_scans != last_launder) { - last_launder = inactq_scans; + if (nfreed > 0) { + nfreed = 0; last_target = target; } else if (last_target - target >= vm_background_launder_max * PAGE_SIZE / 1024) { @@ -1089,7 +1085,8 @@ vm_pageout_laundry_worker(void *arg) if (target == 0) vmd->vmd_laundry_request = VM_LAUNDRY_IDLE; - inactq_scans = vmd->vmd_inactq_scans; + nfreed += vmd->vmd_clean_pages_freed; + vmd->vmd_clean_pages_freed = 0; vm_pagequeue_unlock(pq); } } @@ -1367,7 +1364,8 @@ vm_pageout_scan(struct vm_domain *vmd, int pass, int shortage) VM_LAUNDRY_BACKGROUND; wakeup(&vmd->vmd_laundry_request); } - vmd->vmd_inactq_scans++; + vmd->vmd_clean_pages_freed += + starting_page_shortage - page_shortage; vm_pagequeue_unlock(pq); } diff --git a/sys/vm/vm_pagequeue.h b/sys/vm/vm_pagequeue.h index 894b4b57d31b..e84bcc533277 100644 --- a/sys/vm/vm_pagequeue.h +++ b/sys/vm/vm_pagequeue.h @@ -86,6 +86,7 @@ struct sysctl_oid; * d vm_domainset_lock * a atomic * c const after boot + * q page queue lock */ struct vm_domain { struct vm_pagequeue vmd_pagequeues[PQ_COUNT]; @@ -112,15 +113,15 @@ struct vm_domain { int vmd_pageout_pages_needed; /* (d) page daemon waiting for pages? */ bool vmd_minset; /* (d) Are we in vm_min_domains? */ bool vmd_severeset; /* (d) Are we in vm_severe_domains? */ - int vmd_inactq_scans; enum { VM_LAUNDRY_IDLE = 0, VM_LAUNDRY_BACKGROUND, VM_LAUNDRY_SHORTFALL } vmd_laundry_request; - /* Paging thresholds. */ - u_int vmd_background_launder_target; + /* Paging thresholds and targets. */ + u_int vmd_clean_pages_freed; /* (q) accumulator for laundry thread */ + u_int vmd_background_launder_target; /* (c) */ u_int vmd_free_reserved; /* (c) pages reserved for deadlock */ u_int vmd_free_target; /* (c) pages desired free */ u_int vmd_free_min; /* (c) pages desired free */