[haiku-commits] r35733 - haiku/trunk/src/system/kernel/cache

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 3 Mar 2010 11:28:57 +0100 (CET)

Author: axeld
Date: 2010-03-03 11:28:57 +0100 (Wed, 03 Mar 2010)
New Revision: 35733
Changeset: http://dev.haiku-os.org/changeset/35733/haiku

Modified:
   haiku/trunk/src/system/kernel/cache/block_cache.cpp
Log:
* Replaced cached_block::accessed (the number of accesses) with last_accessed
  (the time of the last access), as what we really want is a frequency/last
  access time scoring, and accessed alone is useless for that.
* put_cached_block() no longer frees any unused blocks.
* The low memory handler will now only lock the cache if there is something
  to do. Also, it did not take address space warnings into account.
* Even when memory is critical, we don't free all unused blocks anymore - if
  the number of blocks we free now (10000) is not sufficient to get out of the
  critical condition, chances are good that we will be called again :-)
* block_notifier_and_writer() now tries to make sure that the total block cache
  memory consumption grows not much larger than half of the available RAM.
* This should all help to limit the block cache usage a bit better. Hopefully,
  a checkfs run will no longer run out of memory here (couldn't test yet).


Modified: haiku/trunk/src/system/kernel/cache/block_cache.cpp
===================================================================
--- haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-03-03 07:59:53 UTC 
(rev 35732)
+++ haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-03-03 10:28:57 UTC 
(rev 35733)
@@ -24,6 +24,7 @@
 #include <util/DoublyLinkedList.h>
 #include <util/AutoLock.h>
 #include <util/khash.h>
+#include <vm/vm_page.h>
 
 #include "kernel_debug_config.h"
 
@@ -66,7 +67,7 @@
        void*                   compare;
 #endif
        int32                   ref_count;
-       int32                   accessed;
+       int32                   last_accessed;
        bool                    busy_reading : 1;
        bool                    busy_writing : 1;
        bool                    is_writing : 1;
@@ -81,6 +82,8 @@
        cache_transaction* previous_transaction;
 
        bool CanBeWritten() const;
+       int32 LastAccess() const
+               { return system_time() / 1000000L - last_accessed; }
 
        static int Compare(void* _cacheEntry, const void* _block);
        static uint32 Hash(void* _cacheEntry, const void* _block, uint32 range);
@@ -136,8 +139,7 @@
 
        void                    Free(void* buffer);
        void*                   Allocate();
-       void                    RemoveUnusedBlocks(int32 maxAccessed = LONG_MAX,
-                                               int32 count = LONG_MAX);
+       void                    RemoveUnusedBlocks(int32 count, int32 
minSecondsOld = 0);
        void                    RemoveBlock(cached_block* block);
        void                    DiscardBlock(cached_block* block);
        void                    FreeBlock(cached_block* block);
@@ -1365,7 +1367,7 @@
        if (low_resource_state(B_KERNEL_RESOURCE_PAGES | 
B_KERNEL_RESOURCE_MEMORY
                        | B_KERNEL_RESOURCE_ADDRESS_SPACE) != 
B_NO_LOW_RESOURCE) {
                // recycle existing before allocating a new one
-               RemoveUnusedBlocks(1, 2);
+               RemoveUnusedBlocks(2);
        }
 
        void* block = object_cache_alloc(buffer_cache, 0);
@@ -1373,7 +1375,7 @@
                return block;
 
        // recycle existing before allocating a new one
-       RemoveUnusedBlocks(1, 2);
+       RemoveUnusedBlocks(100);
 
        return object_cache_alloc(buffer_cache, 0);
 }
@@ -1433,7 +1435,7 @@
 
        block->block_number = blockNumber;
        block->ref_count = 0;
-       block->accessed = 0;
+       block->last_accessed = 0;
        block->transaction_next = NULL;
        block->transaction = block->previous_transaction = NULL;
        block->original_data = NULL;
@@ -1455,18 +1457,22 @@
 
 
 void
-block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
+block_cache::RemoveUnusedBlocks(int32 count, int32 minSecondsOld)
 {
-       TRACE(("block_cache: remove up to %ld unused blocks\n", count));
+       TRACE(("block_cache: remove up to %" B_PRId32 " unused blocks\n", 
count));
 
        for (block_list::Iterator iterator = unused_blocks.GetIterator();
                        cached_block* block = iterator.Next();) {
-               if (maxAccessed < block->accessed || block->busy_reading)
+               if (minSecondsOld >= block->LastAccess()) {
+                       // The list is sorted by last access
+                       break;
+               }
+               if (block->busy_reading || block->busy_writing)
                        continue;
 
                TB(Flush(this, block));
-               TRACE(("  remove block %Ld, accessed %ld times\n",
-                       block->block_number, block->accessed));
+               TRACE(("  remove block %Ld, last accessed %" B_PRId32 "\n",
+                       block->block_number, block->last_accessed));
 
                // this can only happen if no transactions are used
                if (block->is_dirty && !block->discard) {
@@ -1519,42 +1525,41 @@
 void
 block_cache::_LowMemoryHandler(void* data, uint32 resources, int32 level)
 {
-       block_cache* cache = (block_cache*)data;
-       MutexLocker locker(&cache->lock);
-
-       if (!locker.IsLocked()) {
-               // If our block_cache were deleted, it could be that we had
-               // been called before that deletion went through, therefore,
-               // acquiring its lock might fail.
-               return;
-       }
-
        TRACE(("block_cache: low memory handler called with level %ld\n", 
level));
 
        // free some blocks according to the low memory state
        // (if there is enough memory left, we don't free any)
 
-       int32 free = 1;
-       int32 accessed = 1;
-       switch (low_resource_state(
-                       B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY)) {
+       int32 free = 0;
+       int32 secondsOld = 0;
+       switch (level) {
                case B_NO_LOW_RESOURCE:
                        return;
                case B_LOW_RESOURCE_NOTE:
                        free = 50;
-                       accessed = 2;
+                       secondsOld = 120;
                        break;
                case B_LOW_RESOURCE_WARNING:
                        free = 200;
-                       accessed = 10;
+                       secondsOld = 10;
                        break;
                case B_LOW_RESOURCE_CRITICAL:
-                       free = LONG_MAX;
-                       accessed = LONG_MAX;
+                       free = 10000;
+                       secondsOld = 0;
                        break;
        }
 
-       cache->RemoveUnusedBlocks(accessed, free);
+       block_cache* cache = (block_cache*)data;
+       MutexLocker locker(&cache->lock);
+
+       if (!locker.IsLocked()) {
+               // If our block_cache were deleted, it could be that we had
+               // been called before that deletion went through, therefore,
+               // acquiring its lock might fail.
+               return;
+       }
+
+       cache->RemoveUnusedBlocks(free, secondsOld);
 }
 
 
@@ -1742,27 +1747,6 @@
                        cache->unused_blocks.Add(block);
                }
        }
-
-       // Free some blocks according to the low memory state
-       // (if there is enough memory left, we don't free any)
-
-       int32 free = 1;
-       switch (low_resource_state(
-                       B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY)) {
-               case B_NO_LOW_RESOURCE:
-                       return;
-               case B_LOW_RESOURCE_NOTE:
-                       free = 1;
-                       break;
-               case B_LOW_RESOURCE_WARNING:
-                       free = 5;
-                       break;
-               case B_LOW_RESOURCE_CRITICAL:
-                       free = 20;
-                       break;
-       }
-
-       cache->RemoveUnusedBlocks(LONG_MAX, free);
 }
 
 
@@ -1856,7 +1840,7 @@
        }
 
        block->ref_count++;
-       block->accessed++;
+       block->last_accessed = system_time() / 1000000L;
 
        return block;
 }
@@ -2022,7 +2006,7 @@
        kprintf("%08lx %9Ld %08lx %08lx %08lx %5ld %6ld %c%c%c%c%c%c %08lx 
%08lx\n",
                (addr_t)block, block->block_number,
                (addr_t)block->current_data, (addr_t)block->original_data,
-               (addr_t)block->parent_data, block->ref_count, block->accessed,
+               (addr_t)block->parent_data, block->ref_count, 
block->LastAccess(),
                block->busy_reading ? 'r' : '-', block->busy_writing ? 'w' : 
'-',
                block->is_writing ? 'W' : '-', block->is_dirty ? 'D' : '-',
                block->unused ? 'U' : '-', block->discard ? 'D' : '-',
@@ -2039,7 +2023,7 @@
        kprintf(" original data: %p\n", block->original_data);
        kprintf(" parent data:   %p\n", block->parent_data);
        kprintf(" ref_count:     %ld\n", block->ref_count);
-       kprintf(" accessed:      %ld\n", block->accessed);
+       kprintf(" accessed:      %ld\n", block->LastAccess());
        kprintf(" flags:        ");
        if (block->busy_reading)
                kprintf(" busy_reading");
@@ -2514,6 +2498,13 @@
                        }
 
                        writer.Write();
+
+                       if ((block_cache_used_memory() / B_PAGE_SIZE)
+                                       > vm_page_num_pages() / 2) {
+                               // Try to reduce memory usage to half of the 
available
+                               // RAM at maximum
+                               cache->RemoveUnusedBlocks(500, 10);
+                       }
                }
 
                MutexLocker _(sCachesMemoryUseLock);


Other related posts:

  • » [haiku-commits] r35733 - haiku/trunk/src/system/kernel/cache - axeld