From owner-svn-src-all@freebsd.org Sun Sep 27 04:36:10 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id F09C2A0A5C4; Sun, 27 Sep 2015 04:36:10 +0000 (UTC) (envelope-from alc@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id E1056235; Sun, 27 Sep 2015 04:36:10 +0000 (UTC) (envelope-from alc@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t8R4aAM5074957; Sun, 27 Sep 2015 04:36:10 GMT (envelope-from alc@FreeBSD.org) Received: (from alc@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t8R4aAG5074955; Sun, 27 Sep 2015 04:36:10 GMT (envelope-from alc@FreeBSD.org) Message-Id: <201509270436.t8R4aAG5074955@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: alc set sender to alc@FreeBSD.org using -f From: Alan Cox Date: Sun, 27 Sep 2015 04:36:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r288294 - stable/10/sys/vm X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 27 Sep 2015 04:36:11 -0000 Author: alc Date: Sun Sep 27 04:36:09 2015 New Revision: 288294 URL: https://svnweb.freebsd.org/changeset/base/288294 Log: MFC r285282 The intention of r254304 was to scan the active queue continuously. However, I've observed the active queue scan stopping when there are frequent free page shortages and the inactive queue is steadily refilled by other mechanisms, such as the sequential access heuristic in vm_fault() or madvise(2). To remedy this problem, record the time of the last active queue scan, and always scan a number of pages proportional to the time since the last scan, regardless of whether that last scan was a timeout-triggered ("pass == 0") or free-page-shortage-triggered ("pass > 0") scan. Also, on a timeout-triggered scan, allow a full scan of the active queue when the system is short of inactive pages. Modified: stable/10/sys/vm/vm_page.h stable/10/sys/vm/vm_pageout.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/vm/vm_page.h ============================================================================== --- stable/10/sys/vm/vm_page.h Sun Sep 27 04:25:07 2015 (r288293) +++ stable/10/sys/vm/vm_page.h Sun Sep 27 04:36:09 2015 (r288294) @@ -227,6 +227,7 @@ struct vm_domain { long vmd_segs; /* bitmask of the segments */ boolean_t vmd_oom; int vmd_pass; /* local pagedaemon pass */ + int vmd_last_active_scan; struct vm_page vmd_marker; /* marker for pagedaemon private use */ }; Modified: stable/10/sys/vm/vm_pageout.c ============================================================================== --- stable/10/sys/vm/vm_pageout.c Sun Sep 27 04:25:07 2015 (r288293) +++ stable/10/sys/vm/vm_pageout.c Sun Sep 27 04:36:09 2015 (r288294) @@ -926,9 +926,10 @@ vm_pageout_scan(struct vm_domain *vmd, i vm_page_t m, next; struct vm_pagequeue *pq; vm_object_t object; + long min_scan; int act_delta, addl_page_shortage, deficit, maxscan, page_shortage; int vnodes_skipped = 0; - int maxlaunder; + int maxlaunder, scan_tick, scanned; int lockmode; boolean_t queues_locked; @@ -1359,34 +1360,37 @@ relock_queues: * If we're just idle polling attempt to visit every * active page within 'update_period' seconds. */ - if (pass == 0 && vm_pageout_update_period != 0) { - maxscan /= vm_pageout_update_period; - page_shortage = maxscan; - } + scan_tick = ticks; + if (vm_pageout_update_period != 0) { + min_scan = pq->pq_cnt; + min_scan *= scan_tick - vmd->vmd_last_active_scan; + min_scan /= hz * vm_pageout_update_period; + } else + min_scan = 0; + if (min_scan > 0 || (page_shortage > 0 && maxscan > 0)) + vmd->vmd_last_active_scan = scan_tick; /* - * Scan the active queue for things we can deactivate. We nominally - * track the per-page activity counter and use it to locate - * deactivation candidates. - */ - m = TAILQ_FIRST(&pq->pq_pl); - while (m != NULL && maxscan-- > 0 && page_shortage > 0) { + * Scan the active queue for pages that can be deactivated. Update + * the per-page activity counter and use it to identify deactivation + * candidates. + */ + for (m = TAILQ_FIRST(&pq->pq_pl), scanned = 0; m != NULL && (scanned < + min_scan || (page_shortage > 0 && scanned < maxscan)); m = next, + scanned++) { KASSERT(m->queue == PQ_ACTIVE, ("vm_pageout_scan: page %p isn't active", m)); next = TAILQ_NEXT(m, plinks.q); - if ((m->flags & PG_MARKER) != 0) { - m = next; + if ((m->flags & PG_MARKER) != 0) continue; - } KASSERT((m->flags & PG_FICTITIOUS) == 0, ("Fictitious page %p cannot be in active queue", m)); KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("Unmanaged page %p cannot be in active queue", m)); if (!vm_pageout_page_lock(m, &next)) { vm_page_unlock(m); - m = next; continue; } @@ -1439,7 +1443,6 @@ relock_queues: } else vm_page_requeue_locked(m); vm_page_unlock(m); - m = next; } vm_pagequeue_unlock(pq); #if !defined(NO_SWAPPING) @@ -1627,6 +1630,7 @@ vm_pageout_worker(void *arg) */ KASSERT(domain->vmd_segs != 0, ("domain without segments")); + domain->vmd_last_active_scan = ticks; vm_pageout_init_marker(&domain->vmd_marker, PQ_INACTIVE); /*