From owner-svn-src-all@FreeBSD.ORG Sat Jul 7 19:39:09 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 62967106566C; Sat, 7 Jul 2012 19:39:09 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 42CA38FC0C; Sat, 7 Jul 2012 19:39:09 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q67Jd9eV080111; Sat, 7 Jul 2012 19:39:09 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q67Jd9lq080108; Sat, 7 Jul 2012 19:39:09 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201207071939.q67Jd9lq080108@svn.freebsd.org> From: Konstantin Belousov Date: Sat, 7 Jul 2012 19:39:09 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r238212 - in head/sys: sys vm X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 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: Sat, 07 Jul 2012 19:39:09 -0000 Author: kib Date: Sat Jul 7 19:39:08 2012 New Revision: 238212 URL: http://svn.freebsd.org/changeset/base/238212 Log: Drop page queues mutex on each iteration of vm_pageout_scan over the inactive queue, unless busy page is found. Dropping the mutex often should allow the other lock acquires to proceed without waiting for whole inactive scan to finish. On machines with lot of physical memory scan often need to iterate a lot before it finishes or finds a page which requires laundring, causing high latency for other lock waiters. Suggested and reviewed by: alc MFC after: 3 weeks Modified: head/sys/sys/vmmeter.h head/sys/vm/vm_pageout.c Modified: head/sys/sys/vmmeter.h ============================================================================== --- head/sys/sys/vmmeter.h Sat Jul 7 19:12:15 2012 (r238211) +++ head/sys/sys/vmmeter.h Sat Jul 7 19:39:08 2012 (r238212) @@ -79,7 +79,7 @@ struct vmmeter { u_int v_pdpages; /* (q) pages analyzed by daemon */ u_int v_tcached; /* (p) total pages cached */ - u_int v_dfree; /* (q) pages freed by daemon */ + u_int v_dfree; /* (p) pages freed by daemon */ u_int v_pfree; /* (p) pages freed by exiting processes */ u_int v_tfree; /* (p) total pages freed */ /* Modified: head/sys/vm/vm_pageout.c ============================================================================== --- head/sys/vm/vm_pageout.c Sat Jul 7 19:12:15 2012 (r238211) +++ head/sys/vm/vm_pageout.c Sat Jul 7 19:39:08 2012 (r238212) @@ -743,6 +743,7 @@ vm_pageout_scan(int pass) int actcount; int vnodes_skipped = 0; int maxlaunder; + boolean_t queues_locked; /* * Decrease registered cache sizes. @@ -784,6 +785,7 @@ vm_pageout_scan(int pass) if (pass) maxlaunder = 10000; vm_page_lock_queues(); + queues_locked = TRUE; rescan0: addl_page_shortage = addl_page_shortage_init; maxscan = cnt.v_inactive_count; @@ -791,6 +793,8 @@ rescan0: for (m = TAILQ_FIRST(&vm_page_queues[PQ_INACTIVE].pl); m != NULL && maxscan-- > 0 && page_shortage > 0; m = next) { + KASSERT(queues_locked, ("unlocked queues")); + mtx_assert(&vm_page_queue_mtx, MA_OWNED); cnt.v_pdpages++; @@ -850,6 +854,16 @@ rescan0: } /* + * We unlock vm_page_queue_mtx, invalidating the + * 'next' pointer. Use our marker to remember our + * place. + */ + TAILQ_INSERT_AFTER(&vm_page_queues[PQ_INACTIVE].pl, + m, &marker, pageq); + vm_page_unlock_queues(); + queues_locked = FALSE; + + /* * If the object is not being used, we ignore previous * references. */ @@ -873,7 +887,7 @@ rescan0: vm_page_unlock(m); m->act_count += actcount + ACT_ADVANCE; VM_OBJECT_UNLOCK(object); - continue; + goto relock_queues; } /* @@ -889,7 +903,7 @@ rescan0: vm_page_unlock(m); m->act_count += actcount + ACT_ADVANCE + 1; VM_OBJECT_UNLOCK(object); - continue; + goto relock_queues; } /* @@ -924,7 +938,7 @@ rescan0: * Invalid pages can be easily freed */ vm_page_free(m); - cnt.v_dfree++; + PCPU_INC(cnt.v_dfree); --page_shortage; } else if (m->dirty == 0) { /* @@ -947,6 +961,8 @@ rescan0: * the thrash point for a heavily loaded machine. */ m->flags |= PG_WINATCFLS; + vm_page_lock_queues(); + queues_locked = TRUE; vm_page_requeue(m); } else if (maxlaunder > 0) { /* @@ -976,21 +992,13 @@ rescan0: if (!swap_pageouts_ok || (object->flags & OBJ_DEAD)) { vm_page_unlock(m); VM_OBJECT_UNLOCK(object); + vm_page_lock_queues(); + queues_locked = TRUE; vm_page_requeue(m); - continue; + goto relock_queues; } /* - * Following operations may unlock - * vm_page_queue_mtx, invalidating the 'next' - * pointer. To prevent an inordinate number - * of restarts we use our marker to remember - * our place. - * - */ - TAILQ_INSERT_AFTER(&vm_page_queues[PQ_INACTIVE].pl, - m, &marker, pageq); - /* * The object is already known NOT to be dead. It * is possible for the vget() to block the whole * pageout daemon, but the new low-memory handling @@ -1014,7 +1022,6 @@ rescan0: * of time. */ if (object->type == OBJT_VNODE) { - vm_page_unlock_queues(); vm_page_unlock(m); vp = object->handle; if (vp->v_type == VREG && @@ -1044,6 +1051,7 @@ rescan0: VM_OBJECT_LOCK(object); vm_page_lock(m); vm_page_lock_queues(); + queues_locked = TRUE; /* * The page might have been moved to another * queue during potential blocking in vget() @@ -1075,6 +1083,8 @@ rescan0: * be undergoing I/O, so skip it */ if (m->hold_count) { + vm_page_lock_queues(); + queues_locked = TRUE; vm_page_unlock(m); vm_page_requeue(m); if (object->flags & OBJ_MIGHTBEDIRTY) @@ -1093,32 +1103,37 @@ rescan0: * the (future) cleaned page. Otherwise we could wind * up laundering or cleaning too many pages. */ - vm_page_unlock_queues(); if (vm_pageout_clean(m) != 0) { --page_shortage; --maxlaunder; } - vm_page_lock_queues(); unlock_and_continue: vm_page_lock_assert(m, MA_NOTOWNED); VM_OBJECT_UNLOCK(object); if (mp != NULL) { - vm_page_unlock_queues(); + if (queues_locked) { + vm_page_unlock_queues(); + queues_locked = FALSE; + } if (vp != NULL) vput(vp); VFS_UNLOCK_GIANT(vfslocked); vm_object_deallocate(object); vn_finished_write(mp); - vm_page_lock_queues(); } - next = TAILQ_NEXT(&marker, pageq); - TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, - &marker, pageq); vm_page_lock_assert(m, MA_NOTOWNED); - continue; + goto relock_queues; } vm_page_unlock(m); VM_OBJECT_UNLOCK(object); +relock_queues: + if (!queues_locked) { + vm_page_lock_queues(); + queues_locked = TRUE; + } + next = TAILQ_NEXT(&marker, pageq); + TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, + &marker, pageq); } /*