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:
269
lib/isc/mem.c
269
lib/isc/mem.c
@@ -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 */
|
||||
|
Reference in New Issue
Block a user