From 5387c4e16bb186629bcc05be4173c84a75d5544e Mon Sep 17 00:00:00 2001 From: "brendan%mozilla.org" Date: Tue, 29 Aug 2000 01:52:13 +0000 Subject: [PATCH] Add possibly-too-verbose NS_TraceMallocDumpAllocations and its JS window-level function, for leak and bloat analysis. --- dom/src/base/nsJSEnvironment.cpp | 32 +++++++++++++++----- tools/trace-malloc/lib/nsTraceMalloc.c | 41 +++++++++++++++++++++++++- tools/trace-malloc/lib/nsTraceMalloc.h | 10 +++++++ xpcom/base/nsTraceMalloc.c | 41 +++++++++++++++++++++++++- xpcom/base/nsTraceMalloc.h | 10 +++++++ 5 files changed, 125 insertions(+), 9 deletions(-) diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index ffa8dbda8bc0..f23ee6bc9dcc 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -1088,14 +1088,32 @@ TraceMallocLogTimestamp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, j return JS_TRUE; } +static JSBool +TraceMallocDumpAllocations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + JSString *str; + const char *pathname; + + str = JS_ValueToString(cx, argv[0]); + if (!str) + return JS_FALSE; + pathname = JS_GetStringBytes(str); + if (NS_TraceMallocDumpAllocations(pathname) < 0) { + JS_ReportError(cx, "can't dump to %s: %s", pathname, strerror(errno)); + return JS_FALSE; + } + return JS_TRUE; +} + static JSFunctionSpec TraceMallocFunctions[] = { - {"TraceMallocDisable", TraceMallocDisable, 0, 0, 0}, - {"TraceMallocEnable", TraceMallocEnable, 0, 0, 0}, - {"TraceMallocOpenLogFile", TraceMallocOpenLogFile, 1, 0, 0}, - {"TraceMallocChangeLogFD", TraceMallocChangeLogFD, 1, 0, 0}, - {"TraceMallocCloseLogFD", TraceMallocCloseLogFD, 1, 0, 0}, - {"TraceMallocLogTimestamp", TraceMallocLogTimestamp, 1, 0, 0}, - {NULL, NULL, 0, 0, 0} + {"TraceMallocDisable", TraceMallocDisable, 0, 0, 0}, + {"TraceMallocEnable", TraceMallocEnable, 0, 0, 0}, + {"TraceMallocOpenLogFile", TraceMallocOpenLogFile, 1, 0, 0}, + {"TraceMallocChangeLogFD", TraceMallocChangeLogFD, 1, 0, 0}, + {"TraceMallocCloseLogFD", TraceMallocCloseLogFD, 1, 0, 0}, + {"TraceMallocLogTimestamp", TraceMallocLogTimestamp, 1, 0, 0}, + {"TraceMallocDumpAllocations", TraceMallocDumpAllocations, 1, 0, 0}, + {NULL, NULL, 0, 0, 0} }; #endif /* NS_TRACE_MALLOC */ diff --git a/tools/trace-malloc/lib/nsTraceMalloc.c b/tools/trace-malloc/lib/nsTraceMalloc.c index bf6fff62775b..33535e73875c 100644 --- a/tools/trace-malloc/lib/nsTraceMalloc.c +++ b/tools/trace-malloc/lib/nsTraceMalloc.c @@ -44,6 +44,7 @@ */ #include #include +#include #include #include #include @@ -374,6 +375,7 @@ struct callsite { uint32 serial; lfd_set lfdset; char *name; + int offset; callsite *parent; callsite *siblings; callsite *kids; @@ -387,7 +389,7 @@ static uint32 callsite_serial_generator = 0; static uint32 tmstats_serial_generator = 0; /* Root of the tree of callsites, the sum of all (cycle-compressed) stacks. */ -static callsite calltree_root = {0, 0, LFD_SET_STATIC_INITIALIZER, NULL, NULL, NULL, NULL}; +static callsite calltree_root = {0, 0, LFD_SET_STATIC_INITIALIZER, NULL, 0, NULL, NULL, NULL}; /* Basic instrumentation. */ static nsTMStats tmstats = NS_TMSTATS_STATIC_INITIALIZER; @@ -693,6 +695,7 @@ static callsite *calltree(uint32 *bp) site->serial = ++callsite_serial_generator; LFD_ZERO(&site->lfdset); site->name = method; + site->offset = offset; site->parent = parent; site->siblings = parent->kids; parent->kids = site; @@ -1259,4 +1262,40 @@ NS_TraceMallocLogTimestamp(const char *caption) PR_ExitMonitor(tmmon); } +static PRIntn +allocation_enumerator(PLHashEntry *he, PRIntn i, void *arg) +{ + allocation *alloc = (allocation*) he; + FILE *ofp = (FILE*) arg; + callsite *site = (callsite*) he->value; + + fprintf(ofp, "%8p %9lu ", he->key, (unsigned long) alloc->size); + while (site) { + if (site->name || site->parent) + fprintf(ofp, " %s+%d", site->name, site->offset); + site = site->parent; + if (site) + fputc(';', ofp); + } + fputc('\n', ofp); + return HT_ENUMERATE_NEXT; +} + +PR_IMPLEMENT(int) +NS_TraceMallocDumpAllocations(const char *pathname) +{ + FILE *ofp; + int rv; + + ofp = fopen(pathname, "w"); + if (!ofp) + return -1; + fprintf(ofp, "Address size stack\n"); + if (allocations) + PL_HashTableEnumerateEntries(allocations, allocation_enumerator, ofp); + rv = ferror(ofp) ? -1 : 0; + fclose(ofp); + return rv; +} + #endif /* NS_TRACE_MALLOC */ diff --git a/tools/trace-malloc/lib/nsTraceMalloc.h b/tools/trace-malloc/lib/nsTraceMalloc.h index 733d447dd02e..bc08dceff6a2 100644 --- a/tools/trace-malloc/lib/nsTraceMalloc.h +++ b/tools/trace-malloc/lib/nsTraceMalloc.h @@ -158,6 +158,16 @@ PR_EXTERN(void) NS_TraceMallocCloseLogFD(int fd); */ PR_EXTERN(void) NS_TraceMallocLogTimestamp(const char *caption); +/** + * Dump a human-readable listing of current allocations and their compressed + * stack backtraces to the file named by pathname. Beware this file may have + * very long lines. + * + * Return -1 on error with errno set by the system, 0 on success. + */ +PR_EXTERN(int) +NS_TraceMallocDumpAllocations(const char *pathname); + PR_END_EXTERN_C #endif /* nsTraceMalloc_h___ */ diff --git a/xpcom/base/nsTraceMalloc.c b/xpcom/base/nsTraceMalloc.c index bf6fff62775b..33535e73875c 100644 --- a/xpcom/base/nsTraceMalloc.c +++ b/xpcom/base/nsTraceMalloc.c @@ -44,6 +44,7 @@ */ #include #include +#include #include #include #include @@ -374,6 +375,7 @@ struct callsite { uint32 serial; lfd_set lfdset; char *name; + int offset; callsite *parent; callsite *siblings; callsite *kids; @@ -387,7 +389,7 @@ static uint32 callsite_serial_generator = 0; static uint32 tmstats_serial_generator = 0; /* Root of the tree of callsites, the sum of all (cycle-compressed) stacks. */ -static callsite calltree_root = {0, 0, LFD_SET_STATIC_INITIALIZER, NULL, NULL, NULL, NULL}; +static callsite calltree_root = {0, 0, LFD_SET_STATIC_INITIALIZER, NULL, 0, NULL, NULL, NULL}; /* Basic instrumentation. */ static nsTMStats tmstats = NS_TMSTATS_STATIC_INITIALIZER; @@ -693,6 +695,7 @@ static callsite *calltree(uint32 *bp) site->serial = ++callsite_serial_generator; LFD_ZERO(&site->lfdset); site->name = method; + site->offset = offset; site->parent = parent; site->siblings = parent->kids; parent->kids = site; @@ -1259,4 +1262,40 @@ NS_TraceMallocLogTimestamp(const char *caption) PR_ExitMonitor(tmmon); } +static PRIntn +allocation_enumerator(PLHashEntry *he, PRIntn i, void *arg) +{ + allocation *alloc = (allocation*) he; + FILE *ofp = (FILE*) arg; + callsite *site = (callsite*) he->value; + + fprintf(ofp, "%8p %9lu ", he->key, (unsigned long) alloc->size); + while (site) { + if (site->name || site->parent) + fprintf(ofp, " %s+%d", site->name, site->offset); + site = site->parent; + if (site) + fputc(';', ofp); + } + fputc('\n', ofp); + return HT_ENUMERATE_NEXT; +} + +PR_IMPLEMENT(int) +NS_TraceMallocDumpAllocations(const char *pathname) +{ + FILE *ofp; + int rv; + + ofp = fopen(pathname, "w"); + if (!ofp) + return -1; + fprintf(ofp, "Address size stack\n"); + if (allocations) + PL_HashTableEnumerateEntries(allocations, allocation_enumerator, ofp); + rv = ferror(ofp) ? -1 : 0; + fclose(ofp); + return rv; +} + #endif /* NS_TRACE_MALLOC */ diff --git a/xpcom/base/nsTraceMalloc.h b/xpcom/base/nsTraceMalloc.h index 733d447dd02e..bc08dceff6a2 100644 --- a/xpcom/base/nsTraceMalloc.h +++ b/xpcom/base/nsTraceMalloc.h @@ -158,6 +158,16 @@ PR_EXTERN(void) NS_TraceMallocCloseLogFD(int fd); */ PR_EXTERN(void) NS_TraceMallocLogTimestamp(const char *caption); +/** + * Dump a human-readable listing of current allocations and their compressed + * stack backtraces to the file named by pathname. Beware this file may have + * very long lines. + * + * Return -1 on error with errno set by the system, 0 on success. + */ +PR_EXTERN(int) +NS_TraceMallocDumpAllocations(const char *pathname); + PR_END_EXTERN_C #endif /* nsTraceMalloc_h___ */