зеркало из https://github.com/mozilla/pjs.git
Cleaned up nsTraceRefcnt environment variables. r=kipp,beard
This commit is contained in:
Родитель
882fb6588b
Коммит
39ddb330f1
|
@ -81,10 +81,9 @@ nsAboutBloat::NewChannel(const char *verb,
|
||||||
inStr = do_QueryInterface(s, &rv);
|
inStr = do_QueryInterface(s, &rv);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
}
|
}
|
||||||
else
|
else if (leaks) {
|
||||||
if (leaks) {
|
// dump the current set of leaks.
|
||||||
// dump the current set of leaks.
|
GC_gcollect();
|
||||||
GC_gcollect();
|
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> s;
|
nsCOMPtr<nsISupports> s;
|
||||||
const char* msg = "Memory leaks dumped.";
|
const char* msg = "Memory leaks dumped.";
|
||||||
|
@ -115,19 +114,14 @@ nsAboutBloat::NewChannel(const char *verb,
|
||||||
dumpFileName += time;
|
dumpFileName += time;
|
||||||
file += (const char*)dumpFileName;
|
file += (const char*)dumpFileName;
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> out;
|
FILE* out = ::fopen(file, "w");
|
||||||
rv = NS_NewTypicalOutputFileStream(getter_AddRefs(out), file);
|
if (out == nsnull)
|
||||||
if (NS_FAILED(rv)) return rv;
|
return NS_ERROR_FAILURE;
|
||||||
nsCOMPtr<nsIOutputStream> outStr = do_QueryInterface(out, &rv);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = nsTraceRefcnt::DumpStatistics(statType, outStr);
|
rv = nsTraceRefcnt::DumpStatistics(statType, out);
|
||||||
|
::fclose(out);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// close the output stream to flush it to disk
|
|
||||||
outStr = null_nsCOMPtr();
|
|
||||||
out = null_nsCOMPtr();
|
|
||||||
|
|
||||||
size = file.GetFileSize();
|
size = file.GetFileSize();
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> in;
|
nsCOMPtr<nsISupports> in;
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#include "plstr.h"
|
#include "plstr.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIOutputStream.h"
|
|
||||||
#include "nsIFileStream.h"
|
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
@ -66,24 +64,21 @@ static PRLock* gTraceLock;
|
||||||
#define UNLOCK_TRACELOG()
|
#define UNLOCK_TRACELOG()
|
||||||
#endif /* ! NS_MT_SUPPORTED */
|
#endif /* ! NS_MT_SUPPORTED */
|
||||||
|
|
||||||
static PRLogModuleInfo* gTraceRefcntLog;
|
|
||||||
|
|
||||||
static PLHashTable* gBloatView;
|
static PLHashTable* gBloatView;
|
||||||
static PLHashTable* gTypesToLog;
|
static PLHashTable* gTypesToLog;
|
||||||
|
|
||||||
static PRBool gLogging;
|
static PRBool gLogging;
|
||||||
static PRBool gLogAllRefcnts;
|
|
||||||
static PRBool gLogSomeRefcnts;
|
|
||||||
static PRBool gLogToLeaky;
|
static PRBool gLogToLeaky;
|
||||||
static PRBool gTrackBloat;
|
static PRBool gLogLeaksOnly;
|
||||||
static PRBool gLogCalls;
|
|
||||||
static PRBool gLogNewAndDelete;
|
|
||||||
static PRBool gDumpLeaksOnly;
|
|
||||||
|
|
||||||
static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
|
static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
|
||||||
static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
|
static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
|
||||||
|
|
||||||
static FILE *gLoggingStream = stderr;
|
static PRBool gInitialized = PR_FALSE;
|
||||||
|
static FILE *gBloatLog = nsnull;
|
||||||
|
static FILE *gRefcntsLog = nsnull;
|
||||||
|
static FILE *gAllocLog = nsnull;
|
||||||
|
static FILE *gLeakyLog = nsnull;
|
||||||
|
|
||||||
#define XPCOM_REFCNT_TRACK_BLOAT 0x1
|
#define XPCOM_REFCNT_TRACK_BLOAT 0x1
|
||||||
#define XPCOM_REFCNT_LOG_ALL 0x2
|
#define XPCOM_REFCNT_LOG_ALL 0x2
|
||||||
|
@ -173,7 +168,7 @@ public:
|
||||||
static PRIntn DumpNewEntry(PLHashEntry *he, PRIntn i, void *arg) {
|
static PRIntn DumpNewEntry(PLHashEntry *he, PRIntn i, void *arg) {
|
||||||
BloatEntry* entry = (BloatEntry*)he->value;
|
BloatEntry* entry = (BloatEntry*)he->value;
|
||||||
if (entry) {
|
if (entry) {
|
||||||
nsresult rv = entry->Dump(i, (nsIOutputStream*)arg, &entry->mNewStats);
|
nsresult rv = entry->Dump(i, (FILE*)arg, &entry->mNewStats);
|
||||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
||||||
entry->Accumulate();
|
entry->Accumulate();
|
||||||
}
|
}
|
||||||
|
@ -184,7 +179,7 @@ public:
|
||||||
BloatEntry* entry = (BloatEntry*)he->value;
|
BloatEntry* entry = (BloatEntry*)he->value;
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Accumulate();
|
entry->Accumulate();
|
||||||
nsresult rv = entry->Dump(i, (nsIOutputStream*)arg, &entry->mAllStats);
|
nsresult rv = entry->Dump(i, (FILE*)arg, &entry->mAllStats);
|
||||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
||||||
}
|
}
|
||||||
return HT_ENUMERATE_NEXT;
|
return HT_ENUMERATE_NEXT;
|
||||||
|
@ -210,7 +205,7 @@ public:
|
||||||
total->mClassSize += mClassSize; // adjust for average in DumpTotal
|
total->mClassSize += mClassSize; // adjust for average in DumpTotal
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult DumpTotal(PRUint32 nClasses, nsIOutputStream* out) {
|
nsresult DumpTotal(PRUint32 nClasses, FILE* out) {
|
||||||
mClassSize /= nClasses;
|
mClassSize /= nClasses;
|
||||||
return Dump(-1, out, &mAllStats);
|
return Dump(-1, out, &mAllStats);
|
||||||
}
|
}
|
||||||
|
@ -242,30 +237,17 @@ public:
|
||||||
(stats->mCreates != stats->mDestroys));
|
(stats->mCreates != stats->mDestroys));
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult PrintDumpHeader(nsIOutputStream* out, const char* msg) {
|
static nsresult PrintDumpHeader(FILE* out, const char* msg) {
|
||||||
nsresult rv;
|
fprintf(out, "\n== BloatView: %s\n\n", msg);
|
||||||
char buf[256];
|
fprintf(out,
|
||||||
PRUint32 cnt, writeCnt;
|
|
||||||
cnt = PR_snprintf(buf, 256,
|
|
||||||
" %s -- Bloaty: Refcounting and Memory Bloat Statistics\n", msg);
|
|
||||||
rv = out->Write(buf, cnt, &writeCnt);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
cnt = PR_snprintf(buf, 256,
|
|
||||||
" |<------Class----->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
|
" |<------Class----->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
|
||||||
rv = out->Write(buf, cnt, &writeCnt);
|
fprintf(out,
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
cnt = PR_snprintf(buf, 256,
|
|
||||||
" Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n");
|
" Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n");
|
||||||
rv = out->Write(buf, cnt, &writeCnt);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult Dump(PRIntn i, nsIOutputStream* out, nsTraceRefcntStats* stats) {
|
nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntStats* stats) {
|
||||||
if (gDumpLeaksOnly && !HaveLeaks(stats)) {
|
if (gLogLeaksOnly && !HaveLeaks(stats)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
double nRefs = stats->mAddRefs + stats->mReleases;
|
double nRefs = stats->mAddRefs + stats->mReleases;
|
||||||
|
@ -289,23 +271,18 @@ public:
|
||||||
stats->mCreates != 0 ||
|
stats->mCreates != 0 ||
|
||||||
meanObjs != 0 ||
|
meanObjs != 0 ||
|
||||||
stddevObjs != 0) {
|
stddevObjs != 0) {
|
||||||
char buf[256];
|
fprintf(out, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
|
||||||
PRUint32 cnt, writeCnt;
|
i+1, mClassName,
|
||||||
cnt = PR_snprintf(buf, 256, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
|
mClassSize,
|
||||||
i+1, mClassName,
|
(stats->mCreates - stats->mDestroys) * mClassSize,
|
||||||
mClassSize,
|
stats->mCreates,
|
||||||
(stats->mCreates - stats->mDestroys) * mClassSize,
|
(stats->mCreates - stats->mDestroys),
|
||||||
stats->mCreates,
|
meanObjs,
|
||||||
(stats->mCreates - stats->mDestroys),
|
stddevObjs,
|
||||||
meanObjs,
|
stats->mAddRefs,
|
||||||
stddevObjs,
|
(stats->mAddRefs - stats->mReleases),
|
||||||
stats->mAddRefs,
|
meanRefs,
|
||||||
(stats->mAddRefs - stats->mReleases),
|
stddevRefs);
|
||||||
meanRefs,
|
|
||||||
stddevRefs);
|
|
||||||
nsresult rv = out->Write(buf, cnt, &writeCnt);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -351,50 +328,47 @@ GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
|
||||||
#endif /* NS_BUILD_REFCNT_LOGGING */
|
#endif /* NS_BUILD_REFCNT_LOGGING */
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsTraceRefcnt::DumpStatistics(StatisticsType type,
|
nsTraceRefcnt::DumpStatistics(StatisticsType type, FILE* out)
|
||||||
nsIOutputStream* out)
|
|
||||||
{
|
{
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (!gTrackBloat || !gBloatView) {
|
if (gBloatLog == nsnull || gBloatView == nsnull) {
|
||||||
return NS_OK;
|
fprintf(stdout, "### ERROR: Can't dump bloat statistics because XPCOM_MEM_BLOAT_LOG isn't set.\n");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
if (out == nsnull) {
|
||||||
|
out = gBloatLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
if (gDumpLeaksOnly) {
|
|
||||||
fprintf(gLoggingStream, "Bloaty: Only dumping data about objects that leaked\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool wasLogging = gLogging;
|
PRBool wasLogging = gLogging;
|
||||||
gLogging = PR_FALSE; // turn off logging for this method
|
gLogging = PR_FALSE; // turn off logging for this method
|
||||||
|
|
||||||
BloatEntry total("TOTAL", 0);
|
BloatEntry total("TOTAL", 0);
|
||||||
nsCOMPtr<nsIOutputStream> outStr = dont_QueryInterface(out);
|
|
||||||
if (out == nsnull) {
|
|
||||||
nsCOMPtr<nsISupports> outSupports;
|
|
||||||
rv = NS_NewOutputConsoleStream(getter_AddRefs(outSupports));
|
|
||||||
if (NS_FAILED(rv)) goto done;
|
|
||||||
outStr = do_QueryInterface(outSupports, &rv);
|
|
||||||
if (NS_FAILED(rv)) goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRIntn (*dump)(PLHashEntry *he, PRIntn i, void *arg);
|
PRIntn (*dump)(PLHashEntry *he, PRIntn i, void *arg);
|
||||||
const char* msg;
|
const char* msg;
|
||||||
if (type == NEW_STATS) {
|
if (type == NEW_STATS) {
|
||||||
dump = BloatEntry::DumpNewEntry;
|
dump = BloatEntry::DumpNewEntry;
|
||||||
msg = "NEW RESULTS";
|
if (gLogLeaksOnly)
|
||||||
|
msg = "NEW (incremental) LEAK STATISTICS";
|
||||||
|
else
|
||||||
|
msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dump = BloatEntry::DumpAllEntry;
|
dump = BloatEntry::DumpAllEntry;
|
||||||
msg = "ALL RESULTS";
|
if (gLogLeaksOnly)
|
||||||
|
msg = "ALL (cumulative) LEAK STATISTICS";
|
||||||
|
else
|
||||||
|
msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
|
||||||
}
|
}
|
||||||
rv = BloatEntry::PrintDumpHeader(outStr, msg);
|
rv = BloatEntry::PrintDumpHeader(out, msg);
|
||||||
if (NS_FAILED(rv)) goto done;
|
if (NS_FAILED(rv)) goto done;
|
||||||
|
|
||||||
PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
|
PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
|
||||||
total.DumpTotal(gBloatView->nentries, outStr);
|
total.DumpTotal(gBloatView->nentries, out);
|
||||||
|
|
||||||
PL_HashTableEnumerateEntries(gBloatView, dump, outStr);
|
PL_HashTableEnumerateEntries(gBloatView, dump, out);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
gLogging = wasLogging;
|
gLogging = wasLogging;
|
||||||
|
@ -443,115 +417,118 @@ static PRBool LogThisType(const char* aTypeName)
|
||||||
return nsnull != he;
|
return nsnull != he;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PRBool InitLog(const char* envVar, const char* msg, FILE* *result)
|
||||||
|
{
|
||||||
|
const char* value = getenv(envVar);
|
||||||
|
if (value) {
|
||||||
|
if (nsCRT::strcmp(value, "1") == 0) {
|
||||||
|
*result = stdout;
|
||||||
|
fprintf(stdout, "### %s defined -- logging %s to stdout\n",
|
||||||
|
envVar, msg);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
else if (nsCRT::strcmp(value, "2") == 0) {
|
||||||
|
*result = stderr;
|
||||||
|
fprintf(stdout, "### %s defined -- logging %s to stderr\n",
|
||||||
|
envVar, msg);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FILE *stream = ::fopen(value, "w");
|
||||||
|
if (stream != NULL) {
|
||||||
|
*result = stream;
|
||||||
|
fprintf(stdout, "### %s defined -- logging %s to %s\n",
|
||||||
|
envVar, msg, value);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
|
||||||
|
envVar, msg, value);
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void InitTraceLog(void)
|
static void InitTraceLog(void)
|
||||||
{
|
{
|
||||||
if (0 == gTraceRefcntLog) {
|
if (gInitialized) return;
|
||||||
gTraceRefcntLog = PR_NewLogModule("xpcomrefcnt");
|
gInitialized = PR_TRUE;
|
||||||
|
|
||||||
if (getenv("MOZ_DUMP_LEAKS")) {
|
PRBool defined;
|
||||||
gDumpLeaksOnly = PR_TRUE;
|
defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
|
||||||
|
if (!defined)
|
||||||
|
gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
|
||||||
|
if (defined || gLogLeaksOnly) {
|
||||||
|
RecreateBloatView();
|
||||||
|
if (NS_WARN_IF_FALSE(gBloatView, "out of memory")) {
|
||||||
|
gBloatLog = nsnull;
|
||||||
|
gLogLeaksOnly = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// See if user is redirecting the trace.
|
(void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
|
||||||
const char* traceLogName = getenv("MOZ_TRACE_LOG");
|
|
||||||
if (traceLogName) {
|
|
||||||
FILE *stream = ::fopen(traceLogName, "w");
|
|
||||||
if (stream != NULL)
|
|
||||||
gLoggingStream = stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if bloaty is enabled
|
(void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
|
||||||
if (XPCOM_REFCNT_TRACK_BLOAT & gTraceRefcntLog->level) {
|
|
||||||
gTrackBloat = PR_TRUE;
|
|
||||||
RecreateBloatView();
|
|
||||||
if (NS_WARN_IF_FALSE(gBloatView, "out of memory")) {
|
|
||||||
gTrackBloat = PR_FALSE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(gLoggingStream, "XPCOM: using turbo mega bloatvision\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if raw nspr logging is enabled
|
defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
|
||||||
if (XPCOM_REFCNT_LOG_ALL & gTraceRefcntLog->level) {
|
if (defined) {
|
||||||
gLogAllRefcnts = PR_TRUE;
|
gLogToLeaky = PR_TRUE;
|
||||||
fprintf(gLoggingStream, "XPCOM: logging all refcnt calls\n");
|
void* p = nsnull;
|
||||||
}
|
void* q = nsnull;
|
||||||
else if (XPCOM_REFCNT_LOG_SOME & gTraceRefcntLog->level) {
|
|
||||||
gLogSomeRefcnts = PR_TRUE;
|
|
||||||
gTypesToLog = PL_NewHashTable(256,
|
|
||||||
PL_HashString,
|
|
||||||
PL_CompareStrings,
|
|
||||||
PL_CompareValues,
|
|
||||||
NULL, NULL);
|
|
||||||
if (NS_WARN_IF_FALSE(gTypesToLog, "out of memory")) {
|
|
||||||
gLogSomeRefcnts = PR_FALSE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if defined(XP_UNIX) || defined (XP_PC) || defined(XP_MAC)
|
|
||||||
char* types = getenv("MOZ_TRACE_REFCNT_TYPES");
|
|
||||||
if (types) {
|
|
||||||
fprintf(gLoggingStream, "XPCOM: logging some refcnt calls: ");
|
|
||||||
char* cp = types;
|
|
||||||
for (;;) {
|
|
||||||
char* cm = strchr(cp, ',');
|
|
||||||
if (cm) {
|
|
||||||
*cm = '\0';
|
|
||||||
}
|
|
||||||
PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
|
|
||||||
fprintf(gLoggingStream, "%s ", cp);
|
|
||||||
if (!cm) break;
|
|
||||||
*cm = ',';
|
|
||||||
cp = cm + 1;
|
|
||||||
}
|
|
||||||
fprintf(gLoggingStream, "\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(gLoggingStream, "XPCOM: MOZ_TRACE_REFCNTS_TYPE wasn't set; can't log some refcnts\n");
|
|
||||||
gLogSomeRefcnts = PR_FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (XPCOM_REFCNT_LOG_CALLS & gTraceRefcntLog->level) {
|
|
||||||
gLogCalls = PR_TRUE;
|
|
||||||
}
|
|
||||||
if (XPCOM_REFCNT_LOG_NEW & gTraceRefcntLog->level) {
|
|
||||||
gLogNewAndDelete = PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if we should log to leaky instead of to nspr
|
|
||||||
if (XPCOM_REFCNT_LOG_TO_LEAKY & gTraceRefcntLog->level) {
|
|
||||||
gLogToLeaky = PR_TRUE;
|
|
||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
void* p = dlsym(0, "__log_addref");
|
p = dlsym(0, "__log_addref");
|
||||||
if (p) {
|
q = dlsym(0, "__log_release");
|
||||||
leakyLogAddRef = (void (*)(void*,int,int)) p;
|
|
||||||
p = dlsym(0, "__log_release");
|
|
||||||
if (p) {
|
|
||||||
leakyLogRelease = (void (*)(void*,int,int)) p;
|
|
||||||
fprintf(gLoggingStream, "XPCOM: logging addref/release calls to leaky\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gLogToLeaky = PR_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gLogToLeaky = PR_FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
if (p && q) {
|
||||||
|
leakyLogAddRef = (void (*)(void*,int,int)) p;
|
||||||
|
leakyLogRelease = (void (*)(void*,int,int)) q;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
gLogToLeaky = PR_FALSE;
|
||||||
|
fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (gTrackBloat || gLogAllRefcnts || gLogSomeRefcnts ||
|
const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
|
||||||
gLogCalls || gLogNewAndDelete) {
|
if (classes) {
|
||||||
gLogging = PR_TRUE;
|
// if XPCOM_LOG_REFCNTS was set to some value, the value is interpreted
|
||||||
|
// as a list of class names to track
|
||||||
|
gTypesToLog = PL_NewHashTable(256,
|
||||||
|
PL_HashString,
|
||||||
|
PL_CompareStrings,
|
||||||
|
PL_CompareValues,
|
||||||
|
NULL, NULL);
|
||||||
|
if (NS_WARN_IF_FALSE(gTypesToLog, "out of memory")) {
|
||||||
|
fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
|
||||||
|
const char* cp = classes;
|
||||||
|
for (;;) {
|
||||||
|
char* cm = strchr(cp, ',');
|
||||||
|
if (cm) {
|
||||||
|
*cm = '\0';
|
||||||
|
}
|
||||||
|
PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
|
||||||
|
fprintf(stdout, "%s ", cp);
|
||||||
|
if (!cm) break;
|
||||||
|
*cm = ',';
|
||||||
|
cp = cm + 1;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog) {
|
||||||
|
gLogging = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(NS_MT_SUPPORTED)
|
#if defined(NS_MT_SUPPORTED)
|
||||||
gTraceLock = PR_NewLock();
|
gTraceLock = PR_NewLock();
|
||||||
#endif /* NS_MT_SUPPORTED */
|
#endif /* NS_MT_SUPPORTED */
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -902,9 +879,10 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
|
#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
|
||||||
|
if (gAllocLog || gRefcntsLog) {
|
||||||
HANDLE myProcess = ::GetCurrentProcess();
|
HANDLE myProcess = ::GetCurrentProcess();
|
||||||
|
|
||||||
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
||||||
|
@ -919,7 +897,7 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
|
||||||
0);
|
0);
|
||||||
// DWORD lastError = 0;
|
// DWORD lastError = 0;
|
||||||
// if (!b) lastError = ::GetLastError();
|
// if (!b) lastError = ::GetLastError();
|
||||||
// fprintf(gLoggingStream, "loading symbols for library %s => %s [%d]\n", aLibraryName,
|
// fprintf(gLogStream, "loading symbols for library %s => %s [%d]\n", aLibraryName,
|
||||||
// b ? "true" : "false", lastError);
|
// b ? "true" : "false", lastError);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -941,12 +919,12 @@ nsTraceRefcnt::LogAddRef(void* aPtr,
|
||||||
PRUint32 classSize)
|
PRUint32 classSize)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aClazz, classSize);
|
BloatEntry* entry = GetBloatEntry(aClazz, classSize);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->AddRef(aRefCnt);
|
entry->AddRef(aRefCnt);
|
||||||
|
@ -959,23 +937,23 @@ nsTraceRefcnt::LogAddRef(void* aPtr,
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogNewXPCOM instead to get file and line numbers.)
|
// using LogNewXPCOM instead to get file and line numbers.)
|
||||||
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
||||||
if (aRefCnt == 1 && (gLogNewAndDelete || loggingThisType)) {
|
if (aRefCnt == 1 && (gAllocLog || loggingThisType)) {
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Create\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Create\n",
|
||||||
aClazz, PRInt32(aPtr));
|
aClazz, PRInt32(aPtr));
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogAddRefCall instead to get file and line numbers.)
|
// using LogAddRefCall instead to get file and line numbers.)
|
||||||
if (gLogAllRefcnts || loggingThisType) {
|
if (gRefcntsLog || loggingThisType) {
|
||||||
if (gLogToLeaky) {
|
if (gLogToLeaky) {
|
||||||
(*leakyLogAddRef)(aPtr, aRefCnt - 1, aRefCnt);
|
(*leakyLogAddRef)(aPtr, aRefCnt - 1, aRefCnt);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Can't use PR_LOG(), b/c it truncates the line
|
// Can't use PR_LOG(), b/c it truncates the line
|
||||||
fprintf(gLoggingStream,
|
fprintf(gRefcntsLog,
|
||||||
"\n<%s> 0x%08X AddRef %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
"\n<%s> 0x%08X AddRef %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -992,12 +970,12 @@ nsTraceRefcnt::LogRelease(void* aPtr,
|
||||||
const char* aClazz)
|
const char* aClazz)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aClazz, (PRUint32)-1);
|
BloatEntry* entry = GetBloatEntry(aClazz, (PRUint32)-1);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Release(aRefCnt);
|
entry->Release(aRefCnt);
|
||||||
|
@ -1008,15 +986,15 @@ nsTraceRefcnt::LogRelease(void* aPtr,
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogReleaseCall instead to get file and line numbers.)
|
// using LogReleaseCall instead to get file and line numbers.)
|
||||||
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
||||||
if (gLogAllRefcnts || loggingThisType) {
|
if (gRefcntsLog || loggingThisType) {
|
||||||
if (gLogToLeaky) {
|
if (gLogToLeaky) {
|
||||||
(*leakyLogRelease)(aPtr, aRefCnt + 1, aRefCnt);
|
(*leakyLogRelease)(aPtr, aRefCnt + 1, aRefCnt);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Can't use PR_LOG(), b/c it truncates the line
|
// Can't use PR_LOG(), b/c it truncates the line
|
||||||
fprintf(gLoggingStream,
|
fprintf(gRefcntsLog,
|
||||||
"\n<%s> 0x%08X Release %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
"\n<%s> 0x%08X Release %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,11 +1003,11 @@ nsTraceRefcnt::LogRelease(void* aPtr,
|
||||||
|
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogDeleteXPCOM instead to get file and line numbers.)
|
// using LogDeleteXPCOM instead to get file and line numbers.)
|
||||||
if (aRefCnt == 0 && (gLogNewAndDelete || loggingThisType)) {
|
if (aRefCnt == 0 && (gAllocLog || loggingThisType)) {
|
||||||
fprintf(gLoggingStream,
|
fprintf(gAllocLog,
|
||||||
"\n<%s> 0x%08X Destroy\n",
|
"\n<%s> 0x%08X Destroy\n",
|
||||||
aClazz, PRInt32(aPtr));
|
aClazz, PRInt32(aPtr));
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1046,14 +1024,14 @@ nsTraceRefcnt::LogAddRefCall(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (gLogCalls) {
|
if (gRefcntsLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<Call> 0x%08X AddRef %d=>%d in %s (line %d)\n",
|
fprintf(gRefcntsLog, "\n<Call> 0x%08X AddRef %d=>%d in %s (line %d)\n",
|
||||||
aPtr, aNewRefcnt-1, aNewRefcnt, aFile, aLine);
|
aPtr, aNewRefcnt-1, aNewRefcnt, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1070,15 +1048,15 @@ nsTraceRefcnt::LogReleaseCall(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogCalls) {
|
if (gRefcntsLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<Call> 0x%08X Release %d=>%d in %s (line %d)\n",
|
fprintf(gRefcntsLog, "\n<Call> 0x%08X Release %d=>%d in %s (line %d)\n",
|
||||||
aPtr, aNewRefcnt+1, aNewRefcnt, aFile, aLine);
|
aPtr, aNewRefcnt+1, aNewRefcnt, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1096,15 +1074,15 @@ nsTraceRefcnt::LogNewXPCOM(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogNewAndDelete) {
|
if (gAllocLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X NewXPCOM in %s (line %d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X NewXPCOM in %s (line %d)\n",
|
||||||
aType, aPtr, aFile, aLine);
|
aType, aPtr, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1119,15 +1097,15 @@ nsTraceRefcnt::LogDeleteXPCOM(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogNewAndDelete) {
|
if (gAllocLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
|
||||||
aType, aPtr, aFile, aLine);
|
"?", aPtr, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1141,13 +1119,13 @@ nsTraceRefcnt::LogCtor(void* aPtr,
|
||||||
PRUint32 aInstanceSize)
|
PRUint32 aInstanceSize)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Ctor();
|
entry->Ctor();
|
||||||
|
@ -1157,10 +1135,10 @@ nsTraceRefcnt::LogCtor(void* aPtr,
|
||||||
#ifndef NS_LOSING_ARCHITECTURE
|
#ifndef NS_LOSING_ARCHITECTURE
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogNewXPCOM instead to get file and line numbers.)
|
// using LogNewXPCOM instead to get file and line numbers.)
|
||||||
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
|
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Ctor (%d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Ctor (%d)\n",
|
||||||
aType, PRInt32(aPtr), aInstanceSize);
|
aType, PRInt32(aPtr), aInstanceSize);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1174,13 +1152,13 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
|
||||||
PRUint32 aInstanceSize)
|
PRUint32 aInstanceSize)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Dtor();
|
entry->Dtor();
|
||||||
|
@ -1190,10 +1168,10 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
|
||||||
#ifndef NS_LOSING_ARCHITECTURE
|
#ifndef NS_LOSING_ARCHITECTURE
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogDeleteXPCOM instead to get file and line numbers.)
|
// using LogDeleteXPCOM instead to get file and line numbers.)
|
||||||
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
|
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Dtor (%d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Dtor (%d)\n",
|
||||||
aType, PRInt32(aPtr), aInstanceSize);
|
aType, PRInt32(aPtr), aInstanceSize);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -107,8 +107,6 @@ PR_END_MACRO
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
class nsIOutputStream;
|
|
||||||
|
|
||||||
struct nsTraceRefcntStats {
|
struct nsTraceRefcntStats {
|
||||||
nsrefcnt mAddRefs;
|
nsrefcnt mAddRefs;
|
||||||
nsrefcnt mReleases;
|
nsrefcnt mReleases;
|
||||||
|
@ -182,7 +180,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS,
|
static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS,
|
||||||
nsIOutputStream* out = 0);
|
FILE* out = 0);
|
||||||
|
|
||||||
static NS_COM void ResetStatistics(void);
|
static NS_COM void ResetStatistics(void);
|
||||||
|
|
||||||
|
@ -196,7 +194,6 @@ public:
|
||||||
char * aBuffer,
|
char * aBuffer,
|
||||||
int aBufLen);
|
int aBufLen);
|
||||||
|
|
||||||
// XXX change this to take an nsIOutputStream
|
|
||||||
static NS_COM void WalkTheStack(FILE* aStream);
|
static NS_COM void WalkTheStack(FILE* aStream);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#include "plstr.h"
|
#include "plstr.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIOutputStream.h"
|
|
||||||
#include "nsIFileStream.h"
|
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
@ -66,24 +64,21 @@ static PRLock* gTraceLock;
|
||||||
#define UNLOCK_TRACELOG()
|
#define UNLOCK_TRACELOG()
|
||||||
#endif /* ! NS_MT_SUPPORTED */
|
#endif /* ! NS_MT_SUPPORTED */
|
||||||
|
|
||||||
static PRLogModuleInfo* gTraceRefcntLog;
|
|
||||||
|
|
||||||
static PLHashTable* gBloatView;
|
static PLHashTable* gBloatView;
|
||||||
static PLHashTable* gTypesToLog;
|
static PLHashTable* gTypesToLog;
|
||||||
|
|
||||||
static PRBool gLogging;
|
static PRBool gLogging;
|
||||||
static PRBool gLogAllRefcnts;
|
|
||||||
static PRBool gLogSomeRefcnts;
|
|
||||||
static PRBool gLogToLeaky;
|
static PRBool gLogToLeaky;
|
||||||
static PRBool gTrackBloat;
|
static PRBool gLogLeaksOnly;
|
||||||
static PRBool gLogCalls;
|
|
||||||
static PRBool gLogNewAndDelete;
|
|
||||||
static PRBool gDumpLeaksOnly;
|
|
||||||
|
|
||||||
static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
|
static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
|
||||||
static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
|
static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
|
||||||
|
|
||||||
static FILE *gLoggingStream = stderr;
|
static PRBool gInitialized = PR_FALSE;
|
||||||
|
static FILE *gBloatLog = nsnull;
|
||||||
|
static FILE *gRefcntsLog = nsnull;
|
||||||
|
static FILE *gAllocLog = nsnull;
|
||||||
|
static FILE *gLeakyLog = nsnull;
|
||||||
|
|
||||||
#define XPCOM_REFCNT_TRACK_BLOAT 0x1
|
#define XPCOM_REFCNT_TRACK_BLOAT 0x1
|
||||||
#define XPCOM_REFCNT_LOG_ALL 0x2
|
#define XPCOM_REFCNT_LOG_ALL 0x2
|
||||||
|
@ -173,7 +168,7 @@ public:
|
||||||
static PRIntn DumpNewEntry(PLHashEntry *he, PRIntn i, void *arg) {
|
static PRIntn DumpNewEntry(PLHashEntry *he, PRIntn i, void *arg) {
|
||||||
BloatEntry* entry = (BloatEntry*)he->value;
|
BloatEntry* entry = (BloatEntry*)he->value;
|
||||||
if (entry) {
|
if (entry) {
|
||||||
nsresult rv = entry->Dump(i, (nsIOutputStream*)arg, &entry->mNewStats);
|
nsresult rv = entry->Dump(i, (FILE*)arg, &entry->mNewStats);
|
||||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
||||||
entry->Accumulate();
|
entry->Accumulate();
|
||||||
}
|
}
|
||||||
|
@ -184,7 +179,7 @@ public:
|
||||||
BloatEntry* entry = (BloatEntry*)he->value;
|
BloatEntry* entry = (BloatEntry*)he->value;
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Accumulate();
|
entry->Accumulate();
|
||||||
nsresult rv = entry->Dump(i, (nsIOutputStream*)arg, &entry->mAllStats);
|
nsresult rv = entry->Dump(i, (FILE*)arg, &entry->mAllStats);
|
||||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Dump failed");
|
||||||
}
|
}
|
||||||
return HT_ENUMERATE_NEXT;
|
return HT_ENUMERATE_NEXT;
|
||||||
|
@ -210,7 +205,7 @@ public:
|
||||||
total->mClassSize += mClassSize; // adjust for average in DumpTotal
|
total->mClassSize += mClassSize; // adjust for average in DumpTotal
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult DumpTotal(PRUint32 nClasses, nsIOutputStream* out) {
|
nsresult DumpTotal(PRUint32 nClasses, FILE* out) {
|
||||||
mClassSize /= nClasses;
|
mClassSize /= nClasses;
|
||||||
return Dump(-1, out, &mAllStats);
|
return Dump(-1, out, &mAllStats);
|
||||||
}
|
}
|
||||||
|
@ -242,30 +237,17 @@ public:
|
||||||
(stats->mCreates != stats->mDestroys));
|
(stats->mCreates != stats->mDestroys));
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult PrintDumpHeader(nsIOutputStream* out, const char* msg) {
|
static nsresult PrintDumpHeader(FILE* out, const char* msg) {
|
||||||
nsresult rv;
|
fprintf(out, "\n== BloatView: %s\n\n", msg);
|
||||||
char buf[256];
|
fprintf(out,
|
||||||
PRUint32 cnt, writeCnt;
|
|
||||||
cnt = PR_snprintf(buf, 256,
|
|
||||||
" %s -- Bloaty: Refcounting and Memory Bloat Statistics\n", msg);
|
|
||||||
rv = out->Write(buf, cnt, &writeCnt);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
cnt = PR_snprintf(buf, 256,
|
|
||||||
" |<------Class----->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
|
" |<------Class----->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
|
||||||
rv = out->Write(buf, cnt, &writeCnt);
|
fprintf(out,
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
cnt = PR_snprintf(buf, 256,
|
|
||||||
" Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n");
|
" Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n");
|
||||||
rv = out->Write(buf, cnt, &writeCnt);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult Dump(PRIntn i, nsIOutputStream* out, nsTraceRefcntStats* stats) {
|
nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntStats* stats) {
|
||||||
if (gDumpLeaksOnly && !HaveLeaks(stats)) {
|
if (gLogLeaksOnly && !HaveLeaks(stats)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
double nRefs = stats->mAddRefs + stats->mReleases;
|
double nRefs = stats->mAddRefs + stats->mReleases;
|
||||||
|
@ -289,23 +271,18 @@ public:
|
||||||
stats->mCreates != 0 ||
|
stats->mCreates != 0 ||
|
||||||
meanObjs != 0 ||
|
meanObjs != 0 ||
|
||||||
stddevObjs != 0) {
|
stddevObjs != 0) {
|
||||||
char buf[256];
|
fprintf(out, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
|
||||||
PRUint32 cnt, writeCnt;
|
i+1, mClassName,
|
||||||
cnt = PR_snprintf(buf, 256, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
|
mClassSize,
|
||||||
i+1, mClassName,
|
(stats->mCreates - stats->mDestroys) * mClassSize,
|
||||||
mClassSize,
|
stats->mCreates,
|
||||||
(stats->mCreates - stats->mDestroys) * mClassSize,
|
(stats->mCreates - stats->mDestroys),
|
||||||
stats->mCreates,
|
meanObjs,
|
||||||
(stats->mCreates - stats->mDestroys),
|
stddevObjs,
|
||||||
meanObjs,
|
stats->mAddRefs,
|
||||||
stddevObjs,
|
(stats->mAddRefs - stats->mReleases),
|
||||||
stats->mAddRefs,
|
meanRefs,
|
||||||
(stats->mAddRefs - stats->mReleases),
|
stddevRefs);
|
||||||
meanRefs,
|
|
||||||
stddevRefs);
|
|
||||||
nsresult rv = out->Write(buf, cnt, &writeCnt);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
|
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -351,50 +328,47 @@ GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
|
||||||
#endif /* NS_BUILD_REFCNT_LOGGING */
|
#endif /* NS_BUILD_REFCNT_LOGGING */
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsTraceRefcnt::DumpStatistics(StatisticsType type,
|
nsTraceRefcnt::DumpStatistics(StatisticsType type, FILE* out)
|
||||||
nsIOutputStream* out)
|
|
||||||
{
|
{
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (!gTrackBloat || !gBloatView) {
|
if (gBloatLog == nsnull || gBloatView == nsnull) {
|
||||||
return NS_OK;
|
fprintf(stdout, "### ERROR: Can't dump bloat statistics because XPCOM_MEM_BLOAT_LOG isn't set.\n");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
if (out == nsnull) {
|
||||||
|
out = gBloatLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
if (gDumpLeaksOnly) {
|
|
||||||
fprintf(gLoggingStream, "Bloaty: Only dumping data about objects that leaked\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool wasLogging = gLogging;
|
PRBool wasLogging = gLogging;
|
||||||
gLogging = PR_FALSE; // turn off logging for this method
|
gLogging = PR_FALSE; // turn off logging for this method
|
||||||
|
|
||||||
BloatEntry total("TOTAL", 0);
|
BloatEntry total("TOTAL", 0);
|
||||||
nsCOMPtr<nsIOutputStream> outStr = dont_QueryInterface(out);
|
|
||||||
if (out == nsnull) {
|
|
||||||
nsCOMPtr<nsISupports> outSupports;
|
|
||||||
rv = NS_NewOutputConsoleStream(getter_AddRefs(outSupports));
|
|
||||||
if (NS_FAILED(rv)) goto done;
|
|
||||||
outStr = do_QueryInterface(outSupports, &rv);
|
|
||||||
if (NS_FAILED(rv)) goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRIntn (*dump)(PLHashEntry *he, PRIntn i, void *arg);
|
PRIntn (*dump)(PLHashEntry *he, PRIntn i, void *arg);
|
||||||
const char* msg;
|
const char* msg;
|
||||||
if (type == NEW_STATS) {
|
if (type == NEW_STATS) {
|
||||||
dump = BloatEntry::DumpNewEntry;
|
dump = BloatEntry::DumpNewEntry;
|
||||||
msg = "NEW RESULTS";
|
if (gLogLeaksOnly)
|
||||||
|
msg = "NEW (incremental) LEAK STATISTICS";
|
||||||
|
else
|
||||||
|
msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dump = BloatEntry::DumpAllEntry;
|
dump = BloatEntry::DumpAllEntry;
|
||||||
msg = "ALL RESULTS";
|
if (gLogLeaksOnly)
|
||||||
|
msg = "ALL (cumulative) LEAK STATISTICS";
|
||||||
|
else
|
||||||
|
msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
|
||||||
}
|
}
|
||||||
rv = BloatEntry::PrintDumpHeader(outStr, msg);
|
rv = BloatEntry::PrintDumpHeader(out, msg);
|
||||||
if (NS_FAILED(rv)) goto done;
|
if (NS_FAILED(rv)) goto done;
|
||||||
|
|
||||||
PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
|
PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
|
||||||
total.DumpTotal(gBloatView->nentries, outStr);
|
total.DumpTotal(gBloatView->nentries, out);
|
||||||
|
|
||||||
PL_HashTableEnumerateEntries(gBloatView, dump, outStr);
|
PL_HashTableEnumerateEntries(gBloatView, dump, out);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
gLogging = wasLogging;
|
gLogging = wasLogging;
|
||||||
|
@ -443,115 +417,118 @@ static PRBool LogThisType(const char* aTypeName)
|
||||||
return nsnull != he;
|
return nsnull != he;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PRBool InitLog(const char* envVar, const char* msg, FILE* *result)
|
||||||
|
{
|
||||||
|
const char* value = getenv(envVar);
|
||||||
|
if (value) {
|
||||||
|
if (nsCRT::strcmp(value, "1") == 0) {
|
||||||
|
*result = stdout;
|
||||||
|
fprintf(stdout, "### %s defined -- logging %s to stdout\n",
|
||||||
|
envVar, msg);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
else if (nsCRT::strcmp(value, "2") == 0) {
|
||||||
|
*result = stderr;
|
||||||
|
fprintf(stdout, "### %s defined -- logging %s to stderr\n",
|
||||||
|
envVar, msg);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FILE *stream = ::fopen(value, "w");
|
||||||
|
if (stream != NULL) {
|
||||||
|
*result = stream;
|
||||||
|
fprintf(stdout, "### %s defined -- logging %s to %s\n",
|
||||||
|
envVar, msg, value);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
|
||||||
|
envVar, msg, value);
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void InitTraceLog(void)
|
static void InitTraceLog(void)
|
||||||
{
|
{
|
||||||
if (0 == gTraceRefcntLog) {
|
if (gInitialized) return;
|
||||||
gTraceRefcntLog = PR_NewLogModule("xpcomrefcnt");
|
gInitialized = PR_TRUE;
|
||||||
|
|
||||||
if (getenv("MOZ_DUMP_LEAKS")) {
|
PRBool defined;
|
||||||
gDumpLeaksOnly = PR_TRUE;
|
defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
|
||||||
|
if (!defined)
|
||||||
|
gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
|
||||||
|
if (defined || gLogLeaksOnly) {
|
||||||
|
RecreateBloatView();
|
||||||
|
if (NS_WARN_IF_FALSE(gBloatView, "out of memory")) {
|
||||||
|
gBloatLog = nsnull;
|
||||||
|
gLogLeaksOnly = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// See if user is redirecting the trace.
|
(void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
|
||||||
const char* traceLogName = getenv("MOZ_TRACE_LOG");
|
|
||||||
if (traceLogName) {
|
|
||||||
FILE *stream = ::fopen(traceLogName, "w");
|
|
||||||
if (stream != NULL)
|
|
||||||
gLoggingStream = stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if bloaty is enabled
|
(void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
|
||||||
if (XPCOM_REFCNT_TRACK_BLOAT & gTraceRefcntLog->level) {
|
|
||||||
gTrackBloat = PR_TRUE;
|
|
||||||
RecreateBloatView();
|
|
||||||
if (NS_WARN_IF_FALSE(gBloatView, "out of memory")) {
|
|
||||||
gTrackBloat = PR_FALSE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(gLoggingStream, "XPCOM: using turbo mega bloatvision\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if raw nspr logging is enabled
|
defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
|
||||||
if (XPCOM_REFCNT_LOG_ALL & gTraceRefcntLog->level) {
|
if (defined) {
|
||||||
gLogAllRefcnts = PR_TRUE;
|
gLogToLeaky = PR_TRUE;
|
||||||
fprintf(gLoggingStream, "XPCOM: logging all refcnt calls\n");
|
void* p = nsnull;
|
||||||
}
|
void* q = nsnull;
|
||||||
else if (XPCOM_REFCNT_LOG_SOME & gTraceRefcntLog->level) {
|
|
||||||
gLogSomeRefcnts = PR_TRUE;
|
|
||||||
gTypesToLog = PL_NewHashTable(256,
|
|
||||||
PL_HashString,
|
|
||||||
PL_CompareStrings,
|
|
||||||
PL_CompareValues,
|
|
||||||
NULL, NULL);
|
|
||||||
if (NS_WARN_IF_FALSE(gTypesToLog, "out of memory")) {
|
|
||||||
gLogSomeRefcnts = PR_FALSE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if defined(XP_UNIX) || defined (XP_PC) || defined(XP_MAC)
|
|
||||||
char* types = getenv("MOZ_TRACE_REFCNT_TYPES");
|
|
||||||
if (types) {
|
|
||||||
fprintf(gLoggingStream, "XPCOM: logging some refcnt calls: ");
|
|
||||||
char* cp = types;
|
|
||||||
for (;;) {
|
|
||||||
char* cm = strchr(cp, ',');
|
|
||||||
if (cm) {
|
|
||||||
*cm = '\0';
|
|
||||||
}
|
|
||||||
PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
|
|
||||||
fprintf(gLoggingStream, "%s ", cp);
|
|
||||||
if (!cm) break;
|
|
||||||
*cm = ',';
|
|
||||||
cp = cm + 1;
|
|
||||||
}
|
|
||||||
fprintf(gLoggingStream, "\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(gLoggingStream, "XPCOM: MOZ_TRACE_REFCNTS_TYPE wasn't set; can't log some refcnts\n");
|
|
||||||
gLogSomeRefcnts = PR_FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (XPCOM_REFCNT_LOG_CALLS & gTraceRefcntLog->level) {
|
|
||||||
gLogCalls = PR_TRUE;
|
|
||||||
}
|
|
||||||
if (XPCOM_REFCNT_LOG_NEW & gTraceRefcntLog->level) {
|
|
||||||
gLogNewAndDelete = PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if we should log to leaky instead of to nspr
|
|
||||||
if (XPCOM_REFCNT_LOG_TO_LEAKY & gTraceRefcntLog->level) {
|
|
||||||
gLogToLeaky = PR_TRUE;
|
|
||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
void* p = dlsym(0, "__log_addref");
|
p = dlsym(0, "__log_addref");
|
||||||
if (p) {
|
q = dlsym(0, "__log_release");
|
||||||
leakyLogAddRef = (void (*)(void*,int,int)) p;
|
|
||||||
p = dlsym(0, "__log_release");
|
|
||||||
if (p) {
|
|
||||||
leakyLogRelease = (void (*)(void*,int,int)) p;
|
|
||||||
fprintf(gLoggingStream, "XPCOM: logging addref/release calls to leaky\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gLogToLeaky = PR_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gLogToLeaky = PR_FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
if (p && q) {
|
||||||
|
leakyLogAddRef = (void (*)(void*,int,int)) p;
|
||||||
|
leakyLogRelease = (void (*)(void*,int,int)) q;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
gLogToLeaky = PR_FALSE;
|
||||||
|
fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (gTrackBloat || gLogAllRefcnts || gLogSomeRefcnts ||
|
const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
|
||||||
gLogCalls || gLogNewAndDelete) {
|
if (classes) {
|
||||||
gLogging = PR_TRUE;
|
// if XPCOM_LOG_REFCNTS was set to some value, the value is interpreted
|
||||||
|
// as a list of class names to track
|
||||||
|
gTypesToLog = PL_NewHashTable(256,
|
||||||
|
PL_HashString,
|
||||||
|
PL_CompareStrings,
|
||||||
|
PL_CompareValues,
|
||||||
|
NULL, NULL);
|
||||||
|
if (NS_WARN_IF_FALSE(gTypesToLog, "out of memory")) {
|
||||||
|
fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
|
||||||
|
const char* cp = classes;
|
||||||
|
for (;;) {
|
||||||
|
char* cm = strchr(cp, ',');
|
||||||
|
if (cm) {
|
||||||
|
*cm = '\0';
|
||||||
|
}
|
||||||
|
PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
|
||||||
|
fprintf(stdout, "%s ", cp);
|
||||||
|
if (!cm) break;
|
||||||
|
*cm = ',';
|
||||||
|
cp = cm + 1;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog) {
|
||||||
|
gLogging = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(NS_MT_SUPPORTED)
|
#if defined(NS_MT_SUPPORTED)
|
||||||
gTraceLock = PR_NewLock();
|
gTraceLock = PR_NewLock();
|
||||||
#endif /* NS_MT_SUPPORTED */
|
#endif /* NS_MT_SUPPORTED */
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -902,9 +879,10 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
|
#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
|
||||||
|
if (gAllocLog || gRefcntsLog) {
|
||||||
HANDLE myProcess = ::GetCurrentProcess();
|
HANDLE myProcess = ::GetCurrentProcess();
|
||||||
|
|
||||||
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
||||||
|
@ -919,7 +897,7 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
|
||||||
0);
|
0);
|
||||||
// DWORD lastError = 0;
|
// DWORD lastError = 0;
|
||||||
// if (!b) lastError = ::GetLastError();
|
// if (!b) lastError = ::GetLastError();
|
||||||
// fprintf(gLoggingStream, "loading symbols for library %s => %s [%d]\n", aLibraryName,
|
// fprintf(gLogStream, "loading symbols for library %s => %s [%d]\n", aLibraryName,
|
||||||
// b ? "true" : "false", lastError);
|
// b ? "true" : "false", lastError);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -941,12 +919,12 @@ nsTraceRefcnt::LogAddRef(void* aPtr,
|
||||||
PRUint32 classSize)
|
PRUint32 classSize)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aClazz, classSize);
|
BloatEntry* entry = GetBloatEntry(aClazz, classSize);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->AddRef(aRefCnt);
|
entry->AddRef(aRefCnt);
|
||||||
|
@ -959,23 +937,23 @@ nsTraceRefcnt::LogAddRef(void* aPtr,
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogNewXPCOM instead to get file and line numbers.)
|
// using LogNewXPCOM instead to get file and line numbers.)
|
||||||
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
||||||
if (aRefCnt == 1 && (gLogNewAndDelete || loggingThisType)) {
|
if (aRefCnt == 1 && (gAllocLog || loggingThisType)) {
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Create\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Create\n",
|
||||||
aClazz, PRInt32(aPtr));
|
aClazz, PRInt32(aPtr));
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogAddRefCall instead to get file and line numbers.)
|
// using LogAddRefCall instead to get file and line numbers.)
|
||||||
if (gLogAllRefcnts || loggingThisType) {
|
if (gRefcntsLog || loggingThisType) {
|
||||||
if (gLogToLeaky) {
|
if (gLogToLeaky) {
|
||||||
(*leakyLogAddRef)(aPtr, aRefCnt - 1, aRefCnt);
|
(*leakyLogAddRef)(aPtr, aRefCnt - 1, aRefCnt);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Can't use PR_LOG(), b/c it truncates the line
|
// Can't use PR_LOG(), b/c it truncates the line
|
||||||
fprintf(gLoggingStream,
|
fprintf(gRefcntsLog,
|
||||||
"\n<%s> 0x%08X AddRef %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
"\n<%s> 0x%08X AddRef %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -992,12 +970,12 @@ nsTraceRefcnt::LogRelease(void* aPtr,
|
||||||
const char* aClazz)
|
const char* aClazz)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aClazz, (PRUint32)-1);
|
BloatEntry* entry = GetBloatEntry(aClazz, (PRUint32)-1);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Release(aRefCnt);
|
entry->Release(aRefCnt);
|
||||||
|
@ -1008,15 +986,15 @@ nsTraceRefcnt::LogRelease(void* aPtr,
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogReleaseCall instead to get file and line numbers.)
|
// using LogReleaseCall instead to get file and line numbers.)
|
||||||
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
|
||||||
if (gLogAllRefcnts || loggingThisType) {
|
if (gRefcntsLog || loggingThisType) {
|
||||||
if (gLogToLeaky) {
|
if (gLogToLeaky) {
|
||||||
(*leakyLogRelease)(aPtr, aRefCnt + 1, aRefCnt);
|
(*leakyLogRelease)(aPtr, aRefCnt + 1, aRefCnt);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Can't use PR_LOG(), b/c it truncates the line
|
// Can't use PR_LOG(), b/c it truncates the line
|
||||||
fprintf(gLoggingStream,
|
fprintf(gRefcntsLog,
|
||||||
"\n<%s> 0x%08X Release %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
"\n<%s> 0x%08X Release %d\n", aClazz, PRInt32(aPtr), aRefCnt);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,11 +1003,11 @@ nsTraceRefcnt::LogRelease(void* aPtr,
|
||||||
|
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogDeleteXPCOM instead to get file and line numbers.)
|
// using LogDeleteXPCOM instead to get file and line numbers.)
|
||||||
if (aRefCnt == 0 && (gLogNewAndDelete || loggingThisType)) {
|
if (aRefCnt == 0 && (gAllocLog || loggingThisType)) {
|
||||||
fprintf(gLoggingStream,
|
fprintf(gAllocLog,
|
||||||
"\n<%s> 0x%08X Destroy\n",
|
"\n<%s> 0x%08X Destroy\n",
|
||||||
aClazz, PRInt32(aPtr));
|
aClazz, PRInt32(aPtr));
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1046,14 +1024,14 @@ nsTraceRefcnt::LogAddRefCall(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
if (gLogCalls) {
|
if (gRefcntsLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<Call> 0x%08X AddRef %d=>%d in %s (line %d)\n",
|
fprintf(gRefcntsLog, "\n<Call> 0x%08X AddRef %d=>%d in %s (line %d)\n",
|
||||||
aPtr, aNewRefcnt-1, aNewRefcnt, aFile, aLine);
|
aPtr, aNewRefcnt-1, aNewRefcnt, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1070,15 +1048,15 @@ nsTraceRefcnt::LogReleaseCall(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogCalls) {
|
if (gRefcntsLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<Call> 0x%08X Release %d=>%d in %s (line %d)\n",
|
fprintf(gRefcntsLog, "\n<Call> 0x%08X Release %d=>%d in %s (line %d)\n",
|
||||||
aPtr, aNewRefcnt+1, aNewRefcnt, aFile, aLine);
|
aPtr, aNewRefcnt+1, aNewRefcnt, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gRefcntsLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1096,15 +1074,15 @@ nsTraceRefcnt::LogNewXPCOM(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogNewAndDelete) {
|
if (gAllocLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X NewXPCOM in %s (line %d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X NewXPCOM in %s (line %d)\n",
|
||||||
aType, aPtr, aFile, aLine);
|
aType, aPtr, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1119,15 +1097,15 @@ nsTraceRefcnt::LogDeleteXPCOM(void* aPtr,
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
#ifdef NS_LOSING_ARCHITECTURE
|
#ifdef NS_LOSING_ARCHITECTURE
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogNewAndDelete) {
|
if (gAllocLog) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
|
||||||
aType, aPtr, aFile, aLine);
|
"?", aPtr, aFile, aLine);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
|
|
||||||
UNLOCK_TRACELOG();
|
UNLOCK_TRACELOG();
|
||||||
}
|
}
|
||||||
|
@ -1141,13 +1119,13 @@ nsTraceRefcnt::LogCtor(void* aPtr,
|
||||||
PRUint32 aInstanceSize)
|
PRUint32 aInstanceSize)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Ctor();
|
entry->Ctor();
|
||||||
|
@ -1157,10 +1135,10 @@ nsTraceRefcnt::LogCtor(void* aPtr,
|
||||||
#ifndef NS_LOSING_ARCHITECTURE
|
#ifndef NS_LOSING_ARCHITECTURE
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogNewXPCOM instead to get file and line numbers.)
|
// using LogNewXPCOM instead to get file and line numbers.)
|
||||||
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
|
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Ctor (%d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Ctor (%d)\n",
|
||||||
aType, PRInt32(aPtr), aInstanceSize);
|
aType, PRInt32(aPtr), aInstanceSize);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1174,13 +1152,13 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
|
||||||
PRUint32 aInstanceSize)
|
PRUint32 aInstanceSize)
|
||||||
{
|
{
|
||||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||||
if (gTraceRefcntLog == nsnull)
|
if (!gInitialized)
|
||||||
InitTraceLog();
|
InitTraceLog();
|
||||||
|
|
||||||
if (gLogging) {
|
if (gLogging) {
|
||||||
LOCK_TRACELOG();
|
LOCK_TRACELOG();
|
||||||
|
|
||||||
if (gTrackBloat) {
|
if (gBloatLog) {
|
||||||
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->Dtor();
|
entry->Dtor();
|
||||||
|
@ -1190,10 +1168,10 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
|
||||||
#ifndef NS_LOSING_ARCHITECTURE
|
#ifndef NS_LOSING_ARCHITECTURE
|
||||||
// (If we're on a losing architecture, don't do this because we'll be
|
// (If we're on a losing architecture, don't do this because we'll be
|
||||||
// using LogDeleteXPCOM instead to get file and line numbers.)
|
// using LogDeleteXPCOM instead to get file and line numbers.)
|
||||||
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
|
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
|
||||||
fprintf(gLoggingStream, "\n<%s> 0x%08X Dtor (%d)\n",
|
fprintf(gAllocLog, "\n<%s> 0x%08X Dtor (%d)\n",
|
||||||
aType, PRInt32(aPtr), aInstanceSize);
|
aType, PRInt32(aPtr), aInstanceSize);
|
||||||
WalkTheStack(gLoggingStream);
|
WalkTheStack(gAllocLog);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -107,8 +107,6 @@ PR_END_MACRO
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
class nsIOutputStream;
|
|
||||||
|
|
||||||
struct nsTraceRefcntStats {
|
struct nsTraceRefcntStats {
|
||||||
nsrefcnt mAddRefs;
|
nsrefcnt mAddRefs;
|
||||||
nsrefcnt mReleases;
|
nsrefcnt mReleases;
|
||||||
|
@ -182,7 +180,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS,
|
static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS,
|
||||||
nsIOutputStream* out = 0);
|
FILE* out = 0);
|
||||||
|
|
||||||
static NS_COM void ResetStatistics(void);
|
static NS_COM void ResetStatistics(void);
|
||||||
|
|
||||||
|
@ -196,7 +194,6 @@ public:
|
||||||
char * aBuffer,
|
char * aBuffer,
|
||||||
int aBufLen);
|
int aBufLen);
|
||||||
|
|
||||||
// XXX change this to take an nsIOutputStream
|
|
||||||
static NS_COM void WalkTheStack(FILE* aStream);
|
static NS_COM void WalkTheStack(FILE* aStream);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче