[haiku-commits] r37681 - haiku/trunk/src/system/kernel/vm

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 22 Jul 2010 13:32:42 +0200 (CEST)

Author: bonefish
Date: 2010-07-22 13:32:42 +0200 (Thu, 22 Jul 2010)
New Revision: 37681
Changeset: http://dev.haiku-os.org/changeset/37681

Modified:
   haiku/trunk/src/system/kernel/vm/vm_page.cpp
Log:
* PageWriteWrapper::Done(): Returns whether the page was successfully written,
  now.
* PageWriterRun::Go(): Returns the number of pages that could not be written.
* page_writer()/next_modified_page():
  - Don't use a marker page anymore. A visited page is requeued at the tail.
    This also makes the functions that schedule pages work a bit better (they
    queue the pages at the head of the queue).
  - Have an eye on pages that are busy or failed to write. If we ran through
    the whole modified queue without writing a single page, sleep for a short
    time. This mitigates the busyness the page writer falls into when there
    are enough modified pages to make it run all the time but none that can be
    written successfully.


Modified: haiku/trunk/src/system/kernel/vm/vm_page.cpp
===================================================================
--- haiku/trunk/src/system/kernel/vm/vm_page.cpp        2010-07-22 11:10:48 UTC 
(rev 37680)
+++ haiku/trunk/src/system/kernel/vm/vm_page.cpp        2010-07-22 11:32:42 UTC 
(rev 37681)
@@ -1480,28 +1480,22 @@
 }
 
 
-static vm_page *
-next_modified_page(struct vm_page &marker)
+static vm_page*
+next_modified_page(page_num_t& maxPagesToSee)
 {
        InterruptsSpinLocker locker(sModifiedPageQueue.GetLock());
-       vm_page *page;
 
-       DEBUG_PAGE_ACCESS_CHECK(&marker);
+       while (maxPagesToSee > 0) {
+               vm_page* page = sModifiedPageQueue.Head();
+               if (page == NULL)
+                       return NULL;
 
-       if (marker.State() == PAGE_STATE_MODIFIED) {
-               page = sModifiedPageQueue.Next(&marker);
-               sModifiedPageQueue.Remove(&marker);
-               marker.SetState(PAGE_STATE_UNUSED);
-       } else
-               page = sModifiedPageQueue.Head();
+               sModifiedPageQueue.Requeue(page, true);
 
-       for (; page != NULL; page = sModifiedPageQueue.Next(page)) {
-               if (!page->busy) {
-                       // insert marker
-                       marker.SetState(PAGE_STATE_MODIFIED);
-                       sModifiedPageQueue.InsertAfter(page, &marker);
+               maxPagesToSee--;
+
+               if (!page->busy)
                        return page;
-               }
        }
 
        return NULL;
@@ -1521,7 +1515,7 @@
 
        void PrepareNextRun();
        void AddPage(vm_page* page);
-       void Go();
+       uint32 Go();
 
        void PageWritten(PageWriteTransfer* transfer, status_t status,
                bool partialTransfer, size_t bytesTransferred);
@@ -1569,7 +1563,7 @@
        PageWriteWrapper();
        ~PageWriteWrapper();
        void SetTo(vm_page* page);
-       void Done(status_t result);
+       bool Done(status_t result);
 
 private:
        vm_page*                        fPage;
@@ -1628,8 +1622,10 @@
 
 /*!    The page's cache must be locked.
        The page queues must not be locked.
+       \return \c true if the page was written successfully respectively could 
be
+               handled somehow, \c false otherwise.
 */
-void
+bool
 PageWriteWrapper::Done(status_t result)
 {
        if (!fIsActive)
@@ -1640,6 +1636,8 @@
        fPage->busy = false;
                // Set unbusy and notify later by hand, since we might free the 
page.
 
+       bool success = true;
+
        if (result == B_OK) {
                // put it into the active/inactive queue
                move_page_to_appropriate_queue(fPage);
@@ -1677,11 +1675,15 @@
 
                        fPage->busy_writing = false;
                        DEBUG_PAGE_ACCESS_END(fPage);
+
+                       success = false;
                }
        }
 
        fCache->NotifyPageEvents(fPage, PAGE_EVENT_NOT_BUSY);
        fIsActive = false;
+
+       return success;
 }
 
 
@@ -1842,7 +1844,10 @@
 }
 
 
-void
+/*!    Writes all pages previously added.
+       \return The number of pages that could not be written or otherwise 
handled.
+*/
+uint32
 PageWriterRun::Go()
 {
        fPendingTransfers = fTransferCount;
@@ -1860,13 +1865,16 @@
 
        // mark pages depending on whether they could be written or not
 
+       uint32 failedPages = 0;
        uint32 wrapperIndex = 0;
        for (uint32 i = 0; i < fTransferCount; i++) {
                PageWriteTransfer& transfer = fTransfers[i];
                transfer.Cache()->Lock();
 
-               for (uint32 j = 0; j < transfer.PageCount(); j++)
-                       fWrappers[wrapperIndex++].Done(transfer.Status());
+               for (uint32 j = 0; j < transfer.PageCount(); j++) {
+                       if (!fWrappers[wrapperIndex++].Done(transfer.Status()))
+                               failedPages++;
+               }
 
                transfer.Cache()->Unlock();
        }
@@ -1885,6 +1893,8 @@
                        cache->ReleaseRef();
                }
        }
+
+       return failedPages;
 }
 
 
@@ -1918,8 +1928,7 @@
                return B_ERROR;
        }
 
-       vm_page marker;
-       init_page_marker(marker);
+       page_num_t pagesSinceLastSuccessfulWrite = 0;
 
        while (true) {
 // TODO: Maybe wait shorter when memory is low!
@@ -1928,10 +1937,17 @@
                                // all 3 seconds when no one triggers us
                }
 
-               int32 modifiedPages = sModifiedPageQueue.Count();
+               page_num_t modifiedPages = sModifiedPageQueue.Count();
                if (modifiedPages == 0)
                        continue;
 
+               if (modifiedPages <= pagesSinceLastSuccessfulWrite) {
+                       // We ran through the whole queue without being able to 
write a
+                       // single page. Take a break.
+                       snooze(500000);
+                       pagesSinceLastSuccessfulWrite = 0;
+               }
+
 #if ENABLE_SWAP_SUPPORT
                page_stats pageStats;
                get_page_stats(pageStats);
@@ -1962,8 +1978,10 @@
                // collect pages to be written
                pageCollectionTime -= system_time();
 
-               while (numPages < kNumPages) {
-                       vm_page *page = next_modified_page(marker);
+               page_num_t maxPagesToSee = modifiedPages;
+
+               while (numPages < kNumPages && maxPagesToSee > 0) {
+                       vm_page *page = next_modified_page(maxPagesToSee);
                        if (page == NULL)
                                break;
 
@@ -2038,7 +2056,7 @@
 
                // write pages to disk and do all the cleanup
                pageWritingTime -= system_time();
-               run.Go();
+               uint32 failedPages = run.Go();
                pageWritingTime += system_time();
 
                // debug output only...
@@ -2054,9 +2072,14 @@
                        pageCollectionTime = 0;
                        pageWritingTime = 0;
                }
+
+               if (failedPages == numPages) {
+                       pagesSinceLastSuccessfulWrite
+                               += modifiedPages - maxPagesToSee - numPages;
+               } else
+                       pagesSinceLastSuccessfulWrite = 0;
        }
 
-       remove_page_marker(marker);
        return B_OK;
 }
 


Other related posts:

  • » [haiku-commits] r37681 - haiku/trunk/src/system/kernel/vm - ingo_weinhold