--------------------- PatchSet 2095 Date: 2001/04/26 17:13:03 Author: akroonmaa Branch: chunked_mempools Tag: (none) Log: Finished freelist Cache and its cleanup handler. Ready for testdrive. cleanups Members: include/MemPool.h:1.1.2.5->1.1.2.6 include/util.h:1.7.16.2->1.7.16.3 lib/MemPool.c:1.1.2.4->1.1.2.5 src/MemPoolStats.c:1.1.2.6->1.1.2.7 Index: squid/include/MemPool.h =================================================================== RCS file: /cvsroot/squid-sf//squid/include/Attic/MemPool.h,v retrieving revision 1.1.2.5 retrieving revision 1.1.2.6 diff -u -r1.1.2.5 -r1.1.2.6 --- squid/include/MemPool.h 19 Apr 2001 23:53:39 -0000 1.1.2.5 +++ squid/include/MemPool.h 26 Apr 2001 17:13:03 -0000 1.1.2.6 @@ -60,7 +60,6 @@ void *freeCache; MemChunk *nextFreeChunk; MemChunk *Chunks; - MemChunk *lastchunk; MemPoolMeter meter; splayNode *allChunks; }; @@ -68,10 +67,9 @@ struct _MemChunk { void *freeList; void *objCache; - int count; + int inuse_count; MemChunk *nextFreeChunk; MemChunk *next; - MemChunk *prev; time_t lastref; }; Index: squid/include/util.h =================================================================== RCS file: /cvsroot/squid-sf//squid/include/util.h,v retrieving revision 1.7.16.2 retrieving revision 1.7.16.3 diff -u -r1.7.16.2 -r1.7.16.3 --- squid/include/util.h 19 Apr 2001 23:53:39 -0000 1.7.16.2 +++ squid/include/util.h 26 Apr 2001 17:13:03 -0000 1.7.16.3 @@ -1,5 +1,5 @@ /* - * $Id: util.h,v 1.7.16.2 2001/04/19 23:53:39 akroonmaa Exp $ + * $Id: util.h,v 1.7.16.3 2001/04/26 17:13:03 akroonmaa Exp $ * * AUTHOR: Harvest Derived * @@ -136,6 +136,7 @@ /* gb_type operations */ #define gb_flush_limit (0x3FFFFFFF) #define gb_inc(gb, delta) { if ((gb)->bytes > gb_flush_limit || delta > gb_flush_limit) gb_flush(gb); (gb)->bytes += delta; (gb)->count++; } +#define gb_incb(gb, delta) { if ((gb)->bytes > gb_flush_limit || delta > gb_flush_limit) gb_flush(gb); (gb)->bytes += delta; } #define gb_incc(gb, delta) { if ((gb)->bytes > gb_flush_limit || delta > gb_flush_limit) gb_flush(gb); (gb)->count+= delta; } extern double gb_to_double(const gb_t *); extern const char *gb_to_str(const gb_t *); Index: squid/lib/MemPool.c =================================================================== RCS file: /cvsroot/squid-sf//squid/lib/Attic/MemPool.c,v retrieving revision 1.1.2.4 retrieving revision 1.1.2.5 diff -u -r1.1.2.4 -r1.1.2.5 --- squid/lib/MemPool.c 19 Apr 2001 23:53:39 -0000 1.1.2.4 +++ squid/lib/MemPool.c 26 Apr 2001 17:13:03 -0000 1.1.2.5 @@ -68,18 +68,20 @@ * chunk with free items in it. * * In cachemgr output, there are new columns for chunking. Special item, - * Fragm, is shown to estimate approximately fragmentation of chunked + * Frag, is shown to estimate approximately fragmentation of chunked * pools. Fragmentation is calculated by taking amount of items in use, * calculating needed amount of chunks to fit all, and then comparing to - * actual amount of chunks in use. Fragm number, in percent, is showing + * actual amount of chunks in use. Frag number, in percent, is showing * how many percent of chunks are in use excessively. 100% meaning that * twice the needed amount of chunks are in use. + * "part" item shows number of chunks partially filled. This shows how + * badly fragmentation is spread across all chunks. * * Andres Kroonmaa. */ -#define SPLAY 1 #define DISABLE_POOLS 0 +#define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */ #include #include @@ -175,15 +177,13 @@ memMeterDel(TheMeter.idle, pool->capacity * pool->obj_size); pool->idle -= pool->capacity; pool->chunkCount--; - if (pool->lastchunk == chunk) - pool->lastchunk = chunk->prev; lastPool = pool; pool->allChunks = splay_delete(chunk, pool->allChunks, (SPLAYCMP *) memCompChunks); xfree(chunk->objCache); xfree(chunk); } -inline void +void memPoolPush(MemPool * pool, void *obj) { void **Free; @@ -215,7 +215,6 @@ return Free; } /* then try perchunk freelist chain */ - if (pool->nextFreeChunk == NULL) { /* no chunk with frees, so create new one */ memPoolCreateChunk(pool); @@ -226,7 +225,7 @@ Free = chunk->freeList; chunk->freeList = *Free; *Free = NULL; - chunk->count++; + chunk->inuse_count++; chunk->lastref = squid_curtime; if (chunk->freeList == NULL) { @@ -252,7 +251,6 @@ if (new->objCache < chunk->objCache) { /* we are lowest ram chunk, insert as first chunk */ new->next = chunk; - chunk->prev = new; pool->Chunks = new; return; } @@ -261,16 +259,12 @@ /* new chunk is in lower ram, insert here */ new->next = chunk->next; chunk->next = new; - new->prev = chunk; - new->next->prev = new; return; } chunk = chunk->next; } /* we are the worst chunk in chain, add as last */ chunk->next = new; - new->prev = chunk; - pool->lastchunk = new; return; } @@ -328,14 +322,23 @@ assert(pool); } -#define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */ - void memPoolFlushMeters(MemPool * pool) { size_t calls; size_t bytes; + calls = pool->free_calls; + if (calls) { + bytes = pool->obj_size * pool->free_calls; + memMeterDel(pool->meter.inuse, calls); + memMeterAdd(pool->meter.idle, calls); + mem_pool_free_calls += calls; + + memMeterDel(TheMeter.inuse, bytes); + memMeterAdd(TheMeter.idle, bytes); + pool->free_calls = 0; + } calls = pool->alloc_calls; if (calls) { bytes = pool->obj_size * pool->alloc_calls; @@ -343,28 +346,20 @@ memMeterAdd(pool->meter.inuse, calls); gb_incc(&pool->meter.saved, calls); gb_incc(&pool->meter.total, calls); + gb_incc(&TheMeter.saved, calls); + gb_incc(&TheMeter.total, calls); + gb_incc(&mem_traffic_volume, calls); mem_pool_alloc_calls += calls; memMeterAdd(TheMeter.inuse, bytes); - gb_inc(&TheMeter.saved, bytes); - gb_inc(&TheMeter.total, bytes); - gb_inc(&mem_traffic_volume, bytes); + gb_incb(&TheMeter.saved, bytes); + gb_incb(&TheMeter.total, bytes); + gb_incb(&mem_traffic_volume, bytes); memMeterDel(TheMeter.idle, bytes); memMeterDel(pool->meter.idle, calls); pool->alloc_calls = 0; } - calls = pool->free_calls; - if (calls) { - bytes = pool->obj_size * pool->free_calls; - memMeterDel(pool->meter.inuse, calls); - memMeterAdd(pool->meter.idle, calls); - mem_pool_free_calls += calls; - - memMeterDel(TheMeter.inuse, bytes); - memMeterAdd(TheMeter.idle, bytes); - pool->free_calls = 0; - } } void * @@ -411,29 +406,84 @@ void memPoolClean(MemPool * pool, time_t maxage) { - MemChunk *chunk, *freechunk; + MemChunk *chunk, *freechunk, *listTail; + void **Free; time_t age; - chunk = pool->Chunks; -// if (!chunk) - return; - /* we start from pool->Chunks->next, so first chunk is never released */ - /* We skip chunk that is nextbest, so lowest chunk with frees is not released */ + if (!pool) + return; + if (!pool->Chunks) + return; + + + /* + * 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 + */ + + while ((Free = pool->freeCache) != NULL) { + lastPool = pool; + pool->allChunks = splay_splay(Free, pool->allChunks, (SPLAYCMP *) memCompObjChunks); + assert(splayLastResult == 0); + chunk = pool->allChunks->data; + assert(chunk->inuse_count > 0); + chunk->inuse_count--; + pool->freeCache = *Free; /* remove from global cache */ + *Free = chunk->freeList; /* stuff into chunks freelist */ + chunk->freeList = Free; + chunk->lastref = squid_curtime; + } + + /* Now we have all chunks in this pool cleared up, all free items returned to their home */ + /* We start now checking all chunks to see if we can release any */ + /* We start from pool->Chunks->next, so first chunk is not released */ + /* Recreate nextFreeChunk list from scratch */ + chunk = pool->Chunks; while ((freechunk = chunk->next) != NULL) { age = squid_curtime - freechunk->lastref; - if ((freechunk != pool->nextFreeChunk) && /* Skip chunk if its nextbest */ - (freechunk->count == 0) && (age >= maxage) - ) { - chunk->next = freechunk->next; - if (freechunk->next) - freechunk->next->prev = chunk; - memPoolChunkDestroy(pool, freechunk); - } + freechunk->nextFreeChunk = NULL; + if (freechunk->inuse_count == 0) + if (age >= maxage) { + chunk->next = freechunk->next; + memPoolChunkDestroy(pool, freechunk); + freechunk = NULL; + } if (chunk->next == NULL) break; chunk = chunk->next; } + + /* Recreate nextFreeChunk list from scratch */ + /* Populate nextFreeChunk list in order of "most filled chunk first" */ + /* in case of equal fill, put chunk in lower ram first */ + /* First (create time) chunk is always on top, no matter how full */ + + chunk = pool->Chunks; + pool->nextFreeChunk = chunk; + chunk->nextFreeChunk = NULL; + + while (chunk->next) { + chunk->next->nextFreeChunk = NULL; + if (chunk->next->inuse_count < pool->capacity) { + listTail = pool->nextFreeChunk; + while (listTail->nextFreeChunk) { + if (chunk->next->inuse_count > listTail->nextFreeChunk->inuse_count) + break; + if ((chunk->next->inuse_count == listTail->nextFreeChunk->inuse_count) && + (chunk->next->objCache < listTail->nextFreeChunk->objCache)) + break; + listTail = listTail->nextFreeChunk; + } + chunk->next->nextFreeChunk = listTail->nextFreeChunk; + listTail->nextFreeChunk = chunk->next; + } + chunk = chunk->next; + } + /* We started from 2nd chunk. If first chunk is full, remove it */ + if (pool->nextFreeChunk->inuse_count == pool->capacity) + pool->nextFreeChunk = pool->nextFreeChunk->nextFreeChunk; + return; } Index: squid/src/MemPoolStats.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/MemPoolStats.c,v retrieving revision 1.1.2.6 retrieving revision 1.1.2.7 diff -u -r1.1.2.6 -r1.1.2.7 --- squid/src/MemPoolStats.c 19 Apr 2001 23:53:39 -0000 1.1.2.6 +++ squid/src/MemPoolStats.c 26 Apr 2001 17:13:03 -0000 1.1.2.7 @@ -105,16 +105,19 @@ { int i; int cleanable = 0; + int shift = 1; + int maxage = clean_interval; + if (TheMeter.idle.level > mem_idle_limit) + maxage = shift = 0; for (i = 0; i < Pools.count; i++) { MemPool *pool = Pools.items[i]; memPoolFlushMeters(pool); - if (pool->meter.idle.level > (pool->capacity << 1) ) { - memPoolClean(pool, (time_t) clean_interval); + if (pool->meter.idle.level > (pool->capacity << shift) ) { + memPoolClean(pool, (time_t) maxage); cleanable++; } } - eventAdd("memPoolCleanIdlePools", memPoolCleanIdlePools, NULL, clean_interval, 1); } @@ -170,8 +173,8 @@ /* MemPoolMeter */ static void -memPoolMeterReport(const MemPoolMeter * pm, size_t obj_size, -//memPoolMeterReport( MemPoolMeter * pm, size_t obj_size, +//memPoolMeterReport(const MemPoolMeter * pm, size_t obj_size, +memPoolMeterReport( MemPoolMeter * pm, size_t obj_size, int alloc_count, int inuse_count, int idle_count, StoreEntry * e) { assert(pm); @@ -211,6 +214,7 @@ } static int freecount; /* need these outside memPoolReport() */ +static int partial; static int inuse; void @@ -224,11 +228,13 @@ #if CHUNKS storeAppendPrintf(e, "%4d\t %4d\t ", toKB(pool->obj_size * pool->capacity), pool->capacity); - freecount=0; + freecount=partial=0; chunk = pool->Chunks; while (chunk) { - if (chunk->count == 0) + if (chunk->inuse_count == 0) freecount++; + else if (chunk->inuse_count < pool->capacity) + partial++; chunk = chunk->next; } inuse = pool->chunkCount - freecount; @@ -240,8 +246,8 @@ excess = inuse - needed ; - storeAppendPrintf(e, "%4d\t %4d\t %4d\t %.1f\t ", - pool->chunkCount, inuse, freecount, + storeAppendPrintf(e, "%4d\t %4d\t %4d\t %4d\t %.1f\t ", + pool->chunkCount, inuse, freecount, partial, xpercent( excess, needed ) ); /* Fragmentation calculation: @@ -267,16 +273,17 @@ int chunk_count = 0; int nuse_count = 0; int free_count = 0; + int part_count = 0; int i; /* caption */ storeAppendPrintf(e, "Current memory usage:\n"); /* heading */ storeAppendPrintf(e, "Pool\t Obj Size\t" - " Chunks\t\t\t\t\t\t" + " Chunks\t\t\t\t\t\t\t" "Allocated\t\t\t\t\t In Use\t\t\t\t Idle\t\t\t Allocations Saved\t\t\t Hit Rate\t\n" " \t (bytes)\t" "KB/ch\t obj/ch\t" - "(#)\t used\t free\t %Fragm\t " + "(#)\t used\t free\t part\t %Frag\t " "(#)\t (KB)\t high (KB)\t high (hrs)\t %%Tot\t" "(#)\t (KB)\t high (KB)\t %%alloc\t" "(#)\t (KB)\t high (KB)\t" @@ -287,11 +294,13 @@ xm_deltat = current_dtime - xm_time; xm_time = current_dtime; for (i = 0; i < Pools.count ; i++) { - const MemPool *pool = Pools.items[i]; + MemPool *pool = Pools.items[i]; memPoolFlushMeters(Pools.items[i]); + memPoolClean(pool, (time_t) 555555); /* don't want to get chunks released before reporting */ if (memPoolWasUsed(pool)) { memPoolReport(pool, e); free_count += freecount; + part_count += partial; nuse_count += inuse; chunk_count += pool->chunkCount; alloc_count += pool->meter.alloc.level; @@ -305,8 +314,8 @@ overhd_size += sizeof(Pools) + Pools.capacity * sizeof(MemPool *); /* totals */ storeAppendPrintf(e, "%-20s\t %-4s\t ", "Total", "-"); - storeAppendPrintf(e, "- \t -\t %4d\t %4d\t %4d\t -\t ", - chunk_count, nuse_count, free_count); + storeAppendPrintf(e, "- \t -\t %4d\t %4d\t %4d\t %4d\t -\t ", + chunk_count, nuse_count, free_count, part_count); memPoolMeterReport(&TheMeter, 1, alloc_count, inuse_count, idle_count, e); storeAppendPrintf(e, "Cumulative allocated volume: %s\n", gb_to_str(&mem_traffic_volume));