Author: alc
Date: Tue Oct 25 16:35:08 2011
New Revision: 226740
URL: http://svn.freebsd.org/changeset/base/226740

Log:
  Speed up vm_page_cache() and vm_page_remove() by checking for a few
  common cases that can be handled in constant time.  The insight being
  that a page's parent in the vm object's tree is very often its
  predecessor or successor in the vm object's ordered memq.
  
  Tested by:    jhb
  MFC after:    10 days

Modified:
  head/sys/vm/vm_page.c

Modified: head/sys/vm/vm_page.c
==============================================================================
--- head/sys/vm/vm_page.c       Tue Oct 25 16:30:16 2011        (r226739)
+++ head/sys/vm/vm_page.c       Tue Oct 25 16:35:08 2011        (r226740)
@@ -908,7 +908,7 @@ void
 vm_page_remove(vm_page_t m)
 {
        vm_object_t object;
-       vm_page_t root;
+       vm_page_t next, prev, root;
 
        if ((m->oflags & VPO_UNMANAGED) == 0)
                vm_page_lock_assert(m, MA_OWNED);
@@ -923,15 +923,42 @@ vm_page_remove(vm_page_t m)
        /*
         * Now remove from the object's list of backed pages.
         */
-       if (m != object->root)
-               vm_page_splay(m->pindex, object->root);
-       if (m->left == NULL)
-               root = m->right;
-       else {
-               root = vm_page_splay(m->pindex, m->left);
-               root->right = m->right;
+       if ((next = TAILQ_NEXT(m, listq)) != NULL && next->left == m) {
+               /*
+                * Since the page's successor in the list is also its parent
+                * in the tree, its right subtree must be empty.
+                */
+               next->left = m->left;
+               KASSERT(m->right == NULL,
+                   ("vm_page_remove: page %p has right child", m));
+       } else if ((prev = TAILQ_PREV(m, pglist, listq)) != NULL &&
+           prev->right == m) {
+               /*
+                * Since the page's predecessor in the list is also its parent
+                * in the tree, its left subtree must be empty.
+                */
+               KASSERT(m->left == NULL,
+                   ("vm_page_remove: page %p has left child", m));
+               prev->right = m->right;
+       } else {
+               if (m != object->root)
+                       vm_page_splay(m->pindex, object->root);
+               if (m->left == NULL)
+                       root = m->right;
+               else if (m->right == NULL)
+                       root = m->left;
+               else {
+                       /*
+                        * Move the page's successor to the root, because
+                        * pages are usually removed in ascending order.
+                        */
+                       if (m->right != next)
+                               vm_page_splay(m->pindex, m->right);
+                       next->left = m->left;
+                       root = next;
+               }
+               object->root = root;
        }
-       object->root = root;
        TAILQ_REMOVE(&object->memq, m, listq);
 
        /*
@@ -2021,7 +2048,7 @@ void
 vm_page_cache(vm_page_t m)
 {
        vm_object_t object;
-       vm_page_t root;
+       vm_page_t next, prev, root;
 
        vm_page_lock_assert(m, MA_OWNED);
        object = m->object;
@@ -2056,15 +2083,42 @@ vm_page_cache(vm_page_t m)
         * Remove the page from the object's collection of resident
         * pages. 
         */
-       if (m != object->root)
-               vm_page_splay(m->pindex, object->root);
-       if (m->left == NULL)
-               root = m->right;
-       else {
-               root = vm_page_splay(m->pindex, m->left);
-               root->right = m->right;
+       if ((next = TAILQ_NEXT(m, listq)) != NULL && next->left == m) {
+               /*
+                * Since the page's successor in the list is also its parent
+                * in the tree, its right subtree must be empty.
+                */
+               next->left = m->left;
+               KASSERT(m->right == NULL,
+                   ("vm_page_cache: page %p has right child", m));
+       } else if ((prev = TAILQ_PREV(m, pglist, listq)) != NULL &&
+           prev->right == m) {
+               /*
+                * Since the page's predecessor in the list is also its parent
+                * in the tree, its left subtree must be empty.
+                */
+               KASSERT(m->left == NULL,
+                   ("vm_page_cache: page %p has left child", m));
+               prev->right = m->right;
+       } else {
+               if (m != object->root)
+                       vm_page_splay(m->pindex, object->root);
+               if (m->left == NULL)
+                       root = m->right;
+               else if (m->right == NULL)
+                       root = m->left;
+               else {
+                       /*
+                        * Move the page's successor to the root, because
+                        * pages are usually removed in ascending order.
+                        */
+                       if (m->right != next)
+                               vm_page_splay(m->pindex, m->right);
+                       next->left = m->left;
+                       root = next;
+               }
+               object->root = root;
        }
-       object->root = root;
        TAILQ_REMOVE(&object->memq, m, listq);
        object->resident_page_count--;
 
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to