From 1cafaecaf595342ef972c727904eaeb1454bd511 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 18 Jun 2010 21:17:11 +0000 Subject: [PATCH] * Introduced block_cache::unused_block_count, which counts the elements of block_cache::unused_blocks. * block_cache::Allocate(): No longer removes unused blocks when in a low resource state. That just removed too many blocks too quickly, when the cache was actively used for writing, seriously affecting performance. * block_cache::_LowMemoryHandler(): Compute the number of unused blocks to remove depending on the total unused block number. This way we cull huge block caches with lots of old blocks much quicker. Treats part of #5816. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37170 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/cache/block_cache.cpp | 33 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/system/kernel/cache/block_cache.cpp b/src/system/kernel/cache/block_cache.cpp index bc1cff838f..08d706b979 100644 --- a/src/system/kernel/cache/block_cache.cpp +++ b/src/system/kernel/cache/block_cache.cpp @@ -115,6 +115,7 @@ struct block_cache : DoublyLinkedListLinkImpl { object_cache* buffer_cache; block_list unused_blocks; + uint32 unused_block_count; ConditionVariable busy_reading_condition; uint32 busy_reading_count; @@ -1260,6 +1261,7 @@ BlockWriter::_BlockDone(cached_block* block, hash_iterator* iterator) // the block is no longer used block->unused = true; fCache->unused_blocks.Add(block); + fCache->unused_block_count++; } TB2(BlockData(fCache, block, "after write")); @@ -1297,6 +1299,7 @@ block_cache::block_cache(int _fd, off_t numBlocks, size_t blockSize, last_transaction(NULL), transaction_hash(NULL), buffer_cache(NULL), + unused_block_count(0), busy_reading_count(0), busy_reading_waiters(false), busy_writing_count(0), @@ -1363,12 +1366,6 @@ block_cache::Free(void* buffer) void* block_cache::Allocate() { - 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(2); - } - void* block = object_cache_alloc(buffer_cache, 0); if (block != NULL) return block; @@ -1483,6 +1480,7 @@ block_cache::RemoveUnusedBlocks(int32 count, int32 minSecondsOld) // remove block from lists iterator.Remove(); + unused_block_count--; RemoveBlock(block); if (--count <= 0) @@ -1529,26 +1527,26 @@ block_cache::_LowMemoryHandler(void* data, uint32 resources, int32 level) // free some blocks according to the low memory state // (if there is enough memory left, we don't free any) + block_cache* cache = (block_cache*)data; int32 free = 0; int32 secondsOld = 0; switch (level) { case B_NO_LOW_RESOURCE: return; case B_LOW_RESOURCE_NOTE: - free = 50; + free = cache->unused_block_count / 8; secondsOld = 120; break; case B_LOW_RESOURCE_WARNING: - free = 200; + free = cache->unused_block_count / 4; secondsOld = 10; break; case B_LOW_RESOURCE_CRITICAL: - free = 10000; + free = cache->unused_block_count / 2; secondsOld = 0; break; } - block_cache* cache = (block_cache*)data; MutexLocker locker(&cache->lock); if (!locker.IsLocked()) { @@ -1558,7 +1556,14 @@ block_cache::_LowMemoryHandler(void* data, uint32 resources, int32 level) return; } +#ifdef TRACE_BLOCK_CACHE + uint32 oldUnused = cache->unused_block_count; +#endif + cache->RemoveUnusedBlocks(free, secondsOld); + + TRACE(("block_cache::_LowMemoryHandler(): %p: unused: %lu -> %lu\n", cache, + oldUnused, cache->unused_block_count)); } @@ -1576,6 +1581,7 @@ block_cache::_GetUnusedBlock() // remove block from lists iterator.Remove(); + unused_block_count--; hash_remove(hash, block); // TODO: see if parent/compare data is handled correctly here! @@ -1748,6 +1754,7 @@ put_cached_block(block_cache* cache, cached_block* block) ASSERT(block->original_data == NULL && block->parent_data == NULL); cache->unused_blocks.Add(block); + cache->unused_block_count++; } } } @@ -1816,6 +1823,7 @@ retry: //TRACE(("remove block %Ld from unused\n", blockNumber)); block->unused = false; cache->unused_blocks.Remove(block); + cache->unused_block_count--; } if (*_allocated && readBlock) { @@ -2193,8 +2201,8 @@ dump_cache(int argc, char** argv) } kprintf(" %ld blocks total, %ld dirty, %ld discarded, %ld referenced, %ld " - "busy, %ld in unused.\n", count, dirty, discarded, referenced, - cache->busy_reading_count, cache->unused_blocks.Count()); + "busy, %" B_PRIu32 " in unused.\n", count, dirty, discarded, referenced, + cache->busy_reading_count, cache->unused_block_count); hash_close(cache->hash, &iterator, false); return 0; @@ -3377,6 +3385,7 @@ block_cache_discard(void* _cache, off_t blockNumber, size_t numBlocks) if (block->unused) { cache->unused_blocks.Remove(block); + cache->unused_block_count--; cache->RemoveBlock(block); } else { if (block->transaction != NULL && block->parent_data != NULL