=== modified file 'src/mem.cc' --- src/mem.cc 2010-10-28 18:52:59 +0000 +++ src/mem.cc 2011-03-31 20:11:46 +0000 @@ -44,85 +44,99 @@ #include "SquidTime.h" #if HAVE_IOMANIP #include #endif #if HAVE_OSTREAM #include #endif /* module globals */ const size_t squidSystemPageSize=getpagesize(); /* local prototypes */ static void memStringStats(std::ostream &); /* module locals */ static MemAllocator *MemPools[MEM_MAX]; static double xm_time = 0; static double xm_deltat = 0; +/* all pools are ready to be used */ +static bool MemIsInitialized=false; + /* string pools */ -#define mem_str_pool_count 3 +#define mem_str_pool_count 6 static const struct { const char *name; size_t obj_size; } - +/* note: string pools must be sorted in ascending order by size */ StrPoolsAttrs[mem_str_pool_count] = { - { "Short Strings", MemAllocator::RoundedSize(36), - }, /* to fit rfc1123 and similar */ + }, /* to fit rfc1123 and similar */ { "Medium Strings", MemAllocator::RoundedSize(128), - }, /* to fit most urls */ + }, /* to fit most urls */ { "Long Strings", MemAllocator::RoundedSize(512) - } /* other */ + }, + { + "1KB Strings", MemAllocator::RoundedSize(1024) + }, + { + "4KB Strings", MemAllocator::RoundedSize(4096) + }, + { + "16KB Strings", MemAllocator::RoundedSize(1024*16) + } }; +// must be at least one byte bigger than the biggest string size +static const size_t SizeOfStringBeforePoolsAreInitialized = 1024*16+4; + static struct { MemAllocator *pool; } StrPools[mem_str_pool_count]; static MemMeter StrCountMeter; static MemMeter StrVolumeMeter; static MemMeter HugeBufCountMeter; static MemMeter HugeBufVolumeMeter; /* local routines */ static void memStringStats(std::ostream &stream) { int i; int pooled_count = 0; size_t pooled_volume = 0; /* heading */ stream << "String Pool\t Impact\t\t\n \t (%strings)\t (%volume)\n"; /* table body */ - for (i = 0; i < mem_str_pool_count; i++) { + for (i = 0; i < mem_str_pool_count; ++i) { const MemAllocator *pool = StrPools[i].pool; const int plevel = pool->getMeter().inuse.level; stream << std::setw(20) << std::left << pool->objectType(); stream << std::right << "\t " << xpercentInt(plevel, StrCountMeter.level); stream << "\t " << xpercentInt(plevel * pool->objectSize(), StrVolumeMeter.level) << "\n"; pooled_count += plevel; pooled_volume += plevel * pool->objectSize(); } /* malloc strings */ stream << std::setw(20) << std::left << "Other Strings"; stream << std::right << "\t "; stream << xpercentInt(StrCountMeter.level - pooled_count, StrCountMeter.level) << "\t "; stream << xpercentInt(StrVolumeMeter.level - pooled_volume, StrVolumeMeter.level) << "\n\n"; } static void @@ -173,90 +187,96 @@ assert(MemPools[type] == NULL); MemPools[type] = memPoolCreate(name, size); MemPools[type]->zeroOnPush(zeroOnPush); } /* find appropriate pool and use it (pools always init buffer with 0s) */ void * memAllocate(mem_type type) { return MemPools[type]->alloc(); } /* give memory back to the pool */ void memFree(void *p, int type) { MemPools[type]->freeOne(p); } -/* allocate a variable size buffer using best-fit pool */ void * memAllocString(size_t net_size, size_t * gross_size) { - int i; MemAllocator *pool = NULL; assert(gross_size); - for (i = 0; i < mem_str_pool_count; i++) { + // if pools are not yet ready, make sure that + // the requested size is not poolable + if (!MemIsInitialized && net_size < SizeOfStringBeforePoolsAreInitialized) + net_size=SizeOfStringBeforePoolsAreInitialized; + + unsigned int i=0; + for (i = 0; i < mem_str_pool_count; ++i) { if (net_size <= StrPoolsAttrs[i].obj_size) { pool = StrPools[i].pool; break; } } - *gross_size = pool ? StrPoolsAttrs[i].obj_size : net_size; assert(*gross_size >= net_size); + // may forget [de]allocations until MemIsInitialized memMeterInc(StrCountMeter); memMeterAdd(StrVolumeMeter, *gross_size); return pool ? pool->alloc() : xcalloc(1, net_size); } extern size_t memStringCount(); size_t memStringCount() { size_t result = 0; for (int counter = 0; counter < mem_str_pool_count; ++counter) result += memPoolInUseCount(StrPools[counter].pool); return result; } /* free buffer allocated with memAllocString() */ void memFreeString(size_t size, void *buf) { - int i; MemAllocator *pool = NULL; - assert(size && buf); + assert(buf); - for (i = 0; i < mem_str_pool_count; i++) { - if (size <= StrPoolsAttrs[i].obj_size) { - assert(size == StrPoolsAttrs[i].obj_size); - pool = StrPools[i].pool; - break; + if (MemIsInitialized) { + for (unsigned int i = 0; i < mem_str_pool_count; ++i) { + if (size <= StrPoolsAttrs[i].obj_size) { + assert(size == StrPoolsAttrs[i].obj_size); + pool = StrPools[i].pool; + break; + } } } + // may forget [de]allocations until MemIsInitialized memMeterDec(StrCountMeter); memMeterDel(StrVolumeMeter, size); pool ? pool->freeOne(buf) : xfree(buf); } /* Find the best fit MEM_X_BUF type */ static mem_type memFindBufSizeType(size_t net_size, size_t * gross_size) { mem_type type; size_t size; if (net_size <= 2 * 1024) { type = MEM_2K_BUF; size = 2 * 1024; } else if (net_size <= 4 * 1024) { type = MEM_4K_BUF; size = 4 * 1024; } else if (net_size <= 8 * 1024) { type = MEM_8K_BUF; @@ -413,48 +433,49 @@ memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0); #if USE_CACHE_DIGESTS memDataInit(MEM_CACHE_DIGEST, "CacheDigest", sizeof(CacheDigest), 0); #endif memDataInit(MEM_LINK_LIST, "link_list", sizeof(link_list), 10); memDataInit(MEM_DLINK_NODE, "dlink_node", sizeof(dlink_node), 10); memDataInit(MEM_DREAD_CTRL, "dread_ctrl", sizeof(dread_ctrl), 0); memDataInit(MEM_DWRITE_Q, "dwrite_q", sizeof(dwrite_q), 0); memDataInit(MEM_HTTP_HDR_CC, "HttpHdrCc", sizeof(HttpHdrCc), 0); memDataInit(MEM_HTTP_HDR_CONTENT_RANGE, "HttpHdrContRange", sizeof(HttpHdrContRange), 0); memDataInit(MEM_NETDBENTRY, "netdbEntry", sizeof(netdbEntry), 0); memDataInit(MEM_NET_DB_NAME, "net_db_name", sizeof(net_db_name), 0); memDataInit(MEM_RELIST, "relist", sizeof(relist), 0); memDataInit(MEM_CLIENT_INFO, "ClientInfo", sizeof(ClientInfo), 0); memDataInit(MEM_MD5_DIGEST, "MD5 digest", SQUID_MD5_DIGEST_LENGTH, 0); MemPools[MEM_MD5_DIGEST]->setChunkSize(512 * 1024); /** Lastly init the string pools. */ - for (i = 0; i < mem_str_pool_count; i++) { + for (i = 0; i < mem_str_pool_count; ++i) { StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size); StrPools[i].pool->zeroOnPush(false); if (StrPools[i].pool->objectSize() != StrPoolsAttrs[i].obj_size) debugs(13, 1, "Notice: " << StrPoolsAttrs[i].name << " is " << StrPools[i].pool->objectSize() << " bytes instead of requested " << StrPoolsAttrs[i].obj_size << " bytes"); } + MemIsInitialized=true; /** \par * finally register with the cache manager */ RegisterWithCacheManager(); } void Mem::Report() { debugs(13, 3, "Memory pools are '" << (Config.onoff.mem_pools ? "on" : "off") << "'; limit: " << std::setprecision(3) << toMB(MemPools::GetInstance().idleLimit()) << " MB"); } void Mem::RegisterWithCacheManager(void) { Mgr::RegisterAction("mem", "Memory Utilization", Mem::Stats, 0, 1); } @@ -586,41 +607,41 @@ { int excess = 0; int needed = 0; 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; /* Chunks */ if (mp_st->chunk_capacity) { stream << std::setw(4) << toKB(mp_st->obj_size * mp_st->chunk_capacity) << delim; stream << std::setw(4) << mp_st->chunk_capacity << delim; needed = mp_st->items_inuse / mp_st->chunk_capacity; if (mp_st->items_inuse % mp_st->chunk_capacity) - needed++; + ++needed; excess = mp_st->chunks_inuse - needed; stream << std::setw(4) << mp_st->chunks_alloc << delim; stream << std::setw(4) << mp_st->chunks_inuse << delim; stream << std::setw(4) << mp_st->chunks_free << delim; stream << std::setw(4) << mp_st->chunks_partial << delim; stream << std::setprecision(3) << xpercent(excess, needed) << delim; } else { stream << delim; stream << delim; stream << delim; stream << delim; stream << delim; stream << delim; stream << delim; } /* * Fragmentation calculation: * needed = inuse.level / chunk_capacity @@ -715,51 +736,51 @@ "(#)/sec\t" "\n"; xm_deltat = current_dtime - xm_time; xm_time = current_dtime; /* Get stats for Totals report line */ memPoolGetGlobalStats(&mp_total); MemPoolStats *sortme = (MemPoolStats *) xcalloc(mp_total.tot_pools_alloc ,sizeof(*sortme)); int npools = 0; /* main table */ iter = memPoolIterate(); while ((pool = memPoolIterateNext(iter))) { pool->getStats(&mp_stats); if (!mp_stats.pool) /* pool destroyed */ continue; - if (mp_stats.pool->getMeter().gb_allocated.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++; + ++not_used; } memPoolIterateDone(&iter); qsort(sortme, npools, sizeof(*sortme), MemPoolReportSorter); - for (int i = 0; i< npools; i++) { + for (int i = 0; i< npools; ++i) { PoolReport(&sortme[i], mp_total.TheMeter, stream); } xfree(sortme); mp_stats.pool = NULL; mp_stats.label = "Total"; mp_stats.meter = mp_total.TheMeter; mp_stats.obj_size = 1; mp_stats.chunk_capacity = 0; mp_stats.chunk_size = 0; mp_stats.chunks_alloc = mp_total.tot_chunks_alloc; mp_stats.chunks_inuse = mp_total.tot_chunks_inuse; mp_stats.chunks_partial = mp_total.tot_chunks_partial; mp_stats.chunks_free = mp_total.tot_chunks_free; mp_stats.items_alloc = mp_total.tot_items_alloc; mp_stats.items_inuse = mp_total.tot_items_inuse; mp_stats.items_idle = mp_total.tot_items_idle; mp_stats.overhead = mp_total.tot_overhead;