--------------------- PatchSet 2206 Date: 2001/05/04 14:40:44 Author: akroonmaa Branch: chunked_mempools Tag: (none) Log: Implemented the new API. Dropped use of Array, use linklist instead. Implemented finally memPoolDestroy() Implemented Iterator Members: lib/MemPool.c:1.1.2.15->1.1.2.16 Index: squid/lib/MemPool.c =================================================================== RCS file: /cvsroot/squid-sf//squid/lib/Attic/MemPool.c,v retrieving revision 1.1.2.15 retrieving revision 1.1.2.16 diff -u -r1.1.2.15 -r1.1.2.16 --- squid/lib/MemPool.c 3 May 2001 14:31:39 -0000 1.1.2.15 +++ squid/lib/MemPool.c 4 May 2001 14:40:44 -0000 1.1.2.16 @@ -3,7 +3,7 @@ * $Id$ * * DEBUG: section 63 Low Level Memory Pool Management - * AUTHOR: Alex Rousskov + * AUTHOR: Alex Rousskov, Andres Kroonmaa * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- @@ -85,6 +85,9 @@ #include #include "config.h" +#if HAVE_STRING_H +#include +#endif #include "Stack.h" #include "MemPool.h" @@ -94,59 +97,87 @@ */ extern time_t squid_curtime; -/* Public user API */ -MemPool *memPoolCreate(const char *label, size_t obj_size); -void memPoolTune(MemPool * pool, size_t chunksize, int unused); -void *memPoolAlloc(MemPool * pool); -void memPoolFree(MemPool * pool, void *obj); -void memPoolDestroy(MemPool * pool); -int memPoolGetStats(MemPoolStats * stats, MemPool * pool, int index); - -/* Module housekeeping */ -void memPoolInit(void); -void memPoolClean(MemPool * pool, time_t maxage, int new_idle_limit); +/* Allocator API */ +extern MemPool *memPoolCreate(const char *label, size_t obj_size); +extern void *memPoolAlloc(MemPool * pool); +extern void memPoolFree(MemPool * pool, void *obj); +extern void memPoolDestroy(MemPool ** pool); + +extern MemPoolIterator *memPoolIterate(void); +extern MemPool *memPoolIterateNext(MemPoolIterator * iter); +extern void memPoolIterateDone(MemPoolIterator ** iter); + +/* Tune API */ +extern void memPoolSetChunkSize(MemPool * pool, size_t chunksize); +extern void memPoolSetIdleLimit(size_t new_idle_limit); + +/* Stats API */ +extern int memPoolGetStats(MemPoolStats * stats, MemPool * pool); +extern int memPoolGetGlobalStats(MemPoolGlobalStats * stats); -/* Helpers */ -void memMeterSyncHWater(MemMeter * m); +/* Module housekeeping API */ +extern void memPoolClean(time_t maxage); /* local data */ +static int mempool_initialised = 0; static int mem_idle_limit = 0; -static Array PoolArray; +static MemPool *memPools = NULL; +static int memPools_alloc = 0; + static MemPoolMeter TheMeter; +static MemPoolIterator Iterator; static int Pool_id_counter = 0; -static int bounds; static MemPool *lastPool; /* local prototypes */ static int memCompChunks(MemChunk * chunkA, MemChunk * chunkB); static int memCompObjChunks(void *obj, MemChunk * chunk); -static MemChunk * memPoolChunkNew(MemPool * pool); +static MemChunk *memPoolChunkNew(MemPool * pool); static void memPoolChunkDestroy(MemPool * pool, MemChunk * chunk); static void memPoolPush(MemPool * pool, void *obj); -static void * memPoolGet(MemPool * pool); +static void *memPoolGet(MemPool * pool); static void memPoolCreateChunk(MemPool * pool); -static void memPoolFlushMetersOne(MemPool * pool); static void memPoolFlushMeters(MemPool * pool); +static void memPoolFlushMetersFull(MemPool * pool); +static void memPoolFlushMetersAll(void); static void memPoolCleanOne(MemPool * pool, time_t maxage); -static void memPoolGetStatsOne(MemPoolStats * stats, MemPool * pool); -static void memArrayInit(Array * a); -#if UNUSED_CODE -static void memArrayClean(Array * s); -static void memArrayDestroy(Array * s); -#endif -static void memArrayAppend(Array * s, void *obj); -static void memArrayGrow(Array * a, int min_capacity); +static void memPoolInit(void); + +MemPoolIterator * +memPoolIterate(void) +{ + Iterator.pool = memPools; + return &Iterator; +} void -memMeterSyncHWater(MemMeter * m) +memPoolIterateDone(MemPoolIterator ** iter) { - assert(m); - if (m->hwater_level < m->level) { - m->hwater_level = m->level; - m->hwater_stamp = squid_curtime; - } + assert(iter); + Iterator.pool = NULL; + *iter = NULL; +} + +MemPool * +memPoolIterateNext(MemPoolIterator * iter) +{ + MemPool *pool; + assert(iter); + + pool = iter->pool; + if (!pool) + return NULL; + + iter->pool = pool->next; + return pool; +} + +void +memPoolSetIdleLimit(size_t new_idle_limit) +{ + mem_idle_limit = new_idle_limit; } /* Compare chunks */ @@ -160,6 +191,7 @@ static int memCompObjChunks(void *obj, MemChunk * chunk) { + int bounds; bounds = obj - chunk->objCache; if (bounds < 0) return -1; @@ -294,16 +326,18 @@ return; } -void +static void memPoolInit(void) { - memArrayInit(&PoolArray); + memPools = NULL; + memPools_alloc = 0; memset(&TheMeter, 0, sizeof(TheMeter)); - mem_idle_limit = 0; + mem_idle_limit = 2 * MB; + mempool_initialised = 1; } void -memPoolTune(MemPool * pool, size_t chunksize, int unused) +memPoolSetChunkSize(MemPool * pool, size_t chunksize) { int cap; size_t csize = chunksize; @@ -332,17 +366,30 @@ MemPool * memPoolCreate(const char *label, size_t obj_size) { - MemPool *pool = xcalloc(1, sizeof(MemPool)); + MemPool *pool, *last_pool; + + if (!mempool_initialised) + memPoolInit(); + + pool = xcalloc(1, sizeof(MemPool)); assert(label && obj_size); pool->label = label; pool->obj_size = obj_size; pool->obj_size = ((obj_size + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *); - memPoolTune(pool, MEM_CHUNK_SIZE, 0); + memPoolSetChunkSize(pool, MEM_CHUNK_SIZE); + /* Append as Last */ + for (last_pool = memPools; last_pool && last_pool->next;) + last_pool = last_pool->next; + if (last_pool) + last_pool->next = pool; + else + memPools = pool; + + memPools_alloc++; pool->memPID = ++Pool_id_counter; - memArrayAppend(&PoolArray, pool); return pool; } @@ -351,13 +398,39 @@ * is used at the end of the program only */ void -memPoolDestroy(MemPool * pool) +memPoolDestroy(MemPool ** pool) { + MemChunk *chunk, *fchunk; + MemPool *find_pool, *free_pool, *prev_pool; + assert(pool); + assert(*pool); + free_pool = *pool; + memPoolFlushMetersFull(free_pool); + memPoolCleanOne(free_pool, 0); + assert(free_pool->inuse == 0 && "While trying to destroy pool"); + + for (chunk = free_pool->Chunks; (fchunk = chunk) != NULL; chunk = chunk->next) + memPoolChunkDestroy(free_pool, fchunk); + + assert(memPools && "Called memPoolDestroy, but no pool exists!"); + + /* Pool clean, remove it from List and free */ + for (find_pool = memPools, prev_pool = NULL; (find_pool && free_pool != find_pool); find_pool = find_pool->next) + prev_pool = find_pool; + assert(find_pool && "pool to destroy not found"); + + if (prev_pool) + prev_pool->next = free_pool->next; + else + memPools = free_pool->next; + xfree(free_pool); + memPools_alloc--; + *pool = NULL; } static void -memPoolFlushMetersOne(MemPool * pool) +memPoolFlushMeters(MemPool * pool) { size_t calls; @@ -381,20 +454,22 @@ } } +static void +memPoolFlushMetersFull(MemPool * pool) +{ + memPoolFlushMeters(pool); + pool->meter.gb_saved.bytes = pool->meter.gb_saved.count * pool->obj_size; + pool->meter.gb_freed.bytes = pool->meter.gb_freed.count * pool->obj_size; +} + /* * Updates all pool counters, and recreates TheMeter totals from all pools */ static void -memPoolFlushMeters(MemPool * pool) +memPoolFlushMetersAll(void) { - int i; - MemPool *onePool; - if (pool) { - memPoolFlushMetersOne(pool); - pool->meter.gb_saved.bytes = pool->meter.gb_saved.count * pool->obj_size; - pool->meter.gb_freed.bytes = pool->meter.gb_freed.count * pool->obj_size; - return; - } + MemPool *pool; + MemPoolIterator *iter; TheMeter.alloc.level = 0; TheMeter.inuse.level = 0; @@ -403,18 +478,17 @@ TheMeter.gb_saved.bytes = 0; TheMeter.gb_freed.count = 0; TheMeter.gb_freed.bytes = 0; - for (i = 0; i < PoolArray.count; i++) { - onePool = PoolArray.items[i]; - memPoolFlushMetersOne(onePool); - memMeterAdd(TheMeter.alloc, onePool->meter.alloc.level * onePool->obj_size); - memMeterAdd(TheMeter.inuse, onePool->meter.inuse.level * onePool->obj_size); - memMeterAdd(TheMeter.idle, onePool->meter.idle.level * onePool->obj_size); - TheMeter.gb_saved.count += onePool->meter.gb_saved.count; - TheMeter.gb_freed.count += onePool->meter.gb_freed.count; - TheMeter.gb_saved.bytes += onePool->meter.gb_saved.count * onePool->obj_size; - TheMeter.gb_freed.bytes += onePool->meter.gb_freed.count * onePool->obj_size; - onePool->meter.gb_saved.bytes = onePool->meter.gb_saved.count * onePool->obj_size; - onePool->meter.gb_freed.bytes = onePool->meter.gb_freed.count * onePool->obj_size; + + iter = memPoolIterate(); + while ((pool = memPoolIterateNext(iter))) { + memPoolFlushMetersFull(pool); + memMeterAdd(TheMeter.alloc, pool->meter.alloc.level * pool->obj_size); + memMeterAdd(TheMeter.inuse, pool->meter.inuse.level * pool->obj_size); + memMeterAdd(TheMeter.idle, pool->meter.idle.level * pool->obj_size); + TheMeter.gb_saved.count += pool->meter.gb_saved.count; + TheMeter.gb_freed.count += pool->meter.gb_freed.count; + TheMeter.gb_saved.bytes += pool->meter.gb_saved.bytes; + TheMeter.gb_freed.bytes += pool->meter.gb_freed.bytes; } } @@ -428,13 +502,11 @@ assert(pool->idle); pool->idle--; pool->inuse++; - - assert(pool->inuse <= pool->meter.alloc.level); #else p = xcalloc(1, pool->obj_size); #endif if (++pool->alloc_calls == FLUSH_LIMIT) - memPoolFlushMetersOne(pool); + memPoolFlushMeters(pool); return p; } @@ -446,10 +518,9 @@ #if !DISABLE_POOLS memPoolPush(pool, obj); - pool->idle++; + assert(pool->inuse); pool->inuse--; - - assert(pool->idle <= pool->meter.alloc.level); + pool->idle++; #else xfree(obj); #endif @@ -457,7 +528,6 @@ } - /* removes empty Chunks from pool */ static void memPoolCleanOne(MemPool * pool, time_t maxage) @@ -471,7 +541,7 @@ if (!pool->Chunks) return; - + memPoolFlushMetersFull(pool); /* * OK, so we have to go through all the global freeCache and find the Chunk * any given Free belongs to, and stuff it into that Chunk's freelist @@ -553,50 +623,50 @@ * memPool memory usage to specified minimum. */ void -memPoolClean(MemPool * pool, time_t maxage, int new_idle_limit) +memPoolClean(time_t maxage) { - int i; - MemPool *onePool; + MemPool *pool; + MemPoolIterator *iter; + int shift = 1; - if (pool) { - memPoolFlushMetersOne(pool); - memPoolCleanOne(pool, maxage); - return; - } - if (new_idle_limit >= 0) - mem_idle_limit = new_idle_limit; - memPoolFlushMeters(NULL); + memPoolFlushMetersAll(); if (TheMeter.idle.level > mem_idle_limit) maxage = shift = 0; - for (i = 0; i < PoolArray.count; i++) { - onePool = PoolArray.items[i]; - if (onePool->meter.idle.level > (onePool->chunk_capacity << shift)) { - memPoolCleanOne(onePool, maxage); + + iter = memPoolIterate(); + while ((pool = memPoolIterateNext(iter))) { + if (pool->meter.idle.level > (pool->chunk_capacity << shift)) { + memPoolCleanOne(pool, maxage); } } + memPoolIterateDone(&iter); } +/* Persistent Pool stats. for GlobalStats accumulation */ +static MemPoolStats pp_stats; + /* * Update MemPoolStats struct for single pool */ -static void -memPoolGetStatsOne(MemPoolStats * stats, MemPool * pool) +int +memPoolGetStats(MemPoolStats * stats, MemPool * pool) { MemChunk *chunk; int chunks_free = 0; int chunks_partial = 0; - memPoolClean(pool, (time_t) 555555, -1); /* don't want to get chunks released before reporting */ + if (stats != &pp_stats) /* need skip memset for GlobalStats accumulation */ + memset(stats, 0, sizeof(MemPoolStats)); + + memPoolCleanOne(pool, (time_t) 555555); /* don't want to get chunks released before reporting */ + stats->pool = pool; stats->label = pool->label; stats->meter = &pool->meter; stats->obj_size = pool->obj_size; stats->chunk_capacity = pool->chunk_capacity; - stats->chunks_alloc += pool->chunkCount; - stats->overhead += sizeof(MemPool) + sizeof(MemPool *) + pool->chunkCount * sizeof(MemChunk); - stats->mem_idle_limit = mem_idle_limit; - + /* gather stats for each Chunk */ chunk = pool->Chunks; while (chunk) { if (chunk->inuse_count == 0) @@ -605,112 +675,60 @@ chunks_partial++; chunk = chunk->next; } - stats->chunks_free += chunks_free; - stats->chunks_partial += chunks_partial; + stats->chunks_alloc += pool->chunkCount; stats->chunks_inuse += pool->chunkCount - chunks_free; + stats->chunks_partial += chunks_partial; + stats->chunks_free += chunks_free; stats->items_alloc += pool->meter.alloc.level; stats->items_inuse += pool->meter.inuse.level; stats->items_idle += pool->meter.idle.level; + + stats->overhead += sizeof(MemPool) + pool->chunkCount * sizeof(MemChunk) + strlen(pool->label) + 1; + + return stats->items_inuse; } /* - * Get Pool accounting statistics either by pool or by index - * If neither is specified, Totals statistics is returned + * Totals statistics is returned */ int -memPoolGetStats(MemPoolStats * stats, MemPool * pool, int index) -{ - int i; - memset(stats, 0, sizeof(MemPoolStats)); - if (index >= PoolArray.count) - return 0; - if (pool) { - memPoolGetStatsOne(stats, pool); - return 0; - } - if (index >= 0) { - pool = PoolArray.items[index]; - if (!pool) - return index + 1; - memPoolGetStatsOne(stats, pool); - return index + 1; - } - /* index < 0 && pool==NULL */ - /* gather all stats for Totals */ - memPoolFlushMeters(NULL); /* recreate TheMeter */ - for (i = 0; i < PoolArray.count; i++) { - pool = PoolArray.items[i]; - memPoolGetStatsOne(stats, pool); - } - stats->pool = NULL; - stats->label = "Totals"; - stats->chunk_capacity = 0; - stats->obj_size = 0; - stats->overhead += sizeof(Array) + PoolArray.capacity * sizeof(MemPool *); - stats->mem_idle_limit = mem_idle_limit; - stats->meter = &TheMeter; - return i; -} - -static void -memArrayInit(Array * a) +memPoolGetGlobalStats(MemPoolGlobalStats * stats) { - assert(a); - memset(a, 0, sizeof(Array)); -} + int pools_inuse = 0; + MemPool *pool; + MemPoolIterator *iter; -#if UNUSED_CODE -static void -memArrayClean(Array * a) -{ - assert(a); - /* could also warn if some objects are left */ - xfree(a->items); - a->items = NULL; -} - -#endif + memset(stats, 0, sizeof(MemPoolGlobalStats)); + memset(&pp_stats, 0, sizeof(MemPoolStats)); -#if UNUSED_CODE -static void -memArrayDestroy(Array * a) -{ - assert(a); - memArrayClean(a); - xfree(a); -} + memPoolFlushMetersAll(); /* recreate TheMeter */ -#endif + /* gather all stats for Totals */ + iter = memPoolIterate(); + while ((pool = memPoolIterateNext(iter))) { + if (memPoolGetStats(&pp_stats, pool) > 0) + pools_inuse++; + } + memPoolIterateDone(&iter); + + stats->TheMeter = &TheMeter; + + stats->tot_pools_alloc = memPools_alloc; + stats->tot_pools_inuse = pools_inuse; + stats->tot_pools_mempid = Pool_id_counter; + + stats->tot_chunks_alloc = pp_stats.chunks_alloc; + stats->tot_chunks_inuse = pp_stats.chunks_inuse; + stats->tot_chunks_partial = pp_stats.chunks_partial; + stats->tot_chunks_free = pp_stats.chunks_free; + stats->tot_items_alloc = pp_stats.items_alloc; + stats->tot_items_inuse = pp_stats.items_inuse; + stats->tot_items_idle = pp_stats.items_idle; -static void -memArrayAppend(Array * a, void *obj) -{ - assert(a); - if (a->count >= a->capacity) - memArrayGrow(a, a->count + 1); - a->items[a->count++] = obj; -} + stats->tot_overhead += pp_stats.overhead + memPools_alloc * sizeof(MemPool *); + stats->mem_idle_limit = mem_idle_limit; -/* grows internal buffer to satisfy required minimal capacity */ -static void -memArrayGrow(Array * a, int min_capacity) -{ - const int min_delta = 32; - int delta; - assert(a->capacity < min_capacity); - delta = min_capacity; - /* make delta a multiple of min_delta */ - delta += min_delta - 1; - delta /= min_delta; - delta *= min_delta; - /* actual grow */ - assert(delta > 0); - a->capacity += delta; - a->items = a->items ? - xrealloc(a->items, a->capacity * sizeof(void *)) : - xmalloc(a->capacity * sizeof(void *)); - /* reset, just in case */ - memset(a->items + a->count, 0, (a->capacity - a->count) * sizeof(void *)); + return pools_inuse; }