Bug 674922 - report per-frame-type numbers in about:memory; r=njn,roc

This commit is contained in:
Nathan Froyd 2012-06-06 13:29:16 -04:00
parent d958723b7d
commit 620badd810
10 changed files with 154 additions and 26 deletions

View File

@ -9600,7 +9600,8 @@ nsIDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
if (mPresShell) {
mPresShell->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf,
&aWindowSizes->mLayoutArenas,
&aWindowSizes->mArenaStats,
&aWindowSizes->mLayoutPresShell,
&aWindowSizes->mLayoutStyleSets,
&aWindowSizes->mLayoutTextRuns,
&aWindowSizes->mLayoutPresContext);

View File

@ -181,10 +181,11 @@ CollectWindowReports(nsGlobalWindow *aWindow,
"Memory used by style sheets within a window.");
aWindowTotalSizes->mStyleSheets += windowSizes.mStyleSheets;
REPORT("/layout/arenas", windowSizes.mLayoutArenas,
"Memory used by layout PresShell, PresContext, and other related "
"areas within a window.");
aWindowTotalSizes->mLayoutArenas += windowSizes.mLayoutArenas;
REPORT("/layout/pres-shell", windowSizes.mLayoutPresShell,
"Memory used by layout's PresShell, along with any structures "
"allocated in its arena and not measured elsewhere, "
"within a window.");
aWindowTotalSizes->mLayoutPresShell += windowSizes.mLayoutPresShell;
REPORT("/layout/style-sets", windowSizes.mLayoutStyleSets,
"Memory used by style sets within a window.");
@ -200,6 +201,34 @@ CollectWindowReports(nsGlobalWindow *aWindow,
"within a window.");
aWindowTotalSizes->mLayoutPresContext += windowSizes.mLayoutPresContext;
// There are many different kinds of frames, but it is very likely
// that only a few matter. Implement a cutoff so we don't bloat
// about:memory with many uninteresting entries.
static const size_t FRAME_SUNDRIES_THRESHOLD = 8192;
size_t frameSundriesSize = 0;
#define FRAME_ID(classname) \
{ \
size_t frameSize \
= windowSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname); \
if (frameSize < FRAME_SUNDRIES_THRESHOLD) { \
frameSundriesSize += frameSize; \
} else { \
REPORT("/layout/frames/" # classname, frameSize, \
"Memory used by frames of " \
"type " #classname " within a window."); \
aWindowTotalSizes->mArenaStats.FRAME_ID_STAT_FIELD(classname) \
+= frameSize; \
} \
}
#include "nsFrameIdList.h"
#undef FRAME_ID
if (frameSundriesSize > 0) {
REPORT("/layout/frames/sundries", frameSundriesSize,
"The sum of all memory used by frames which were too small "
"to be shown individually.");
}
#undef REPORT
return NS_OK;
@ -288,7 +317,7 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
"Memory used for style sheets within windows. "
"This is the sum of all windows' 'style-sheets' numbers.");
REPORT("window-objects-layout-arenas", windowTotalSizes.mLayoutArenas,
REPORT("window-objects-layout-pres-shell", windowTotalSizes.mLayoutPresShell,
"Memory used by layout PresShell and other related "
"areas within windows. This is the sum of all windows' "
"'layout/arenas' numbers.");
@ -305,6 +334,16 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
"Memory used for layout PresContexts within windows. "
"This is the sum of all windows' 'layout/pres-contexts' numbers.");
size_t frameTotal = 0;
#define FRAME_ID(classname) \
frameTotal += windowTotalSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname);
#include "nsFrameIdList.h"
#undef FRAME_ID
REPORT("window-objects-layout-frames", frameTotal,
"Memory used for layout frames within windows. "
"This is the sum of all windows' 'layout/frames/' numbers.");
#undef REPORT
return NS_OK;

View File

@ -12,6 +12,7 @@
#include "nsWeakReference.h"
#include "nsAutoPtr.h"
#include "mozilla/TimeStamp.h"
#include "nsArenaMemoryStats.h"
// This should be used for any nsINode sub-class that has fields of its own
// that it needs to measure; any sub-class that doesn't use it will inherit
@ -27,13 +28,14 @@ public:
mMallocSizeOf = aMallocSizeOf;
}
nsMallocSizeOfFun mMallocSizeOf;
nsArenaMemoryStats mArenaStats;
size_t mDOMElementNodes;
size_t mDOMTextNodes;
size_t mDOMCDATANodes;
size_t mDOMCommentNodes;
size_t mDOMOther;
size_t mStyleSheets;
size_t mLayoutArenas;
size_t mLayoutPresShell;
size_t mLayoutStyleSets;
size_t mLayoutTextRuns;
size_t mLayoutPresContext;

View File

@ -29,6 +29,7 @@ EXPORTS_NAMESPACES = mozilla
EXPORTS = \
FrameLayerBuilder.h \
FramePropertyTable.h \
nsArenaMemoryStats.h \
nsBidi.h \
nsBidiPresUtils.h \
nsCaret.h \

View File

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsArenaMemoryStats_h
#define nsArenaMemoryStats_h
#define FRAME_ID_STAT_FIELD(classname) mArena##classname
struct nsArenaMemoryStats {
#define FRAME_ID(classname) size_t FRAME_ID_STAT_FIELD(classname);
#include "nsFrameIdList.h"
#undef FRAME_ID
size_t mOther;
};
#endif // nsArenaMemoryStats_h

View File

@ -78,6 +78,7 @@ class nsARefreshObserver;
class nsAccessibilityService;
#endif
class nsIWidget;
class nsArenaMemoryStats;
typedef short SelectionType;
typedef PRUint64 nsFrameState;
@ -1231,10 +1232,11 @@ public:
virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0;
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
size_t *aArenasSize,
nsArenaMemoryStats *aArenaObjectsSize,
size_t *aPresShellSize,
size_t *aStyleSetsSize,
size_t *aTextRunsSize,
size_t *aPresContextSize) const = 0;
size_t *aPresContextSize) = 0;
/**
* Methods that retrieve the cached font inflation preferences.

View File

@ -15,6 +15,7 @@
#include "prmem.h"
#include "prinit.h"
#include "prlog.h"
#include "nsArenaMemoryStats.h"
#ifdef MOZ_CRASHREPORTER
#include "nsICrashReporter.h"
@ -251,11 +252,13 @@ public:
typedef PRUint32 KeyType;
nsTArray<void *> mEntries;
size_t mEntrySize;
size_t mEntriesEverAllocated;
typedef const void* KeyTypePointer;
KeyTypePointer mKey;
FreeList(KeyTypePointer aKey) : mEntrySize(0), mKey(aKey) {}
FreeList(KeyTypePointer aKey)
: mEntrySize(0), mEntriesEverAllocated(0), mKey(aKey) {}
// Default copy constructor and destructor are ok.
bool KeyEquals(KeyTypePointer const aKey) const
@ -327,6 +330,7 @@ struct nsPresArena::State {
}
// Allocate a new chunk from the arena
list->mEntriesEverAllocated++;
PL_ARENA_ALLOCATE(result, &mPool, aSize);
return result;
}
@ -354,7 +358,7 @@ struct nsPresArena::State {
return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf);
}
size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
size_t SizeOfIncludingThisFromMalloc(nsMallocSizeOfFun aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
@ -370,12 +374,66 @@ struct nsPresArena::State {
aMallocSizeOf);
return n;
}
struct EnumerateData {
nsArenaMemoryStats* stats;
size_t total;
};
static PLDHashOperator FreeListEnumerator(FreeList* aEntry, void* aData)
{
EnumerateData* data = static_cast<EnumerateData*>(aData);
// Note that we're not measuring the size of the entries on the free
// list here. The free list knows how many objects we've allocated
// ever (which includes any objects that may be on the FreeList's
// |mEntries| at this point) and we're using that to determine the
// total size of objects allocated with a given ID.
size_t totalSize = aEntry->mEntrySize * aEntry->mEntriesEverAllocated;
size_t* p;
switch (NS_PTR_TO_INT32(aEntry->mKey)) {
#define FRAME_ID(classname) \
case nsQueryFrame::classname##_id: \
p = &data->stats->FRAME_ID_STAT_FIELD(classname); \
break;
#include "nsFrameIdList.h"
#undef FRAME_ID
default:
return PL_DHASH_NEXT;
}
*p += totalSize;
data->total += totalSize;
return PL_DHASH_NEXT;
}
void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
nsArenaMemoryStats* aArenaStats)
{
// We do a complicated dance here because we want to measure the
// space taken up by the different kinds of objects in the arena,
// but we don't have pointers to those objects. And even if we did,
// we wouldn't be able to use aMallocSizeOf on them, since they were
// allocated out of malloc'd chunks of memory. So we compute the
// size of the arena as known by malloc and we add up the sizes of
// all the objects that we care about. Subtracting these two
// quantities gives us a catch-all "other" number, which includes
// slop in the arena itself as well as the size of objects that
// we've not measured explicitly.
size_t mallocSize = SizeOfIncludingThisFromMalloc(aMallocSizeOf);
EnumerateData data = { aArenaStats, 0 };
mFreeLists.EnumerateEntries(FreeListEnumerator, &data);
aArenaStats->mOther = mallocSize - data.total;
}
};
size_t
nsPresArena::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
void
nsPresArena::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
nsArenaMemoryStats* aArenaStats)
{
return mState ? mState->SizeOfIncludingThis(aMallocSizeOf) : 0;
mState->SizeOfIncludingThis(aMallocSizeOf, aArenaStats);
}
#else
@ -402,11 +460,9 @@ struct nsPresArena::State
}
};
size_t
nsPresArena::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
{
return 0;
}
void
nsPresArena::SizeOfExcludingThis(nsMallocSizeOfFun, nsArenaMemoryStats*)
{}
#endif // DEBUG_TRACEMALLOC_PRESARENA

View File

@ -13,6 +13,8 @@
#include "mozilla/StandardInteger.h"
class nsArenaMemoryStats;
// Uncomment this to disable arenas, instead forwarding to
// malloc for every allocation.
//#define DEBUG_TRACEMALLOC_PRESARENA 1
@ -56,7 +58,12 @@ public:
NS_HIDDEN_(void*) AllocateByObjectID(ObjectID aID, size_t aSize);
NS_HIDDEN_(void) FreeByObjectID(ObjectID aID, void* aPtr);
size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
/**
* Fill aArenaStats with sizes of interesting objects allocated in
* this arena and its mOther field with the size of everything else.
*/
void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
nsArenaMemoryStats* aArenaStats);
/**
* Get the poison value that can be used to fill a memory space with

View File

@ -8927,13 +8927,15 @@ PresShell::GetRootPresShell()
void
PresShell::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
size_t *aArenasSize,
nsArenaMemoryStats *aArenaObjectsSize,
size_t *aPresShellSize,
size_t *aStyleSetsSize,
size_t *aTextRunsSize,
size_t *aPresContextSize) const
size_t *aPresContextSize)
{
*aArenasSize = aMallocSizeOf(this);
*aArenasSize += mFrameArena.SizeOfExcludingThis(aMallocSizeOf);
mFrameArena.SizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize);
*aPresShellSize = aMallocSizeOf(this);
*aPresShellSize += aArenaObjectsSize->mOther;
*aStyleSetsSize = StyleSet()->SizeOfIncludingThis(aMallocSizeOf);

View File

@ -316,10 +316,11 @@ public:
}
void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
size_t *aArenasSize,
nsArenaMemoryStats *aArenaObjectsSize,
size_t *aPresShellSize,
size_t *aStyleSetsSize,
size_t *aTextRunsSize,
size_t *aPresContextSize) const;
size_t *aPresContextSize);
size_t SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf) const;
// This data is stored as a content property (nsGkAtoms::scrolling) on