]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Refactor memory pools statistics gathering (#1186)
authorAmos Jeffries <yadij@users.noreply.github.com>
Fri, 2 Dec 2022 05:02:44 +0000 (05:02 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Fri, 2 Dec 2022 05:02:47 +0000 (05:02 +0000)
21 files changed:
include/util.h
lib/Makefile.am
lib/stub_memaccount.c [deleted file]
src/mem/Allocator.h
src/mem/AllocatorProxy.cc
src/mem/AllocatorProxy.h
src/mem/Makefile.am
src/mem/Pool.cc
src/mem/Pool.h
src/mem/PoolChunked.cc
src/mem/PoolChunked.h
src/mem/PoolMalloc.cc
src/mem/PoolMalloc.h
src/mem/Stats.cc [new file with mode: 0644]
src/mem/Stats.h [new file with mode: 0644]
src/mem/forward.h
src/mem/minimal.cc
src/mem/old_api.cc
src/snmp_agent.cc
src/stat.cc
src/tests/stub_libmem.cc

index d64745fa514b89424edd60fc7da27becc3849d8a..03d92d36815ff8b17fd3c309d2958aa54d595941 100644 (file)
@@ -38,11 +38,6 @@ SQUIDCEXTERN const char *double_to_str(char *buf, int buf_size, double value);
 extern const char *gb_to_str(const gb_t *);
 extern void gb_flush(gb_t *);  /* internal, do not use this */
 
-/*
- * Returns the amount of known allocated memory
- */
-int statMemoryAccounted(void);
-
 SQUIDCEXTERN unsigned int RoundTo(const unsigned int num, const unsigned int what);
 
 #endif /* SQUID_UTIL_H */
index d1fb753083adeeb8a1de2d4224751622299768dd..6d463de9071a0b11e903740afa5da3928c7806ac 100644 (file)
@@ -68,7 +68,6 @@ libmiscutil_la_SOURCES = \
        getfullhostname.c \
        heap.c \
        radix.c \
-       stub_memaccount.c \
        util.c \
        xusleep.c
 
diff --git a/lib/stub_memaccount.c b/lib/stub_memaccount.c
deleted file mode 100644 (file)
index adbc1af..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 1996-2022 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.
- */
-
-/* Stub function for programs not implementing statMemoryAccounted */
-#include "squid.h"
-#include "util.h"
-
-int
-statMemoryAccounted(void)
-{
-    return -1;
-}
-
index 19403db86e564cdfccbd3c74e473f645845ecca2..ff5035a3b40c1eccb57a4270556cc7c5bb621ba1 100644 (file)
@@ -27,7 +27,7 @@ public:
      * fill the given object with statistical data about pool
      * \returns Number of objects in use, ie. allocated.
      */
-    virtual int getStats(MemPoolStats *, int accumulate = 0) = 0;
+    virtual size_t getStats(PoolStats &) = 0;
 
     virtual PoolMeter const &getMeter() const = 0;
 
index cc6a33c366ce02a427d1bb2069ff7967c947016b..76d155731a084406205f2202ce85e1b7e6f0d7e4 100644 (file)
@@ -10,6 +10,7 @@
 #include "mem/AllocatorProxy.h"
 #include "mem/Meter.h"
 #include "mem/Pool.h"
+#include "mem/Stats.h"
 
 void *
 Mem::AllocatorProxy::alloc()
@@ -57,8 +58,8 @@ Mem::AllocatorProxy::getMeter() const
     return getAllocator()->getMeter();
 }
 
-int
-Mem::AllocatorProxy::getStats(MemPoolStats * stats)
+size_t
+Mem::AllocatorProxy::getStats(PoolStats &stats)
 {
     return getAllocator()->getStats(stats);
 }
index a778964561d6cfdf26e25e2be293af2b947a12a6..93f3a83ec9d666a830722d8b8f9430849a539c1a 100644 (file)
@@ -12,8 +12,8 @@
 // XXX: remove AllocatorProxy.h include from mem/forward.h
 namespace Mem {
 class Allocator;
+class PoolStats;
 }
-class MemPoolStats;
 
 /**
  * \hideinitializer
@@ -78,7 +78,7 @@ public:
      * \param stats Object to be filled with statistical data about pool.
      * \retval      Number of objects in use, ie. allocated.
      */
-    int getStats(MemPoolStats * stats);
+    size_t getStats(PoolStats &stats);
 
     void zeroBlocks(bool doIt);
 
index 230314395334053fbde8573337b011fd38b12e09..e41bfd73cf37742c613fcf47a2b934a01068524f 100644 (file)
@@ -29,6 +29,8 @@ libmem_la_SOURCES = \
        PoolMalloc.cc \
        PoolMalloc.h \
        PoolingAllocator.h \
+       Stats.cc \
+       Stats.h \
        old_api.cc
 
 # a bare-bones implementation of few libmem.la APIs sufficient for helpers use
index f213a8ba0db6cc0225bb4f244adc5c3520c697e0..43a329905d7c68f7b16907f908a0db03ea53bc74 100644 (file)
@@ -13,6 +13,7 @@
 #include "squid.h"
 #include "mem/PoolChunked.h"
 #include "mem/PoolMalloc.h"
+#include "mem/Stats.h"
 
 #include <cassert>
 #include <cstring>
@@ -21,9 +22,7 @@
 
 extern time_t squid_curtime;
 
-static Mem::PoolMeter TheMeter;
-static MemPoolIterator Iterator;
-static int Pool_id_counter = 0;
+Mem::PoolMeter TheMeter;
 
 MemPools &
 MemPools::GetInstance()
@@ -35,35 +34,6 @@ MemPools::GetInstance()
     return *Instance;
 }
 
-MemPoolIterator *
-memPoolIterate(void)
-{
-    Iterator.pool = MemPools::GetInstance().pools;
-    return &Iterator;
-}
-
-void
-memPoolIterateDone(MemPoolIterator ** iter)
-{
-    assert(iter != nullptr);
-    Iterator.pool = nullptr;
-    *iter = nullptr;
-}
-
-MemImplementingAllocator *
-memPoolIterateNext(MemPoolIterator * iter)
-{
-    MemImplementingAllocator *pool;
-    assert(iter != nullptr);
-
-    pool = iter->pool;
-    if (!pool)
-        return nullptr;
-
-    iter->pool = pool->next;
-    return pool;
-}
-
 /* Change the default value of defaultIsChunked to override
  * all pools - including those used before main() starts where
  * MemPools::GetInstance().setDefaultPoolChunking() can be called.
@@ -77,11 +47,17 @@ MemPools::MemPools()
 MemImplementingAllocator *
 MemPools::create(const char *label, size_t obj_size)
 {
-    ++poolCount;
+    // TODO Use ref-counted Pointer for pool lifecycle management
+    // that is complicated by all the global static pool pointers.
+    // For now leak these Allocator descendants on shutdown.
+
+    MemImplementingAllocator *newPool;
     if (defaultIsChunked)
-        return new MemPoolChunked (label, obj_size);
+        newPool = new MemPoolChunked(label, obj_size);
     else
-        return new MemPoolMalloc (label, obj_size);
+        newPool = new MemPoolMalloc(label, obj_size);
+    pools.push_back(newPool);
+    return pools.back();
 }
 
 void
@@ -129,8 +105,7 @@ MemPools::flushMeters()
 {
     TheMeter.flush();
 
-    MemPoolIterator *iter = memPoolIterate();
-    while (MemImplementingAllocator *pool = memPoolIterateNext(iter)) {
+    for (const auto pool: pools) {
         pool->flushMetersFull();
         // are these TheMeter grow() operations or accumulated volumes ?
         TheMeter.alloc += pool->getMeter().alloc.currentLevel() * pool->obj_size;
@@ -144,7 +119,6 @@ MemPools::flushMeters()
         TheMeter.gb_saved.bytes += pool->getMeter().gb_saved.bytes;
         TheMeter.gb_freed.bytes += pool->getMeter().gb_freed.bytes;
     }
-    memPoolIterateDone(&iter);
 }
 
 void *
@@ -185,109 +159,20 @@ MemPools::clean(time_t maxage)
     if (TheMeter.idle.currentLevel() > idleLimit())
         maxage = shift = 0;
 
-    MemImplementingAllocator *pool;
-    MemPoolIterator *iter;
-    iter = memPoolIterate();
-    while ((pool = memPoolIterateNext(iter)))
+    for (const auto pool: pools) {
         if (pool->idleTrigger(shift))
             pool->clean(maxage);
-    memPoolIterateDone(&iter);
-}
-
-/* Persistent Pool stats. for GlobalStats accumulation */
-static MemPoolStats pp_stats;
-
-/*
- * Totals statistics is returned
- */
-int
-memPoolGetGlobalStats(MemPoolGlobalStats * stats)
-{
-    int pools_inuse = 0;
-    MemPoolIterator *iter;
-
-    memset(stats, 0, sizeof(MemPoolGlobalStats));
-    memset(&pp_stats, 0, sizeof(MemPoolStats));
-
-    MemPools::GetInstance().flushMeters(); /* recreate TheMeter */
-
-    /* gather all stats for Totals */
-    iter = memPoolIterate();
-    while (const auto pool = memPoolIterateNext(iter)) {
-        if (pool->getStats(&pp_stats, 1) > 0)
-            ++pools_inuse;
     }
-    memPoolIterateDone(&iter);
-
-    stats->TheMeter = &TheMeter;
-
-    stats->tot_pools_alloc = MemPools::GetInstance().poolCount;
-    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;
-
-    stats->tot_overhead += pp_stats.overhead + MemPools::GetInstance().poolCount * sizeof(Mem::Allocator *);
-    stats->mem_idle_limit = MemPools::GetInstance().idleLimit();
-
-    return pools_inuse;
-}
-
-int
-memPoolsTotalAllocated(void)
-{
-    MemPoolGlobalStats stats;
-    memPoolGetGlobalStats(&stats);
-    return stats.TheMeter->alloc.currentLevel();
 }
 
 MemImplementingAllocator::MemImplementingAllocator(char const * const aLabel, const size_t aSize):
     Mem::Allocator(aLabel),
-    next(nullptr),
     alloc_calls(0),
     free_calls(0),
     saved_calls(0),
     obj_size(RoundedSize(aSize))
 {
-    memPID = ++Pool_id_counter;
-
-    MemImplementingAllocator *last_pool;
-
     assert(aLabel != nullptr && 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;
-
-    /* Abort if the associated pool doesn't exist */
-    assert(MemPools::GetInstance().pools != nullptr );
-
-    /* Pool clean, remove it from List and free */
-    for (find_pool = MemPools::GetInstance().pools, prev_pool = nullptr; (find_pool && this != find_pool); find_pool = find_pool->next)
-        prev_pool = find_pool;
-
-    /* make sure that we found the pool to destroy */
-    assert(find_pool != nullptr);
-
-    if (prev_pool)
-        prev_pool->next = next;
-    else
-        MemPools::GetInstance().pools = next;
-    --MemPools::GetInstance().poolCount;
 }
 
 Mem::PoolMeter const &
index 1087c6cb82bf9e61967f285da2eb0715e0a50e1c..69c1666867b5e24c4ae23e4d50485d13ba05635d 100644 (file)
@@ -32,6 +32,7 @@
 #include "mem/Meter.h"
 #include "util.h"
 
+#include <list>
 #if HAVE_GNUMALLOC_H
 #include <gnumalloc.h>
 #elif HAVE_MALLOC_H
 #define MEM_MAX_FREE  65535 /* unsigned short is max number of items per chunk */
 
 class MemImplementingAllocator;
-class MemPoolStats;
 
-/// \ingroup MemPoolsAPI
-/// TODO: Kill this typedef for C++
-typedef struct _MemPoolGlobalStats MemPoolGlobalStats;
-
-/// \ingroup MemPoolsAPI
-class MemPoolIterator
-{
-public:
-    MemImplementingAllocator *pool;
-    MemPoolIterator * next;
-};
-
-class MemImplementingAllocator;
+/// memory usage totals as of latest MemPools::flushMeters() event
+extern Mem::PoolMeter TheMeter;
 
 /// \ingroup MemPoolsAPI
 class MemPools
@@ -85,10 +74,10 @@ public:
     void flushMeters();
 
     /**
-     \param label   Name for the pool. Displayed in stats.
-     \param obj_size    Size of elements in MemPool.
+     * Create an allocator with given name to allocate fixed-size objects
+     * of the specified size.
      */
-    MemImplementingAllocator * create(const char *label, size_t obj_size);
+    MemImplementingAllocator *create(const char *, size_t);
 
     /**
      * Sets upper limit in bytes to amount of free ram kept in pools. This is
@@ -129,8 +118,7 @@ public:
 
     void setDefaultPoolChunking(bool const &);
 
-    MemImplementingAllocator *pools = nullptr;
-    int poolCount = 0;
+    std::list<MemImplementingAllocator *> pools;
     bool defaultIsChunked = false;
 
 private:
@@ -147,7 +135,6 @@ public:
     typedef Mem::PoolMeter PoolMeter; // TODO remove
 
     MemImplementingAllocator(char const *aLabel, size_t aSize);
-    virtual ~MemImplementingAllocator();
 
     virtual PoolMeter &getMeter();
     virtual void flushMetersFull();
@@ -166,9 +153,6 @@ protected:
     virtual void *allocate() = 0;
     virtual void deallocate(void *, bool aggressive) = 0;
     PoolMeter meter;
-    int memPID;
-public:
-    MemImplementingAllocator *next;
 public:
     size_t alloc_calls;
     size_t free_calls;
@@ -176,95 +160,8 @@ public:
     size_t obj_size;
 };
 
-/// \ingroup MemPoolsAPI
-class MemPoolStats
-{
-public:
-    typedef Mem::PoolMeter PoolMeter; // TODO remove
-    typedef Mem::Allocator Allocator; // TODO remove
-
-    Allocator *pool;
-    const char *label;
-    PoolMeter *meter;
-    int obj_size;
-    int chunk_capacity;
-    int chunk_size;
-
-    int chunks_alloc;
-    int chunks_inuse;
-    int chunks_partial;
-    int chunks_free;
-
-    int items_alloc;
-    int items_inuse;
-    int items_idle;
-
-    int overhead;
-};
-
-/// \ingroup MemPoolsAPI
-/// TODO: Classify and add constructor/destructor to initialize properly.
-struct _MemPoolGlobalStats {
-    typedef Mem::PoolMeter PoolMeter; // TODO remove
-
-    PoolMeter *TheMeter;
-
-    int tot_pools_alloc;
-    int tot_pools_inuse;
-    int tot_pools_mempid;
-
-    int tot_chunks_alloc;
-    int tot_chunks_inuse;
-    int tot_chunks_partial;
-    int tot_chunks_free;
-
-    int tot_items_alloc;
-    int tot_items_inuse;
-    int tot_items_idle;
-
-    int tot_overhead;
-    ssize_t mem_idle_limit;
-};
-
-/// \ingroup MemPoolsAPI
 /// Creates a named MemPool of elements with the given size
 #define memPoolCreate MemPools::GetInstance().create
 
-/* Allocator API */
-/**
- \ingroup MemPoolsAPI
- * Initialise iteration through all of the pools.
- * \returns Iterator for use by memPoolIterateNext() and memPoolIterateDone()
- */
-extern MemPoolIterator * memPoolIterate(void);
-
-/**
- \ingroup MemPoolsAPI
- * Get next pool pointer, until getting NULL pointer.
- */
-extern MemImplementingAllocator * memPoolIterateNext(MemPoolIterator * iter);
-
-/**
- \ingroup MemPoolsAPI
- * Should be called after finished with iterating through all pools.
- */
-extern void memPoolIterateDone(MemPoolIterator ** iter);
-
-/**
- \ingroup MemPoolsAPI
- *
- * Fills a MemPoolGlobalStats with statistical data about overall
- * usage for all pools.
- *
- * \param stats   Object to be filled with statistical data.
- *
- * \return Number of pools that have at least one object in use.
- *        Ie. number of dirty pools.
- */
-extern int memPoolGetGlobalStats(MemPoolGlobalStats * stats);
-
-/// \ingroup MemPoolsAPI
-extern int memPoolsTotalAllocated(void);
-
 #endif /* _MEM_POOL_H_ */
 
index 30d9a8c1d9bfc2bb3a0cdcf04adebd0c411a44b9..f786a8cd68fb304bbd9080e0566f4d02e3a9d885 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "squid.h"
 #include "mem/PoolChunked.h"
+#include "mem/Stats.h"
 
 #include <cassert>
 #include <cstring>
@@ -429,26 +430,20 @@ MemPoolChunked::idleTrigger(int shift) const
     return meter.idle.currentLevel() > (chunk_capacity << shift);
 }
 
-/*
- * Update MemPoolStats struct for single pool
- */
-int
-MemPoolChunked::getStats(MemPoolStats * stats, int accumulate)
+size_t
+MemPoolChunked::getStats(Mem::PoolStats &stats)
 {
     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 = &meter;
-    stats->obj_size = obj_size;
-    stats->chunk_capacity = chunk_capacity;
+    stats.pool = this;
+    stats.label = objectType();
+    stats.meter = &meter;
+    stats.obj_size = obj_size;
+    stats.chunk_capacity = chunk_capacity;
 
     /* gather stats for each Chunk */
     chunk = Chunks;
@@ -460,16 +455,16 @@ MemPoolChunked::getStats(MemPoolStats * stats, int accumulate)
         chunk = chunk->next;
     }
 
-    stats->chunks_alloc += chunkCount;
-    stats->chunks_inuse += chunkCount - chunks_free;
-    stats->chunks_partial += chunks_partial;
-    stats->chunks_free += chunks_free;
+    stats.chunks_alloc += chunkCount;
+    stats.chunks_inuse += chunkCount - chunks_free;
+    stats.chunks_partial += chunks_partial;
+    stats.chunks_free += chunks_free;
 
-    stats->items_alloc += meter.alloc.currentLevel();
-    stats->items_inuse += meter.inuse.currentLevel();
-    stats->items_idle += meter.idle.currentLevel();
+    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;
+    stats.overhead += sizeof(MemPoolChunked) + chunkCount * sizeof(MemChunk) + strlen(objectType()) + 1;
 
     return meter.inuse.currentLevel();
 }
index 6f38b5d09997b24bd45051eeae36f2a223c1de36..18d4f50cb5e609f66888783b1e93337d91134f44 100644 (file)
@@ -26,13 +26,12 @@ public:
     ~MemPoolChunked();
     void convertFreeCacheToChunkFreeCache();
     virtual void clean(time_t maxage);
-
     void createChunk();
     void *get();
     void push(void *obj);
 
     /* Mem::Allocator API */
-    virtual int getStats(MemPoolStats *, int);
+    virtual size_t getStats(Mem::PoolStats &);
     virtual int getInUseCount();
     virtual void setChunkSize(size_t);
 
index 7ebf5d5f92fe8af318312f1880dbd22b89438351..57be80248c3202f1a886554e4b93512e15d0fd55 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "squid.h"
 #include "mem/PoolMalloc.h"
+#include "mem/Stats.h"
 
 #include <cassert>
 #include <cstring>
@@ -56,28 +57,25 @@ MemPoolMalloc::deallocate(void *obj, bool aggressive)
 }
 
 /* TODO extract common logic to MemAllocate */
-int
-MemPoolMalloc::getStats(MemPoolStats * stats, int accumulate)
+size_t
+MemPoolMalloc::getStats(Mem::PoolStats &stats)
 {
-    if (!accumulate)    /* need skip memset for GlobalStats accumulation */
-        memset(stats, 0, sizeof(MemPoolStats));
-
-    stats->pool = this;
-    stats->label = objectType();
-    stats->meter = &meter;
-    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.currentLevel();
-    stats->items_inuse += meter.inuse.currentLevel();
-    stats->items_idle += meter.idle.currentLevel();
-
-    stats->overhead += sizeof(MemPoolMalloc) + strlen(objectType()) + 1;
+    stats.pool = this;
+    stats.label = objectType();
+    stats.meter = &meter;
+    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.currentLevel();
+    stats.items_inuse += meter.inuse.currentLevel();
+    stats.items_idle += meter.idle.currentLevel();
+
+    stats.overhead += sizeof(MemPoolMalloc) + strlen(objectType()) + 1;
 
     return meter.inuse.currentLevel();
 }
index d92e13d9e679bc82e221301642b760c6e20e448a..84083446404517e2348579f96505092534357059 100644 (file)
@@ -42,7 +42,7 @@ public:
     virtual void clean(time_t maxage);
 
     /* Mem::Allocator API */
-    virtual int getStats(MemPoolStats *, int);
+    virtual size_t getStats(Mem::PoolStats &);
     virtual int getInUseCount();
 
 protected:
diff --git a/src/mem/Stats.cc b/src/mem/Stats.cc
new file mode 100644 (file)
index 0000000..d86fc48
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 1996-2022 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.
+ */
+
+#include "squid.h"
+#include "mem/Pool.h"
+#include "mem/Stats.h"
+
+size_t
+Mem::GlobalStats(PoolStats &stats)
+{
+    MemPools::GetInstance().flushMeters();
+
+    stats.meter = &TheMeter;
+    stats.label = "Total";
+    stats.obj_size = 1;
+    stats.overhead += sizeof(MemPools);
+
+    /* gather all stats for Totals */
+    size_t pools_inuse = 0;
+    for (const auto pool: MemPools::GetInstance().pools) {
+        if (pool->getStats(stats) > 0)
+            ++pools_inuse;
+        stats.overhead += sizeof(Allocator *);
+    }
+
+    return pools_inuse;
+}
diff --git a/src/mem/Stats.h b/src/mem/Stats.h
new file mode 100644 (file)
index 0000000..170ae9e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1996-2022 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_STATS_H
+#define SQUID__SRC_MEM_STATS_H
+
+#include "mem/forward.h"
+
+namespace Mem
+{
+
+class PoolStats
+{
+public:
+    Allocator *pool = nullptr;
+    const char *label = nullptr;
+    PoolMeter *meter = nullptr;
+    int obj_size = 0;
+    int chunk_capacity = 0;
+    int chunk_size = 0;
+
+    int chunks_alloc = 0;
+    int chunks_inuse = 0;
+    int chunks_partial = 0;
+    int chunks_free = 0;
+
+    int items_alloc = 0;
+    int items_inuse = 0;
+    int items_idle = 0;
+
+    int overhead = 0;
+};
+
+/**
+ * Fills a Mem::PoolStats with statistical data about overall
+ * usage for all pools.
+ *
+ * \return Number of pools that have at least one object in use.
+ *        Ie. number of dirty pools.
+ */
+extern size_t GlobalStats(PoolStats &);
+
+} // namespace Mem
+
+#endif /* SQUID__SRC_MEM_STATS_H */
index b5869f621ed117d4ea79771309dd4f7dcc1bfe65..47eaa8c6122219f8adf1c7dab0a53b4d7ce8c1d6 100644 (file)
 #include <iosfwd>
 
 class StoreEntry;
-class MemPoolStats;
 
 /// Memory Management
 namespace Mem
 {
 class Meter;
 class PoolMeter;
+class PoolStats;
 
 void Init();
 void Stats(StoreEntry *);
 void CleanIdlePools(void *unused);
 void Report(std::ostream &);
-void PoolReport(const MemPoolStats *, const PoolMeter *, std::ostream &);
+void PoolReport(const PoolStats *, const PoolMeter *, std::ostream &);
 };
 
 extern const size_t squidSystemPageSize;
index 6efaac70e44b31b7785df17c4b372ac646433ce1..28ff2a9ff71c7f5674d03b7f47f22d8ca9d7bf47 100644 (file)
@@ -36,8 +36,8 @@ Mem::AllocatorProxy::inUseCount() const
     return Alive;
 }
 
-int
-Mem::AllocatorProxy::getStats(MemPoolStats *)
+size_t
+Mem::AllocatorProxy::getStats(PoolStats &)
 {
     return Alive;
 }
index ce9062e17f2a325d4d98ee8bb5b14668ac045a3f..dfee4b4ee0c82a58a978061c3ecc7219c24e4911 100644 (file)
@@ -19,6 +19,7 @@
 #include "mem/forward.h"
 #include "mem/Meter.h"
 #include "mem/Pool.h"
+#include "mem/Stats.h"
 #include "MemBuf.h"
 #include "mgr/Registration.h"
 #include "SquidConfig.h"
@@ -484,16 +485,17 @@ memCheckInit(void)
 void
 memClean(void)
 {
-    MemPoolGlobalStats stats;
     if (Config.MemPools.limit > 0) // do not reset if disabled or same
         MemPools::GetInstance().setIdleLimit(0);
     MemPools::GetInstance().clean(0);
-    memPoolGetGlobalStats(&stats);
 
-    if (stats.tot_items_inuse)
-        debugs(13, 2, "memCleanModule: " << stats.tot_items_inuse <<
-               " items in " << stats.tot_chunks_inuse << " chunks and " <<
-               stats.tot_pools_inuse << " pools are left dirty");
+    Mem::PoolStats stats;
+    const auto poolsInUse = Mem::GlobalStats(stats);
+    if (stats.items_inuse) {
+        debugs(13, 2, stats.items_inuse <<
+               " items in " << stats.chunks_inuse << " chunks and " <<
+               poolsInUse << " pools are left dirty");
+    }
 }
 
 int
@@ -577,7 +579,7 @@ memFreeBufFunc(size_t size)
 }
 
 void
-Mem::PoolReport(const MemPoolStats * mp_st, const PoolMeter * AllMeter, std::ostream &stream)
+Mem::PoolReport(const PoolStats *mp_st, const PoolMeter *AllMeter, std::ostream &stream)
 {
     int excess = 0;
     int needed = 0;
@@ -646,34 +648,11 @@ Mem::PoolReport(const MemPoolStats * mp_st, const PoolMeter * AllMeter, std::ost
     pm->gb_oallocated.count = pm->gb_allocated.count;
 }
 
-static int
-MemPoolReportSorter(const void *a, const void *b)
-{
-    const MemPoolStats *A =  (MemPoolStats *) a;
-    const MemPoolStats *B =  (MemPoolStats *) b;
-
-    // use this to sort on %Total Allocated
-    //
-    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 (pb > pa)
-        return 1;
-
-    return 0;
-}
-
 void
 Mem::Report(std::ostream &stream)
 {
     static char buf[64];
-    static MemPoolStats mp_stats;
-    static MemPoolGlobalStats mp_total;
     int not_used = 0;
-    MemPoolIterator *iter;
 
     /* caption */
     stream << "Current memory usage:\n";
@@ -699,67 +678,46 @@ Mem::Report(std::ostream &stream)
     xm_time = current_dtime;
 
     /* Get stats for Totals report line */
-    memPoolGetGlobalStats(&mp_total);
+    PoolStats mp_total;
+    const auto poolsInUse = GlobalStats(mp_total);
 
-    MemPoolStats *sortme = (MemPoolStats *) xcalloc(mp_total.tot_pools_alloc,sizeof(*sortme));
-    int npools = 0;
+    std::vector<PoolStats> usedPools;
+    usedPools.reserve(poolsInUse);
 
     /* main table */
-    iter = memPoolIterate();
-
-    while (const auto pool = memPoolIterateNext(iter)) {
-        pool->getStats(&mp_stats);
+    for (const auto pool : MemPools::GetInstance().pools) {
+        PoolStats mp_stats;
+        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 */
-            sortme[npools] = mp_stats;
-            ++npools;
-        } else {
+        if (mp_stats.pool->getMeter().gb_allocated.count > 0)
+            usedPools.emplace_back(mp_stats);
+        else
             ++not_used;
-        }
     }
 
-    memPoolIterateDone(&iter);
-
-    qsort(sortme, npools, sizeof(*sortme), MemPoolReportSorter);
+    // sort on %Total Allocated (largest first)
+    std::sort(usedPools.begin(), usedPools.end(), [](const PoolStats &a, const PoolStats &b) {
+        return (double(a.obj_size) * a.meter->alloc.currentLevel()) > (double(b.obj_size) * b.meter->alloc.currentLevel());
+    });
 
-    for (int i = 0; i< npools; ++i) {
-        PoolReport(&sortme[i], mp_total.TheMeter, stream);
+    for (const auto &pool: usedPools) {
+        PoolReport(&pool, mp_total.meter, stream);
     }
 
-    xfree(sortme);
-
-    mp_stats.pool = nullptr;
-    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;
-
-    PoolReport(&mp_stats, mp_total.TheMeter, stream);
+    PoolReport(&mp_total, mp_total.meter, stream);
 
     /* Cumulative */
-    stream << "Cumulative allocated volume: "<< double_to_str(buf, 64, mp_total.TheMeter->gb_allocated.bytes) << "\n";
+    stream << "Cumulative allocated volume: "<< double_to_str(buf, 64, mp_total.meter->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.currentLevel()) << "%)\n";
+    stream << "Current overhead: " << mp_total.overhead << " bytes (" <<
+           std::setprecision(3) << xpercent(mp_total.overhead, mp_total.meter->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";
+    if (MemPools::GetInstance().idleLimit() >= 0)
+        stream << "Idle pool limit: " << std::setprecision(2) << toMB(MemPools::GetInstance().idleLimit()) << " MB\n";
     /* limits */
-    stream << "Total Pools created: " << mp_total.tot_pools_alloc << "\n";
-    stream << "Pools ever used:     " << mp_total.tot_pools_alloc - not_used << " (shown above)\n";
-    stream << "Currently in use:    " << mp_total.tot_pools_inuse << "\n";
+    auto poolCount = MemPools::GetInstance().pools.size();
+    stream << "Total Pools created: " << poolCount << "\n";
+    stream << "Pools ever used:     " << poolCount - not_used << " (shown above)\n";
+    stream << "Currently in use:    " << poolsInUse << "\n";
 }
 
index 32b60a36ab78f56199c60b4ba186d2689e170a76..ab756da9d04b8505dea18bcb74dafb763f828ce2 100644 (file)
@@ -12,6 +12,8 @@
 #include "cache_snmp.h"
 #include "CachePeer.h"
 #include "globals.h"
+#include "mem/Meter.h"
+#include "mem/Stats.h"
 #include "mem_node.h"
 #include "neighbors.h"
 #include "snmp_agent.h"
@@ -339,11 +341,14 @@ snmp_prfSysFn(variable_list * Var, snint * ErrP)
                                       SMI_COUNTER32);
         break;
 
-    case PERF_SYS_MEMUSAGE:
+    case PERF_SYS_MEMUSAGE: {
+        Mem::PoolStats stats;
+        Mem::GlobalStats(stats);
         Answer = snmp_var_new_integer(Var->name, Var->name_length,
-                                      (snint) statMemoryAccounted() >> 10,
+                                      (snint) stats.meter->alloc.currentLevel() >> 10,
                                       ASN_INTEGER);
-        break;
+    }
+    break;
 
     case PERF_SYS_CPUTIME:
         squid_getrusage(&rusage);
index e0b532253a5871be6b995d4d4d8cdd78ec442634..6860a4904270fad9d939005ef45eccceba5f5290 100644 (file)
@@ -24,6 +24,7 @@
 #include "HttpRequest.h"
 #include "IoStats.h"
 #include "mem/Pool.h"
+#include "mem/Stats.h"
 #include "mem_node.h"
 #include "MemBuf.h"
 #include "MemObject.h"
@@ -532,13 +533,12 @@ GetInfo(Mgr::InfoActionData& stats)
 
 #endif
 
-    stats.total_accounted = statMemoryAccounted();
-
     {
-        MemPoolGlobalStats mp_stats;
-        memPoolGetGlobalStats(&mp_stats);
-        stats.gb_saved_count = mp_stats.TheMeter->gb_saved.count;
-        stats.gb_freed_count = mp_stats.TheMeter->gb_freed.count;
+        Mem::PoolStats mp_stats;
+        Mem::GlobalStats(mp_stats);
+        stats.gb_saved_count = mp_stats.meter->gb_saved.count;
+        stats.gb_freed_count = mp_stats.meter->gb_freed.count;
+        stats.total_accounted = mp_stats.meter->alloc.currentLevel();
     }
 
     stats.max_fd = Squid_MaxFD;
@@ -724,8 +724,8 @@ DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry)
     storeAppendPrintf(sentry, "\tTotal accounted:       %6.0f KB\n",
                       stats.total_accounted / 1024);
     {
-        MemPoolGlobalStats mp_stats;
-        memPoolGetGlobalStats(&mp_stats);
+        Mem::PoolStats mp_stats;
+        Mem::GlobalStats(mp_stats); // XXX: called just for its side effects
         storeAppendPrintf(sentry, "\tmemPoolAlloc calls: %9.0f\n",
                           stats.gb_saved_count);
         storeAppendPrintf(sentry, "\tmemPoolFree calls:  %9.0f\n",
@@ -1918,9 +1918,3 @@ statGraphDump(StoreEntry * e)
 
 #endif /* STAT_GRAPHS */
 
-int
-statMemoryAccounted(void)
-{
-    return memPoolsTotalAllocated();
-}
-
index 93b764abfbff9ac8410acedf7625184caeb67bd5..d49b33b0b84c15c7b3d0d835af51c7f99a2855e7 100644 (file)
@@ -20,14 +20,14 @@ void *Mem::AllocatorProxy::alloc() {return xmalloc(64*1024);}
 void Mem::AllocatorProxy::freeOne(void *address) {xfree(address);}
 int Mem::AllocatorProxy::inUseCount() const {return 0;}
 //Mem::PoolMeter const &Mem::AllocatorProxy::getMeter() const STUB_RETSTATREF(PoolMeter)
-int Mem::AllocatorProxy::getStats(MemPoolStats *) STUB_RETVAL(0)
+size_t Mem::AllocatorProxy::getStats(PoolStats &) STUB_RETVAL(0)
 
 #include "mem/forward.h"
 void Mem::Init() STUB_NOP
 void Mem::Stats(StoreEntry *) STUB_NOP
 void Mem::CleanIdlePools(void *) STUB_NOP
 void Mem::Report(std::ostream &) STUB_NOP
-void Mem::PoolReport(const MemPoolStats *, const PoolMeter *, std::ostream &) STUB_NOP
+void Mem::PoolReport(const PoolStats *, const PoolMeter *, std::ostream &) STUB_NOP
 //const size_t squidSystemPageSize = 4096;
 void memClean(void) STUB
 void memInitModule(void) STUB
@@ -87,17 +87,13 @@ void MemPools::clean(time_t) STUB
 void MemPools::setDefaultPoolChunking(bool const &) STUB
 
 //MemImplementingAllocator::MemImplementingAllocator(char const *, size_t) STUB_NOP
-//MemImplementingAllocator::~MemImplementingAllocator();
 Mem::PoolMeter const &MemImplementingAllocator::getMeter() const STUB_RETSTATREF(PoolMeter)
 Mem::PoolMeter &MemImplementingAllocator::getMeter() STUB_RETSTATREF(PoolMeter)
 void MemImplementingAllocator::flushMetersFull() STUB
 void MemImplementingAllocator::flushMeters() STUB
 void *MemImplementingAllocator::alloc() STUB_RETVAL(nullptr)
 void MemImplementingAllocator::freeOne(void *) STUB
+size_t MemImplementingAllocator::objectSize() const { return obj_size; }
 
-MemPoolIterator * memPoolIterate(void) STUB_RETVAL(nullptr)
-MemImplementingAllocator * memPoolIterateNext(MemPoolIterator *) STUB_RETVAL(nullptr)
-void memPoolIterateDone(MemPoolIterator **) STUB
-int memPoolGetGlobalStats(MemPoolGlobalStats *) STUB_RETVAL(0)
-int memPoolsTotalAllocated(void) STUB_RETVAL(0)
-
+#include "mem/Stats.h"
+size_t Mem::GlobalStats(PoolStats &) STUB_RETVAL(0)