* 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
This commit is contained in:
parent
1cdc3cbbe4
commit
1cafaecaf5
|
@ -115,6 +115,7 @@ struct block_cache : DoublyLinkedListLinkImpl<block_cache> {
|
||||||
|
|
||||||
object_cache* buffer_cache;
|
object_cache* buffer_cache;
|
||||||
block_list unused_blocks;
|
block_list unused_blocks;
|
||||||
|
uint32 unused_block_count;
|
||||||
|
|
||||||
ConditionVariable busy_reading_condition;
|
ConditionVariable busy_reading_condition;
|
||||||
uint32 busy_reading_count;
|
uint32 busy_reading_count;
|
||||||
|
@ -1260,6 +1261,7 @@ BlockWriter::_BlockDone(cached_block* block, hash_iterator* iterator)
|
||||||
// the block is no longer used
|
// the block is no longer used
|
||||||
block->unused = true;
|
block->unused = true;
|
||||||
fCache->unused_blocks.Add(block);
|
fCache->unused_blocks.Add(block);
|
||||||
|
fCache->unused_block_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
TB2(BlockData(fCache, block, "after write"));
|
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),
|
last_transaction(NULL),
|
||||||
transaction_hash(NULL),
|
transaction_hash(NULL),
|
||||||
buffer_cache(NULL),
|
buffer_cache(NULL),
|
||||||
|
unused_block_count(0),
|
||||||
busy_reading_count(0),
|
busy_reading_count(0),
|
||||||
busy_reading_waiters(false),
|
busy_reading_waiters(false),
|
||||||
busy_writing_count(0),
|
busy_writing_count(0),
|
||||||
|
@ -1363,12 +1366,6 @@ block_cache::Free(void* buffer)
|
||||||
void*
|
void*
|
||||||
block_cache::Allocate()
|
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);
|
void* block = object_cache_alloc(buffer_cache, 0);
|
||||||
if (block != NULL)
|
if (block != NULL)
|
||||||
return block;
|
return block;
|
||||||
|
@ -1483,6 +1480,7 @@ block_cache::RemoveUnusedBlocks(int32 count, int32 minSecondsOld)
|
||||||
|
|
||||||
// remove block from lists
|
// remove block from lists
|
||||||
iterator.Remove();
|
iterator.Remove();
|
||||||
|
unused_block_count--;
|
||||||
RemoveBlock(block);
|
RemoveBlock(block);
|
||||||
|
|
||||||
if (--count <= 0)
|
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
|
// free some blocks according to the low memory state
|
||||||
// (if there is enough memory left, we don't free any)
|
// (if there is enough memory left, we don't free any)
|
||||||
|
|
||||||
|
block_cache* cache = (block_cache*)data;
|
||||||
int32 free = 0;
|
int32 free = 0;
|
||||||
int32 secondsOld = 0;
|
int32 secondsOld = 0;
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case B_NO_LOW_RESOURCE:
|
case B_NO_LOW_RESOURCE:
|
||||||
return;
|
return;
|
||||||
case B_LOW_RESOURCE_NOTE:
|
case B_LOW_RESOURCE_NOTE:
|
||||||
free = 50;
|
free = cache->unused_block_count / 8;
|
||||||
secondsOld = 120;
|
secondsOld = 120;
|
||||||
break;
|
break;
|
||||||
case B_LOW_RESOURCE_WARNING:
|
case B_LOW_RESOURCE_WARNING:
|
||||||
free = 200;
|
free = cache->unused_block_count / 4;
|
||||||
secondsOld = 10;
|
secondsOld = 10;
|
||||||
break;
|
break;
|
||||||
case B_LOW_RESOURCE_CRITICAL:
|
case B_LOW_RESOURCE_CRITICAL:
|
||||||
free = 10000;
|
free = cache->unused_block_count / 2;
|
||||||
secondsOld = 0;
|
secondsOld = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
block_cache* cache = (block_cache*)data;
|
|
||||||
MutexLocker locker(&cache->lock);
|
MutexLocker locker(&cache->lock);
|
||||||
|
|
||||||
if (!locker.IsLocked()) {
|
if (!locker.IsLocked()) {
|
||||||
|
@ -1558,7 +1556,14 @@ block_cache::_LowMemoryHandler(void* data, uint32 resources, int32 level)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACE_BLOCK_CACHE
|
||||||
|
uint32 oldUnused = cache->unused_block_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
cache->RemoveUnusedBlocks(free, secondsOld);
|
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
|
// remove block from lists
|
||||||
iterator.Remove();
|
iterator.Remove();
|
||||||
|
unused_block_count--;
|
||||||
hash_remove(hash, block);
|
hash_remove(hash, block);
|
||||||
|
|
||||||
// TODO: see if parent/compare data is handled correctly here!
|
// 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
|
ASSERT(block->original_data == NULL
|
||||||
&& block->parent_data == NULL);
|
&& block->parent_data == NULL);
|
||||||
cache->unused_blocks.Add(block);
|
cache->unused_blocks.Add(block);
|
||||||
|
cache->unused_block_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1816,6 +1823,7 @@ retry:
|
||||||
//TRACE(("remove block %Ld from unused\n", blockNumber));
|
//TRACE(("remove block %Ld from unused\n", blockNumber));
|
||||||
block->unused = false;
|
block->unused = false;
|
||||||
cache->unused_blocks.Remove(block);
|
cache->unused_blocks.Remove(block);
|
||||||
|
cache->unused_block_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*_allocated && readBlock) {
|
if (*_allocated && readBlock) {
|
||||||
|
@ -2193,8 +2201,8 @@ dump_cache(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf(" %ld blocks total, %ld dirty, %ld discarded, %ld referenced, %ld "
|
kprintf(" %ld blocks total, %ld dirty, %ld discarded, %ld referenced, %ld "
|
||||||
"busy, %ld in unused.\n", count, dirty, discarded, referenced,
|
"busy, %" B_PRIu32 " in unused.\n", count, dirty, discarded, referenced,
|
||||||
cache->busy_reading_count, cache->unused_blocks.Count());
|
cache->busy_reading_count, cache->unused_block_count);
|
||||||
|
|
||||||
hash_close(cache->hash, &iterator, false);
|
hash_close(cache->hash, &iterator, false);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3377,6 +3385,7 @@ block_cache_discard(void* _cache, off_t blockNumber, size_t numBlocks)
|
||||||
|
|
||||||
if (block->unused) {
|
if (block->unused) {
|
||||||
cache->unused_blocks.Remove(block);
|
cache->unused_blocks.Remove(block);
|
||||||
|
cache->unused_block_count--;
|
||||||
cache->RemoveBlock(block);
|
cache->RemoveBlock(block);
|
||||||
} else {
|
} else {
|
||||||
if (block->transaction != NULL && block->parent_data != NULL
|
if (block->transaction != NULL && block->parent_data != NULL
|
||||||
|
|
Loading…
Reference in New Issue