diff --git a/CHANGES b/CHANGES index 73f3fb34c5..7011bc863c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2346. [func] Memory statistics now cover all active memory contexts + in increased detail. [RT #17580] + 2345. [bug] named-checkconf failed to detect when forwarders were set at both the options/view level and in a root zone. [RT #17671] diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in index 2f2a1d86b9..c07d4dfa15 100644 --- a/bin/named/Makefile.in +++ b/bin/named/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.99 2008/01/22 22:50:10 marka Exp $ +# $Id: Makefile.in,v 1.100 2008/03/31 05:00:29 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -134,7 +134,7 @@ bind9.xsl.h: bind9.xsl convertxsl.pl ${PERL} ${srcdir}/convertxsl.pl < ${srcdir}/bind9.xsl > bind9.xsl.h depend: bind9.xsl.h -server.@O@: bind9.xsl.h +statschannel.@O@: bind9.xsl.h installdirs: $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl index 25f727384f..7f8a8cdf3e 100644 --- a/bin/named/bind9.xsl +++ b/bin/named/bind9.xsl @@ -15,7 +15,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + +
+ + + + + + + + + + +
Memory Usage Summary
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Memory Contexts
IDNameReferencesTotalUseInUseMaxUseBlockSizePoolsHiWaterLoWater
+ + + + + + + + + + + + + + + + + + + +
diff --git a/bin/named/client.c b/bin/named/client.c index 7153b140e6..db6e634585 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.c,v 1.253 2008/01/18 23:46:57 tbox Exp $ */ +/* $Id: client.c,v 1.254 2008/03/31 05:00:29 marka Exp $ */ #include @@ -1848,15 +1848,17 @@ client_timeout(isc_task_t *task, isc_event_t *event) { static isc_result_t get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) { isc_mem_t *clientmctx; -#if NMCTXS > 0 isc_result_t result; -#endif /* * Caller must be holding the manager lock. */ - if (ns_g_clienttest) - return (isc_mem_create(0, 0, mctxp)); + if (ns_g_clienttest) { + result = isc_mem_create(0, 0, mctxp); + if (result == ISC_R_SUCCESS) + isc_mem_setname(*mctxp, "client", NULL); + return (result); + } #if NMCTXS > 0 INSIST(manager->nextmctx < NMCTXS); clientmctx = manager->mctxpool[manager->nextmctx]; @@ -1864,6 +1866,7 @@ get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) { result = isc_mem_create(0, 0, &clientmctx); if (result != ISC_R_SUCCESS) return (result); + isc_mem_setname(clientmctx, "client", NULL); manager->mctxpool[manager->nextmctx] = clientmctx; } diff --git a/bin/named/server.c b/bin/named/server.c index 0a0ec984af..9ea2f88b6c 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.502 2008/02/18 04:43:47 marka Exp $ */ +/* $Id: server.c,v 1.503 2008/03/31 05:00:29 marka Exp $ */ /*! \file */ @@ -1042,6 +1042,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, CHECK(isc_mem_create(0, 0, &cmctx)); CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, ns_g_timermgr)); + isc_mem_setname(cmctx, "acache", NULL); isc_mem_detach(&cmctx); } if (view->acache != NULL) { @@ -1162,6 +1163,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, CHECK(isc_mem_create(0, 0, &cmctx)); CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, view->rdclass, "rbt", 0, NULL, &cache)); + isc_mem_setname(cmctx, "cache", NULL); } dns_view_setcache(view, cache); diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 10c923970c..3bdef8bddf 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: statschannel.c,v 1.5 2008/01/24 02:00:44 jinmei Exp $ */ +/* $Id: statschannel.c,v 1.6 2008/03/31 05:00:29 marka Exp $ */ /*! \file */ @@ -131,7 +131,7 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { xmlTextWriterEndElement(writer); /* server */ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); - isc_mem_renderxml(server->mctx, writer); + isc_mem_renderxml(writer); TRY0(xmlTextWriterEndElement(writer)); /* memory */ TRY0(xmlTextWriterEndElement(writer)); /* statistics */ diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 0dfadb48f6..471290ea15 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -31,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: dst_api.c,v 1.11 2007/08/28 07:20:42 tbox Exp $ + * $Id: dst_api.c,v 1.12 2008/03/31 05:00:30 marka Exp $ */ /*! \file */ @@ -162,6 +162,7 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { NULL, &dst__memory_pool, 0); if (result != ISC_R_SUCCESS) return (result); + isc_mem_setname(dst__memory_pool, "dst", NULL); isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); #else isc_mem_attach(mctx, &dst__memory_pool); diff --git a/lib/dns/name.c b/lib/dns/name.c index a15c7d239f..a067c13ac3 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.c,v 1.163 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: name.c,v 1.164 2008/03/31 05:00:30 marka Exp $ */ /*! \file */ @@ -1303,6 +1303,7 @@ totext_filter_proc_key_init(void) { result = isc_mem_create2(0, 0, &thread_key_mctx, 0); if (result != ISC_R_SUCCESS) goto unlock; + isc_mem_setname(thread_key_mctx, "threadkey", NULL); isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE); if (!thread_key_initialized && diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 1855c49c10..e883011ddd 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.361 2008/03/28 23:47:02 tbox Exp $ */ +/* $Id: resolver.c,v 1.362 2008/03/31 05:00:30 marka Exp $ */ /*! \file */ @@ -6367,6 +6367,7 @@ dns_resolver_create(dns_view_t *view, #endif snprintf(name, sizeof(name), "res%u", i); isc_task_setname(res->buckets[i].task, name, res); + isc_mem_setname(res->buckets[i].mctx, name, NULL); ISC_LIST_INIT(res->buckets[i].fctxs); res->buckets[i].exiting = ISC_FALSE; buckets_created++; diff --git a/lib/dns/view.c b/lib/dns/view.c index 762b1922ff..4cfbcc26ca 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.c,v 1.143 2007/06/18 23:47:42 tbox Exp $ */ +/* $Id: view.c,v 1.144 2008/03/31 05:00:30 marka Exp $ */ /*! \file */ @@ -578,6 +578,7 @@ dns_view_createresolver(dns_view_t *view, } result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb); + isc_mem_setname(mctx, "ADB", NULL); isc_mem_detach(&mctx); if (result != ISC_R_SUCCESS) { dns_resolver_shutdown(view->resolver); diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h index 08175d1f64..2d41d04237 100644 --- a/lib/isc/include/isc/mem.h +++ b/lib/isc/include/isc/mem.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.h,v 1.77 2008/02/07 02:45:49 marka Exp $ */ +/* $Id: mem.h,v 1.78 2008/03/31 05:00:30 marka Exp $ */ #ifndef ISC_MEM_H #define ISC_MEM_H 1 @@ -406,6 +406,59 @@ isc_mem_references(isc_mem_t *ctx); * Return the current reference count. */ +void +isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag); +/*%< + * Name 'ctx'. + * + * Notes: + * + *\li Only the first 15 characters of 'name' will be copied. + * + *\li 'tag' is for debugging purposes only. + * + * Requires: + * + *\li 'ctx' is a valid ctx. + */ + +const char * +isc_mem_getname(isc_mem_t *ctx); +/*%< + * Get the name of 'ctx', as previously set using isc_mem_setname(). + * + * Requires: + *\li 'ctx' is a valid ctx. + * + * Returns: + *\li A non-NULL pointer to a null-terminated string. + * If the ctx has not been named, the string is + * empty. + */ + +void * +isc_mem_gettag(isc_mem_t *ctx); +/*%< + * Get the tag value for 'task', as previously set using isc_mem_setname(). + * + * Requires: + *\li 'ctx' is a valid ctx. + * + * Notes: + *\li This function is for debugging purposes only. + * + * Requires: + *\li 'ctx' is a valid task. + */ + +#ifdef HAVE_LIBXML2 +void +isc_mem_renderxml(xmlTextWriterPtr writer); +/*%< + * Render all contexts' statistics and status in XML for writer. + */ +#endif /* HAVE_LIBXML2 */ + /* * Memory pools */ @@ -568,11 +621,6 @@ isc__mempool_get(isc_mempool_t * _ISC_MEM_FLARG); void isc__mempool_put(isc_mempool_t *, void * _ISC_MEM_FLARG); -#ifdef HAVE_LIBXML2 -void -isc_mem_renderxml(isc_mem_t *mgr, xmlTextWriterPtr writer); -#endif /* HAVE_LIBXML2 */ - ISC_LANG_ENDDECLS #endif /* ISC_MEM_H */ diff --git a/lib/isc/mem.c b/lib/isc/mem.c index 4b14ad0ef9..fb723e3564 100644 --- a/lib/isc/mem.c +++ b/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 #include #include +#include #include #include @@ -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 */