Date: Mon, 22 Aug 2016 01:41:04 +0000 (UTC) From: Mark Johnston <markj@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r304577 - user/alc/PQ_LAUNDRY/sys/vm Message-ID: <201608220141.u7M1f4M8076794@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 -=
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608220141.u7M1f4M8076794>