# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: henrik@henriknordstrom.net-20100528235108-\ # fvvjfwdmd0ovbvpw # target_branch: http://www.squid-cache.org/bzr/squid3/trunk/ # testament_sha1: b77080d7563b976aab0bf8bb77362627e0e3cd2d # timestamp: 2010-05-29 01:51:44 +0200 # base_revision_id: henrik@henriknordstrom.net-20100528215627-\ # agkq7l8rn7lertwg # # Begin patch === modified file 'include/MemPool.h' --- include/MemPool.h 2010-03-21 03:08:26 +0000 +++ include/MemPool.h 2010-05-28 23:51:08 +0000 @@ -1,5 +1,5 @@ -#ifndef _MEM_POOLS_H_ -#define _MEM_POOLS_H_ +#ifndef _MEM_POOL_H_ +#define _MEM_POOL_H_ /** \defgroup MemPoolsAPI Memory Management (Memory Pool Allocator) @@ -63,7 +63,6 @@ #define MEM_MAX_FREE 65535 /* ushort is max number of items per chunk */ class MemImplementingAllocator; -class MemChunk; class MemPoolStats; /// \ingroup MemPoolsAPI @@ -97,17 +96,20 @@ class MemPoolMeter { public: + MemPoolMeter(); void flush(); MemMeter alloc; MemMeter inuse; MemMeter idle; - /** account Allocations */ + + /** history Allocations */ + mgb_t gb_allocated; + mgb_t gb_oallocated; + + /** account Saved Allocations */ mgb_t gb_saved; - /** history Allocations */ - mgb_t gb_osaved; - /** account Free calls */ mgb_t gb_freed; }; @@ -130,13 +132,6 @@ MemImplementingAllocator * create(const char *label, size_t obj_size); /** - \param label Name for the pool. Displayed in stats. - \param obj_size Size of elements in MemPool. - \param chunked ?? - */ - MemImplementingAllocator * create(const char *label, size_t obj_size, bool const chunked); - - /** * Sets upper limit in bytes to amount of free ram kept in pools. This is * not strict upper limit, but a hint. When MemPools are over this limit, * totally free chunks are immediately considered for release. Otherwise @@ -197,7 +192,7 @@ \param stats Object to be filled with statistical data about pool. \retval Number of objects in use, ie. allocated. */ - virtual int getStats(MemPoolStats * stats) = 0; + virtual int getStats(MemPoolStats * stats, int accumulate = 0) = 0; virtual MemPoolMeter const &getMeter() const = 0; @@ -325,6 +320,7 @@ { public: MemImplementingAllocator(char const *aLabel, size_t aSize); + ~MemImplementingAllocator(); virtual MemPoolMeter const &getMeter() const; virtual MemPoolMeter &getMeter(); virtual void flushMetersFull(); @@ -342,111 +338,23 @@ virtual bool idleTrigger(int shift) const = 0; virtual void clean(time_t maxage) = 0; - /** Hint to the allocator - may be ignored */ - virtual void setChunkSize(size_t chunksize) {} virtual size_t objectSize() const; virtual int getInUseCount() = 0; protected: virtual void *allocate() = 0; virtual void deallocate(void *) = 0; -private: MemPoolMeter meter; + int memPID; public: MemImplementingAllocator *next; public: size_t alloc_calls; size_t free_calls; + size_t saved_calls; size_t obj_size; }; /// \ingroup MemPoolsAPI -class MemPool : public MemImplementingAllocator -{ -public: - friend class MemChunk; - MemPool(const char *label, size_t obj_size); - ~MemPool(); - void convertFreeCacheToChunkFreeCache(); - virtual void clean(time_t maxage); - - /** - \param stats Object to be filled with statistical data about pool. - \retval Number of objects in use, ie. allocated. - */ - virtual int getStats(MemPoolStats * stats); - - void createChunk(); - void *get(); - void push(void *obj); - virtual int getInUseCount(); -protected: - virtual void *allocate(); - virtual void deallocate(void *); -public: - /** - * Allows you tune chunk size of pooling. Objects are allocated in chunks - * instead of individually. This conserves memory, reduces fragmentation. - * Because of that memory can be freed also only in chunks. Therefore - * there is tradeoff between memory conservation due to chunking and free - * memory fragmentation. - * - \note As a general guideline, increase chunk size only for pools that keep - * very many items for relatively long time. - */ - virtual void setChunkSize(size_t chunksize); - - virtual bool idleTrigger(int shift) const; - - size_t chunk_size; - int chunk_capacity; - int memPID; - int chunkCount; - size_t inuse; - size_t idle; - void *freeCache; - MemChunk *nextFreeChunk; - MemChunk *Chunks; - Splay allChunks; -}; - -/// \ingroup MemPoolsAPI -class MemMalloc : public MemImplementingAllocator -{ -public: - MemMalloc(char const *label, size_t aSize); - virtual bool idleTrigger(int shift) const; - virtual void clean(time_t maxage); - - /** - \param stats Object to be filled with statistical data about pool. - \retval Number of objects in use, ie. allocated. - */ - virtual int getStats(MemPoolStats * stats); - - virtual int getInUseCount(); -protected: - virtual void *allocate(); - virtual void deallocate(void *); -private: - int inuse; -}; - -/// \ingroup MemPoolsAPI -class MemChunk -{ -public: - MemChunk(MemPool *pool); - ~MemChunk(); - void *freeList; - void *objCache; - int inuse_count; - MemChunk *nextFreeChunk; - MemChunk *next; - time_t lastref; - MemPool *pool; -}; - -/// \ingroup MemPoolsAPI class MemPoolStats { public: @@ -536,4 +444,4 @@ } -#endif /* _MEM_POOLS_H_ */ +#endif /* _MEM_POOL_H_ */ === added file 'include/MemPoolChunked.h' --- include/MemPoolChunked.h 1970-01-01 00:00:00 +0000 +++ include/MemPoolChunked.h 2010-05-28 21:53:06 +0000 @@ -0,0 +1,82 @@ +#ifndef _MEM_POOL_CHUNKED_H_ +#define _MEM_POOL_CHUNKED_H_ + +#include "MemPool.h" + +/// \ingroup MemPoolsAPI +#define MEM_PAGE_SIZE 4096 +/// \ingroup MemPoolsAPI +#define MEM_CHUNK_SIZE 4096 * 4 +/// \ingroup MemPoolsAPI +#define MEM_CHUNK_MAX_SIZE 256 * 1024 /* 2MB */ +/// \ingroup MemPoolsAPI +#define MEM_MIN_FREE 32 +/// \ingroup MemPoolsAPI +#define MEM_MAX_FREE 65535 /* ushort is max number of items per chunk */ + +class MemChunk; + +/// \ingroup MemPoolsAPI +class MemPoolChunked : public MemImplementingAllocator +{ +public: + friend class MemChunk; + MemPoolChunked(const char *label, size_t obj_size); + ~MemPoolChunked(); + void convertFreeCacheToChunkFreeCache(); + virtual void clean(time_t maxage); + + /** + \param stats Object to be filled with statistical data about pool. + \retval Number of objects in use, ie. allocated. + */ + virtual int getStats(MemPoolStats * stats, int accumulate); + + void createChunk(); + void *get(); + void push(void *obj); + virtual int getInUseCount(); +protected: + virtual void *allocate(); + virtual void deallocate(void *); +public: + /** + * Allows you tune chunk size of pooling. Objects are allocated in chunks + * instead of individually. This conserves memory, reduces fragmentation. + * Because of that memory can be freed also only in chunks. Therefore + * there is tradeoff between memory conservation due to chunking and free + * memory fragmentation. + * + \note As a general guideline, increase chunk size only for pools that keep + * very many items for relatively long time. + */ + virtual void setChunkSize(size_t chunksize); + + virtual bool idleTrigger(int shift) const; + + size_t chunk_size; + int chunk_capacity; + int memPID; + int chunkCount; + void *freeCache; + MemChunk *nextFreeChunk; + MemChunk *Chunks; + Splay allChunks; +}; + +/// \ingroup MemPoolsAPI +class MemChunk +{ +public: + MemChunk(MemPoolChunked *pool); + ~MemChunk(); + void *freeList; + void *objCache; + int inuse_count; + MemChunk *nextFreeChunk; + MemChunk *next; + time_t lastref; + MemPoolChunked *pool; +}; + +#endif /* _MEM_POOL_CHUNKED_H_ */ === added file 'include/MemPoolMalloc.h' --- include/MemPoolMalloc.h 1970-01-01 00:00:00 +0000 +++ include/MemPoolMalloc.h 2010-05-28 21:53:06 +0000 @@ -0,0 +1,47 @@ +#ifndef _MEM_POOL_MALLOC_H_ +#define _MEM_POOL_MALLOC_H_ + +/** + \defgroup MemPoolsAPI Memory Management (Memory Pool Allocator) + \ingroup Components + * + *\par + * MemPools are a pooled memory allocator running on top of malloc(). It's + * purpose is to reduce memory fragmentation and provide detailed statistics + * on memory consumption. + * + \par + * Preferably all memory allocations in Squid should be done using MemPools + * or one of the types built on top of it (i.e. cbdata). + * + \note Usually it is better to use cbdata types as these gives you additional + * safeguards in references and typechecking. However, for high usage pools where + * the cbdata functionality of cbdata is not required directly using a MemPool + * might be the way to go. + */ + +#include "MemPool.h" + +/// \ingroup MemPoolsAPI +class MemPoolMalloc : public MemImplementingAllocator +{ +public: + MemPoolMalloc(char const *label, size_t aSize); + virtual bool idleTrigger(int shift) const; + virtual void clean(time_t maxage); + + /** + \param stats Object to be filled with statistical data about pool. + \retval Number of objects in use, ie. allocated. + */ + virtual int getStats(MemPoolStats * stats, int accumulate); + + virtual int getInUseCount(); +protected: + virtual void *allocate(); + virtual void deallocate(void *); +private: +}; + + +#endif /* _MEM_POOL_MALLOC_H_ */ === modified file 'lib/Makefile.am' --- lib/Makefile.am 2009-12-19 11:56:02 +0000 +++ lib/Makefile.am 2010-05-28 21:53:06 +0000 @@ -49,6 +49,8 @@ win32lib.c libmiscutil_a_SOURCES = \ MemPool.cc \ + MemPoolChunked.cc \ + MemPoolMalloc.cc \ base64.c \ charset.c \ getfullhostname.c \ === modified file 'lib/MemPool.cc' --- lib/MemPool.cc 2010-04-14 21:04:28 +0000 +++ lib/MemPool.cc 2010-05-28 23:51:08 +0000 @@ -87,6 +87,8 @@ #endif #include "MemPool.h" +#include "MemPoolChunked.h" +#include "MemPoolMalloc.h" #define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */ #define MEM_MAX_MMAP_CHUNKS 2048 @@ -107,10 +109,6 @@ static int Pool_id_counter = 0; -/* local prototypes */ -static int memCompChunks(MemChunk * const &, MemChunk * const &); -static int memCompObjChunks(void * const &, MemChunk * const &); - MemPools & MemPools::GetInstance() { @@ -165,195 +163,6 @@ return mem_idle_limit; } -/* Compare chunks */ -static int -memCompChunks(MemChunk * const &chunkA, MemChunk * const &chunkB) -{ - if (chunkA->objCache > chunkB->objCache) - return 1; - else if (chunkA->objCache < chunkB->objCache) - return -1; - else - return 0; -} - -/* Compare object to chunk */ -static int -memCompObjChunks(void *const &obj, MemChunk * const &chunk) -{ - /* object is lower in memory than the chunks arena */ - if (obj < chunk->objCache) - return -1; - /* object is within the pool */ - if (obj < (void *) ((char *) chunk->objCache + chunk->pool->chunk_size)) - return 0; - /* object is above the pool */ - return 1; -} - -MemChunk::MemChunk(MemPool *aPool) -{ - /* should have a pool for this too - - * note that this requres: - * allocate one chunk for the pool of chunks's first chunk - * allocate a chunk from that pool - * move the contents of one chunk into the other - * free the first chunk. - */ - inuse_count = 0; - next = NULL; - pool = aPool; - - objCache = xcalloc(1, pool->chunk_size); - freeList = objCache; - void **Free = (void **)freeList; - - for (int i = 1; i < pool->chunk_capacity; i++) { - *Free = (void *) ((char *) Free + pool->obj_size); - void **nextFree = (void **)*Free; - (void) VALGRIND_MAKE_MEM_NOACCESS(Free, pool->obj_size); - Free = nextFree; - } - nextFreeChunk = pool->nextFreeChunk; - pool->nextFreeChunk = this; - - memMeterAdd(pool->getMeter().alloc, pool->chunk_capacity); - memMeterAdd(pool->getMeter().idle, pool->chunk_capacity); - pool->idle += pool->chunk_capacity; - pool->chunkCount++; - lastref = squid_curtime; - pool->allChunks.insert(this, memCompChunks); -} - -MemPool::MemPool(const char *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize) -{ - chunk_size = 0; - chunk_capacity = 0; - memPID = 0; - chunkCount = 0; - inuse = 0; - idle = 0; - freeCache = 0; - nextFreeChunk = 0; - Chunks = 0; - next = 0; - MemImplementingAllocator *last_pool; - - assert(aLabel != NULL && aSize); - - setChunkSize(MEM_CHUNK_SIZE); - - /* Append as Last */ - for (last_pool = MemPools::GetInstance().pools; last_pool && last_pool->next;) - last_pool = last_pool->next; - if (last_pool) - last_pool->next = this; - else - MemPools::GetInstance().pools = this; - - memPID = ++Pool_id_counter; -} - -MemChunk::~MemChunk() -{ - memMeterDel(pool->getMeter().alloc, pool->chunk_capacity); - memMeterDel(pool->getMeter().idle, pool->chunk_capacity); - pool->idle -= pool->chunk_capacity; - pool->chunkCount--; - pool->allChunks.remove(this, memCompChunks); - xfree(objCache); -} - -void -MemPool::push(void *obj) -{ - void **Free; - /* XXX We should figure out a sane way of avoiding having to clear - * all buffers. For example data buffers such as used by MemBuf do - * not really need to be cleared.. There was a condition based on - * the object size here, but such condition is not safe. - */ - if (doZeroOnPush) - memset(obj, 0, obj_size); - Free = (void **)obj; - *Free = freeCache; - freeCache = obj; - (void) VALGRIND_MAKE_MEM_NOACCESS(obj, obj_size); -} - -/* - * Find a chunk with a free item. - * Create new chunk on demand if no chunk with frees found. - * Insert new chunk in front of lowest ram chunk, making it preferred in future, - * and resulting slow compaction towards lowest ram area. - */ -void * -MemPool::get() -{ - void **Free; - - /* first, try cache */ - if (freeCache) { - Free = (void **)freeCache; - (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size); - freeCache = *Free; - *Free = NULL; - return Free; - } - /* then try perchunk freelist chain */ - if (nextFreeChunk == NULL) { - /* no chunk with frees, so create new one */ - createChunk(); - } - /* now we have some in perchunk freelist chain */ - MemChunk *chunk = nextFreeChunk; - - Free = (void **)chunk->freeList; - chunk->freeList = *Free; - *Free = NULL; - chunk->inuse_count++; - chunk->lastref = squid_curtime; - - if (chunk->freeList == NULL) { - /* last free in this chunk, so remove us from perchunk freelist chain */ - nextFreeChunk = chunk->nextFreeChunk; - } - (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size); - return Free; -} - -/* just create a new chunk and place it into a good spot in the chunk chain */ -void -MemPool::createChunk() -{ - MemChunk *chunk, *newChunk; - - newChunk = new MemChunk(this); - - chunk = Chunks; - if (chunk == NULL) { /* first chunk in pool */ - Chunks = newChunk; - return; - } - if (newChunk->objCache < chunk->objCache) { - /* we are lowest ram chunk, insert as first chunk */ - newChunk->next = chunk; - Chunks = newChunk; - return; - } - while (chunk->next) { - if (newChunk->objCache < chunk->next->objCache) { - /* new chunk is in lower ram, insert here */ - newChunk->next = chunk->next; - chunk->next = newChunk; - return; - } - chunk = chunk->next; - } - /* we are the worst chunk in chain, add as last */ - chunk->next = newChunk; -} - /* Change the default calue of defaultIsChunked to override * all pools - including those used before main() starts where * MemPools::GetInstance().setDefaultPoolChunking() can be called. @@ -369,49 +178,14 @@ #endif } -void -MemPool::setChunkSize(size_t chunksize) -{ - int cap; - size_t csize = chunksize; - - if (Chunks) /* unsafe to tamper */ - return; - - csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE; /* round up to page size */ - cap = csize / obj_size; - - if (cap < MEM_MIN_FREE) - cap = MEM_MIN_FREE; - if (cap * obj_size > MEM_CHUNK_MAX_SIZE) - cap = MEM_CHUNK_MAX_SIZE / obj_size; - if (cap > MEM_MAX_FREE) - cap = MEM_MAX_FREE; - if (cap < 1) - cap = 1; - - csize = cap * obj_size; - csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE; /* round up to page size */ - cap = csize / obj_size; - - chunk_capacity = cap; - chunk_size = csize; -} - MemImplementingAllocator * MemPools::create(const char *label, size_t obj_size) { - return create (label, obj_size, defaultIsChunked); -} - -MemImplementingAllocator * -MemPools::create(const char *label, size_t obj_size, bool const chunked) -{ ++poolCount; - if (chunked) - return new MemPool (label, obj_size); + if (defaultIsChunked) + return new MemPoolChunked (label, obj_size); else - return new MemMalloc (label, obj_size); + return new MemPoolMalloc (label, obj_size); } void @@ -420,40 +194,6 @@ defaultIsChunked = aBool; } -/* - * warning: we do not clean this entry from Pools assuming destruction - * is used at the end of the program only - */ -MemPool::~MemPool() -{ - MemChunk *chunk, *fchunk; - MemImplementingAllocator *find_pool, *prev_pool; - - flushMetersFull(); - clean(0); - assert(inuse == 0 && "While trying to destroy pool"); - - chunk = Chunks; - while ( (fchunk = chunk) != NULL) { - chunk = chunk->next; - delete fchunk; - } - /* TODO we should be doing something about the original Chunks pointer here. */ - - assert(MemPools::GetInstance().pools != NULL && "Called MemPool::~MemPool, but no pool exists!"); - - /* Pool clean, remove it from List and free */ - for (find_pool = MemPools::GetInstance().pools, prev_pool = NULL; (find_pool && this != find_pool); find_pool = find_pool->next) - prev_pool = find_pool; - assert(find_pool != NULL && "pool to destroy not found"); - - if (prev_pool) - prev_pool->next = next; - else - MemPools::GetInstance().pools = next; - --MemPools::GetInstance().poolCount; -} - char const * MemAllocator::objectType() const { @@ -473,17 +213,18 @@ calls = free_calls; if (calls) { - getMeter().gb_freed.count += calls; - memMeterDel(getMeter().inuse, calls); - memMeterAdd(getMeter().idle, calls); + meter.gb_freed.count += calls; free_calls = 0; } calls = alloc_calls; if (calls) { + meter.gb_allocated.count += calls; + alloc_calls = 0; + } + calls = saved_calls; + if (calls) { meter.gb_saved.count += calls; - memMeterAdd(meter.inuse, calls); - memMeterDel(meter.idle, calls); - alloc_calls = 0; + saved_calls = 0; } } @@ -491,6 +232,7 @@ MemImplementingAllocator::flushMetersFull() { flushMeters(); + getMeter().gb_allocated.bytes = getMeter().gb_allocated.count * obj_size; getMeter().gb_saved.bytes = getMeter().gb_saved.count * obj_size; getMeter().gb_freed.bytes = getMeter().gb_freed.count * obj_size; } @@ -501,11 +243,21 @@ alloc.level = 0; inuse.level = 0; idle.level = 0; + gb_allocated.count = 0; + gb_allocated.bytes = 0; + gb_oallocated.count = 0; + gb_oallocated.bytes = 0; gb_saved.count = 0; gb_saved.bytes = 0; gb_freed.count = 0; gb_freed.bytes = 0; } + +MemPoolMeter::MemPoolMeter() +{ + flush(); +} + /* * Updates all pool counters, and recreates TheMeter totals from all pools */ @@ -523,8 +275,10 @@ memMeterAdd(TheMeter.alloc, pool->getMeter().alloc.level * pool->obj_size); memMeterAdd(TheMeter.inuse, pool->getMeter().inuse.level * pool->obj_size); memMeterAdd(TheMeter.idle, pool->getMeter().idle.level * pool->obj_size); + TheMeter.gb_allocated.count += pool->getMeter().gb_allocated.count; TheMeter.gb_saved.count += pool->getMeter().gb_saved.count; TheMeter.gb_freed.count += pool->getMeter().gb_freed.count; + TheMeter.gb_allocated.bytes += pool->getMeter().gb_allocated.bytes; TheMeter.gb_saved.bytes += pool->getMeter().gb_saved.bytes; TheMeter.gb_freed.bytes += pool->getMeter().gb_freed.bytes; } @@ -532,20 +286,6 @@ } void * -MemMalloc::allocate() -{ - inuse++; - return xcalloc(1, obj_size); -} - -void -MemMalloc::deallocate(void *obj) -{ - inuse--; - xfree(obj); -} - -void * MemImplementingAllocator::alloc() { if (++alloc_calls == FLUSH_LIMIT) @@ -563,123 +303,6 @@ ++free_calls; } -int -MemPool::getInUseCount() -{ - return inuse; -} - -void * -MemPool::allocate() -{ - void *p = get(); - assert(idle); - --idle; - ++inuse; - return p; -} - -void -MemPool::deallocate(void *obj) -{ - push(obj); - assert(inuse); - --inuse; - ++idle; -} - -void -MemPool::convertFreeCacheToChunkFreeCache() -{ - void *Free; - /* - * 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 = freeCache) != NULL) { - MemChunk *chunk = NULL; - chunk = const_cast(*allChunks.find(Free, memCompObjChunks)); - assert(splayLastResult == 0); - assert(chunk->inuse_count > 0); - chunk->inuse_count--; - (void) VALGRIND_MAKE_MEM_DEFINED(Free, sizeof(void *)); - freeCache = *(void **)Free; /* remove from global cache */ - *(void **)Free = chunk->freeList; /* stuff into chunks freelist */ - (void) VALGRIND_MAKE_MEM_NOACCESS(Free, sizeof(void *)); - chunk->freeList = Free; - chunk->lastref = squid_curtime; - } - -} - -/* removes empty Chunks from pool */ -void -MemPool::clean(time_t maxage) -{ - MemChunk *chunk, *freechunk, *listTail; - time_t age; - - if (!this) - return; - if (!Chunks) - return; - - flushMetersFull(); - convertFreeCacheToChunkFreeCache(); - /* 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 Chunks->next, so first chunk is not released */ - /* Recreate nextFreeChunk list from scratch */ - - chunk = Chunks; - while ((freechunk = chunk->next) != NULL) { - age = squid_curtime - freechunk->lastref; - freechunk->nextFreeChunk = NULL; - if (freechunk->inuse_count == 0) - if (age >= maxage) { - chunk->next = freechunk->next; - delete 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 = Chunks; - nextFreeChunk = chunk; - chunk->nextFreeChunk = NULL; - - while (chunk->next) { - chunk->next->nextFreeChunk = NULL; - if (chunk->next->inuse_count < chunk_capacity) { - listTail = 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 (nextFreeChunk->inuse_count == chunk_capacity) - nextFreeChunk = nextFreeChunk->nextFreeChunk; - - return; -} - /* * Returns all cached frees to their home chunks * If chunks unreferenced age is over, destroys Idle chunk @@ -707,96 +330,10 @@ memPoolIterateDone(&iter); } -bool -MemPool::idleTrigger(int shift) const -{ - return getMeter().idle.level > (chunk_capacity << shift); -} - /* Persistent Pool stats. for GlobalStats accumulation */ static MemPoolStats pp_stats; /* - * Update MemPoolStats struct for single pool - */ -int -MemPool::getStats(MemPoolStats * stats) -{ - MemChunk *chunk; - int chunks_free = 0; - int chunks_partial = 0; - - if (stats != &pp_stats) /* need skip memset for GlobalStats accumulation */ - /* XXX Fixme */ - memset(stats, 0, sizeof(MemPoolStats)); - - clean((time_t) 555555); /* don't want to get chunks released before reporting */ - - stats->pool = this; - stats->label = objectType(); - stats->meter = &getMeter(); - stats->obj_size = obj_size; - stats->chunk_capacity = chunk_capacity; - - /* gather stats for each Chunk */ - chunk = Chunks; - while (chunk) { - if (chunk->inuse_count == 0) - chunks_free++; - else if (chunk->inuse_count < chunk_capacity) - chunks_partial++; - chunk = chunk->next; - } - - stats->chunks_alloc += chunkCount; - stats->chunks_inuse += chunkCount - chunks_free; - stats->chunks_partial += chunks_partial; - stats->chunks_free += chunks_free; - - stats->items_alloc += getMeter().alloc.level; - stats->items_inuse += getMeter().inuse.level; - stats->items_idle += getMeter().idle.level; - - stats->overhead += sizeof(MemPool) + chunkCount * sizeof(MemChunk) + strlen(objectType()) + 1; - - return getMeter().inuse.level; -} - -/* TODO extract common logic to MemAllocate */ -int -MemMalloc::getStats(MemPoolStats * stats) -{ - if (stats != &pp_stats) /* need skip memset for GlobalStats accumulation */ - /* XXX Fixme */ - memset(stats, 0, sizeof(MemPoolStats)); - - stats->pool = this; - stats->label = objectType(); - stats->meter = &getMeter(); - stats->obj_size = obj_size; - stats->chunk_capacity = 0; - - stats->chunks_alloc += 0; - stats->chunks_inuse += 0; - stats->chunks_partial += 0; - stats->chunks_free += 0; - - stats->items_alloc += getMeter().alloc.level; - stats->items_inuse += getMeter().inuse.level; - stats->items_idle += getMeter().idle.level; - - stats->overhead += sizeof(MemMalloc) + strlen(objectType()) + 1; - - return getMeter().inuse.level; -} - -int -MemMalloc::getInUseCount() -{ - return inuse; -} - -/* * Totals statistics is returned */ int @@ -814,7 +351,7 @@ /* gather all stats for Totals */ iter = memPoolIterate(); while ((pool = memPoolIterateNext(iter))) { - if (pool->getStats(&pp_stats) > 0) + if (pool->getStats(&pp_stats, 1) > 0) pools_inuse++; } memPoolIterateDone(&iter); @@ -833,7 +370,7 @@ stats->tot_items_inuse = pp_stats.items_inuse; stats->tot_items_idle = pp_stats.items_idle; - stats->tot_overhead += pp_stats.overhead + MemPools::GetInstance().poolCount * sizeof(MemPool *); + stats->tot_overhead += pp_stats.overhead + MemPools::GetInstance().poolCount * sizeof(MemAllocator *); stats->mem_idle_limit = MemPools::GetInstance().mem_idle_limit; return pools_inuse; @@ -848,19 +385,6 @@ return ((s + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*); } -MemMalloc::MemMalloc(char const *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize) { inuse = 0; } - -bool -MemMalloc::idleTrigger(int shift) const -{ - return false; -} - -void -MemMalloc::clean(time_t maxage) -{ -} - int memPoolInUseCount(MemAllocator * pool) { @@ -935,8 +459,39 @@ next(NULL), alloc_calls(0), free_calls(0), + saved_calls(0), obj_size(RoundedSize(aSize)) { + memPID = ++Pool_id_counter; + + MemImplementingAllocator *last_pool; + + assert(aLabel != NULL && aSize); + /* Append as Last */ + for (last_pool = MemPools::GetInstance().pools; last_pool && last_pool->next;) + last_pool = last_pool->next; + if (last_pool) + last_pool->next = this; + else + MemPools::GetInstance().pools = this; +} + +MemImplementingAllocator::~MemImplementingAllocator() +{ + MemImplementingAllocator *find_pool, *prev_pool; + + assert(MemPools::GetInstance().pools != NULL && "Called MemImplementingAllocator::~MemImplementingAllocator, but no pool exists!"); + + /* Pool clean, remove it from List and free */ + for (find_pool = MemPools::GetInstance().pools, prev_pool = NULL; (find_pool && this != find_pool); find_pool = find_pool->next) + prev_pool = find_pool; + assert(find_pool != NULL && "pool to destroy not found"); + + if (prev_pool) + prev_pool->next = next; + else + MemPools::GetInstance().pools = next; + --MemPools::GetInstance().poolCount; } void === added file 'lib/MemPoolChunked.cc' --- lib/MemPoolChunked.cc 1970-01-01 00:00:00 +0000 +++ lib/MemPoolChunked.cc 2010-05-28 23:51:08 +0000 @@ -0,0 +1,498 @@ + +/* + * $Id$ + * + * DEBUG: section 63 Low Level Memory Pool Management + * AUTHOR: Alex Rousskov, Andres Kroonmaa, Robert Collins + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please see the + * CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +/* + * Old way: + * xmalloc each item separately, upon free stack into idle pool array. + * each item is individually malloc()ed from system, imposing libmalloc + * overhead, and additionally we add our overhead of pointer size per item + * as we keep a list of pointer to free items. + * + * Chunking: + * xmalloc Chunk that fits at least MEM_MIN_FREE (32) items in an array, but + * limit Chunk size to MEM_CHUNK_MAX_SIZE (256K). Chunk size is rounded up to + * MEM_PAGE_SIZE (4K), trying to have chunks in multiples of VM_PAGE size. + * Minimum Chunk size is MEM_CHUNK_SIZE (16K). + * A number of items fits into a single chunk, depending on item size. + * Maximum number of items per chunk is limited to MEM_MAX_FREE (65535). + * + * We populate Chunk with a linkedlist, each node at first word of item, + * and pointing at next free item. Chunk->FreeList is pointing at first + * free node. Thus we stuff free housekeeping into the Chunk itself, and + * omit pointer overhead per item. + * + * Chunks are created on demand, and new chunks are inserted into linklist + * of chunks so that Chunks with smaller pointer value are placed closer + * to the linklist head. Head is a hotspot, servicing most of requests, so + * slow sorting occurs and Chunks in highest memory tend to become idle + * and freeable. + * + * event is registered that runs every 15 secs and checks reference time + * of each idle chunk. If a chunk is not referenced for 15 secs, it is + * released. + * + * [If mem_idle_limit is exceeded with pools, every chunk that becomes + * idle is immediately considered for release, unless this is the only + * chunk with free items in it.] (not implemented) + * + * In cachemgr output, there are new columns for chunking. Special item, + * 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. 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. + * Copyright (c) 2003, Robert Collins + */ + +#include "config.h" +#if HAVE_ASSERT_H +#include +#endif + +#include "MemPoolChunked.h" + +#define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */ +#define MEM_MAX_MMAP_CHUNKS 2048 + +#if HAVE_STRING_H +#include +#endif + +/* + * XXX This is a boundary violation between lib and src.. would be good + * if it could be solved otherwise, but left for now. + */ +extern time_t squid_curtime; + +/* local prototypes */ +static int memCompChunks(MemChunk * const &, MemChunk * const &); +static int memCompObjChunks(void * const &, MemChunk * const &); + +/* Compare chunks */ +static int +memCompChunks(MemChunk * const &chunkA, MemChunk * const &chunkB) +{ + if (chunkA->objCache > chunkB->objCache) + return 1; + else if (chunkA->objCache < chunkB->objCache) + return -1; + else + return 0; +} + +/* Compare object to chunk */ +static int +memCompObjChunks(void *const &obj, MemChunk * const &chunk) +{ + /* object is lower in memory than the chunks arena */ + if (obj < chunk->objCache) + return -1; + /* object is within the pool */ + if (obj < (void *) ((char *) chunk->objCache + chunk->pool->chunk_size)) + return 0; + /* object is above the pool */ + return 1; +} + +MemChunk::MemChunk(MemPoolChunked *aPool) +{ + /* should have a pool for this too - + * note that this requres: + * allocate one chunk for the pool of chunks's first chunk + * allocate a chunk from that pool + * move the contents of one chunk into the other + * free the first chunk. + */ + inuse_count = 0; + next = NULL; + pool = aPool; + + objCache = xcalloc(1, pool->chunk_size); + freeList = objCache; + void **Free = (void **)freeList; + + for (int i = 1; i < pool->chunk_capacity; i++) { + *Free = (void *) ((char *) Free + pool->obj_size); + void **nextFree = (void **)*Free; + (void) VALGRIND_MAKE_MEM_NOACCESS(Free, pool->obj_size); + Free = nextFree; + } + nextFreeChunk = pool->nextFreeChunk; + pool->nextFreeChunk = this; + + memMeterAdd(pool->getMeter().alloc, pool->chunk_capacity); + memMeterAdd(pool->getMeter().idle, pool->chunk_capacity); + pool->chunkCount++; + lastref = squid_curtime; + pool->allChunks.insert(this, memCompChunks); +} + +MemPoolChunked::MemPoolChunked(const char *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize) +{ + chunk_size = 0; + chunk_capacity = 0; + chunkCount = 0; + freeCache = 0; + nextFreeChunk = 0; + Chunks = 0; + next = 0; + + setChunkSize(MEM_CHUNK_SIZE); +} + +MemChunk::~MemChunk() +{ + memMeterDel(pool->getMeter().alloc, pool->chunk_capacity); + memMeterDel(pool->getMeter().idle, pool->chunk_capacity); + pool->chunkCount--; + pool->allChunks.remove(this, memCompChunks); + xfree(objCache); +} + +void +MemPoolChunked::push(void *obj) +{ + void **Free; + /* XXX We should figure out a sane way of avoiding having to clear + * all buffers. For example data buffers such as used by MemBuf do + * not really need to be cleared.. There was a condition based on + * the object size here, but such condition is not safe. + */ + if (doZeroOnPush) + memset(obj, 0, obj_size); + Free = (void **)obj; + *Free = freeCache; + freeCache = obj; + (void) VALGRIND_MAKE_MEM_NOACCESS(obj, obj_size); +} + +/* + * Find a chunk with a free item. + * Create new chunk on demand if no chunk with frees found. + * Insert new chunk in front of lowest ram chunk, making it preferred in future, + * and resulting slow compaction towards lowest ram area. + */ +void * +MemPoolChunked::get() +{ + void **Free; + + saved_calls++; + + /* first, try cache */ + if (freeCache) { + Free = (void **)freeCache; + (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size); + freeCache = *Free; + *Free = NULL; + return Free; + } + /* then try perchunk freelist chain */ + if (nextFreeChunk == NULL) { + /* no chunk with frees, so create new one */ + saved_calls--; // compensate for the ++ above + createChunk(); + } + /* now we have some in perchunk freelist chain */ + MemChunk *chunk = nextFreeChunk; + + Free = (void **)chunk->freeList; + chunk->freeList = *Free; + *Free = NULL; + chunk->inuse_count++; + chunk->lastref = squid_curtime; + + if (chunk->freeList == NULL) { + /* last free in this chunk, so remove us from perchunk freelist chain */ + nextFreeChunk = chunk->nextFreeChunk; + } + (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size); + return Free; +} + +/* just create a new chunk and place it into a good spot in the chunk chain */ +void +MemPoolChunked::createChunk() +{ + MemChunk *chunk, *newChunk; + + newChunk = new MemChunk(this); + + chunk = Chunks; + if (chunk == NULL) { /* first chunk in pool */ + Chunks = newChunk; + return; + } + if (newChunk->objCache < chunk->objCache) { + /* we are lowest ram chunk, insert as first chunk */ + newChunk->next = chunk; + Chunks = newChunk; + return; + } + while (chunk->next) { + if (newChunk->objCache < chunk->next->objCache) { + /* new chunk is in lower ram, insert here */ + newChunk->next = chunk->next; + chunk->next = newChunk; + return; + } + chunk = chunk->next; + } + /* we are the worst chunk in chain, add as last */ + chunk->next = newChunk; +} + +void +MemPoolChunked::setChunkSize(size_t chunksize) +{ + int cap; + size_t csize = chunksize; + + if (Chunks) /* unsafe to tamper */ + return; + + csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE; /* round up to page size */ + cap = csize / obj_size; + + if (cap < MEM_MIN_FREE) + cap = MEM_MIN_FREE; + if (cap * obj_size > MEM_CHUNK_MAX_SIZE) + cap = MEM_CHUNK_MAX_SIZE / obj_size; + if (cap > MEM_MAX_FREE) + cap = MEM_MAX_FREE; + if (cap < 1) + cap = 1; + + csize = cap * obj_size; + csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE; /* round up to page size */ + cap = csize / obj_size; + + chunk_capacity = cap; + chunk_size = csize; +} + +/* + * warning: we do not clean this entry from Pools assuming destruction + * is used at the end of the program only + */ +MemPoolChunked::~MemPoolChunked() +{ + MemChunk *chunk, *fchunk; + + flushMetersFull(); + clean(0); + assert(getMeter().inuse.level == 0 && "While trying to destroy pool"); + + chunk = Chunks; + while ( (fchunk = chunk) != NULL) { + chunk = chunk->next; + delete fchunk; + } + /* TODO we should be doing something about the original Chunks pointer here. */ + +} + +int +MemPoolChunked::getInUseCount() +{ + return getMeter().inuse.level; +} + +void * +MemPoolChunked::allocate() +{ + void *p = get(); + assert(meter.idle.level > 0); + memMeterDec(meter.idle); + memMeterInc(meter.inuse); + return p; +} + +void +MemPoolChunked::deallocate(void *obj) +{ + push(obj); + assert(meter.inuse.level > 0); + memMeterDec(meter.inuse); + memMeterInc(meter.idle); +} + +void +MemPoolChunked::convertFreeCacheToChunkFreeCache() +{ + void *Free; + /* + * 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 = freeCache) != NULL) { + MemChunk *chunk = NULL; + chunk = const_cast(*allChunks.find(Free, memCompObjChunks)); + assert(splayLastResult == 0); + assert(chunk->inuse_count > 0); + chunk->inuse_count--; + (void) VALGRIND_MAKE_MEM_DEFINED(Free, sizeof(void *)); + freeCache = *(void **)Free; /* remove from global cache */ + *(void **)Free = chunk->freeList; /* stuff into chunks freelist */ + (void) VALGRIND_MAKE_MEM_NOACCESS(Free, sizeof(void *)); + chunk->freeList = Free; + chunk->lastref = squid_curtime; + } + +} + +/* removes empty Chunks from pool */ +void +MemPoolChunked::clean(time_t maxage) +{ + MemChunk *chunk, *freechunk, *listTail; + time_t age; + + if (!this) + return; + if (!Chunks) + return; + + flushMetersFull(); + convertFreeCacheToChunkFreeCache(); + /* 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 Chunks->next, so first chunk is not released */ + /* Recreate nextFreeChunk list from scratch */ + + chunk = Chunks; + while ((freechunk = chunk->next) != NULL) { + age = squid_curtime - freechunk->lastref; + freechunk->nextFreeChunk = NULL; + if (freechunk->inuse_count == 0) + if (age >= maxage) { + chunk->next = freechunk->next; + delete 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 = Chunks; + nextFreeChunk = chunk; + chunk->nextFreeChunk = NULL; + + while (chunk->next) { + chunk->next->nextFreeChunk = NULL; + if (chunk->next->inuse_count < chunk_capacity) { + listTail = 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 (nextFreeChunk->inuse_count == chunk_capacity) + nextFreeChunk = nextFreeChunk->nextFreeChunk; + + return; +} + +bool +MemPoolChunked::idleTrigger(int shift) const +{ + return getMeter().idle.level > (chunk_capacity << shift); +} + +/* + * Update MemPoolStats struct for single pool + */ +int +MemPoolChunked::getStats(MemPoolStats * stats, int accumulate) +{ + MemChunk *chunk; + int chunks_free = 0; + int chunks_partial = 0; + + if (!accumulate) /* need skip memset for GlobalStats accumulation */ + memset(stats, 0, sizeof(MemPoolStats)); + + clean((time_t) 555555); /* don't want to get chunks released before reporting */ + + stats->pool = this; + stats->label = objectType(); + stats->meter = &getMeter(); + stats->obj_size = obj_size; + stats->chunk_capacity = chunk_capacity; + + /* gather stats for each Chunk */ + chunk = Chunks; + while (chunk) { + if (chunk->inuse_count == 0) + chunks_free++; + else if (chunk->inuse_count < chunk_capacity) + chunks_partial++; + chunk = chunk->next; + } + + stats->chunks_alloc += chunkCount; + stats->chunks_inuse += chunkCount - chunks_free; + stats->chunks_partial += chunks_partial; + stats->chunks_free += chunks_free; + + stats->items_alloc += getMeter().alloc.level; + stats->items_inuse += getMeter().inuse.level; + stats->items_idle += getMeter().idle.level; + + stats->overhead += sizeof(MemPoolChunked) + chunkCount * sizeof(MemChunk) + strlen(objectType()) + 1; + + return getMeter().inuse.level; +} === added file 'lib/MemPoolMalloc.cc' --- lib/MemPoolMalloc.cc 1970-01-01 00:00:00 +0000 +++ lib/MemPoolMalloc.cc 2010-05-28 21:53:06 +0000 @@ -0,0 +1,117 @@ + +/* + * $Id$ + * + * DEBUG: section 63 Low Level Memory Pool Management + * AUTHOR: Alex Rousskov, Andres Kroonmaa, Robert Collins + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please see the + * CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + + +#include "config.h" +#if HAVE_ASSERT_H +#include +#endif + +#include "MemPoolMalloc.h" + +#if HAVE_STRING_H +#include +#endif + +/* + * XXX This is a boundary violation between lib and src.. would be good + * if it could be solved otherwise, but left for now. + */ +extern time_t squid_curtime; + +void * +MemPoolMalloc::allocate() +{ + memMeterInc(meter.alloc); + memMeterInc(meter.inuse); + return xcalloc(1, obj_size); +} + +void +MemPoolMalloc::deallocate(void *obj) +{ + memMeterDec(meter.inuse); + memMeterDec(meter.alloc); + xfree(obj); +} + +/* TODO extract common logic to MemAllocate */ +int +MemPoolMalloc::getStats(MemPoolStats * stats, int accumulate) +{ + if (!accumulate) /* need skip memset for GlobalStats accumulation */ + memset(stats, 0, sizeof(MemPoolStats)); + + stats->pool = this; + stats->label = objectType(); + stats->meter = &getMeter(); + stats->obj_size = obj_size; + stats->chunk_capacity = 0; + + stats->chunks_alloc += 0; + stats->chunks_inuse += 0; + stats->chunks_partial += 0; + stats->chunks_free += 0; + + stats->items_alloc += meter.alloc.level; + stats->items_inuse += meter.inuse.level; + stats->items_idle += meter.idle.level; + + stats->overhead += sizeof(MemPoolMalloc) + strlen(objectType()) + 1; + + return meter.inuse.level; +} + +int +MemPoolMalloc::getInUseCount() +{ + return meter.inuse.level; +} + +MemPoolMalloc::MemPoolMalloc(char const *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize) +{ +} + +bool +MemPoolMalloc::idleTrigger(int shift) const +{ + return false; +} + +void +MemPoolMalloc::clean(time_t maxage) +{ +} + === modified file 'src/mem.cc' --- src/mem.cc 2010-03-21 03:08:26 +0000 +++ src/mem.cc 2010-05-28 23:51:08 +0000 @@ -580,6 +580,9 @@ MemPoolMeter *pm = mp_st->meter; const char *delim = "\t "; +#if HAVE_IOMANIP + stream.setf(std::ios_base::fixed); +#endif stream << std::setw(20) << std::left << mp_st->label << delim; stream << std::setw(4) << std::right << mp_st->obj_size << delim; @@ -627,10 +630,10 @@ stream << toKB(mp_st->obj_size * pm->idle.hwater_level) << delim; /* saved */ stream << (int)pm->gb_saved.count << delim; - stream << std::setprecision(3) << xpercent(pm->gb_saved.count, AllMeter->gb_saved.count) << delim; - stream << std::setprecision(3) << xpercent(pm->gb_saved.bytes, AllMeter->gb_saved.bytes) << delim; - stream << std::setprecision(3) << xdiv(pm->gb_saved.count - pm->gb_osaved.count, xm_deltat) << "\n"; - pm->gb_osaved.count = pm->gb_saved.count; + stream << std::setprecision(3) << xpercent(pm->gb_saved.count, AllMeter->gb_allocated.count) << delim; + stream << std::setprecision(3) << xpercent(pm->gb_saved.bytes, AllMeter->gb_allocated.bytes) << delim; + stream << std::setprecision(3) << xdiv(pm->gb_allocated.count - pm->gb_oallocated.count, xm_deltat) << "\n"; + pm->gb_oallocated.count = pm->gb_allocated.count; } static int @@ -683,7 +686,7 @@ "In Use\t\t\t\t\t" "Idle\t\t\t" "Allocations Saved\t\t\t" - "Hit Rate\t" + "Rate\t" "\n" " \t (bytes)\t" "KB/ch\t obj/ch\t" @@ -692,7 +695,7 @@ "(#)\t (KB)\t high (KB)\t high (hrs)\t %alloc\t" "(#)\t (KB)\t high (KB)\t" "(#)\t %cnt\t %vol\t" - "(#) / sec\t" + "(#)/sec\t" "\n"; xm_deltat = current_dtime - xm_time; xm_time = current_dtime; @@ -712,7 +715,7 @@ if (!mp_stats.pool) /* pool destroyed */ continue; - if (mp_stats.pool->getMeter().gb_saved.count > 0) /* this pool has been used */ + if (mp_stats.pool->getMeter().gb_allocated.count > 0) /* this pool has been used */ sortme[npools++] = mp_stats; else not_used++; @@ -746,7 +749,7 @@ PoolReport(&mp_stats, mp_total.TheMeter, stream); /* Cumulative */ - stream << "Cumulative allocated volume: "<< double_to_str(buf, 64, mp_total.TheMeter->gb_saved.bytes) << "\n"; + stream << "Cumulative allocated volume: "<< double_to_str(buf, 64, mp_total.TheMeter->gb_allocated.bytes) << "\n"; /* overhead */ stream << "Current overhead: " << mp_total.tot_overhead << " bytes (" << std::setprecision(3) << xpercent(mp_total.tot_overhead, mp_total.TheMeter->inuse.level) << "%)\n"; # Begin bundle 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 CMh8h6zJ+TSov/4u5IpwoSDFDhuo