mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 1004609, part 8 - Implement a caching version of WalkTheStack using LocationService. r=froydnj
Then use it in ref counting.
This commit is contained in:
parent
997fb49dfe
commit
fb1bd79d45
@ -6,19 +6,23 @@
|
||||
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsXPCOMPrivate.h"
|
||||
#include "nscore.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "prenv.h"
|
||||
#include "plstr.h"
|
||||
#include "prlink.h"
|
||||
#include "nsCRT.h"
|
||||
#include <math.h>
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsStackWalkPrivate.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "CodeAddressService.h"
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
#ifdef XP_WIN
|
||||
@ -206,6 +210,78 @@ static const PLHashAllocOps typesToLogHashAllocOps = {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef STACKWALKING_AVAILABLE
|
||||
|
||||
class CodeAddressServiceStringTable MOZ_FINAL
|
||||
{
|
||||
public:
|
||||
CodeAddressServiceStringTable()
|
||||
: mSet(64)
|
||||
{
|
||||
}
|
||||
|
||||
const char* Intern(const char* aString)
|
||||
{
|
||||
nsCharPtrHashKey* e = mSet.PutEntry(aString);
|
||||
return e->GetKey();
|
||||
}
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return mSet.SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef nsTHashtable<nsCharPtrHashKey> StringSet;
|
||||
StringSet mSet;
|
||||
};
|
||||
|
||||
struct CodeAddressServiceStringAlloc MOZ_FINAL
|
||||
{
|
||||
static char* copy(const char* aStr) { return strdup(aStr); }
|
||||
static void free(char* aPtr) { free(aPtr); }
|
||||
};
|
||||
|
||||
class CodeAddressServiceWriter MOZ_FINAL
|
||||
{
|
||||
public:
|
||||
explicit CodeAddressServiceWriter(FILE* aFile)
|
||||
: mFile(aFile)
|
||||
{
|
||||
}
|
||||
|
||||
void Write(const char* aFmt, ...) const
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, aFmt);
|
||||
vfprintf(mFile, aFmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
private:
|
||||
FILE* mFile;
|
||||
};
|
||||
|
||||
// WalkTheStack does not hold any locks needed by NS_DescribeCodeAddress, so
|
||||
// this class does not need to do anything.
|
||||
struct CodeAddressServiceLock MOZ_FINAL
|
||||
{
|
||||
static void Unlock() {}
|
||||
static void Lock() {}
|
||||
static bool IsLocked() { return true; }
|
||||
};
|
||||
|
||||
typedef mozilla::CodeAddressService<CodeAddressServiceStringTable,
|
||||
CodeAddressServiceStringAlloc,
|
||||
CodeAddressServiceWriter,
|
||||
CodeAddressServiceLock> WalkTheStackCodeAddressService;
|
||||
|
||||
mozilla::StaticAutoPtr<WalkTheStackCodeAddressService> gCodeAddressService;
|
||||
|
||||
#endif // STACKWALKING_AVAILABLE
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BloatEntry
|
||||
{
|
||||
public:
|
||||
@ -883,6 +959,13 @@ PrintStackFrame(void* aPC, void* aSP, void* aClosure)
|
||||
NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf));
|
||||
fputs(buf, stream);
|
||||
}
|
||||
|
||||
static void
|
||||
PrintStackFrameCached(void* aPC, void* aSP, void* aClosure)
|
||||
{
|
||||
CodeAddressServiceWriter *writer = static_cast<CodeAddressServiceWriter*>(aClosure);
|
||||
gCodeAddressService->WriteLocation(*writer, aPC);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -896,6 +979,19 @@ nsTraceRefcnt::WalkTheStack(FILE* aStream)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsTraceRefcnt::WalkTheStackCached(FILE* aStream)
|
||||
{
|
||||
#ifdef STACKWALKING_AVAILABLE
|
||||
if (!gCodeAddressService) {
|
||||
gCodeAddressService = new WalkTheStackCodeAddressService();
|
||||
}
|
||||
CodeAddressServiceWriter writer(aStream);
|
||||
NS_StackWalk(PrintStackFrameCached, /* skipFrames */ 2, /* maxFrames */ 0, &writer,
|
||||
0, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// This thing is exported by libstdc++
|
||||
@ -1038,14 +1134,14 @@ NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt,
|
||||
if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
|
||||
fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Create\n",
|
||||
aClazz, NS_PTR_TO_INT32(aPtr), serialno);
|
||||
nsTraceRefcnt::WalkTheStack(gAllocLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gAllocLog);
|
||||
}
|
||||
|
||||
if (gRefcntsLog && loggingThisType && loggingThisObject) {
|
||||
// Can't use PR_LOG(), b/c it truncates the line
|
||||
fprintf(gRefcntsLog,
|
||||
"\n<%s> 0x%08X %" PRIuPTR " AddRef %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
|
||||
nsTraceRefcnt::WalkTheStack(gRefcntsLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gRefcntsLog);
|
||||
fflush(gRefcntsLog);
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
@ -1090,7 +1186,7 @@ NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz)
|
||||
// Can't use PR_LOG(), b/c it truncates the line
|
||||
fprintf(gRefcntsLog,
|
||||
"\n<%s> 0x%08X %" PRIuPTR " Release %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
|
||||
nsTraceRefcnt::WalkTheStack(gRefcntsLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gRefcntsLog);
|
||||
fflush(gRefcntsLog);
|
||||
}
|
||||
|
||||
@ -1101,7 +1197,7 @@ NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz)
|
||||
fprintf(gAllocLog,
|
||||
"\n<%s> 0x%08X %" PRIdPTR " Destroy\n",
|
||||
aClazz, NS_PTR_TO_INT32(aPtr), serialno);
|
||||
nsTraceRefcnt::WalkTheStack(gAllocLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gAllocLog);
|
||||
}
|
||||
|
||||
if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
|
||||
@ -1142,7 +1238,7 @@ NS_LogCtor(void* aPtr, const char* aType, uint32_t aInstanceSize)
|
||||
if (gAllocLog && loggingThisType && loggingThisObject) {
|
||||
fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Ctor (%d)\n",
|
||||
aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
|
||||
nsTraceRefcnt::WalkTheStack(gAllocLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gAllocLog);
|
||||
}
|
||||
|
||||
UNLOCK_TRACELOG();
|
||||
@ -1184,7 +1280,7 @@ NS_LogDtor(void* aPtr, const char* aType, uint32_t aInstanceSize)
|
||||
if (gAllocLog && loggingThisType && loggingThisObject) {
|
||||
fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Dtor (%d)\n",
|
||||
aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
|
||||
nsTraceRefcnt::WalkTheStack(gAllocLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gAllocLog);
|
||||
}
|
||||
|
||||
UNLOCK_TRACELOG();
|
||||
@ -1228,7 +1324,7 @@ NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject)
|
||||
fprintf(gCOMPtrLog, "\n<?> 0x%08X %" PRIdPTR " nsCOMPtrAddRef %d 0x%08X\n",
|
||||
NS_PTR_TO_INT32(object), serialno, count ? (*count) : -1,
|
||||
NS_PTR_TO_INT32(aCOMPtr));
|
||||
nsTraceRefcnt::WalkTheStack(gCOMPtrLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gCOMPtrLog);
|
||||
}
|
||||
|
||||
UNLOCK_TRACELOG();
|
||||
@ -1272,7 +1368,7 @@ NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject)
|
||||
fprintf(gCOMPtrLog, "\n<?> 0x%08X %" PRIdPTR " nsCOMPtrRelease %d 0x%08X\n",
|
||||
NS_PTR_TO_INT32(object), serialno, count ? (*count) : -1,
|
||||
NS_PTR_TO_INT32(aCOMPtr));
|
||||
nsTraceRefcnt::WalkTheStack(gCOMPtrLog);
|
||||
nsTraceRefcnt::WalkTheStackCached(gCOMPtrLog);
|
||||
}
|
||||
|
||||
UNLOCK_TRACELOG();
|
||||
@ -1289,7 +1385,9 @@ void
|
||||
nsTraceRefcnt::Shutdown()
|
||||
{
|
||||
#ifdef NS_IMPL_REFCNT_LOGGING
|
||||
|
||||
#ifdef STACKWALKING_AVAILABLE
|
||||
gCodeAddressService = nullptr;
|
||||
#endif
|
||||
if (gBloatView) {
|
||||
PL_HashTableDestroy(gBloatView);
|
||||
gBloatView = nullptr;
|
||||
|
@ -28,6 +28,17 @@ public:
|
||||
static void DemangleSymbol(const char* aSymbol, char* aBuffer, int aBufLen);
|
||||
|
||||
static void WalkTheStack(FILE* aStream);
|
||||
|
||||
/**
|
||||
* This is a variant of |WalkTheStack| that uses |CodeAddressService| to cache
|
||||
* the results of |NS_DescribeCodeAddress|. If |WalkTheStackCached| is being
|
||||
* called frequently, it will be a few orders of magnitude faster than
|
||||
* |WalkTheStack|. However, the cache uses a lot of memory, which can cause
|
||||
* OOM crashes. Therefore, this should only be used for things like refcount
|
||||
* logging which walk the stack extremely frequently.
|
||||
*/
|
||||
static void WalkTheStackCached(FILE* aStream);
|
||||
|
||||
/**
|
||||
* Tell nsTraceRefcnt whether refcounting, allocation, and destruction
|
||||
* activity is legal. This is used to trigger assertions for any such
|
||||
|
Loading…
Reference in New Issue
Block a user