Cleaned up nsTraceRefcnt environment variables. r=kipp,beard

This commit is contained in:
warren%netscape.com 1999-10-23 03:16:19 +00:00
Родитель 882fb6588b
Коммит 39ddb330f1
5 изменённых файлов: 387 добавлений и 443 удалений

Просмотреть файл

@ -81,10 +81,9 @@ nsAboutBloat::NewChannel(const char *verb,
inStr = do_QueryInterface(s, &rv);
if (NS_FAILED(rv)) return rv;
}
else
if (leaks) {
// dump the current set of leaks.
GC_gcollect();
else if (leaks) {
// dump the current set of leaks.
GC_gcollect();
nsCOMPtr<nsISupports> s;
const char* msg = "Memory leaks dumped.";
@ -115,19 +114,14 @@ nsAboutBloat::NewChannel(const char *verb,
dumpFileName += time;
file += (const char*)dumpFileName;
nsCOMPtr<nsISupports> out;
rv = NS_NewTypicalOutputFileStream(getter_AddRefs(out), file);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIOutputStream> outStr = do_QueryInterface(out, &rv);
FILE* out = ::fopen(file, "w");
if (out == nsnull)
return NS_ERROR_FAILURE;
rv = nsTraceRefcnt::DumpStatistics(statType, out);
::fclose(out);
if (NS_FAILED(rv)) return rv;
rv = nsTraceRefcnt::DumpStatistics(statType, outStr);
if (NS_FAILED(rv)) return rv;
// close the output stream to flush it to disk
outStr = null_nsCOMPtr();
out = null_nsCOMPtr();
size = file.GetFileSize();
nsCOMPtr<nsISupports> in;

Просмотреть файл

@ -24,8 +24,6 @@
#include "plstr.h"
#include <stdlib.h>
#include "nsCOMPtr.h"
#include "nsIOutputStream.h"
#include "nsIFileStream.h"
#include "nsCRT.h"
#if defined(_WIN32)
@ -66,24 +64,21 @@ static PRLock* gTraceLock;
#define UNLOCK_TRACELOG()
#endif /* ! NS_MT_SUPPORTED */
static PRLogModuleInfo* gTraceRefcntLog;
static PLHashTable* gBloatView;
static PLHashTable* gTypesToLog;
static PRBool gLogging;
static PRBool gLogAllRefcnts;
static PRBool gLogSomeRefcnts;
static PRBool gLogToLeaky;
static PRBool gTrackBloat;
static PRBool gLogCalls;
static PRBool gLogNewAndDelete;
static PRBool gDumpLeaksOnly;
static PRBool gLogLeaksOnly;
static void (*leakyLogAddRef)(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_LOG_ALL 0x2
@ -173,7 +168,7 @@ public:
static PRIntn DumpNewEntry(PLHashEntry *he, PRIntn i, void *arg) {
BloatEntry* entry = (BloatEntry*)he->value;
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");
entry->Accumulate();
}
@ -184,7 +179,7 @@ public:
BloatEntry* entry = (BloatEntry*)he->value;
if (entry) {
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");
}
return HT_ENUMERATE_NEXT;
@ -210,7 +205,7 @@ public:
total->mClassSize += mClassSize; // adjust for average in DumpTotal
}
nsresult DumpTotal(PRUint32 nClasses, nsIOutputStream* out) {
nsresult DumpTotal(PRUint32 nClasses, FILE* out) {
mClassSize /= nClasses;
return Dump(-1, out, &mAllStats);
}
@ -242,30 +237,17 @@ public:
(stats->mCreates != stats->mDestroys));
}
static nsresult PrintDumpHeader(nsIOutputStream* out, const char* msg) {
nsresult rv;
char buf[256];
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,
static nsresult PrintDumpHeader(FILE* out, const char* msg) {
fprintf(out, "\n== BloatView: %s\n\n", msg);
fprintf(out,
" |<------Class----->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
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,
fprintf(out,
" 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;
}
nsresult Dump(PRIntn i, nsIOutputStream* out, nsTraceRefcntStats* stats) {
if (gDumpLeaksOnly && !HaveLeaks(stats)) {
nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntStats* stats) {
if (gLogLeaksOnly && !HaveLeaks(stats)) {
return NS_OK;
}
double nRefs = stats->mAddRefs + stats->mReleases;
@ -289,23 +271,18 @@ public:
stats->mCreates != 0 ||
meanObjs != 0 ||
stddevObjs != 0) {
char buf[256];
PRUint32 cnt, writeCnt;
cnt = PR_snprintf(buf, 256, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
i+1, mClassName,
mClassSize,
(stats->mCreates - stats->mDestroys) * mClassSize,
stats->mCreates,
(stats->mCreates - stats->mDestroys),
meanObjs,
stddevObjs,
stats->mAddRefs,
(stats->mAddRefs - stats->mReleases),
meanRefs,
stddevRefs);
nsresult rv = out->Write(buf, cnt, &writeCnt);
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
fprintf(out, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
i+1, mClassName,
mClassSize,
(stats->mCreates - stats->mDestroys) * mClassSize,
stats->mCreates,
(stats->mCreates - stats->mDestroys),
meanObjs,
stddevObjs,
stats->mAddRefs,
(stats->mAddRefs - stats->mReleases),
meanRefs,
stddevRefs);
}
return NS_OK;
}
@ -351,50 +328,47 @@ GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
#endif /* NS_BUILD_REFCNT_LOGGING */
nsresult
nsTraceRefcnt::DumpStatistics(StatisticsType type,
nsIOutputStream* out)
nsTraceRefcnt::DumpStatistics(StatisticsType type, FILE* out)
{
nsresult rv = NS_OK;
#ifdef NS_BUILD_REFCNT_LOGGING
if (!gTrackBloat || !gBloatView) {
return NS_OK;
if (gBloatLog == nsnull || gBloatView == nsnull) {
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();
if (gDumpLeaksOnly) {
fprintf(gLoggingStream, "Bloaty: Only dumping data about objects that leaked\n");
}
PRBool wasLogging = gLogging;
gLogging = PR_FALSE; // turn off logging for this method
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);
const char* msg;
if (type == NEW_STATS) {
dump = BloatEntry::DumpNewEntry;
msg = "NEW RESULTS";
if (gLogLeaksOnly)
msg = "NEW (incremental) LEAK STATISTICS";
else
msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
}
else {
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;
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:
gLogging = wasLogging;
@ -443,115 +417,118 @@ static PRBool LogThisType(const char* aTypeName)
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)
{
if (0 == gTraceRefcntLog) {
gTraceRefcntLog = PR_NewLogModule("xpcomrefcnt");
if (gInitialized) return;
gInitialized = PR_TRUE;
if (getenv("MOZ_DUMP_LEAKS")) {
gDumpLeaksOnly = PR_TRUE;
PRBool defined;
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.
const char* traceLogName = getenv("MOZ_TRACE_LOG");
if (traceLogName) {
FILE *stream = ::fopen(traceLogName, "w");
if (stream != NULL)
gLoggingStream = stream;
}
}
// See if bloaty is enabled
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");
}
}
(void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
// See if raw nspr logging is enabled
if (XPCOM_REFCNT_LOG_ALL & gTraceRefcntLog->level) {
gLogAllRefcnts = PR_TRUE;
fprintf(gLoggingStream, "XPCOM: logging all refcnt calls\n");
}
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;
}
(void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
// See if we should log to leaky instead of to nspr
if (XPCOM_REFCNT_LOG_TO_LEAKY & gTraceRefcntLog->level) {
gLogToLeaky = PR_TRUE;
defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
if (defined) {
gLogToLeaky = PR_TRUE;
void* p = nsnull;
void* q = nsnull;
#ifdef HAVE_LIBDL
void* p = dlsym(0, "__log_addref");
if (p) {
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;
}
p = dlsym(0, "__log_addref");
q = dlsym(0, "__log_release");
#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 ||
gLogCalls || gLogNewAndDelete) {
gLogging = PR_TRUE;
const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
if (classes) {
// 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)
gTraceLock = PR_NewLock();
gTraceLock = PR_NewLock();
#endif /* NS_MT_SUPPORTED */
}
}
#endif
@ -902,9 +879,10 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
if (gAllocLog || gRefcntsLog) {
HANDLE myProcess = ::GetCurrentProcess();
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
@ -919,7 +897,7 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
0);
// DWORD lastError = 0;
// 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);
}
#endif
@ -941,12 +919,12 @@ nsTraceRefcnt::LogAddRef(void* aPtr,
PRUint32 classSize)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aClazz, classSize);
if (entry) {
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
// using LogNewXPCOM instead to get file and line numbers.)
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
if (aRefCnt == 1 && (gLogNewAndDelete || loggingThisType)) {
fprintf(gLoggingStream, "\n<%s> 0x%08X Create\n",
if (aRefCnt == 1 && (gAllocLog || loggingThisType)) {
fprintf(gAllocLog, "\n<%s> 0x%08X Create\n",
aClazz, PRInt32(aPtr));
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
// (If we're on a losing architecture, don't do this because we'll be
// using LogAddRefCall instead to get file and line numbers.)
if (gLogAllRefcnts || loggingThisType) {
if (gRefcntsLog || loggingThisType) {
if (gLogToLeaky) {
(*leakyLogAddRef)(aPtr, aRefCnt - 1, aRefCnt);
}
else {
// 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);
WalkTheStack(gLoggingStream);
WalkTheStack(gRefcntsLog);
}
}
#endif
@ -992,12 +970,12 @@ nsTraceRefcnt::LogRelease(void* aPtr,
const char* aClazz)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aClazz, (PRUint32)-1);
if (entry) {
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
// using LogReleaseCall instead to get file and line numbers.)
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
if (gLogAllRefcnts || loggingThisType) {
if (gRefcntsLog || loggingThisType) {
if (gLogToLeaky) {
(*leakyLogRelease)(aPtr, aRefCnt + 1, aRefCnt);
}
else {
// 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);
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
// using LogDeleteXPCOM instead to get file and line numbers.)
if (aRefCnt == 0 && (gLogNewAndDelete || loggingThisType)) {
fprintf(gLoggingStream,
if (aRefCnt == 0 && (gAllocLog || loggingThisType)) {
fprintf(gAllocLog,
"\n<%s> 0x%08X Destroy\n",
aClazz, PRInt32(aPtr));
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
#endif
@ -1046,14 +1024,14 @@ nsTraceRefcnt::LogAddRefCall(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogCalls) {
if (gRefcntsLog) {
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);
WalkTheStack(gLoggingStream);
WalkTheStack(gRefcntsLog);
UNLOCK_TRACELOG();
}
@ -1070,15 +1048,15 @@ nsTraceRefcnt::LogReleaseCall(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogCalls) {
if (gRefcntsLog) {
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);
WalkTheStack(gLoggingStream);
WalkTheStack(gRefcntsLog);
UNLOCK_TRACELOG();
}
@ -1096,15 +1074,15 @@ nsTraceRefcnt::LogNewXPCOM(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogNewAndDelete) {
if (gAllocLog) {
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);
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
UNLOCK_TRACELOG();
}
@ -1119,15 +1097,15 @@ nsTraceRefcnt::LogDeleteXPCOM(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogNewAndDelete) {
if (gAllocLog) {
LOCK_TRACELOG();
fprintf(gLoggingStream, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
aType, aPtr, aFile, aLine);
WalkTheStack(gLoggingStream);
fprintf(gAllocLog, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
"?", aPtr, aFile, aLine);
WalkTheStack(gAllocLog);
UNLOCK_TRACELOG();
}
@ -1141,13 +1119,13 @@ nsTraceRefcnt::LogCtor(void* aPtr,
PRUint32 aInstanceSize)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
if (entry) {
entry->Ctor();
@ -1157,10 +1135,10 @@ nsTraceRefcnt::LogCtor(void* aPtr,
#ifndef NS_LOSING_ARCHITECTURE
// (If we're on a losing architecture, don't do this because we'll be
// using LogNewXPCOM instead to get file and line numbers.)
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
fprintf(gLoggingStream, "\n<%s> 0x%08X Ctor (%d)\n",
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
fprintf(gAllocLog, "\n<%s> 0x%08X Ctor (%d)\n",
aType, PRInt32(aPtr), aInstanceSize);
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
#endif
@ -1174,13 +1152,13 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
PRUint32 aInstanceSize)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
if (entry) {
entry->Dtor();
@ -1190,10 +1168,10 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
#ifndef NS_LOSING_ARCHITECTURE
// (If we're on a losing architecture, don't do this because we'll be
// using LogDeleteXPCOM instead to get file and line numbers.)
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
fprintf(gLoggingStream, "\n<%s> 0x%08X Dtor (%d)\n",
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
fprintf(gAllocLog, "\n<%s> 0x%08X Dtor (%d)\n",
aType, PRInt32(aPtr), aInstanceSize);
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
#endif

Просмотреть файл

@ -107,8 +107,6 @@ PR_END_MACRO
//----------------------------------------------------------------------
class nsIOutputStream;
struct nsTraceRefcntStats {
nsrefcnt mAddRefs;
nsrefcnt mReleases;
@ -182,7 +180,7 @@ public:
};
static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS,
nsIOutputStream* out = 0);
FILE* out = 0);
static NS_COM void ResetStatistics(void);
@ -196,7 +194,6 @@ public:
char * aBuffer,
int aBufLen);
// XXX change this to take an nsIOutputStream
static NS_COM void WalkTheStack(FILE* aStream);
};

Просмотреть файл

@ -24,8 +24,6 @@
#include "plstr.h"
#include <stdlib.h>
#include "nsCOMPtr.h"
#include "nsIOutputStream.h"
#include "nsIFileStream.h"
#include "nsCRT.h"
#if defined(_WIN32)
@ -66,24 +64,21 @@ static PRLock* gTraceLock;
#define UNLOCK_TRACELOG()
#endif /* ! NS_MT_SUPPORTED */
static PRLogModuleInfo* gTraceRefcntLog;
static PLHashTable* gBloatView;
static PLHashTable* gTypesToLog;
static PRBool gLogging;
static PRBool gLogAllRefcnts;
static PRBool gLogSomeRefcnts;
static PRBool gLogToLeaky;
static PRBool gTrackBloat;
static PRBool gLogCalls;
static PRBool gLogNewAndDelete;
static PRBool gDumpLeaksOnly;
static PRBool gLogLeaksOnly;
static void (*leakyLogAddRef)(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_LOG_ALL 0x2
@ -173,7 +168,7 @@ public:
static PRIntn DumpNewEntry(PLHashEntry *he, PRIntn i, void *arg) {
BloatEntry* entry = (BloatEntry*)he->value;
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");
entry->Accumulate();
}
@ -184,7 +179,7 @@ public:
BloatEntry* entry = (BloatEntry*)he->value;
if (entry) {
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");
}
return HT_ENUMERATE_NEXT;
@ -210,7 +205,7 @@ public:
total->mClassSize += mClassSize; // adjust for average in DumpTotal
}
nsresult DumpTotal(PRUint32 nClasses, nsIOutputStream* out) {
nsresult DumpTotal(PRUint32 nClasses, FILE* out) {
mClassSize /= nClasses;
return Dump(-1, out, &mAllStats);
}
@ -242,30 +237,17 @@ public:
(stats->mCreates != stats->mDestroys));
}
static nsresult PrintDumpHeader(nsIOutputStream* out, const char* msg) {
nsresult rv;
char buf[256];
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,
static nsresult PrintDumpHeader(FILE* out, const char* msg) {
fprintf(out, "\n== BloatView: %s\n\n", msg);
fprintf(out,
" |<------Class----->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
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,
fprintf(out,
" 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;
}
nsresult Dump(PRIntn i, nsIOutputStream* out, nsTraceRefcntStats* stats) {
if (gDumpLeaksOnly && !HaveLeaks(stats)) {
nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntStats* stats) {
if (gLogLeaksOnly && !HaveLeaks(stats)) {
return NS_OK;
}
double nRefs = stats->mAddRefs + stats->mReleases;
@ -289,23 +271,18 @@ public:
stats->mCreates != 0 ||
meanObjs != 0 ||
stddevObjs != 0) {
char buf[256];
PRUint32 cnt, writeCnt;
cnt = PR_snprintf(buf, 256, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
i+1, mClassName,
mClassSize,
(stats->mCreates - stats->mDestroys) * mClassSize,
stats->mCreates,
(stats->mCreates - stats->mDestroys),
meanObjs,
stddevObjs,
stats->mAddRefs,
(stats->mAddRefs - stats->mReleases),
meanRefs,
stddevRefs);
nsresult rv = out->Write(buf, cnt, &writeCnt);
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(cnt == writeCnt, "failed to write all data");
fprintf(out, "%4d %-20.20s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
i+1, mClassName,
mClassSize,
(stats->mCreates - stats->mDestroys) * mClassSize,
stats->mCreates,
(stats->mCreates - stats->mDestroys),
meanObjs,
stddevObjs,
stats->mAddRefs,
(stats->mAddRefs - stats->mReleases),
meanRefs,
stddevRefs);
}
return NS_OK;
}
@ -351,50 +328,47 @@ GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
#endif /* NS_BUILD_REFCNT_LOGGING */
nsresult
nsTraceRefcnt::DumpStatistics(StatisticsType type,
nsIOutputStream* out)
nsTraceRefcnt::DumpStatistics(StatisticsType type, FILE* out)
{
nsresult rv = NS_OK;
#ifdef NS_BUILD_REFCNT_LOGGING
if (!gTrackBloat || !gBloatView) {
return NS_OK;
if (gBloatLog == nsnull || gBloatView == nsnull) {
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();
if (gDumpLeaksOnly) {
fprintf(gLoggingStream, "Bloaty: Only dumping data about objects that leaked\n");
}
PRBool wasLogging = gLogging;
gLogging = PR_FALSE; // turn off logging for this method
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);
const char* msg;
if (type == NEW_STATS) {
dump = BloatEntry::DumpNewEntry;
msg = "NEW RESULTS";
if (gLogLeaksOnly)
msg = "NEW (incremental) LEAK STATISTICS";
else
msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
}
else {
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;
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:
gLogging = wasLogging;
@ -443,115 +417,118 @@ static PRBool LogThisType(const char* aTypeName)
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)
{
if (0 == gTraceRefcntLog) {
gTraceRefcntLog = PR_NewLogModule("xpcomrefcnt");
if (gInitialized) return;
gInitialized = PR_TRUE;
if (getenv("MOZ_DUMP_LEAKS")) {
gDumpLeaksOnly = PR_TRUE;
PRBool defined;
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.
const char* traceLogName = getenv("MOZ_TRACE_LOG");
if (traceLogName) {
FILE *stream = ::fopen(traceLogName, "w");
if (stream != NULL)
gLoggingStream = stream;
}
}
// See if bloaty is enabled
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");
}
}
(void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
// See if raw nspr logging is enabled
if (XPCOM_REFCNT_LOG_ALL & gTraceRefcntLog->level) {
gLogAllRefcnts = PR_TRUE;
fprintf(gLoggingStream, "XPCOM: logging all refcnt calls\n");
}
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;
}
(void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
// See if we should log to leaky instead of to nspr
if (XPCOM_REFCNT_LOG_TO_LEAKY & gTraceRefcntLog->level) {
gLogToLeaky = PR_TRUE;
defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
if (defined) {
gLogToLeaky = PR_TRUE;
void* p = nsnull;
void* q = nsnull;
#ifdef HAVE_LIBDL
void* p = dlsym(0, "__log_addref");
if (p) {
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;
}
p = dlsym(0, "__log_addref");
q = dlsym(0, "__log_release");
#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 ||
gLogCalls || gLogNewAndDelete) {
gLogging = PR_TRUE;
const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
if (classes) {
// 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)
gTraceLock = PR_NewLock();
gTraceLock = PR_NewLock();
#endif /* NS_MT_SUPPORTED */
}
}
#endif
@ -902,9 +879,10 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
if (gAllocLog || gRefcntsLog) {
HANDLE myProcess = ::GetCurrentProcess();
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
@ -919,7 +897,7 @@ nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
0);
// DWORD lastError = 0;
// 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);
}
#endif
@ -941,12 +919,12 @@ nsTraceRefcnt::LogAddRef(void* aPtr,
PRUint32 classSize)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aClazz, classSize);
if (entry) {
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
// using LogNewXPCOM instead to get file and line numbers.)
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
if (aRefCnt == 1 && (gLogNewAndDelete || loggingThisType)) {
fprintf(gLoggingStream, "\n<%s> 0x%08X Create\n",
if (aRefCnt == 1 && (gAllocLog || loggingThisType)) {
fprintf(gAllocLog, "\n<%s> 0x%08X Create\n",
aClazz, PRInt32(aPtr));
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
// (If we're on a losing architecture, don't do this because we'll be
// using LogAddRefCall instead to get file and line numbers.)
if (gLogAllRefcnts || loggingThisType) {
if (gRefcntsLog || loggingThisType) {
if (gLogToLeaky) {
(*leakyLogAddRef)(aPtr, aRefCnt - 1, aRefCnt);
}
else {
// 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);
WalkTheStack(gLoggingStream);
WalkTheStack(gRefcntsLog);
}
}
#endif
@ -992,12 +970,12 @@ nsTraceRefcnt::LogRelease(void* aPtr,
const char* aClazz)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aClazz, (PRUint32)-1);
if (entry) {
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
// using LogReleaseCall instead to get file and line numbers.)
PRBool loggingThisType = (gTypesToLog && LogThisType(aClazz));
if (gLogAllRefcnts || loggingThisType) {
if (gRefcntsLog || loggingThisType) {
if (gLogToLeaky) {
(*leakyLogRelease)(aPtr, aRefCnt + 1, aRefCnt);
}
else {
// 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);
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
// using LogDeleteXPCOM instead to get file and line numbers.)
if (aRefCnt == 0 && (gLogNewAndDelete || loggingThisType)) {
fprintf(gLoggingStream,
if (aRefCnt == 0 && (gAllocLog || loggingThisType)) {
fprintf(gAllocLog,
"\n<%s> 0x%08X Destroy\n",
aClazz, PRInt32(aPtr));
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
#endif
@ -1046,14 +1024,14 @@ nsTraceRefcnt::LogAddRefCall(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogCalls) {
if (gRefcntsLog) {
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);
WalkTheStack(gLoggingStream);
WalkTheStack(gRefcntsLog);
UNLOCK_TRACELOG();
}
@ -1070,15 +1048,15 @@ nsTraceRefcnt::LogReleaseCall(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogCalls) {
if (gRefcntsLog) {
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);
WalkTheStack(gLoggingStream);
WalkTheStack(gRefcntsLog);
UNLOCK_TRACELOG();
}
@ -1096,15 +1074,15 @@ nsTraceRefcnt::LogNewXPCOM(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogNewAndDelete) {
if (gAllocLog) {
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);
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
UNLOCK_TRACELOG();
}
@ -1119,15 +1097,15 @@ nsTraceRefcnt::LogDeleteXPCOM(void* aPtr,
{
#ifdef NS_BUILD_REFCNT_LOGGING
#ifdef NS_LOSING_ARCHITECTURE
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogNewAndDelete) {
if (gAllocLog) {
LOCK_TRACELOG();
fprintf(gLoggingStream, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
aType, aPtr, aFile, aLine);
WalkTheStack(gLoggingStream);
fprintf(gAllocLog, "\n<%s> 0x%08X Destroy in %s (line %d)\n",
"?", aPtr, aFile, aLine);
WalkTheStack(gAllocLog);
UNLOCK_TRACELOG();
}
@ -1141,13 +1119,13 @@ nsTraceRefcnt::LogCtor(void* aPtr,
PRUint32 aInstanceSize)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
if (entry) {
entry->Ctor();
@ -1157,10 +1135,10 @@ nsTraceRefcnt::LogCtor(void* aPtr,
#ifndef NS_LOSING_ARCHITECTURE
// (If we're on a losing architecture, don't do this because we'll be
// using LogNewXPCOM instead to get file and line numbers.)
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
fprintf(gLoggingStream, "\n<%s> 0x%08X Ctor (%d)\n",
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
fprintf(gAllocLog, "\n<%s> 0x%08X Ctor (%d)\n",
aType, PRInt32(aPtr), aInstanceSize);
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
#endif
@ -1174,13 +1152,13 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
PRUint32 aInstanceSize)
{
#ifdef NS_BUILD_REFCNT_LOGGING
if (gTraceRefcntLog == nsnull)
if (!gInitialized)
InitTraceLog();
if (gLogging) {
LOCK_TRACELOG();
if (gTrackBloat) {
if (gBloatLog) {
BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
if (entry) {
entry->Dtor();
@ -1190,10 +1168,10 @@ nsTraceRefcnt::LogDtor(void* aPtr, const char* aType,
#ifndef NS_LOSING_ARCHITECTURE
// (If we're on a losing architecture, don't do this because we'll be
// using LogDeleteXPCOM instead to get file and line numbers.)
if (gLogNewAndDelete || (gTypesToLog && LogThisType(aType))) {
fprintf(gLoggingStream, "\n<%s> 0x%08X Dtor (%d)\n",
if (gAllocLog || (gTypesToLog && LogThisType(aType))) {
fprintf(gAllocLog, "\n<%s> 0x%08X Dtor (%d)\n",
aType, PRInt32(aPtr), aInstanceSize);
WalkTheStack(gLoggingStream);
WalkTheStack(gAllocLog);
}
#endif

Просмотреть файл

@ -107,8 +107,6 @@ PR_END_MACRO
//----------------------------------------------------------------------
class nsIOutputStream;
struct nsTraceRefcntStats {
nsrefcnt mAddRefs;
nsrefcnt mReleases;
@ -182,7 +180,7 @@ public:
};
static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS,
nsIOutputStream* out = 0);
FILE* out = 0);
static NS_COM void ResetStatistics(void);
@ -196,7 +194,6 @@ public:
char * aBuffer,
int aBufLen);
// XXX change this to take an nsIOutputStream
static NS_COM void WalkTheStack(FILE* aStream);
};