+++ /dev/null
-/*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#ifndef _MEM_METER_H_
-#define _MEM_METER_H_
-
-/* object to track per-action memory usage (e.g. #idle objects) */
-class MemMeter
-{
-public:
- MemMeter() : level(0), hwater_level(0), hwater_stamp(0) {}
- ssize_t level; /* current level (count or volume) */
- ssize_t hwater_level; /* high water mark */
- time_t hwater_stamp; /* timestamp of last high water mark change */
-};
-
-#define memMeterSyncHWater(m) { (m).hwater_level = (m).level; (m).hwater_stamp = squid_curtime ? squid_curtime : time(NULL); }
-#define memMeterCheckHWater(m) { if ((m).hwater_level < (m).level) memMeterSyncHWater((m)); }
-#define memMeterInc(m) { (m).level++; memMeterCheckHWater(m); }
-#define memMeterDec(m) { (m).level--; }
-#define memMeterAdd(m, sz) { (m).level += (sz); memMeterCheckHWater(m); }
-#define memMeterDel(m, sz) { (m).level -= (sz); }
-
-#endif /* _MEM_METER_H_ */
-
#else
int obj_size = pool->objectSize() - cbdata::Offset;
#endif
- storeAppendPrintf(sentry, "%s\t%d\t%ld\t%ld\n", pool->objectType() + 7, obj_size, (long int)pool->getMeter().inuse.level, (long int)obj_size * pool->getMeter().inuse.level);
+ storeAppendPrintf(sentry, "%s\t%d\t%ld\t%ld\n", pool->objectType() + 7, obj_size, (long int)pool->getMeter().inuse.currentLevel(), (long int)obj_size * pool->getMeter().inuse.currentLevel());
}
}
AllocatorProxy.h \
forward.h \
old_api.cc \
+ Meter.h \
Pool.cc \
Pool.h \
PoolChunked.cc \
--- /dev/null
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_MEM_METER_H
+#define SQUID_SRC_MEM_METER_H
+
+#include "SquidTime.h"
+
+namespace Mem
+{
+
+/**
+ * object to track per-action memory usage (e.g. #idle objects)
+ */
+class Meter
+{
+public:
+ Meter() : level(0), hwater_level(0), hwater_stamp(0) {}
+
+ /// flush the meter level back to 0, but leave peak records
+ void flush() {level=0;}
+
+ ssize_t currentLevel() const {return level;}
+ ssize_t peak() const {return hwater_level;}
+ time_t peakTime() const {return hwater_stamp;}
+
+ Meter &operator ++() {++level; checkHighWater(); return *this;}
+ Meter &operator --() {--level; return *this;}
+
+ Meter &operator +=(ssize_t n) { level += n; checkHighWater(); return *this;}
+ Meter &operator -=(ssize_t n) { level -= n; return *this;}
+
+private:
+ /// check the high-water level of this meter and raise if necessary
+ /// recording the timestamp of last high-water peak change
+ void checkHighWater() {
+ if (hwater_level < level) {
+ hwater_level = level;
+ hwater_stamp = squid_curtime ? squid_curtime : time(NULL);
+ }
+ }
+
+ ssize_t level; ///< current level (count or volume)
+ ssize_t hwater_level; ///< high water mark
+ time_t hwater_stamp; ///< timestamp of last high water mark change
+};
+
+} // namespace Mem
+
+#endif /* SQUID_SRC_MEM_METER_H */
+
void
MemPoolMeter::flush()
{
- alloc.level = 0;
- inuse.level = 0;
- idle.level = 0;
+ alloc.flush();
+ inuse.flush();
+ idle.flush();
gb_allocated.count = 0;
gb_allocated.bytes = 0;
gb_oallocated.count = 0;
void
MemPools::flushMeters()
{
- MemImplementingAllocator *pool;
- MemPoolIterator *iter;
-
TheMeter.flush();
- iter = memPoolIterate();
- while ((pool = memPoolIterateNext(iter))) {
+ MemPoolIterator *iter = memPoolIterate();
+ while (MemImplementingAllocator *pool = memPoolIterateNext(iter)) {
pool->flushMetersFull();
- 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);
+ // are these TheMeter grow() operations or accumulated volumes ?
+ TheMeter.alloc += pool->getMeter().alloc.currentLevel() * pool->obj_size;
+ TheMeter.inuse += pool->getMeter().inuse.currentLevel() * pool->obj_size;
+ TheMeter.idle += pool->getMeter().idle.currentLevel() * 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;
return;
int shift = 1;
- if (TheMeter.idle.level > mem_idle_limit)
+ if (TheMeter.idle.currentLevel() > mem_idle_limit)
maxage = shift = 0;
MemImplementingAllocator *pool;
{
MemPoolGlobalStats stats;
memPoolGetGlobalStats(&stats);
- return stats.TheMeter->alloc.level;
+ return stats.TheMeter->alloc.currentLevel();
}
MemImplementingAllocator::MemImplementingAllocator(char const *aLabel, size_t aSize) : MemAllocator(aLabel),
* might be the way to go.
*/
-#include "memMeter.h"
+#include "mem/Meter.h"
#include "splay.h"
#include "util.h"
public:
MemPoolMeter();
void flush();
- MemMeter alloc;
- MemMeter inuse;
- MemMeter idle;
+
+ Mem::Meter alloc;
+ Mem::Meter inuse;
+ Mem::Meter idle;
/** history Allocations */
mgb_t gb_allocated;
nextFreeChunk = pool->nextFreeChunk;
pool->nextFreeChunk = this;
- memMeterAdd(pool->getMeter().alloc, pool->chunk_capacity);
- memMeterAdd(pool->getMeter().idle, pool->chunk_capacity);
+ pool->getMeter().alloc += pool->chunk_capacity;
+ pool->getMeter().idle += pool->chunk_capacity;
++pool->chunkCount;
lastref = squid_curtime;
pool->allChunks.insert(this, memCompChunks);
MemChunk::~MemChunk()
{
- memMeterDel(pool->getMeter().alloc, pool->chunk_capacity);
- memMeterDel(pool->getMeter().idle, pool->chunk_capacity);
+ pool->getMeter().alloc -= pool->chunk_capacity;
+ pool->getMeter().idle -= pool->chunk_capacity;
-- pool->chunkCount;
pool->allChunks.remove(this, memCompChunks);
xfree(objCache);
flushMetersFull();
clean(0);
- assert(meter.inuse.level == 0);
+ assert(meter.inuse.currentLevel() == 0);
chunk = Chunks;
while ( (fchunk = chunk) != NULL) {
int
MemPoolChunked::getInUseCount()
{
- return meter.inuse.level;
+ return meter.inuse.currentLevel();
}
void *
MemPoolChunked::allocate()
{
void *p = get();
- assert(meter.idle.level > 0);
- memMeterDec(meter.idle);
- memMeterInc(meter.inuse);
+ assert(meter.idle.currentLevel() > 0);
+ --meter.idle;
+ ++meter.inuse;
return p;
}
MemPoolChunked::deallocate(void *obj, bool)
{
push(obj);
- assert(meter.inuse.level > 0);
- memMeterDec(meter.inuse);
- memMeterInc(meter.idle);
+ assert(meter.inuse.currentLevel() > 0);
+ --meter.inuse;
+ ++meter.idle;
}
void
bool
MemPoolChunked::idleTrigger(int shift) const
{
- return meter.idle.level > (chunk_capacity << shift);
+ return meter.idle.currentLevel() > (chunk_capacity << shift);
}
/*
stats->chunks_partial += chunks_partial;
stats->chunks_free += chunks_free;
- stats->items_alloc += meter.alloc.level;
- stats->items_inuse += meter.inuse.level;
- stats->items_idle += meter.idle.level;
+ stats->items_alloc += meter.alloc.currentLevel();
+ stats->items_inuse += meter.inuse.currentLevel();
+ stats->items_idle += meter.idle.currentLevel();
stats->overhead += sizeof(MemPoolChunked) + chunkCount * sizeof(MemChunk) + strlen(objectType()) + 1;
- return meter.inuse.level;
+ return meter.inuse.currentLevel();
}
freelist.pop();
}
if (obj) {
- memMeterDec(meter.idle);
+ --meter.idle;
++saved_calls;
} else {
if (doZero)
obj = xcalloc(1, obj_size);
else
obj = xmalloc(obj_size);
- memMeterInc(meter.alloc);
+ ++meter.alloc;
}
- memMeterInc(meter.inuse);
+ ++meter.inuse;
return obj;
}
void
MemPoolMalloc::deallocate(void *obj, bool aggressive)
{
- memMeterDec(meter.inuse);
+ --meter.inuse;
if (aggressive) {
xfree(obj);
- memMeterDec(meter.alloc);
+ --meter.alloc;
} else {
if (doZero)
memset(obj, 0, obj_size);
- memMeterInc(meter.idle);
+ ++meter.idle;
freelist.push(obj);
}
}
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->items_alloc += meter.alloc.currentLevel();
+ stats->items_inuse += meter.inuse.currentLevel();
+ stats->items_idle += meter.idle.currentLevel();
stats->overhead += sizeof(MemPoolMalloc) + strlen(objectType()) + 1;
- return meter.inuse.level;
+ return meter.inuse.currentLevel();
}
int
MemPoolMalloc::getInUseCount()
{
- return meter.inuse.level;
+ return meter.inuse.currentLevel();
}
MemPoolMalloc::MemPoolMalloc(char const *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize)
MemPoolMalloc::~MemPoolMalloc()
{
- assert(meter.inuse.level == 0);
+ assert(meter.inuse.currentLevel() == 0);
clean(0);
}
while (!freelist.empty()) {
void *obj = freelist.top();
freelist.pop();
- memMeterDec(meter.idle);
- memMeterDec(meter.alloc);
+ --meter.idle;
+ --meter.alloc;
xfree(obj);
}
}
class MemPoolStats;
class MemPoolMeter;
+/// Memory Management
namespace Mem
{
void Init();
#include "icmp/net_db.h"
#include "md5.h"
#include "mem/forward.h"
+#include "mem/Meter.h"
#include "mem/Pool.h"
#include "MemBuf.h"
-#include "memMeter.h"
#include "mgr/Registration.h"
#include "SquidConfig.h"
#include "SquidList.h"
}
StrPools[mem_str_pool_count];
-static MemMeter StrCountMeter;
-static MemMeter StrVolumeMeter;
+static Mem::Meter StrCountMeter;
+static Mem::Meter StrVolumeMeter;
-static MemMeter HugeBufCountMeter;
-static MemMeter HugeBufVolumeMeter;
+static Mem::Meter HugeBufCountMeter;
+static Mem::Meter HugeBufVolumeMeter;
/* local routines */
for (i = 0; i < mem_str_pool_count; ++i) {
const MemAllocator *pool = StrPools[i].pool;
- const int plevel = pool->getMeter().inuse.level;
+ const auto plevel = pool->getMeter().inuse.currentLevel();
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";
+ stream << std::right << "\t " << xpercentInt(plevel, StrCountMeter.currentLevel());
+ stream << "\t " << xpercentInt(plevel * pool->objectSize(), StrVolumeMeter.currentLevel()) << "\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";
+ stream << xpercentInt(StrCountMeter.currentLevel() - pooled_count, StrCountMeter.currentLevel()) << "\t ";
+ stream << xpercentInt(StrVolumeMeter.currentLevel() - pooled_volume, StrVolumeMeter.currentLevel()) << "\n\n";
}
static void
memBufStats(std::ostream & stream)
{
stream << "Large buffers: " <<
- HugeBufCountMeter.level << " (" <<
- HugeBufVolumeMeter.level / 1024 << " KB)\n";
+ HugeBufCountMeter.currentLevel() << " (" <<
+ HugeBufVolumeMeter.currentLevel() / 1024 << " KB)\n";
}
void
*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);
+ ++StrCountMeter;
+ StrVolumeMeter += *gross_size;
return pool ? pool->alloc() : xcalloc(1, net_size);
}
}
// may forget [de]allocations until MemIsInitialized
- memMeterDec(StrCountMeter);
- memMeterDel(StrVolumeMeter, size);
+ --StrCountMeter;
+ StrVolumeMeter -= size;
pool ? pool->freeOne(buf) : xfree(buf);
}
if (type != MEM_NONE)
return memAllocate(type);
else {
- memMeterInc(HugeBufCountMeter);
- memMeterAdd(HugeBufVolumeMeter, *gross_size);
+ ++HugeBufCountMeter;
+ HugeBufVolumeMeter += *gross_size;
return xcalloc(1, net_size);
}
}
memFree(buf, type);
else {
xfree(buf);
- memMeterDec(HugeBufCountMeter);
- memMeterDel(HugeBufVolumeMeter, size);
+ --HugeBufCountMeter;
+ HugeBufVolumeMeter -= size;
}
}
return memFree64K;
default:
- memMeterDec(HugeBufCountMeter);
- memMeterDel(HugeBufVolumeMeter, size);
+ --HugeBufCountMeter;
+ HugeBufVolumeMeter -= size;
return cxx_xfree;
}
}
}
/*
* Fragmentation calculation:
- * needed = inuse.level / chunk_capacity
+ * needed = inuse.currentLevel() / chunk_capacity
* excess = used - needed
* fragmentation = excess / needed * 100%
*
*/
/* allocated */
stream << mp_st->items_alloc << delim;
- stream << toKB(mp_st->obj_size * pm->alloc.level) << delim;
- stream << toKB(mp_st->obj_size * pm->alloc.hwater_level) << delim;
- stream << std::setprecision(2) << ((squid_curtime - pm->alloc.hwater_stamp) / 3600.) << delim;
- stream << std::setprecision(3) << xpercent(mp_st->obj_size * pm->alloc.level, AllMeter->alloc.level) << delim;
+ stream << toKB(mp_st->obj_size * pm->alloc.currentLevel()) << delim;
+ stream << toKB(mp_st->obj_size * pm->alloc.peak()) << delim;
+ stream << std::setprecision(2) << ((squid_curtime - pm->alloc.peakTime()) / 3600.) << delim;
+ stream << std::setprecision(3) << xpercent(mp_st->obj_size * pm->alloc.currentLevel(), AllMeter->alloc.currentLevel()) << delim;
/* in use */
stream << mp_st->items_inuse << delim;
- stream << toKB(mp_st->obj_size * pm->inuse.level) << delim;
- stream << toKB(mp_st->obj_size * pm->inuse.hwater_level) << delim;
- stream << std::setprecision(2) << ((squid_curtime - pm->inuse.hwater_stamp) / 3600.) << delim;
- stream << std::setprecision(3) << xpercent(pm->inuse.level, pm->alloc.level) << delim;
+ stream << toKB(mp_st->obj_size * pm->inuse.currentLevel()) << delim;
+ stream << toKB(mp_st->obj_size * pm->inuse.peak()) << delim;
+ stream << std::setprecision(2) << ((squid_curtime - pm->inuse.peakTime()) / 3600.) << delim;
+ stream << std::setprecision(3) << xpercent(pm->inuse.currentLevel(), pm->alloc.currentLevel()) << delim;
/* idle */
stream << mp_st->items_idle << delim;
- stream << toKB(mp_st->obj_size * pm->idle.level) << delim;
- stream << toKB(mp_st->obj_size * pm->idle.hwater_level) << delim;
+ stream << toKB(mp_st->obj_size * pm->idle.currentLevel()) << delim;
+ stream << toKB(mp_st->obj_size * pm->idle.peak()) << delim;
/* saved */
stream << (int)pm->gb_saved.count << delim;
stream << std::setprecision(3) << xpercent(pm->gb_saved.count, AllMeter->gb_allocated.count) << delim;
// use this to sort on %Total Allocated
//
- double pa = (double) A->obj_size * A->meter->alloc.level;
- double pb = (double) B->obj_size * B->meter->alloc.level;
+ double pa = (double) A->obj_size * A->meter->alloc.currentLevel();
+ double pb = (double) B->obj_size * B->meter->alloc.currentLevel();
if (pa > pb)
return -1;
#if 0
// use this to sort on In Use high(hrs)
//
- if (A->meter->inuse.hwater_stamp > B->meter->inuse.hwater_stamp)
+ if (A->meter->inuse.peakTime() > B->meter->inuse.peakTime())
return -1;
- if (B->meter->inuse.hwater_stamp > A->meter->inuse.hwater_stamp)
+ if (B->meter->inuse.peakTime() > A->meter->inuse.peakTime())
return 1;
#endif
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";
+ std::setprecision(3) << xpercent(mp_total.tot_overhead, mp_total.TheMeter->inuse.currentLevel()) << "%)\n";
/* limits */
if (mp_total.mem_idle_limit >= 0)
stream << "Idle pool limit: " << std::setprecision(2) << toMB(mp_total.mem_idle_limit) << " MB\n";