LCOV - code coverage report
Current view: directory - dom/base - nsWindowMemoryReporter.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 88 24 27.3 %
Date: 2012-06-02 Functions: 12 7 58.3 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Mounir Lamouri <mounir.lamouri@mozilla.com> (original author)
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsWindowMemoryReporter.h"
      39                 : #include "nsGlobalWindow.h"
      40                 : 
      41                 : 
      42            1404 : nsWindowMemoryReporter::nsWindowMemoryReporter()
      43                 : {
      44            1404 : }
      45                 : 
      46            4242 : NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter, nsIMemoryMultiReporter)
      47                 : 
      48                 : /* static */
      49                 : void
      50            1404 : nsWindowMemoryReporter::Init()
      51                 : {
      52                 :   // The memory reporter manager is going to own this object.
      53            1404 :   NS_RegisterMemoryMultiReporter(new nsWindowMemoryReporter());
      54            1404 : }
      55                 : 
      56                 : static bool
      57               0 : AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
      58                 : {
      59               0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
      60               0 :   nsCOMPtr<nsIURI> uri;
      61                 : 
      62               0 :   if (doc) {
      63               0 :     uri = doc->GetDocumentURI();
      64                 :   }
      65                 : 
      66               0 :   if (!uri) {
      67               0 :     nsIPrincipal *principal = aWindow->GetPrincipal();
      68                 : 
      69               0 :     if (principal) {
      70               0 :       principal->GetURI(getter_AddRefs(uri));
      71                 :     }
      72                 :   }
      73                 : 
      74               0 :   if (!uri) {
      75               0 :     return false;
      76                 :   }
      77                 : 
      78               0 :   nsCString spec;
      79               0 :   uri->GetSpec(spec);
      80                 : 
      81                 :   // A hack: replace forward slashes with '\\' so they aren't
      82                 :   // treated as path separators.  Users of the reporters
      83                 :   // (such as about:memory) have to undo this change.
      84               0 :   spec.ReplaceChar('/', '\\');
      85                 : 
      86               0 :   aStr += spec;
      87                 : 
      88               0 :   return true;
      89                 : }
      90                 : 
      91               0 : NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "windows")
      92                 : 
      93                 : static nsresult
      94               0 : CollectWindowReports(nsGlobalWindow *aWindow,
      95                 :                      nsWindowSizes *aWindowTotalSizes,
      96                 :                      nsIMemoryMultiReporterCallback *aCb,
      97                 :                      nsISupports *aClosure)
      98                 : {
      99                 :   // DOM window objects fall into one of three categories:
     100                 :   // - "active" windows are currently either displayed in an active
     101                 :   //   tab, or a child of such a window.
     102                 :   // - "cached" windows are in the fastback cache.
     103                 :   // - "other" windows are closed (or navigated away from w/o being
     104                 :   //   cached) yet held alive by either a website or our code. The
     105                 :   //   latter case may be a memory leak, but not necessarily.
     106                 :   //
     107                 :   // For inner windows we show how much memory the window and its
     108                 :   // document etc use, and we report those per URI, where the URI is
     109                 :   // the document URI, if available, or the codebase of the principal
     110                 :   // in the window. In the case where we're unable to find a URI we're
     111                 :   // dealing with a chrome window with no document in it (or
     112                 :   // somesuch), and for that we make the URI be the string "[system]".
     113                 :   //
     114                 :   // For outer windows we simply group them all together and just show
     115                 :   // the combined count and amount of memory used, which is generally
     116                 :   // a constant amount per window (since all the actual data lives in
     117                 :   // the inner window).
     118                 :   //
     119                 :   // The path we give to the reporter callback for inner windows are
     120                 :   // as follows:
     121                 :   //
     122                 :   //   explicit/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
     123                 :   //
     124                 :   // Where:
     125                 :   // - <category> is active, cached, or other, as described above.
     126                 :   // - <top-outer-id> is the window id (nsPIDOMWindow::WindowID()) of
     127                 :   //   the top outer window (i.e. tab, or top level chrome window).
     128                 :   // - <top-inner-id> is the window id of the top window's inner
     129                 :   //   window.
     130                 :   // - <id> is the window id of the inner window in question.
     131                 :   // - <uri> is the URI per above description.
     132                 :   //
     133                 :   // Exposing the window ids is done to get logical grouping in
     134                 :   // about:memory, and also for debuggability since one can get to the
     135                 :   // nsGlobalWindow for a window id by calling the static method
     136                 :   // nsGlobalWindow::GetInnerWindowWithId(id) (or
     137                 :   // GetOuterWindowWithId(id) in a debugger.
     138                 :   //
     139                 :   // For outer windows we simply use:
     140                 :   // 
     141                 :   //   explicit/window-objects/<category>/outer-windows
     142                 :   //
     143                 :   // Which gives us simple counts of how many outer windows (and their
     144                 :   // combined sizes) per category.
     145                 : 
     146               0 :   nsCAutoString windowPath("explicit/window-objects/");
     147                 : 
     148               0 :   nsIDocShell *docShell = aWindow->GetDocShell();
     149                 : 
     150               0 :   nsGlobalWindow *top = aWindow->GetTop();
     151               0 :   nsWindowSizes windowSizes(DOMStyleMallocSizeOf);
     152               0 :   aWindow->SizeOfIncludingThis(&windowSizes);
     153                 : 
     154               0 :   if (docShell && aWindow->IsFrozen()) {
     155               0 :     windowPath += NS_LITERAL_CSTRING("cached/");
     156               0 :   } else if (docShell) {
     157               0 :     windowPath += NS_LITERAL_CSTRING("active/");
     158                 :   } else {
     159               0 :     windowPath += NS_LITERAL_CSTRING("other/");
     160                 :   }
     161                 : 
     162               0 :   if (aWindow->IsInnerWindow()) {
     163               0 :     windowPath += NS_LITERAL_CSTRING("top=");
     164                 : 
     165               0 :     if (top) {
     166               0 :       windowPath.AppendInt(top->WindowID());
     167                 : 
     168               0 :       nsGlobalWindow *topInner = top->GetCurrentInnerWindowInternal();
     169               0 :       if (topInner) {
     170               0 :         windowPath += NS_LITERAL_CSTRING(" (inner=");
     171               0 :         windowPath.AppendInt(topInner->WindowID());
     172               0 :         windowPath += NS_LITERAL_CSTRING(")");
     173                 :       }
     174                 :     } else {
     175               0 :       windowPath += NS_LITERAL_CSTRING("none");
     176                 :     }
     177                 : 
     178               0 :     windowPath += NS_LITERAL_CSTRING("/inner-window(id=");
     179               0 :     windowPath.AppendInt(aWindow->WindowID());
     180               0 :     windowPath += NS_LITERAL_CSTRING(", uri=");
     181                 : 
     182               0 :     if (!AppendWindowURI(aWindow, windowPath)) {
     183               0 :       windowPath += NS_LITERAL_CSTRING("[system]");
     184                 :     }
     185                 : 
     186               0 :     windowPath += NS_LITERAL_CSTRING(")");
     187                 :   } else {
     188                 :     // Combine all outer windows per section (active/cached/other) as
     189                 :     // they basically never contain anything of interest, and are
     190                 :     // always pretty much the same size.
     191                 : 
     192               0 :     windowPath += NS_LITERAL_CSTRING("outer-windows");
     193                 :   }
     194                 : 
     195                 : #define REPORT(_path1, _path2, _amount, _desc)                                \
     196                 :   do {                                                                        \
     197                 :     if (_amount > 0) {                                                        \
     198                 :         nsCAutoString path(_path1);                                           \
     199                 :         path += _path2;                                                       \
     200                 :         nsresult rv;                                                          \
     201                 :         rv = aCb->Callback(EmptyCString(), path, nsIMemoryReporter::KIND_HEAP,\
     202                 :                       nsIMemoryReporter::UNITS_BYTES, _amount,                \
     203                 :                       NS_LITERAL_CSTRING(_desc), aClosure);                   \
     204                 :         NS_ENSURE_SUCCESS(rv, rv);                                            \
     205                 :     }                                                                         \
     206                 :   } while (0)
     207                 : 
     208               0 :   REPORT(windowPath, "/dom", windowSizes.mDOM,
     209                 :          "Memory used by a window and the DOM within it.");
     210               0 :   aWindowTotalSizes->mDOM += windowSizes.mDOM;
     211                 : 
     212               0 :   REPORT(windowPath, "/style-sheets", windowSizes.mStyleSheets,
     213                 :          "Memory used by style sheets within a window.");
     214               0 :   aWindowTotalSizes->mStyleSheets += windowSizes.mStyleSheets;
     215                 : 
     216               0 :   REPORT(windowPath, "/layout/arenas", windowSizes.mLayoutArenas,
     217                 :          "Memory used by layout PresShell, PresContext, and other related "
     218                 :          "areas within a window.");
     219               0 :   aWindowTotalSizes->mLayoutArenas += windowSizes.mLayoutArenas;
     220                 : 
     221               0 :   REPORT(windowPath, "/layout/style-sets", windowSizes.mLayoutStyleSets,
     222                 :          "Memory used by style sets within a window.");
     223               0 :   aWindowTotalSizes->mLayoutStyleSets += windowSizes.mLayoutStyleSets;
     224                 : 
     225               0 :   REPORT(windowPath, "/layout/text-runs", windowSizes.mLayoutTextRuns,
     226                 :          "Memory used for text-runs (glyph layout) in the PresShell's frame "
     227                 :          "tree, within a window.");
     228               0 :   aWindowTotalSizes->mLayoutTextRuns += windowSizes.mLayoutTextRuns;
     229                 : 
     230                 : #undef REPORT
     231                 : 
     232               0 :   return NS_OK;
     233                 : }
     234                 : 
     235                 : typedef nsTArray< nsRefPtr<nsGlobalWindow> > WindowArray;
     236                 : 
     237                 : static
     238                 : PLDHashOperator
     239               0 : GetWindows(const PRUint64& aId, nsGlobalWindow*& aWindow, void* aClosure)
     240                 : {
     241               0 :   ((WindowArray *)aClosure)->AppendElement(aWindow);
     242                 : 
     243               0 :   return PL_DHASH_NEXT;
     244                 : }
     245                 : 
     246                 : NS_IMETHODIMP
     247               0 : nsWindowMemoryReporter::GetName(nsACString &aName)
     248                 : {
     249               0 :   aName.AssignLiteral("window-objects");
     250               0 :   return NS_OK;
     251                 : }
     252                 : 
     253                 : NS_IMETHODIMP
     254               3 : nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
     255                 :                                        nsISupports* aClosure)
     256                 : {
     257                 :   nsGlobalWindow::WindowByIdTable* windowsById =
     258               3 :     nsGlobalWindow::GetWindowsTable();
     259               3 :   NS_ENSURE_TRUE(windowsById, NS_OK);
     260                 : 
     261                 :   // Hold on to every window in memory so that window objects can't be
     262                 :   // destroyed while we're calling the memory reporter callback.
     263               6 :   WindowArray windows;
     264               3 :   windowsById->Enumerate(GetWindows, &windows);
     265                 : 
     266                 :   // Collect window memory usage.
     267               3 :   nsRefPtr<nsGlobalWindow> *w = windows.Elements();
     268               3 :   nsRefPtr<nsGlobalWindow> *end = w + windows.Length();
     269               3 :   nsWindowSizes windowTotalSizes(NULL);
     270               3 :   for (; w != end; ++w) {
     271               0 :     nsresult rv = CollectWindowReports(*w, &windowTotalSizes, aCb, aClosure);
     272               0 :     NS_ENSURE_SUCCESS(rv, rv);
     273                 :   }
     274                 : 
     275                 : #define REPORT(_path, _amount, _desc)                                         \
     276                 :   do {                                                                        \
     277                 :     nsresult rv;                                                              \
     278                 :     rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path),             \
     279                 :                        nsIMemoryReporter::KIND_OTHER,                         \
     280                 :                        nsIMemoryReporter::UNITS_BYTES, _amount,               \
     281                 :                        NS_LITERAL_CSTRING(_desc), aClosure);                  \
     282                 :     NS_ENSURE_SUCCESS(rv, rv);                                                \
     283                 :   } while (0)
     284                 : 
     285               3 :   REPORT("window-objects-dom", windowTotalSizes.mDOM, 
     286                 :          "Memory used for the DOM within windows. "
     287                 :          "This is the sum of all windows' 'dom' numbers.");
     288                 :     
     289               3 :   REPORT("window-objects-style-sheets", windowTotalSizes.mStyleSheets, 
     290                 :          "Memory used for style sheets within windows. "
     291                 :          "This is the sum of all windows' 'style-sheets' numbers.");
     292                 :     
     293               3 :   REPORT("window-objects-layout-arenas", windowTotalSizes.mLayoutArenas, 
     294                 :          "Memory used by layout PresShell, PresContext, and other related "
     295                 :          "areas within windows. This is the sum of all windows' "
     296                 :          "'layout/arenas' numbers.");
     297                 :     
     298               3 :   REPORT("window-objects-layout-style-sets", windowTotalSizes.mLayoutStyleSets, 
     299                 :          "Memory used for style sets within windows. "
     300                 :          "This is the sum of all windows' 'layout/style-sets' numbers.");
     301                 :     
     302               3 :   REPORT("window-objects-layout-text-runs", windowTotalSizes.mLayoutTextRuns, 
     303                 :          "Memory used for text runs within windows. "
     304                 :          "This is the sum of all windows' 'layout/text-runs' numbers.");
     305                 : 
     306                 : #undef REPORT
     307                 :     
     308               3 :   return NS_OK;
     309                 : }
     310                 : 
     311                 : NS_IMETHODIMP
     312               3 : nsWindowMemoryReporter::GetExplicitNonHeap(PRInt64* aAmount)
     313                 : {
     314                 :   // This reporter only measures heap memory.
     315               3 :   *aAmount = 0;
     316               3 :   return NS_OK;
     317                 : }
     318                 : 
     319                 : 

Generated by: LCOV version 1.7