Bug 713799 - Rearrange the "window-objects" sub-tree in about:memory to make per-tab memory usage more obvious. r=jst.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 12 Mar 2012 23:00:18 -0700
changeset 92309 d762c5089a83d6a207445fdf0443955e34023fa2
parent 92308 ed1d52905a6147ba68248b1b96a7b6a0372ebebf
child 92310 0229c2ac3633c224661c394484e99ed2bb37ec47
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs713799
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 713799 - Rearrange the "window-objects" sub-tree in about:memory to make per-tab memory usage more obvious. r=jst.
dom/base/nsWindowMemoryReporter.cpp
toolkit/components/aboutmemory/tests/test_memoryReporters.xul
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -48,17 +48,17 @@ NS_IMPL_ISUPPORTS1(nsWindowMemoryReporte
 /* static */
 void
 nsWindowMemoryReporter::Init()
 {
   // The memory reporter manager is going to own this object.
   NS_RegisterMemoryMultiReporter(new nsWindowMemoryReporter());
 }
 
-static bool
+static void
 AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
 {
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
   nsCOMPtr<nsIURI> uri;
 
   if (doc) {
     uri = doc->GetDocumentURI();
   }
@@ -66,31 +66,29 @@ AppendWindowURI(nsGlobalWindow *aWindow,
   if (!uri) {
     nsIPrincipal *principal = aWindow->GetPrincipal();
 
     if (principal) {
       principal->GetURI(getter_AddRefs(uri));
     }
   }
 
-  if (!uri) {
-    return false;
-  }
-
-  nsCString spec;
-  uri->GetSpec(spec);
+  if (uri) {
+    nsCString spec;
+    uri->GetSpec(spec);
 
-  // A hack: replace forward slashes with '\\' so they aren't
-  // treated as path separators.  Users of the reporters
-  // (such as about:memory) have to undo this change.
-  spec.ReplaceChar('/', '\\');
+    // A hack: replace forward slashes with '\\' so they aren't
+    // treated as path separators.  Users of the reporters
+    // (such as about:memory) have to undo this change.
+    spec.ReplaceChar('/', '\\');
 
-  aStr += spec;
-
-  return true;
+    aStr += spec;
+  } else {
+    aStr += NS_LITERAL_CSTRING("[system]");
+  }
 }
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "windows")
 
 static nsresult
 CollectWindowReports(nsGlobalWindow *aWindow,
                      nsWindowSizes *aWindowTotalSizes,
                      nsIMemoryMultiReporterCallback *aCb,
@@ -99,135 +97,107 @@ CollectWindowReports(nsGlobalWindow *aWi
   // DOM window objects fall into one of three categories:
   // - "active" windows are currently either displayed in an active
   //   tab, or a child of such a window.
   // - "cached" windows are in the fastback cache.
   // - "other" windows are closed (or navigated away from w/o being
   //   cached) yet held alive by either a website or our code. The
   //   latter case may be a memory leak, but not necessarily.
   //
-  // For inner windows we show how much memory the window and its
-  // document etc use, and we report those per URI, where the URI is
-  // the document URI, if available, or the codebase of the principal
-  // in the window. In the case where we're unable to find a URI we're
-  // dealing with a chrome window with no document in it (or
-  // somesuch), and for that we make the URI be the string "[system]".
+  // For each window we show how much memory the window and its
+  // document, etc, use, and we report those per URI, where the URI is
+  // the document URI, if available, or the codebase of the principal in
+  // the window. In the case where we're unable to find a URI we're
+  // dealing with a chrome window with no document in it (or somesuch),
+  // and for that we make the URI be the string "[system]".
   //
-  // For outer windows we simply group them all together and just show
-  // the combined count and amount of memory used, which is generally
-  // a constant amount per window (since all the actual data lives in
-  // the inner window).
+  // Outer windows are lumped in with inner windows, because the amount
+  // of memory used by outer windows is small.
+  //
+  // The path we give to the reporter callback for "active" and "cached"
+  // windows (both inner and outer) is as follows:
   //
-  // The path we give to the reporter callback for inner windows are
-  // as follows:
+  //   explicit/window-objects/top(<top-outer-uri>, id=<top-outer-id>)/<category>/window(<window-uri>)/...
   //
-  //   explicit/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
+  // The path we give for "other" windows is as follows:
+  //
+  //   explicit/window-objects/top(none)/window(<window-uri>)/...
   //
   // Where:
-  // - <category> is active, cached, or other, as described above.
+  // - <category> is "active" or "cached", as described above.
   // - <top-outer-id> is the window id (nsPIDOMWindow::WindowID()) of
   //   the top outer window (i.e. tab, or top level chrome window).
-  // - <top-inner-id> is the window id of the top window's inner
-  //   window.
-  // - <id> is the window id of the inner window in question.
-  // - <uri> is the URI per above description.
+  // - <top-inner-uri> is the URI of the top outer window.  Excepting
+  //   special windows (such as browser.xul or hiddenWindow.html) it's
+  //   what the address bar shows for the tab.
+  // - <window-uri> is the URI of aWindow.
   //
-  // Exposing the window ids is done to get logical grouping in
-  // about:memory, and also for debuggability since one can get to the
-  // nsGlobalWindow for a window id by calling the static method
-  // nsGlobalWindow::GetInnerWindowWithId(id) (or
-  // GetOuterWindowWithId(id) in a debugger.
-  //
-  // For outer windows we simply use:
-  // 
-  //   explicit/window-objects/<category>/outer-windows
-  //
-  // Which gives us simple counts of how many outer windows (and their
-  // combined sizes) per category.
+  // Exposing the top-outer-id ensures that each tab gets its own
+  // sub-tree, even if multiple tabs are showing the same URI.
 
   nsCAutoString windowPath("explicit/window-objects/");
 
-  nsIDocShell *docShell = aWindow->GetDocShell();
-
   nsGlobalWindow *top = aWindow->GetTop();
-  nsWindowSizes windowSizes(DOMStyleMallocSizeOf);
-  aWindow->SizeOfIncludingThis(&windowSizes);
+  windowPath += NS_LITERAL_CSTRING("top(");
+  if (top) {
+    AppendWindowURI(top, windowPath);
+    windowPath += NS_LITERAL_CSTRING(", id=");
+    windowPath.AppendInt(top->WindowID());
+  } else {
+    windowPath += NS_LITERAL_CSTRING("none");
+  }
+  windowPath += NS_LITERAL_CSTRING(")/");
 
-  if (docShell && aWindow->IsFrozen()) {
-    windowPath += NS_LITERAL_CSTRING("cached/");
-  } else if (docShell) {
-    windowPath += NS_LITERAL_CSTRING("active/");
+  nsIDocShell *docShell = aWindow->GetDocShell();
+  if (docShell) {
+    MOZ_ASSERT(top, "'cached' or 'active' window lacks a top window");
+    windowPath += aWindow->IsFrozen() ? NS_LITERAL_CSTRING("cached/")
+                                      : NS_LITERAL_CSTRING("active/");
   } else {
-    windowPath += NS_LITERAL_CSTRING("other/");
+    MOZ_ASSERT(!top, "'other' window has a top window");
   }
 
-  if (aWindow->IsInnerWindow()) {
-    windowPath += NS_LITERAL_CSTRING("top=");
-
-    if (top) {
-      windowPath.AppendInt(top->WindowID());
-
-      nsGlobalWindow *topInner = top->GetCurrentInnerWindowInternal();
-      if (topInner) {
-        windowPath += NS_LITERAL_CSTRING(" (inner=");
-        windowPath.AppendInt(topInner->WindowID());
-        windowPath += NS_LITERAL_CSTRING(")");
-      }
-    } else {
-      windowPath += NS_LITERAL_CSTRING("none");
-    }
+  windowPath += NS_LITERAL_CSTRING("window(");
+  AppendWindowURI(aWindow, windowPath);
+  windowPath += NS_LITERAL_CSTRING(")");
 
-    windowPath += NS_LITERAL_CSTRING("/inner-window(id=");
-    windowPath.AppendInt(aWindow->WindowID());
-    windowPath += NS_LITERAL_CSTRING(", uri=");
-
-    if (!AppendWindowURI(aWindow, windowPath)) {
-      windowPath += NS_LITERAL_CSTRING("[system]");
-    }
-
-    windowPath += NS_LITERAL_CSTRING(")");
-  } else {
-    // Combine all outer windows per section (active/cached/other) as
-    // they basically never contain anything of interest, and are
-    // always pretty much the same size.
-
-    windowPath += NS_LITERAL_CSTRING("outer-windows");
-  }
-
-#define REPORT(_path1, _path2, _amount, _desc)                                \
+#define REPORT(_pathTail, _amount, _desc)                                     \
   do {                                                                        \
     if (_amount > 0) {                                                        \
-        nsCAutoString path(_path1);                                           \
-        path += _path2;                                                       \
+        nsCAutoString path(windowPath);                                       \
+        path += _pathTail;                                                    \
         nsresult rv;                                                          \
         rv = aCb->Callback(EmptyCString(), path, nsIMemoryReporter::KIND_HEAP,\
                       nsIMemoryReporter::UNITS_BYTES, _amount,                \
                       NS_LITERAL_CSTRING(_desc), aClosure);                   \
         NS_ENSURE_SUCCESS(rv, rv);                                            \
     }                                                                         \
   } while (0)
 
-  REPORT(windowPath, "/dom", windowSizes.mDOM,
+  nsWindowSizes windowSizes(DOMStyleMallocSizeOf);
+  aWindow->SizeOfIncludingThis(&windowSizes);
+
+  REPORT("/dom", windowSizes.mDOM,
          "Memory used by a window and the DOM within it.");
   aWindowTotalSizes->mDOM += windowSizes.mDOM;
 
-  REPORT(windowPath, "/style-sheets", windowSizes.mStyleSheets,
+  REPORT("/style-sheets", windowSizes.mStyleSheets,
          "Memory used by style sheets within a window.");
   aWindowTotalSizes->mStyleSheets += windowSizes.mStyleSheets;
 
-  REPORT(windowPath, "/layout/arenas", windowSizes.mLayoutArenas,
+  REPORT("/layout/arenas", windowSizes.mLayoutArenas,
          "Memory used by layout PresShell, PresContext, and other related "
          "areas within a window.");
   aWindowTotalSizes->mLayoutArenas += windowSizes.mLayoutArenas;
 
-  REPORT(windowPath, "/layout/style-sets", windowSizes.mLayoutStyleSets,
+  REPORT("/layout/style-sets", windowSizes.mLayoutStyleSets,
          "Memory used by style sets within a window.");
   aWindowTotalSizes->mLayoutStyleSets += windowSizes.mLayoutStyleSets;
 
-  REPORT(windowPath, "/layout/text-runs", windowSizes.mLayoutTextRuns,
+  REPORT("/layout/text-runs", windowSizes.mLayoutTextRuns,
          "Memory used for text-runs (glyph layout) in the PresShell's frame "
          "tree, within a window.");
   aWindowTotalSizes->mLayoutTextRuns += windowSizes.mLayoutTextRuns;
 
 #undef REPORT
 
   return NS_OK;
 }
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
@@ -39,17 +39,17 @@
   let vsizeAmounts = [];
   let residentAmounts = [];
   let jsGcHeapAmounts = [];
   let heapAllocatedAmounts = [];
   let storageSqliteAmounts = [];
 
   let areJsCompartmentsPresent = false;
   let isSandboxLocationShown = false;
-  let areInnerWindowsPresent = false;
+  let areWindowObjectsPresent = false;
   let isPlacesPresent = false;
   let isImagesPresent = false;
   let isXptiWorkingSetPresent = false;
   let isAtomTablePresent = false;
 
   let mySandbox = Components.utils.Sandbox(document.nodePrincipal,
                     { sandboxName: "this-is-a-sandbox-name" });
 
@@ -67,18 +67,18 @@
     } else if (aPath === "heap-allocated") {
       heapAllocatedAmounts.push(aAmount);
     } else if (aPath === "storage-sqlite") {
       storageSqliteAmounts.push(aAmount);
 
     // Check the presence of some other notable reporters.
     } else if (aPath.search(/^explicit\/js\/compartment\(/) >= 0) {
       areJsCompartmentsPresent = true;
-    } else if (aPath.search(/^explicit\/window-objects\/.*inner-window\(/) >= 0) {
-      areInnerWindowsPresent = true;
+    } else if (aPath.search(/^explicit\/window-objects\/top\(/) >= 0) {
+      areWindowObjectsPresent = true;
     } else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
       isPlacesPresent = true;
     } else if (aPath.search(/^explicit\/images/) >= 0) {
       isImagesPresent = true;
     } else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) {
       isXptiWorkingSetPresent = true;
     } else if (aPath.search(/^explicit\/atom-table$/) >= 0) {
       isAtomTablePresent = true;
@@ -126,17 +126,17 @@
   checkSpecialReport("vsize",          vsizeAmounts);
   checkSpecialReport("resident",       residentAmounts);
   checkSpecialReport("js-gc-heap",     jsGcHeapAmounts);
   checkSpecialReport("heap-allocated", heapAllocatedAmounts);
   checkSpecialReport("storage-sqlite", storageSqliteAmounts);
 
   ok(areJsCompartmentsPresent,  "js compartments are present");
   ok(isSandboxLocationShown,    "sandbox locations are present");
-  ok(areInnerWindowsPresent,    "inner-windows are present");
+  ok(areWindowObjectsPresent,   "window objects are present");
   ok(isPlacesPresent,           "places is present");
   ok(isImagesPresent,           "images is present");
   ok(isXptiWorkingSetPresent,   "xpti-working-set is present");
   ok(isAtomTablePresent,        "atom-table is present");
 
   ]]>
   </script>
 </window>