Commit cffe96e2 authored by Mark Andrews's avatar Mark Andrews
Browse files

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

                        in increased detail. [RT #17580]
parent 7405bdff
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]
......
......@@ -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}
......
......@@ -15,7 +15,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: bind9.xsl,v 1.13 2007/06/18 23:47:18 tbox Exp $ -->
<!-- $Id: bind9.xsl,v 1.14 2008/03/31 05:00:29 marka Exp $ -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
......@@ -274,6 +274,70 @@ tr.lrow {
</tr>
</xsl:for-each>
</table>
<br />
<table>
<tr class="rowh">
<th colspan="4">Memory Usage Summary</th>
</tr>
<xsl:for-each select="memory/summary/*">
<tr class="lrow">
<td><xsl:value-of select="name()"/></td>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:for-each>
</table>
<br />
<table>
<tr class="rowh">
<th colspan="10">Memory Contexts</th>
</tr>
<tr class="rowh">
<th>ID</th>
<th>Name</th>
<th>References</th>
<th>TotalUse</th>
<th>InUse</th>
<th>MaxUse</th>
<th>BlockSize</th>
<th>Pools</th>
<th>HiWater</th>
<th>LoWater</th>
</tr>
<xsl:for-each select="memory/contexts/context">
<tr class="lrow">
<td>
<xsl:value-of select="id"/>
</td>
<td>
<xsl:value-of select="name"/>
</td>
<td>
<xsl:value-of select="references"/>
</td>
<td>
<xsl:value-of select="total"/>
</td>
<td>
<xsl:value-of select="inuse"/>
</td>
<td>
<xsl:value-of select="maxinuse"/>
</td>
<td>
<xsl:value-of select="blocksize"/>
</td>
<td>
<xsl:value-of select="pools"/>
</td>
<td>
<xsl:value-of select="hiwater"/>
</td>
<td>
<xsl:value-of select="lowater"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
......
......@@ -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 <config.h>
......@@ -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;
}
......
......@@ -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);
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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 &&
......
......@@ -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++;
......
......@@ -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);
......
......@@ -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 */
......@@ -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));
MCTXLOCK(ctx, &ctx->lock);
xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
xmlTextWriterEndElement(writer);
xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
xmlTextWriterStartElement(writer, ISC_XMLCHAR "buckets");
for (i = 0; i <= ctx->max_size; i++) {
s = &ctx->stats[i];
xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
xmlTextWriterWriteFormatString(writer, "%p", ctx);
xmlTextWriterEndElement(writer); /* id */
if (s->totalgets == 0U && s->gets == 0U)
continue;
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);
xmlTextWriterStartElement(writer, ISC_XMLCHAR "bucket");
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); /* references */
summary->total += ctx->total;
xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->total);
xmlTextWriterEndElement(writer); /* total */
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 "maxinuse");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->maxinuse);
xmlTextWriterEndElement(writer); /* maxinuse */
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 "size");
xmlTextWriterWriteFormatString(writer, "%ld", (long)i);
xmlTextWriterEndElement(writer); /* size */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
xmlTextWriterEndElement(writer); /* pools */
summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
xmlTextWriterStartElement(writer, ISC_XMLCHAR "totalgets");
xmlTextWriterWriteFormatString(writer, "%lu", s->totalgets);
xmlTextWriterEndElement(writer); /* totalgets */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->hi_water);
xmlTextWriterEndElement(writer); /* hiwater */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "gets");
xmlTextWriterWriteFormatString(writer, "%lu", s->gets);
xmlTextWriterEndElement(writer); /* gets */
xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
(isc_uint64_t)ctx->lo_water);
xmlTextWriterEndElement(writer); /* lowater */
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 */
}
MCTXUNLOCK(ctx, &ctx->lock);
xmlTextWriterEndElement(writer); /* bucket */
}
xmlTextWriterEndElement(writer); /* buckets */
xmlTextWriterEndElement(writer); /* context */
}
/*
* 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");
void
isc_mem_renderxml(xmlTextWriterPtr writer) {
isc_mem_t *ctx;
summarystat_t summary;
isc_uint64_t lost;