Author: bonefish Date: 2010-06-18 23:17:11 +0200 (Fri, 18 Jun 2010) New Revision: 37170 Changeset: http://dev.haiku-os.org/changeset/37170/haiku Ticket: http://dev.haiku-os.org/ticket/5816 Modified: haiku/trunk/src/system/kernel/cache/block_cache.cpp Log: * 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. Modified: haiku/trunk/src/system/kernel/cache/block_cache.cpp =================================================================== --- haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-06-18 21:05:53 UTC (rev 37169) +++ haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-06-18 21:17:11 UTC (rev 37170) @@ -115,6 +115,7 @@ object_cache* buffer_cache; block_list unused_blocks; + uint32 unused_block_count; ConditionVariable busy_reading_condition; uint32 busy_reading_count; @@ -1260,6 +1261,7 @@ // 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 @@ 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 @@ 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 @@ // remove block from lists iterator.Remove(); + unused_block_count--; RemoveBlock(block); if (--count <= 0) @@ -1529,26 +1527,26 @@ // 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 @@ 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 @@ // 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 @@ ASSERT(block->original_data == NULL && block->parent_data == NULL); cache->unused_blocks.Add(block); + cache->unused_block_count++; } } } @@ -1816,6 +1823,7 @@ //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 @@ } 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 @@ if (block->unused) { cache->unused_blocks.Remove(block); + cache->unused_block_count--; cache->RemoveBlock(block); } else { if (block->transaction != NULL && block->parent_data != NULL