Bug 704723 - Add memory reporter for XPConnect. r=mrbkap.

This commit is contained in:
Nicholas Nethercote 2011-12-05 14:24:28 -08:00
Родитель f28c716617
Коммит c14cf2fc1c
12 изменённых файлов: 345 добавлений и 13 удалений

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

@ -40,6 +40,8 @@
/*
* Double hashing implementation.
*
* Try to keep this file in sync with xpcom/glue/pldhash.cpp.
*/
#include <stdio.h>
#include <stdlib.h>
@ -96,7 +98,7 @@ using namespace js;
#define DECREMENT_RECURSION_LEVEL(table_) \
JS_BEGIN_MACRO \
if (RECURSION_LEVEL(table_) != IMMUTABLE_RECURSION_LEVEL) { \
JSDHASH_ONELINE_ASSERT(RECURSION_LEVEL(table_) > 0); \
JS_ASSERT(RECURSION_LEVEL(table_) > 0); \
--RECURSION_LEVEL(table_); \
} \
JS_END_MACRO
@ -783,6 +785,48 @@ JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg)
return i;
}
struct SizeOfEntryEnumeratorArg
{
size_t total;
JSDHashSizeOfEntryFun sizeOfEntry;
JSMallocSizeOfFun mallocSizeOf;
};
static JSDHashOperator
SizeOfEntryEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
void *arg)
{
SizeOfEntryEnumeratorArg *e = (SizeOfEntryEnumeratorArg *)arg;
e->total += e->sizeOfEntry(hdr, e->mallocSizeOf);
return JS_DHASH_NEXT;
}
extern JS_PUBLIC_API(size_t)
JS_DHashTableSizeOfExcludingThis(JSDHashTable *table,
JSDHashSizeOfEntryFun sizeOfEntry,
JSMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(table->entryStore,
JS_DHASH_TABLE_SIZE(table) * table->entrySize +
ENTRY_STORE_EXTRA);
if (sizeOfEntry) {
SizeOfEntryEnumeratorArg arg = { 0, sizeOfEntry, mallocSizeOf };
JS_DHashTableEnumerate(table, SizeOfEntryEnumerator, &arg);
n += arg.total;
}
return n;
}
extern JS_PUBLIC_API(size_t)
JS_DHashTableSizeOfIncludingThis(JSDHashTable *table,
JSDHashSizeOfEntryFun sizeOfEntry,
JSMallocSizeOfFun mallocSizeOf)
{
return mallocSizeOf(table, sizeof(JSDHashTable)) +
JS_DHashTableSizeOfExcludingThis(table, sizeOfEntry, mallocSizeOf);
}
#ifdef DEBUG
JS_PUBLIC_API(void)
JS_DHashMarkTableImmutable(JSDHashTable *table)

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

@ -40,8 +40,11 @@
#define jsdhash_h___
/*
* Double hashing, a la Knuth 6.
*
* Try to keep this file in sync with xpcom/glue/pldhash.h.
*/
#include "jstypes.h"
#include "jsutil.h"
JS_BEGIN_EXTERN_C
@ -576,6 +579,28 @@ typedef JSDHashOperator
extern JS_PUBLIC_API(uint32)
JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg);
typedef size_t
(* JSDHashSizeOfEntryFun)(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf);
/**
* Measure the size of the table's entry storage, and if |sizeOfEntry| is
* non-NULL, measure the size of things pointed to by entries. Doesn't measure
* |ops| because it's often shared between tables, nor |data| because it's
* opaque.
*/
extern JS_PUBLIC_API(size_t)
JS_DHashTableSizeOfExcludingThis(JSDHashTable *table,
JSDHashSizeOfEntryFun sizeOfEntry,
JSMallocSizeOfFun mallocSizeOf);
/**
* Like JS_DHashTableSizeOfExcludingThis, but includes sizeof(*this).
*/
extern JS_PUBLIC_API(size_t)
JS_DHashTableSizeOfIncludingThis(JSDHashTable *table,
JSDHashSizeOfEntryFun sizeOfEntry,
JSMallocSizeOfFun mallocSizeOf);
#ifdef DEBUG
/**
* Mark a table as immutable for the remainder of its lifetime. This

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

@ -991,6 +991,26 @@ XPCJSRuntime::ActivityCallback(void *arg, JSBool active)
}
}
size_t
XPCJSRuntime::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(XPCJSRuntime));
n += mWrappedJSMap->SizeOfIncludingThis(mallocSizeOf);
n += mIID2NativeInterfaceMap->SizeOfIncludingThis(mallocSizeOf);
n += mClassInfo2NativeSetMap->ShallowSizeOfIncludingThis(mallocSizeOf);
n += mNativeSetMap->SizeOfIncludingThis(mallocSizeOf);
// NULL for the second arg; we're not measuring anything hanging off the
// entries in mJSHolders.
n += JS_DHashTableSizeOfExcludingThis(&mJSHolders, NULL, mallocSizeOf);
// There are other XPCJSRuntime members that could be measured; the above
// ones have been seen by DMD to be worth measuring. More stuff may be
// added later.
return n;
}
/***************************************************************************/
@ -1575,6 +1595,12 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
data->runtimeThreadsStackCommitted += stackCommitted;
}
}
XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
data->xpconnect +=
xpcrt->SizeOfIncludingThis(MemoryReporterMallocSizeOf);
data->xpconnect +=
XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(MemoryReporterMallocSizeOf);
}
JS_DestroyContextNoGC(cx);
@ -1904,6 +1930,11 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
"hardly cost anything.",
callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
nsIMemoryReporter::KIND_HEAP, data.xpconnect,
"Memory used by XPConnect." SLOP_BYTES_STRING,
callback, closure);
ReportMemoryBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
JS_GC_HEAP_KIND, data.gcHeapChunkDirtyUnused,

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

@ -135,6 +135,22 @@ JSObject2WrappedJSMap::~JSObject2WrappedJSMap()
JS_DHashTableDestroy(mTable);
}
size_t
JSObject2WrappedJSMap::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(JSObject2WrappedJSMap));
n += mTable ? JS_DHashTableSizeOfIncludingThis(mTable, SizeOfEntry, mallocSizeOf) : 0;
return n;
}
/* static */ size_t
JSObject2WrappedJSMap::SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf)
{
return mallocSizeOf(((JSObject2WrappedJSMap::Entry*)hdr)->value,
sizeof(nsXPCWrappedJS));
}
/***************************************************************************/
// implement Native2WrappedNativeMap...
@ -161,6 +177,22 @@ Native2WrappedNativeMap::~Native2WrappedNativeMap()
JS_DHashTableDestroy(mTable);
}
size_t
Native2WrappedNativeMap::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(Native2WrappedNativeMap));
n += mTable ? JS_DHashTableSizeOfIncludingThis(mTable, SizeOfEntry, mallocSizeOf) : 0;
return n;
}
/* static */ size_t
Native2WrappedNativeMap::SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf)
{
return mallocSizeOf(((Native2WrappedNativeMap::Entry*)hdr)->value,
sizeof(XPCWrappedNative));
}
/***************************************************************************/
// implement IID2WrappedJSClassMap...
@ -234,6 +266,22 @@ IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
JS_DHashTableDestroy(mTable);
}
size_t
IID2NativeInterfaceMap::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(IID2NativeInterfaceMap));
n += mTable ? JS_DHashTableSizeOfIncludingThis(mTable, SizeOfEntry, mallocSizeOf) : 0;
return n;
}
/* static */ size_t
IID2NativeInterfaceMap::SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf)
{
XPCNativeInterface *iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
return iface->SizeOfIncludingThis(mallocSizeOf);
}
/***************************************************************************/
// implement ClassInfo2NativeSetMap...
@ -260,6 +308,16 @@ ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
JS_DHashTableDestroy(mTable);
}
size_t
ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(ClassInfo2NativeSetMap));
// The second arg is NULL because this is a "shallow" measurement of the map.
n += mTable ? JS_DHashTableSizeOfIncludingThis(mTable, NULL, mallocSizeOf) : 0;
return n;
}
/***************************************************************************/
// implement ClassInfo2WrappedNativeProtoMap...
@ -286,6 +344,22 @@ ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
JS_DHashTableDestroy(mTable);
}
size_t
ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(ClassInfo2WrappedNativeProtoMap));
n += mTable ? JS_DHashTableSizeOfIncludingThis(mTable, SizeOfEntry, mallocSizeOf) : 0;
return n;
}
/* static */ size_t
ClassInfo2WrappedNativeProtoMap::SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf)
{
return mallocSizeOf(((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value,
sizeof(XPCWrappedNativeProto));
}
/***************************************************************************/
// implement NativeSetMap...
@ -394,6 +468,22 @@ NativeSetMap::~NativeSetMap()
JS_DHashTableDestroy(mTable);
}
size_t
NativeSetMap::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(NativeSetMap));
n += mTable ? JS_DHashTableSizeOfIncludingThis(mTable, SizeOfEntry, mallocSizeOf) : 0;
return n;
}
/* static */ size_t
NativeSetMap::SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf)
{
XPCNativeSet *set = ((NativeSetMap::Entry*)hdr)->key_value;
return set->SizeOfIncludingThis(mallocSizeOf);
}
/***************************************************************************/
// implement IID2ThisTranslatorMap...

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

@ -102,10 +102,15 @@ public:
inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
{return JS_DHashTableEnumerate(mTable, f, arg);}
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
~JSObject2WrappedJSMap();
private:
JSObject2WrappedJSMap(); // no implementation
JSObject2WrappedJSMap(int size);
static size_t SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf);
private:
JSDHashTable *mTable;
};
@ -165,10 +170,15 @@ public:
inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
{return JS_DHashTableEnumerate(mTable, f, arg);}
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
~Native2WrappedNativeMap();
private:
Native2WrappedNativeMap(); // no implementation
Native2WrappedNativeMap(int size);
static size_t SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf);
private:
JSDHashTable *mTable;
};
@ -279,10 +289,15 @@ public:
inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
{return JS_DHashTableEnumerate(mTable, f, arg);}
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
~IID2NativeInterfaceMap();
private:
IID2NativeInterfaceMap(); // no implementation
IID2NativeInterfaceMap(int size);
static size_t SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf);
private:
JSDHashTable *mTable;
};
@ -333,6 +348,12 @@ public:
inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
{return JS_DHashTableEnumerate(mTable, f, arg);}
// ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
// So we don't want to count those XPCNativeSets, because they are better
// counted elsewhere (i.e. in XPCJSRuntime::mNativeSetMap, which holds
// pointers to *all* XPCNativeSets). Hence the "Shallow".
size_t ShallowSizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
~ClassInfo2NativeSetMap();
private:
ClassInfo2NativeSetMap(); // no implementation
@ -387,10 +408,15 @@ public:
inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
{return JS_DHashTableEnumerate(mTable, f, arg);}
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
~ClassInfo2WrappedNativeProtoMap();
private:
ClassInfo2WrappedNativeProtoMap(); // no implementation
ClassInfo2WrappedNativeProtoMap(int size);
static size_t SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf);
private:
JSDHashTable *mTable;
};
@ -455,10 +481,15 @@ public:
inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
{return JS_DHashTableEnumerate(mTable, f, arg);}
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
~NativeSetMap();
private:
NativeSetMap(); // no implementation
NativeSetMap(int size);
static size_t SizeOfEntry(JSDHashEntryHdr *hdr, JSMallocSizeOfFun mallocSizeOf);
private:
JSDHashTable *mTable;
};

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

@ -416,6 +416,16 @@ XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst)
delete [] (char*) inst;
}
size_t
XPCNativeInterface::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t computedSize = sizeof(XPCNativeInterface);
if (mMemberCount > 1)
computedSize += (mMemberCount - 1) * sizeof(XPCNativeMember);
return mallocSizeOf(this, computedSize);
}
void
XPCNativeInterface::DebugDump(PRInt16 depth)
{
@ -772,6 +782,16 @@ XPCNativeSet::DestroyInstance(XPCNativeSet* inst)
delete [] (char*) inst;
}
size_t
XPCNativeSet::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t computedSize = sizeof(XPCNativeSet);
if (mInterfaceCount > 1)
computedSize += (mInterfaceCount - 1) * sizeof(XPCNativeInterface *);
return mallocSizeOf(this, computedSize);
}
void
XPCNativeSet::DebugDump(PRInt16 depth)
{

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

@ -989,3 +989,34 @@ XPCWrappedNativeScope::DebugDump(PRInt16 depth)
XPC_LOG_OUTDENT();
#endif
}
size_t
XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
XPCAutoLock lock(rt->GetMapLock());
size_t n = 0;
for (XPCWrappedNativeScope *cur = gScopes; cur; cur = cur->mNext) {
n += cur->SizeOfIncludingThis(mallocSizeOf);
}
return n;
}
size_t
XPCWrappedNativeScope::SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(this, sizeof(XPCWrappedNativeScope));
n += mWrappedNativeMap->SizeOfIncludingThis(mallocSizeOf);
n += mWrappedNativeProtoMap->SizeOfIncludingThis(mallocSizeOf);
n += mMainThreadWrappedNativeProtoMap->SizeOfIncludingThis(mallocSizeOf);
// There are other XPCWrappedNativeScope members that could be measured;
// the above ones have been seen by DMD to be worth measuring. More stuff
// may be added later.
return n;
}

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

@ -815,6 +815,8 @@ public:
return gNewDOMBindingsEnabled;
}
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
private:
XPCJSRuntime(); // no implementation
XPCJSRuntime(nsXPConnect* aXPConnect);
@ -1607,6 +1609,12 @@ public:
void
DebugDump(PRInt16 depth);
static size_t
SizeOfAllScopesIncludingThis(nsMallocSizeOfFun mallocSizeOf);
size_t
SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
JSBool
IsValid() const {return mRuntime != nsnull;}
@ -1812,6 +1820,8 @@ public:
static void DestroyInstance(XPCNativeInterface* inst);
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
protected:
static XPCNativeInterface* NewInstance(XPCCallContext& ccx,
nsIInterfaceInfo* aInfo);
@ -1954,6 +1964,8 @@ public:
static void DestroyInstance(XPCNativeSet* inst);
size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
protected:
static XPCNativeSet* NewInstance(XPCCallContext& ccx,
XPCNativeInterface** array,

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

@ -237,6 +237,7 @@ struct IterateData
runtimeThreadsTemporary(0),
runtimeThreadsRegexpCode(0),
runtimeThreadsStackCommitted(0),
xpconnect(0),
gcHeapChunkTotal(0),
gcHeapChunkCleanUnused(0),
gcHeapChunkDirtyUnused(0),
@ -264,6 +265,7 @@ struct IterateData
PRInt64 runtimeThreadsTemporary;
PRInt64 runtimeThreadsRegexpCode;
PRInt64 runtimeThreadsStackCommitted;
PRInt64 xpconnect;
PRInt64 gcHeapChunkTotal;
PRInt64 gcHeapChunkCleanUnused;
PRInt64 gcHeapChunkDirtyUnused;

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

@ -258,7 +258,7 @@ public:
size_t ShallowSizeOfExcludingThis(nsMallocSizeOfFun mallocSizeOf)
{
if (IsInitialized()) {
return PL_DHashTableShallowSizeOfExcludingThis(&mTable, mallocSizeOf);
return PL_DHashTableSizeOfExcludingThis(&mTable, nsnull, mallocSizeOf);
}
return 0;
}

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

@ -69,7 +69,6 @@
*/
#ifdef DEBUG
#define JSDHASH_ONELINE_ASSERT PR_ASSERT
#define RECURSION_LEVEL(table_) (*(PRUint32*)(table_->entryStore + \
PL_DHASH_TABLE_SIZE(table_) * \
table_->entrySize))
@ -795,12 +794,46 @@ PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg)
return i;
}
size_t
PL_DHashTableShallowSizeOfExcludingThis(PLDHashTable *table,
nsMallocSizeOfFun mallocSizeOf)
struct SizeOfEntryEnumeratorArg
{
return mallocSizeOf(table->entryStore,
PL_DHASH_TABLE_SIZE(table) * table->entrySize);
size_t total;
PLDHashSizeOfEntryFun sizeOfEntry;
nsMallocSizeOfFun mallocSizeOf;
};
static PLDHashOperator
SizeOfEntryEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg)
{
SizeOfEntryEnumeratorArg *e = (SizeOfEntryEnumeratorArg *)arg;
e->total += e->sizeOfEntry(hdr, e->mallocSizeOf);
return PL_DHASH_NEXT;
}
size_t
PL_DHashTableSizeOfExcludingThis(PLDHashTable *table,
PLDHashSizeOfEntryFun sizeOfEntry,
nsMallocSizeOfFun mallocSizeOf)
{
size_t n = 0;
n += mallocSizeOf(table->entryStore,
PL_DHASH_TABLE_SIZE(table) * table->entrySize +
ENTRY_STORE_EXTRA);
if (sizeOfEntry) {
SizeOfEntryEnumeratorArg arg = { 0, sizeOfEntry, mallocSizeOf };
PL_DHashTableEnumerate(table, SizeOfEntryEnumerator, &arg);
n += arg.total;
}
return n;
}
size_t
PL_DHashTableSizeOfIncludingThis(PLDHashTable *table,
PLDHashSizeOfEntryFun sizeOfEntry,
nsMallocSizeOfFun mallocSizeOf)
{
return mallocSizeOf(table, sizeof(PLDHashTable)) +
PL_DHashTableSizeOfExcludingThis(table, sizeOfEntry, mallocSizeOf);
}
#ifdef DEBUG

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

@ -578,14 +578,27 @@ typedef PLDHashOperator
NS_COM_GLUE PRUint32
PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg);
typedef size_t
(* PLDHashSizeOfEntryFun)(PLDHashEntryHdr *hdr, nsMallocSizeOfFun mallocSizeOf);
/**
* Get the hashtable's entry storage size in bytes, excluding sizeof(*this) and
* any heap memory allocated by the objects in the hash table (hence the
* "Shallow").
* Measure the size of the table's entry storage, and if |sizeOfEntry| is
* non-NULL, measure the size of things pointed to by entries. Doesn't measure
* |ops| because it's often shared between tables, nor |data| because it's
* opaque.
*/
NS_COM_GLUE size_t
PL_DHashTableShallowSizeOfExcludingThis(PLDHashTable *table,
nsMallocSizeOfFun mallocSizeOf);
PL_DHashTableSizeOfExcludingThis(PLDHashTable *table,
PLDHashSizeOfEntryFun sizeOfEntry,
nsMallocSizeOfFun mallocSizeOf);
/**
* Like PL_DHashTableSizeOfExcludingThis, but includes sizeof(*this).
*/
NS_COM_GLUE size_t
PL_DHashTableSizeOfIncludingThis(PLDHashTable *table,
PLDHashSizeOfEntryFun sizeOfEntry,
nsMallocSizeOfFun mallocSizeOf);
#ifdef DEBUG
/**