2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

2346. [func] Memory statistics now cover all active memory contexts

in increased detail. [RT #17580]
This commit is contained in:
Mark Andrews
2008-03-31 05:00:30 +00:00
parent 7405bdffd4
commit cffe96e267
12 changed files with 319 additions and 116 deletions

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: mem.c,v 1.141 2008/02/07 02:41:26 marka Exp $ */
/* $Id: mem.c,v 1.142 2008/03/31 05:00:30 marka Exp $ */
/*! \file */
@@ -34,6 +34,7 @@
#include <isc/ondestroy.h>
#include <isc/string.h>
#include <isc/mutex.h>
#include <isc/print.h>
#include <isc/util.h>
#include <isc/xml.h>
@@ -113,6 +114,12 @@ static ISC_LIST(isc_mem_t) contexts;
static isc_once_t once = ISC_ONCE_INIT;
static isc_mutex_t lock;
/*%
* Total size of lost memory due to a bug of external library.
* Locked by the global lock.
*/
static isc_uint64_t totallost;
struct isc_mem {
unsigned int magic;
isc_ondestroy_t ondestroy;
@@ -125,6 +132,8 @@ struct isc_mem {
isc_boolean_t checkfree;
struct stats * stats;
unsigned int references;
char name[16];
void * tag;
size_t quota;
size_t total;
size_t inuse;
@@ -135,6 +144,7 @@ struct isc_mem {
isc_mem_water_t water;
void * water_arg;
ISC_LIST(isc_mempool_t) pools;
unsigned int poolcnt;
/* ISC_MEMFLAG_INTERNAL */
size_t mem_target;
@@ -148,6 +158,7 @@ struct isc_mem {
#if ISC_MEM_TRACKLINES
debuglist_t * debuglist;
unsigned int debuglistcnt;
#endif
unsigned int memalloc_failures;
@@ -259,6 +270,7 @@ add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
dl->count = 1;
ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
mctx->debuglistcnt++;
}
static inline void
@@ -692,6 +704,7 @@ static void
initialize_action(void) {
RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
ISC_LIST_INIT(contexts);
totallost = 0;
}
/*
@@ -742,6 +755,8 @@ isc_mem_createx2(size_t init_max_size, size_t target_size,
ctx->max_size = init_max_size;
ctx->flags = flags;
ctx->references = 1;
memset(ctx->name, 0, sizeof(ctx->name));
ctx->tag = NULL;
ctx->quota = 0;
ctx->total = 0;
ctx->inuse = 0;
@@ -760,8 +775,10 @@ isc_mem_createx2(size_t init_max_size, size_t target_size,
ctx->checkfree = ISC_TRUE;
#if ISC_MEM_TRACKLINES
ctx->debuglist = NULL;
ctx->debuglistcnt = 0;
#endif
ISC_LIST_INIT(ctx->pools);
ctx->poolcnt = 0;
ctx->freelists = NULL;
ctx->basic_blocks = NULL;
ctx->basic_table = NULL;
@@ -862,6 +879,7 @@ destroy(isc_mem_t *ctx) {
LOCK(&lock);
ISC_LIST_UNLINK(contexts, ctx, link);
totallost += ctx->inuse;
UNLOCK(&lock);
INSIST(ISC_LIST_EMPTY(ctx->pools));
@@ -1507,6 +1525,31 @@ isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
(oldwater)(oldwater_arg, ISC_MEM_LOWATER);
}
void
isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
REQUIRE(VALID_CONTEXT(ctx));
LOCK(&ctx->lock);
memset(ctx->name, 0, sizeof(ctx->name));
strncpy(ctx->name, name, sizeof(ctx->name) - 1);
ctx->tag = tag;
UNLOCK(&ctx->lock);
}
const char *
isc_mem_getname(isc_mem_t *ctx) {
REQUIRE(VALID_CONTEXT(ctx));
return (ctx->name);
}
void *
isc_mem_gettag(isc_mem_t *ctx) {
REQUIRE(VALID_CONTEXT(ctx));
return (ctx->tag);
}
/*
* Memory pool stuff
*/
@@ -1546,6 +1589,7 @@ isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
MCTXLOCK(mctx, &mctx->lock);
ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
mctx->poolcnt++;
MCTXUNLOCK(mctx, &mctx->lock);
return (ISC_R_SUCCESS);
@@ -1620,6 +1664,7 @@ isc_mempool_destroy(isc_mempool_t **mpctxp) {
*/
MCTXLOCK(mctx, &mctx->lock);
ISC_LIST_UNLINK(mctx->pools, mpctx, link);
mctx->poolcnt--;
MCTXUNLOCK(mctx, &mctx->lock);
mpctx->magic = 0;
@@ -1978,115 +2023,149 @@ isc_mem_references(isc_mem_t *ctx) {
#ifdef HAVE_LIBXML2
void
isc_mem_renderxml(isc_mem_t *ctx, xmlTextWriterPtr writer)
{
size_t i;
const struct stats *s;
const isc_mempool_t *pool;
typedef struct summarystat {
isc_uint64_t total;
isc_uint64_t inuse;
isc_uint64_t blocksize;
isc_uint64_t contextsize;
} summarystat_t;
static void
renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
REQUIRE(VALID_CONTEXT(ctx));
xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
xmlTextWriterWriteFormatString(writer, "%p", ctx);
xmlTextWriterEndElement(writer); /* id */
if (ctx->name[0] != 0) {
xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
xmlTextWriterEndElement(writer); /* name */
}
REQUIRE(VALID_CONTEXT(ctx));
MCTXLOCK(ctx, &ctx->lock);
summary->contextsize += sizeof(*ctx) +
(ctx->max_size + 1) * sizeof(struct stats) +
ctx->max_size * sizeof(element *) +
ctx->basic_table_count * sizeof(char *);
#if ISC_MEM_TRACKLINES
if (ctx->debuglist != NULL) {
summary->contextsize +=
(ctx->max_size + 1) * sizeof(debuglist_t) +
ctx->debuglistcnt * sizeof(debuglink_t);
}
#endif
xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
xmlTextWriterEndElement(writer);
xmlTextWriterEndElement(writer); /* references */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "buckets");
for (i = 0; i <= ctx->max_size; i++) {
s = &ctx->stats[i];
summary->total += ctx->total;
xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->total);
xmlTextWriterEndElement(writer); /* total */
if (s->totalgets == 0U && s->gets == 0U)
continue;
summary->inuse += ctx->inuse;
xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->inuse);
xmlTextWriterEndElement(writer); /* inuse */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "bucket");
xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->maxinuse);
xmlTextWriterEndElement(writer); /* maxinuse */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "size");
xmlTextWriterWriteFormatString(writer, "%ld", (long)i);
xmlTextWriterEndElement(writer); /* size */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
summary->blocksize += ctx->basic_table_count *
NUM_BASIC_BLOCKS * ctx->mem_target;
xmlTextWriterWriteFormatString(writer,
"%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)
ctx->basic_table_count *
NUM_BASIC_BLOCKS *
ctx->mem_target);
} else
xmlTextWriterWriteFormatString(writer, "%s", "-");
xmlTextWriterEndElement(writer); /* blocksize */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "totalgets");
xmlTextWriterWriteFormatString(writer, "%lu", s->totalgets);
xmlTextWriterEndElement(writer); /* totalgets */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "gets");
xmlTextWriterWriteFormatString(writer, "%lu", s->gets);
xmlTextWriterEndElement(writer); /* gets */
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
(s->blocks != 0U || s->freefrags != 0U)) {
xmlTextWriterStartElement(writer,
ISC_XMLCHAR "blocks");
xmlTextWriterWriteFormatString(writer, "%lu",
s->blocks);
xmlTextWriterEndElement(writer); /* blocks */
xmlTextWriterStartElement(writer,
ISC_XMLCHAR "freefrags");
xmlTextWriterWriteFormatString(writer, "%lu",
s->freefrags);
xmlTextWriterEndElement(writer); /* freefrags */
}
xmlTextWriterEndElement(writer); /* bucket */
}
xmlTextWriterEndElement(writer); /* buckets */
/*
* Note that since a pool can be locked now, these stats might be
* somewhat off if the pool is in active use at the time the stats
* are dumped. The link fields are protected by the isc_mem_t's
* lock, however, so walking this list and extracting integers from
* stats fields is always safe.
*/
xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
pool = ISC_LIST_HEAD(ctx->pools);
while (pool != NULL) {
xmlTextWriterStartElement(writer, ISC_XMLCHAR "pool");
xmlTextWriterWriteElement(writer, ISC_XMLCHAR "name",
ISC_XMLCHAR pool->name);
xmlTextWriterStartElement(writer, ISC_XMLCHAR "size");
xmlTextWriterWriteFormatString(writer, "%ld", (long)pool->size);
xmlTextWriterEndElement(writer); /* size */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxalloc");
xmlTextWriterWriteFormatString(writer, "%u", pool->maxalloc);
xmlTextWriterEndElement(writer); /* maxalloc */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "allocated");
xmlTextWriterWriteFormatString(writer, "%u", pool->allocated);
xmlTextWriterEndElement(writer); /* allocated */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "freecount");
xmlTextWriterWriteFormatString(writer, "%u", pool->freecount);
xmlTextWriterEndElement(writer); /* freecount */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "freemax");
xmlTextWriterWriteFormatString(writer, "%u", pool->freemax);
xmlTextWriterEndElement(writer); /* freemax */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "fillcount");
xmlTextWriterWriteFormatString(writer, "%u", pool->fillcount);
xmlTextWriterEndElement(writer); /* fillcount */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "gets");
xmlTextWriterWriteFormatString(writer, "%u", pool->gets);
xmlTextWriterEndElement(writer); /* gets */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "locked");
xmlTextWriterWriteFormatString(writer, "%s",
((pool->lock == NULL) ? "No" : "Yes"));
xmlTextWriterEndElement(writer); /* locked */
xmlTextWriterEndElement(writer); /* pool */
pool = ISC_LIST_NEXT(pool, link);
}
xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
xmlTextWriterEndElement(writer); /* pools */
summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->hi_water);
xmlTextWriterEndElement(writer); /* hiwater */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->lo_water);
xmlTextWriterEndElement(writer); /* lowater */
MCTXUNLOCK(ctx, &ctx->lock);
xmlTextWriterEndElement(writer); /* context */
}
void
isc_mem_renderxml(xmlTextWriterPtr writer) {
isc_mem_t *ctx;
summarystat_t summary;
isc_uint64_t lost;
memset(&summary, 0, sizeof(summary));
xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
LOCK(&lock);
lost = totallost;
for (ctx = ISC_LIST_HEAD(contexts);
ctx != NULL;
ctx = ISC_LIST_NEXT(ctx, link)) {
renderctx(ctx, &summary, writer);
}
UNLOCK(&lock);
xmlTextWriterEndElement(writer); /* contexts */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
summary.total);
xmlTextWriterEndElement(writer); /* TotalUse */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
summary.inuse);
xmlTextWriterEndElement(writer); /* InUse */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
summary.blocksize);
xmlTextWriterEndElement(writer); /* BlockSize */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
summary.contextsize);
xmlTextWriterEndElement(writer); /* ContextSize */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
lost);
xmlTextWriterEndElement(writer); /* Lost */
xmlTextWriterEndElement(writer); /* summary */
}
#endif /* HAVE_LIBXML2 */