Index: layout/base/nsPresShell.cpp =================================================================== RCS file: /cvsroot/mozilla/layout/base/nsPresShell.cpp,v retrieving revision 3.1064 diff -u -p -8 -r3.1064 nsPresShell.cpp --- layout/base/nsPresShell.cpp 2 Oct 2007 04:37:36 -0000 3.1064 +++ layout/base/nsPresShell.cpp 15 Oct 2007 19:23:11 -0000 @@ -195,16 +195,20 @@ #include "nsIMenuParent.h" #include "nsPlaceholderFrame.h" // Content viewer interfaces #include "nsIContentViewer.h" #include "imgIEncoder.h" #include "gfxPlatform.h" +// Stats +#include "prclist.h" +#include "nsIAboutModule.h" + #include "nsContentCID.h" static NS_DEFINE_CID(kCSSStyleSheetCID, NS_CSS_STYLESHEET_CID); static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID); PRBool nsIPresShell::gIsAccessibilityActive = PR_FALSE; // convert a color value to a string, in the CSS format #RRGGBB // * - initially created for bugs 31816, 20760, 22963 @@ -632,35 +636,39 @@ class FrameArena { public: FrameArena(PRUint32 aArenaSize = 4096); ~FrameArena(); // Memory management functions NS_HIDDEN_(void*) AllocateFrame(size_t aSize); NS_HIDDEN_(void) FreeFrame(size_t aSize, void* aPtr); + PRUint32 GetAllocationStats(PRUint32 *aOnFreelist = nsnull) { if (aOnFreelist) *aOnFreelist = mOnFreelist; return mAllocated; } private: #ifdef DEBUG // Number of frames in the pool PRUint32 mFrameCount; #endif + PRUint32 mAllocated; + PRUint32 mOnFreelist; #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA) // Underlying arena pool PLArenaPool mPool; // The recycler array is sparse with the indices being multiples of 4, // i.e., 0, 4, 8, 12, 16, 20, ... void* mRecyclers[gMaxRecycledSize >> 2]; #endif }; FrameArena::FrameArena(PRUint32 aArenaSize) + : mAllocated(0), mOnFreelist(0) #ifdef DEBUG - : mFrameCount(0) + , mFrameCount(0) #endif { #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA) // Initialize the arena pool PL_INIT_ARENA_POOL(&mPool, "FrameArena", aArenaSize); // Zero out the recyclers array memset(mRecyclers, 0, sizeof(mRecyclers)); @@ -696,56 +704,61 @@ FrameArena::AllocateFrame(size_t aSize) if (aSize < gMaxRecycledSize) { const int index = aSize >> 2; result = mRecyclers[index]; if (result) { // Need to move to the next object void* next = *((void**)result); mRecyclers[index] = next; + mOnFreelist -= aSize; } } if (!result) { // Allocate a new chunk from the arena PL_ARENA_ALLOCATE(result, &mPool, aSize); } #endif + if (result != nsnull) { + mAllocated += aSize; #ifdef DEBUG - if (result != nsnull) ++mFrameCount; #endif + } return result; } void FrameArena::FreeFrame(size_t aSize, void* aPtr) { #ifdef DEBUG --mFrameCount; // Mark the memory with 0xdd in DEBUG builds so that there will be // problems if someone tries to access memory that they've freed. memset(aPtr, 0xdd, aSize); #endif + mAllocated -= aSize; #if defined(DEBUG_TRACEMALLOC_FRAMEARENA) PR_Free(aPtr); #else // Ensure we have correct alignment for pointers. Important for Tru64 aSize = PR_ROUNDUP(aSize, sizeof(void*)); // See if it's a size that we recycle if (aSize < gMaxRecycledSize) { const int index = aSize >> 2; void* currentTop = mRecyclers[index]; mRecyclers[index] = aPtr; *((void**)aPtr) = currentTop; + mOnFreelist += aSize; } #ifdef DEBUG_dbaron else { fprintf(stderr, "WARNING: FrameArena::FreeFrame leaking chunk of %d bytes.\n", aSize); } #endif @@ -759,17 +772,17 @@ struct nsCallbackEventRequest }; // ---------------------------------------------------------------------------- class nsPresShellEventCB; class PresShell : public nsIPresShell, public nsIViewObserver, public nsStubDocumentObserver, public nsISelectionController, public nsIObserver, - public nsSupportsWeakReference + public nsSupportsWeakReference, public PRCList { public: PresShell(); NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW // nsISupports NS_DECL_ISUPPORTS @@ -993,16 +1006,17 @@ public: virtual void ListStyleSheets(FILE *out, PRInt32 aIndent = 0); virtual void VerifyStyleTree(); #endif #ifdef PR_LOGGING static PRLogModuleInfo* gLog; #endif + PRUint32 GetArenaAllocationStats(PRUint32 *aOnFreelist = nsnull) { return mFrameArena.GetAllocationStats(aOnFreelist); } protected: virtual ~PresShell(); void HandlePostedReflowCallbacks(); void UnsuppressAndInvalidate(); void WillCauseReflow() { ++mChangeNestCount; } @@ -1195,16 +1209,17 @@ private: void FireResizeEvent(); static void sResizeEventCallback(nsITimer* aTimer, void* aPresShell) ; nsCOMPtr mResizeEventTimer; typedef void (*nsPluginEnumCallback)(PresShell*, nsIContent*); void EnumeratePlugins(nsIDOMDocument *aDocument, const nsString &aPluginTag, nsPluginEnumCallback aCallback); + }; class nsPresShellEventCB : public nsDispatchingCallback { public: nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {} virtual void HandleEvent(nsEventChainPostVisitor& aVisitor) @@ -1364,32 +1379,35 @@ NS_NewPresShell(nsIPresShell** aInstance PresShell* it = new PresShell(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } return it->QueryInterface(NS_GET_IID(nsIPresShell), (void **) aInstancePtrResult); } +PRCList sPresShellList = PR_INIT_STATIC_CLIST(&sPresShellList); + PresShell::PresShell() { mSelection = nsnull; #ifdef MOZ_REFLOW_PERF mReflowCountMgr = new ReflowCountMgr(); mReflowCountMgr->SetPresContext(mPresContext); mReflowCountMgr->SetPresShell(this); #endif #ifdef PR_LOGGING if (! gLog) gLog = PR_NewLogModule("PresShell"); #endif mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES; mIsThemeSupportDisabled = PR_FALSE; new (this) nsFrameManager(); + PR_APPEND_LINK(this, &sPresShellList); } NS_IMPL_ISUPPORTS8(PresShell, nsIPresShell, nsIDocumentObserver, nsIViewObserver, nsISelectionController, nsISelectionDisplay, nsIObserver, nsISupportsWeakReference, nsIMutationObserver) PresShell::~PresShell() @@ -1408,16 +1426,17 @@ PresShell::~PresShell() delete mStyleSet; delete mFrameConstructor; mCurrentEventContent = nsnull; NS_IF_RELEASE(mPresContext); NS_IF_RELEASE(mDocument); NS_IF_RELEASE(mSelection); + PR_REMOVE_LINK(this); } /** * Initialize the presentation shell. Create view manager and style * manager. */ NS_IMETHODIMP PresShell::Init(nsIDocument* aDocument, @@ -7598,8 +7617,93 @@ void ReflowCountMgr::DisplayDiffsInTotal void ColorToString(nscolor aColor, nsAutoString &aString) { char buf[8]; PR_snprintf(buf, sizeof(buf), "#%02x%02x%02x", NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor)); CopyASCIItoUTF16(buf, aString); } + +class PresShellStats : public nsIAboutModule +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIABOUTMODULE +}; + +NS_IMPL_ISUPPORTS1(PresShellStats, nsIAboutModule) + +NS_IMETHODIMP +PresShellStats::NewChannel(nsIURI *uri, nsIChannel **result) +{ + nsresult rv; + // I would basically kill a man for "make channel with nsAString contents", I confess + nsCOMPtr streamChannel = do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID); + NS_ENSURE_STATE(streamChannel); + + rv = streamChannel->SetURI(uri); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr channel = do_QueryInterface(streamChannel, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr jsonStream = do_CreateInstance("@mozilla.org/io/string-input-stream;1"); + NS_ENSURE_STATE(jsonStream); + + nsCString jsonData("[ "); + + PRCList *iter; + for (iter = PR_LIST_HEAD(&sPresShellList); + iter != &sPresShellList; + iter = PR_NEXT_LINK(iter)) { + + PresShell *shell = (PresShell *)iter; + nsIDocument *doc = shell->GetDocument(); + nsIURI *uri = doc->GetDocumentURI(); + nsCAutoString uriCStr; + uri->GetSpec(uriCStr); + PRUint32 allocated, onFreelist; + allocated = shell->GetArenaAllocationStats(&onFreelist); + + jsonData.Append(" { uri: \""); + jsonData.Append(uriCStr); + jsonData.Append("\", allocated: "); + jsonData.AppendInt(allocated); + jsonData.Append(", onFreelist: "); + jsonData.AppendInt(onFreelist); + jsonData.Append(" }, \n"); + } + + jsonData.Append(" ]"); + + rv = jsonStream->SetData(PromiseFlatCString(jsonData).get(), -1); + NS_ENSURE_SUCCESS(rv, rv); + + rv = streamChannel->SetContentStream(jsonStream); + rv |= channel->SetContentType(NS_LITERAL_CSTRING("text/plain")); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ADDREF(*result = channel); + return NS_OK; +} + +NS_IMETHODIMP +PresShellStats::GetURIFlags(nsIURI *aURI, PRUint32 *aFlags) +{ + *aFlags = 0; + return NS_OK; +} + +nsresult +NS_NewPresShellStats(nsIAboutModule ** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + PresShellStats* it = new PresShellStats(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(NS_GET_IID(nsIAboutModule), + (void **) aInstancePtrResult); +} Index: layout/build/nsLayoutCID.h =================================================================== RCS file: /cvsroot/mozilla/layout/build/nsLayoutCID.h,v retrieving revision 3.58 diff -u -p -8 -r3.58 nsLayoutCID.h --- layout/build/nsLayoutCID.h 4 Oct 2007 06:05:33 -0000 3.58 +++ layout/build/nsLayoutCID.h 15 Oct 2007 19:23:11 -0000 @@ -96,16 +96,20 @@ // {2E363D60-872E-11d2-B531-000000000000} #define NS_CSSPARSER_CID \ { 0x2e363d60, 0x872e, 0x11d2, { 0xb5, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } // {E6FD9940-899D-11d2-8EAE-00805F29F370} #define NS_PRESSHELL_CID \ { 0xe6fd9940, 0x899d, 0x11d2, { 0x8e, 0xae, 0x0, 0x80, 0x5f, 0x29, 0xf3, 0x70 } } +// {4058af6f-204f-43a7-a45a-8ebc127a761d} +#define NS_PRESSHELLSTATS_CID \ +{ 0x4058af6f, 0x204f, 0x43a7, {0xa4, 0x5a, 0x8e, 0xbc, 0x12, 0x7a, 0x76, 0x1d } } + // {95F46161-D177-11d2-BF86-00105A1B0627} #define NS_HTML_CSS_STYLESHEET_CID \ { 0x95f46161, 0xd177, 0x11d2, { 0xbf, 0x86, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 } } // {eaca2576-0d4a-11d3-9d7e-0060088f9ff7} #define NS_CSS_LOADER_CID \ { 0xeaca2576, 0x0d4a, 0x11d3, { 0x9d, 0x7e, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7 } } Index: layout/build/nsLayoutModule.cpp =================================================================== RCS file: /cvsroot/mozilla/layout/build/nsLayoutModule.cpp,v retrieving revision 1.180 diff -u -p -8 -r1.180 nsLayoutModule.cpp --- layout/build/nsLayoutModule.cpp 4 Oct 2007 06:05:33 -0000 1.180 +++ layout/build/nsLayoutModule.cpp 15 Oct 2007 19:23:11 -0000 @@ -94,16 +94,17 @@ #include "nsContentAreaDragDrop.h" #include "nsContentList.h" #include "nsSyncLoadService.h" #include "nsBox.h" #include "nsIFrameTraversal.h" #include "nsLayoutCID.h" #include "nsILanguageAtomService.h" #include "nsStyleSheetService.h" +#include "nsIAboutModule.h" // Transformiix stuff #include "nsXPathEvaluator.h" #include "txMozillaXSLTProcessor.h" #include "txNodeSetAdaptor.h" #include "nsXPath1Scheme.h" #include "nsDOMParser.h" @@ -434,16 +435,19 @@ ctor_(nsISupports* aOuter, REFNSIID aIID #ifdef DEBUG MAKE_CTOR(CreateNewFrameUtil, nsIFrameUtil, NS_NewFrameUtil) MAKE_CTOR(CreateNewLayoutDebugger, nsILayoutDebugger, NS_NewLayoutDebugger) #endif MAKE_CTOR(CreateNewFrameTraversal, nsIFrameTraversal, NS_CreateFrameTraversal) MAKE_CTOR(CreateNewPresShell, nsIPresShell, NS_NewPresShell) + +nsresult NS_NewPresShellStats(nsIAboutModule **); +MAKE_CTOR(CreateNewPresShellStats, nsIAboutModule, NS_NewPresShellStats) #ifdef MOZ_XUL MAKE_CTOR(CreateNewBoxObject, nsIBoxObject, NS_NewBoxObject) MAKE_CTOR(CreateNewListBoxObject, nsIBoxObject, NS_NewListBoxObject) MAKE_CTOR(CreateNewMenuBoxObject, nsIBoxObject, NS_NewMenuBoxObject) MAKE_CTOR(CreateNewPopupBoxObject, nsIBoxObject, NS_NewPopupBoxObject) MAKE_CTOR(CreateNewScrollBoxObject, nsIBoxObject, NS_NewScrollBoxObject) MAKE_CTOR(CreateNewTreeBoxObject, nsIBoxObject, NS_NewTreeBoxObject) MAKE_CTOR(CreateNewContainerBoxObject, nsIBoxObject, NS_NewContainerBoxObject) @@ -803,16 +807,21 @@ static const nsModuleComponentInfo gComp // XXX ick { "Presentation shell", NS_PRESSHELL_CID, nsnull, CreateNewPresShell }, // XXX end ick + { "Presentation shell stats", + NS_PRESSHELLSTATS_CID, + NS_ABOUT_MODULE_CONTRACTID_PREFIX "presshell-stats", + CreateNewPresShellStats }, + #ifdef MOZ_XUL { "XUL Box Object", NS_BOXOBJECT_CID, "@mozilla.org/layout/xul-boxobject;1", CreateNewBoxObject }, { "XUL Listbox Box Object", NS_LISTBOXOBJECT_CID,