Author: axeld Date: 2010-02-24 15:43:20 +0100 (Wed, 24 Feb 2010) New Revision: 35601 Changeset: http://dev.haiku-os.org/changeset/35601/haiku Modified: haiku/trunk/headers/private/kernel/slab/ObjectDepot.h haiku/trunk/headers/private/kernel/slab/Slab.h haiku/trunk/src/system/kernel/cache/block_cache.cpp haiku/trunk/src/system/kernel/slab/HashedObjectCache.cpp haiku/trunk/src/system/kernel/slab/HashedObjectCache.h haiku/trunk/src/system/kernel/slab/ObjectCache.cpp haiku/trunk/src/system/kernel/slab/ObjectCache.h haiku/trunk/src/system/kernel/slab/ObjectDepot.cpp haiku/trunk/src/system/kernel/slab/Slab.cpp haiku/trunk/src/system/kernel/slab/SmallObjectCache.cpp haiku/trunk/src/system/kernel/slab/SmallObjectCache.h haiku/trunk/src/system/kernel/slab/allocator.cpp haiku/trunk/src/system/kernel/vm/vm.cpp Log: * The low resource handler now empties the cache depot's magazines; before, they were never freed unless the cache was destroyed (I just wondered why my system would bury >1G in the magazines). * Made the magazine capacity variable per cache, ie. for larger objects, it's not a good idea to have 64*CPU buffers lying around in the worst case. * Furthermore, the create_object_cache_etc()/object_depot_init() now have arguments for the magazine capacity as well as the maximum number of full unused magazines. * By default, you might want to initialize both to zero, as then some hopefully usable defaults are computed. Otherwise (the only current example is the vm_page_mapping cache) you can just put in the values you'd want there. The page mapping cache uses larger values, as its objects are usually allocated and deleted in larger chunks. * Beware, though, I couldn't test these changes yet as Qemu didn't like to run today. I'll test these changes on another machine now. Modified: haiku/trunk/headers/private/kernel/slab/ObjectDepot.h =================================================================== --- haiku/trunk/headers/private/kernel/slab/ObjectDepot.h 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/headers/private/kernel/slab/ObjectDepot.h 2010-02-24 14:43:20 UTC (rev 35601) @@ -1,4 +1,5 @@ /* + * Copyright 2010, Axel Dörfler. All Rights Reserved. * Copyright 2007, Hugo Santos. All Rights Reserved. * Distributed under the terms of the MIT License. */ @@ -19,9 +20,11 @@ DepotMagazine* empty; size_t full_count; size_t empty_count; + size_t max_count; + size_t magazine_capacity; struct depot_cpu_store* stores; + void* cookie; - void* cookie; void (*return_object)(struct object_depot* depot, void* cookie, void* object, uint32 flags); } object_depot; @@ -31,7 +34,8 @@ extern "C" { #endif -status_t object_depot_init(object_depot* depot, uint32 flags, void* cookie, +status_t object_depot_init(object_depot* depot, size_t capacity, + size_t maxCount, uint32 flags, void* cookie, void (*returnObject)(object_depot* depot, void* cookie, void* object, uint32 flags)); void object_depot_destroy(object_depot* depot, uint32 flags); @@ -45,4 +49,5 @@ } #endif + #endif /* _SLAB_OBJECT_DEPOT_H_ */ Modified: haiku/trunk/headers/private/kernel/slab/Slab.h =================================================================== --- haiku/trunk/headers/private/kernel/slab/Slab.h 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/headers/private/kernel/slab/Slab.h 2010-02-24 14:43:20 UTC (rev 35601) @@ -1,5 +1,5 @@ /* - * Copyright 2008, Axel Dörfler. All Rights Reserved. + * Copyright 2008-2010, Axel Dörfler. All Rights Reserved. * Copyright 2007, Hugo Santos. All Rights Reserved. * * Distributed under the terms of the MIT License. @@ -42,11 +42,12 @@ extern "C" { #endif -object_cache* create_object_cache(const char* name, size_t object_size, +object_cache* create_object_cache(const char* name, size_t objectSize, size_t alignment, void* cookie, object_cache_constructor constructor, - object_cache_destructor); -object_cache* create_object_cache_etc(const char* name, size_t object_size, - size_t alignment, size_t max_byte_usage, uint32 flags, void* cookie, + object_cache_destructor destructor); +object_cache* create_object_cache_etc(const char* name, size_t objectSize, + size_t alignment, size_t maxByteUsage, size_t magazineCapacity, + size_t maxMagazineCount, uint32 flags, void* cookie, object_cache_constructor constructor, object_cache_destructor destructor, object_cache_reclaimer reclaimer); Modified: haiku/trunk/src/system/kernel/cache/block_cache.cpp =================================================================== --- haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -1329,7 +1329,7 @@ mutex_init(&lock, "block cache"); buffer_cache = create_object_cache_etc("block cache buffers", block_size, - 8, 0, CACHE_LARGE_SLAB, NULL, NULL, NULL, NULL); + 8, 0, 0, 0, CACHE_LARGE_SLAB, NULL, NULL, NULL, NULL); if (buffer_cache == NULL) return B_NO_MEMORY; @@ -1472,7 +1472,7 @@ if (block->is_dirty && !block->discard) { if (block->busy_writing) continue; - + BlockWriter::WriteBlock(this, block); } @@ -2022,7 +2022,7 @@ (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, - block->busy_reading ? 'r' : '-', block->busy_writing ? 'w' : '-', + block->busy_reading ? 'r' : '-', block->busy_writing ? 'w' : '-', block->is_writing ? 'W' : '-', block->is_dirty ? 'D' : '-', block->unused ? 'U' : '-', block->discard ? 'D' : '-', (addr_t)block->transaction, @@ -2587,7 +2587,7 @@ block_cache_init(void) { sBlockCache = create_object_cache_etc("cached blocks", sizeof(cached_block), - 8, 0, CACHE_LARGE_SLAB, NULL, NULL, NULL, NULL); + 8, 0, 0, 0, CACHE_LARGE_SLAB, NULL, NULL, NULL, NULL); if (sBlockCache == NULL) return B_NO_MEMORY; @@ -3299,7 +3299,7 @@ } hash_close(cache->hash, &iterator, false); - + status_t status = writer.Write(); locker.Unlock(); Modified: haiku/trunk/src/system/kernel/slab/HashedObjectCache.cpp =================================================================== --- haiku/trunk/src/system/kernel/slab/HashedObjectCache.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/HashedObjectCache.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -51,7 +51,8 @@ /*static*/ HashedObjectCache* HashedObjectCache::Create(const char* name, size_t object_size, - size_t alignment, size_t maximum, uint32 flags, void* cookie, + size_t alignment, size_t maximum, size_t magazineCapacity, + size_t maxMagazineCount, uint32 flags, void* cookie, object_cache_constructor constructor, object_cache_destructor destructor, object_cache_reclaimer reclaimer) { @@ -71,8 +72,9 @@ cache->hash_table.Resize(buffer, hashSize, true); - if (cache->Init(name, object_size, alignment, maximum, flags, cookie, - constructor, destructor, reclaimer) != B_OK) { + if (cache->Init(name, object_size, alignment, maximum, magazineCapacity, + maxMagazineCount, flags, cookie, constructor, destructor, + reclaimer) != B_OK) { cache->Delete(); return NULL; } Modified: haiku/trunk/src/system/kernel/slab/HashedObjectCache.h =================================================================== --- haiku/trunk/src/system/kernel/slab/HashedObjectCache.h 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/HashedObjectCache.h 2010-02-24 14:43:20 UTC (rev 35601) @@ -24,6 +24,8 @@ static HashedObjectCache* Create(const char* name, size_t object_size, size_t alignment, size_t maximum, + size_t magazineCapacity, + size_t maxMagazineCount, uint32 flags, void* cookie, object_cache_constructor constructor, object_cache_destructor destructor, Modified: haiku/trunk/src/system/kernel/slab/ObjectCache.cpp =================================================================== --- haiku/trunk/src/system/kernel/slab/ObjectCache.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/ObjectCache.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -1,5 +1,5 @@ /* - * Copyright 2008, Axel Dörfler. All Rights Reserved. + * Copyright 2008-2010, Axel Dörfler. All Rights Reserved. * Copyright 2007, Hugo Santos. All Rights Reserved. * * Distributed under the terms of the MIT License. @@ -40,10 +40,10 @@ status_t -ObjectCache::Init(const char* name, size_t objectSize, - size_t alignment, size_t maximum, uint32 flags, void* cookie, - object_cache_constructor constructor, object_cache_destructor destructor, - object_cache_reclaimer reclaimer) +ObjectCache::Init(const char* name, size_t objectSize, size_t alignment, + size_t maximum, size_t magazineCapacity, size_t maxMagazineCount, + uint32 flags, void* cookie, object_cache_constructor constructor, + object_cache_destructor destructor, object_cache_reclaimer reclaimer) { strlcpy(this->name, name, sizeof(this->name)); @@ -86,9 +86,17 @@ this->flags |= CACHE_NO_DEPOT; if (!(this->flags & CACHE_NO_DEPOT)) { - status_t status = object_depot_init(&depot, flags, this, - object_cache_return_object_wrapper); - if (status < B_OK) { + // Determine usable magazine configuration values if none had been given + if (magazineCapacity == 0) { + magazineCapacity = objectSize < 256 + ? 32 : (objectSize < 512 ? 16 : 8); + } + if (maxMagazineCount == 0) + maxMagazineCount = magazineCapacity / 2; + + status_t status = object_depot_init(&depot, magazineCapacity, + maxMagazineCount, flags, this, object_cache_return_object_wrapper); + if (status != B_OK) { mutex_destroy(&lock); return status; } Modified: haiku/trunk/src/system/kernel/slab/ObjectCache.h =================================================================== --- haiku/trunk/src/system/kernel/slab/ObjectCache.h 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/ObjectCache.h 2010-02-24 14:43:20 UTC (rev 35601) @@ -1,5 +1,5 @@ /* - * Copyright 2008, Axel Dörfler. All Rights Reserved. + * Copyright 2008-2010, Axel Dörfler. All Rights Reserved. * Copyright 2007, Hugo Santos. All Rights Reserved. * * Distributed under the terms of the MIT License. @@ -80,7 +80,9 @@ status_t Init(const char* name, size_t objectSize, size_t alignment, size_t maximum, - uint32 flags, void* cookie, + size_t magazineCapacity, + size_t maxMagazineCount, uint32 flags, + void* cookie, object_cache_constructor constructor, object_cache_destructor destructor, object_cache_reclaimer reclaimer); Modified: haiku/trunk/src/system/kernel/slab/ObjectDepot.cpp =================================================================== --- haiku/trunk/src/system/kernel/slab/ObjectDepot.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/ObjectDepot.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -19,10 +19,6 @@ #include "slab_private.h" -static const int kMagazineCapacity = 32; - // TODO: Should be dynamically tuned per cache. - - struct DepotMagazine { DepotMagazine* next; uint16 current_round; @@ -80,14 +76,15 @@ static DepotMagazine* -alloc_magazine(uint32 flags) +alloc_magazine(object_depot* depot, uint32 flags) { DepotMagazine* magazine = (DepotMagazine*)slab_internal_alloc( - sizeof(DepotMagazine) + kMagazineCapacity * sizeof(void*), flags); + sizeof(DepotMagazine) + depot->magazine_capacity * sizeof(void*), + flags); if (magazine) { magazine->next = NULL; magazine->current_round = 0; - magazine->round_count = kMagazineCapacity; + magazine->round_count = depot->magazine_capacity; } return magazine; @@ -113,6 +110,8 @@ static bool exchange_with_full(object_depot* depot, DepotMagazine*& magazine) { + ASSERT(magazine->IsEmpty()); + SpinLocker _(depot->inner_lock); if (depot->full == NULL) @@ -128,8 +127,11 @@ static bool -exchange_with_empty(object_depot* depot, DepotMagazine*& magazine) +exchange_with_empty(object_depot* depot, DepotMagazine*& magazine, + DepotMagazine*& freeMagazine) { + ASSERT(magazine == NULL || magazine->IsFull()); + SpinLocker _(depot->inner_lock); if (depot->empty == NULL) @@ -137,9 +139,12 @@ depot->empty_count--; - if (magazine) { - _push(depot->full, magazine); - depot->full_count++; + if (magazine != NULL) { + if (depot->full_count < depot->max_count) { + _push(depot->full, magazine); + depot->full_count++; + } else + freeMagazine = magazine; } magazine = _pop(depot->empty); @@ -168,13 +173,15 @@ status_t -object_depot_init(object_depot* depot, uint32 flags, void* cookie, - void (*return_object)(object_depot* depot, void* cookie, void* object, - uint32 flags)) +object_depot_init(object_depot* depot, size_t capacity, size_t maxCount, + uint32 flags, void* cookie, void (*return_object)(object_depot* depot, + void* cookie, void* object, uint32 flags)) { depot->full = NULL; depot->empty = NULL; depot->full_count = depot->empty_count = 0; + depot->max_count = maxCount; + depot->magazine_capacity = capacity; rw_lock_init(&depot->outer_lock, "object depot"); B_INITIALIZE_SPINLOCK(&depot->inner_lock); @@ -245,6 +252,8 @@ int object_depot_store(object_depot* depot, void* object, uint32 flags) { + DepotMagazine* freeMagazine = NULL; + ReadLocker readLocker(depot->outer_lock); InterruptsLocker interruptsLocker; @@ -256,18 +265,31 @@ // we return the object directly to the slab. while (true) { - if (store->loaded && store->loaded->Push(object)) + if (store->loaded != NULL && store->loaded->Push(object)) return 1; - if ((store->previous && store->previous->IsEmpty()) - || exchange_with_empty(depot, store->previous)) { + if ((store->previous != NULL && store->previous->IsEmpty()) + || exchange_with_empty(depot, store->previous, freeMagazine)) { std::swap(store->loaded, store->previous); + + if (freeMagazine != NULL) { + // Free the magazine that didn't have space in the list + interruptsLocker.Unlock(); + readLocker.Unlock(); + + empty_magazine(depot, freeMagazine, flags); + + readLocker.Lock(); + interruptsLocker.Lock(); + + store = object_depot_cpu(depot); + } } else { // allocate a new empty magazine interruptsLocker.Unlock(); readLocker.Unlock(); - DepotMagazine* magazine = alloc_magazine(flags); + DepotMagazine* magazine = alloc_magazine(depot, flags); if (magazine == NULL) return 0; Modified: haiku/trunk/src/system/kernel/slab/Slab.cpp =================================================================== --- haiku/trunk/src/system/kernel/slab/Slab.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/Slab.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -413,6 +413,11 @@ if (cache->reclaimer) cache->reclaimer(cache->cookie, level); + if ((cache->flags & CACHE_NO_DEPOT) == 0) { + object_depot_make_empty(&cache->depot, 0); + // TODO: what flags? + } + MutexLocker cacheLocker(cache->lock); size_t minimumAllowed; @@ -540,16 +545,16 @@ void* cookie, object_cache_constructor constructor, object_cache_destructor destructor) { - return create_object_cache_etc(name, object_size, alignment, 0, 0, cookie, - constructor, destructor, NULL); + return create_object_cache_etc(name, object_size, alignment, 0, 0, 0, 0, + cookie, constructor, destructor, NULL); } object_cache* create_object_cache_etc(const char* name, size_t objectSize, size_t alignment, - size_t maximum, uint32 flags, void* cookie, - object_cache_constructor constructor, object_cache_destructor destructor, - object_cache_reclaimer reclaimer) + size_t maximum, size_t magazineCapacity, size_t maxMagazineCount, + uint32 flags, void* cookie, object_cache_constructor constructor, + object_cache_destructor destructor, object_cache_reclaimer reclaimer) { ObjectCache* cache; @@ -557,10 +562,12 @@ cache = NULL; } else if (objectSize <= 256) { cache = SmallObjectCache::Create(name, objectSize, alignment, maximum, - flags, cookie, constructor, destructor, reclaimer); + magazineCapacity, maxMagazineCount, flags, cookie, constructor, + destructor, reclaimer); } else { - cache = HashedObjectCache::Create(name, objectSize, alignment, - maximum, flags, cookie, constructor, destructor, reclaimer); + cache = HashedObjectCache::Create(name, objectSize, alignment, maximum, + magazineCapacity, maxMagazineCount, flags, cookie, constructor, + destructor, reclaimer); } if (cache != NULL) { Modified: haiku/trunk/src/system/kernel/slab/SmallObjectCache.cpp =================================================================== --- haiku/trunk/src/system/kernel/slab/SmallObjectCache.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/SmallObjectCache.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -21,7 +21,8 @@ /*static*/ SmallObjectCache* SmallObjectCache::Create(const char* name, size_t object_size, - size_t alignment, size_t maximum, uint32 flags, void* cookie, + size_t alignment, size_t maximum, size_t magazineCapacity, + size_t maxMagazineCount, uint32 flags, void* cookie, object_cache_constructor constructor, object_cache_destructor destructor, object_cache_reclaimer reclaimer) { @@ -31,8 +32,9 @@ SmallObjectCache* cache = new(buffer) SmallObjectCache(); - if (cache->Init(name, object_size, alignment, maximum, flags, cookie, - constructor, destructor, reclaimer) != B_OK) { + if (cache->Init(name, object_size, alignment, maximum, magazineCapacity, + maxMagazineCount, flags, cookie, constructor, destructor, + reclaimer) != B_OK) { cache->Delete(); return NULL; } Modified: haiku/trunk/src/system/kernel/slab/SmallObjectCache.h =================================================================== --- haiku/trunk/src/system/kernel/slab/SmallObjectCache.h 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/SmallObjectCache.h 2010-02-24 14:43:20 UTC (rev 35601) @@ -14,6 +14,8 @@ struct SmallObjectCache : ObjectCache { static SmallObjectCache* Create(const char* name, size_t object_size, size_t alignment, size_t maximum, + size_t magazineCapacity, + size_t maxMagazineCount, uint32 flags, void* cookie, object_cache_constructor constructor, object_cache_destructor destructor, Modified: haiku/trunk/src/system/kernel/slab/allocator.cpp =================================================================== --- haiku/trunk/src/system/kernel/slab/allocator.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/slab/allocator.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -180,8 +180,8 @@ if (size > 2048) flags |= CACHE_NO_DEPOT; - sBlockCaches[index] = create_object_cache_etc(name, size, 0, 0, flags, - NULL, NULL, NULL, NULL); + sBlockCaches[index] = create_object_cache_etc(name, size, 0, 0, 0, 0, + flags, NULL, NULL, NULL, NULL); if (sBlockCaches[index] == NULL) panic("allocator: failed to init block cache"); } Modified: haiku/trunk/src/system/kernel/vm/vm.cpp =================================================================== --- haiku/trunk/src/system/kernel/vm/vm.cpp 2010-02-24 14:10:17 UTC (rev 35600) +++ haiku/trunk/src/system/kernel/vm/vm.cpp 2010-02-24 14:43:20 UTC (rev 35601) @@ -1,6 +1,6 @@ /* * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@xxxxxxx - * Copyright 2002-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * Copyright 2002-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -3395,8 +3395,8 @@ // create the object cache for the page mappings gPageMappingsObjectCache = create_object_cache_etc("page mappings", - sizeof(vm_page_mapping), 0, 0, CACHE_LARGE_SLAB, NULL, NULL, NULL, - NULL); + sizeof(vm_page_mapping), 0, 0, 64, 128, CACHE_LARGE_SLAB, NULL, NULL, + NULL, NULL); if (gPageMappingsObjectCache == NULL) panic("failed to create page mappings object cache");