xpcom/base/nsMemoryReporterManager.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsAtomTable.h"
     8 #include "nsAutoPtr.h"
     9 #include "nsCOMPtr.h"
    10 #include "nsCOMArray.h"
    11 #include "nsPrintfCString.h"
    12 #include "nsServiceManagerUtils.h"
    13 #include "nsMemoryReporterManager.h"
    14 #include "nsITimer.h"
    15 #include "nsThreadUtils.h"
    16 #include "nsIDOMWindow.h"
    17 #include "nsPIDOMWindow.h"
    18 #include "nsIObserverService.h"
    19 #include "nsIGlobalObject.h"
    20 #include "nsIXPConnect.h"
    21 #if defined(XP_UNIX) || defined(MOZ_DMD)
    22 #include "nsMemoryInfoDumper.h"
    23 #endif
    24 #include "mozilla/Attributes.h"
    25 #include "mozilla/PodOperations.h"
    26 #include "mozilla/Services.h"
    27 #include "mozilla/Telemetry.h"
    28 #include "mozilla/dom/PMemoryReportRequestParent.h" // for dom::MemoryReport
    30 #ifndef XP_WIN
    31 #include <unistd.h>
    32 #endif
    34 using namespace mozilla;
    36 #if defined(MOZ_MEMORY)
    37 #  define HAVE_JEMALLOC_STATS 1
    38 #  include "mozmemory.h"
    39 #endif  // MOZ_MEMORY
    41 #if defined(XP_LINUX)
    43 static nsresult
    44 GetProcSelfStatmField(int aField, int64_t* aN)
    45 {
    46   // There are more than two fields, but we're only interested in the first
    47   // two.
    48   static const int MAX_FIELD = 2;
    49   size_t fields[MAX_FIELD];
    50   MOZ_ASSERT(aField < MAX_FIELD, "bad field number");
    51   FILE* f = fopen("/proc/self/statm", "r");
    52   if (f) {
    53     int nread = fscanf(f, "%zu %zu", &fields[0], &fields[1]);
    54     fclose(f);
    55     if (nread == MAX_FIELD) {
    56       *aN = fields[aField] * getpagesize();
    57       return NS_OK;
    58     }
    59   }
    60   return NS_ERROR_FAILURE;
    61 }
    63 #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
    64 static nsresult
    65 VsizeDistinguishedAmount(int64_t* aN)
    66 {
    67   return GetProcSelfStatmField(0, aN);
    68 }
    70 static nsresult
    71 ResidentDistinguishedAmount(int64_t* aN)
    72 {
    73   return GetProcSelfStatmField(1, aN);
    74 }
    76 static nsresult
    77 ResidentFastDistinguishedAmount(int64_t* aN)
    78 {
    79   return ResidentDistinguishedAmount(aN);
    80 }
    82 #define HAVE_RESIDENT_UNIQUE_REPORTER
    83 class ResidentUniqueReporter MOZ_FINAL : public nsIMemoryReporter
    84 {
    85 public:
    86   NS_DECL_ISUPPORTS
    88   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
    89                            nsISupports* aData)
    90   {
    91     // You might be tempted to calculate USS by subtracting the "shared"
    92     // value from the "resident" value in /proc/<pid>/statm. But at least
    93     // on Linux, statm's "shared" value actually counts pages backed by
    94     // files, which has little to do with whether the pages are actually
    95     // shared. /proc/self/smaps on the other hand appears to give us the
    96     // correct information.
    98     FILE* f = fopen("/proc/self/smaps", "r");
    99     if (NS_WARN_IF(!f)) {
   100       return NS_ERROR_UNEXPECTED;
   101     }
   103     int64_t amount = 0;
   104     char line[256];
   105     while (fgets(line, sizeof(line), f)) {
   106       long long val = 0;
   107       if (sscanf(line, "Private_Dirty: %lld kB", &val) == 1 ||
   108           sscanf(line, "Private_Clean: %lld kB", &val) == 1) {
   109         amount += val * 1024; // convert from kB to bytes
   110       }
   111     }
   113     fclose(f);
   115     return MOZ_COLLECT_REPORT(
   116       "resident-unique", KIND_OTHER, UNITS_BYTES, amount,
   117 "Memory mapped by the process that is present in physical memory and not "
   118 "shared with any other processes.  This is also known as the process's unique "
   119 "set size (USS).  This is the amount of RAM we'd expect to be freed if we "
   120 "closed this process.");
   121   }
   122 };
   123 NS_IMPL_ISUPPORTS(ResidentUniqueReporter, nsIMemoryReporter)
   125 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
   126     || defined(__NetBSD__) || defined(__OpenBSD__) \
   127     || defined(__FreeBSD_kernel__)
   129 #include <sys/param.h>
   130 #include <sys/sysctl.h>
   131 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
   132 #include <sys/user.h>
   133 #endif
   135 #include <unistd.h>
   137 #if defined(__NetBSD__)
   138 #undef KERN_PROC
   139 #define KERN_PROC KERN_PROC2
   140 #define KINFO_PROC struct kinfo_proc2
   141 #else
   142 #define KINFO_PROC struct kinfo_proc
   143 #endif
   145 #if defined(__DragonFly__)
   146 #define KP_SIZE(kp) (kp.kp_vm_map_size)
   147 #define KP_RSS(kp) (kp.kp_vm_rssize * getpagesize())
   148 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
   149 #define KP_SIZE(kp) (kp.ki_size)
   150 #define KP_RSS(kp) (kp.ki_rssize * getpagesize())
   151 #elif defined(__NetBSD__)
   152 #define KP_SIZE(kp) (kp.p_vm_msize * getpagesize())
   153 #define KP_RSS(kp) (kp.p_vm_rssize * getpagesize())
   154 #elif defined(__OpenBSD__)
   155 #define KP_SIZE(kp) ((kp.p_vm_dsize + kp.p_vm_ssize                     \
   156                       + kp.p_vm_tsize) * getpagesize())
   157 #define KP_RSS(kp) (kp.p_vm_rssize * getpagesize())
   158 #endif
   160 static nsresult
   161 GetKinfoProcSelf(KINFO_PROC* aProc)
   162 {
   163   int mib[] = {
   164     CTL_KERN,
   165     KERN_PROC,
   166     KERN_PROC_PID,
   167     getpid(),
   168 #if defined(__NetBSD__) || defined(__OpenBSD__)
   169     sizeof(KINFO_PROC),
   170     1,
   171 #endif
   172   };
   173   u_int miblen = sizeof(mib) / sizeof(mib[0]);
   174   size_t size = sizeof(KINFO_PROC);
   175   if (sysctl(mib, miblen, aProc, &size, nullptr, 0)) {
   176     return NS_ERROR_FAILURE;
   177   }
   178   return NS_OK;
   179 }
   181 #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
   182 static nsresult
   183 VsizeDistinguishedAmount(int64_t* aN)
   184 {
   185   KINFO_PROC proc;
   186   nsresult rv = GetKinfoProcSelf(&proc);
   187   if (NS_SUCCEEDED(rv)) {
   188     *aN = KP_SIZE(proc);
   189   }
   190   return rv;
   191 }
   193 static nsresult
   194 ResidentDistinguishedAmount(int64_t* aN)
   195 {
   196   KINFO_PROC proc;
   197   nsresult rv = GetKinfoProcSelf(&proc);
   198   if (NS_SUCCEEDED(rv)) {
   199     *aN = KP_RSS(proc);
   200   }
   201   return rv;
   202 }
   204 static nsresult
   205 ResidentFastDistinguishedAmount(int64_t* aN)
   206 {
   207   return ResidentDistinguishedAmount(aN);
   208 }
   210 #ifdef __FreeBSD__
   211 #include <libutil.h>
   212 #include <algorithm>
   214 static nsresult
   215 GetKinfoVmentrySelf(int64_t* aPrss, uint64_t* aMaxreg)
   216 {
   217   int cnt;
   218   struct kinfo_vmentry *vmmap, *kve;
   219   if ((vmmap = kinfo_getvmmap(getpid(), &cnt)) == nullptr) {
   220     return NS_ERROR_FAILURE;
   221   }
   222   if (aPrss) {
   223     *aPrss = 0;
   224   }
   225   if (aMaxreg) {
   226     *aMaxreg = 0;
   227   }
   229   for (int i = 0; i < cnt; i++) {
   230     kve = &vmmap[i];
   231     if (aPrss) {
   232       *aPrss += kve->kve_private_resident;
   233     }
   234     if (aMaxreg) {
   235       *aMaxreg = std::max(*aMaxreg, kve->kve_end - kve->kve_start);
   236     }
   237   }
   239   free(vmmap);
   240   return NS_OK;
   241 }
   243 #define HAVE_PRIVATE_REPORTER
   244 static nsresult
   245 PrivateDistinguishedAmount(int64_t* aN)
   246 {
   247   int64_t priv;
   248   nsresult rv = GetKinfoVmentrySelf(&priv, nullptr);
   249   NS_ENSURE_SUCCESS(rv, rv);
   250   *aN = priv * getpagesize();
   251   return NS_OK;
   252 }
   254 #define HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER 1
   255 static nsresult
   256 VsizeMaxContiguousDistinguishedAmount(int64_t* aN)
   257 {
   258   uint64_t biggestRegion;
   259   nsresult rv = GetKinfoVmentrySelf(nullptr, &biggestRegion);
   260   if (NS_SUCCEEDED(rv)) {
   261     *aN = biggestRegion;
   262   }
   263   return NS_OK;
   264 }
   265 #endif // FreeBSD
   267 #elif defined(SOLARIS)
   269 #include <procfs.h>
   270 #include <fcntl.h>
   271 #include <unistd.h>
   273 static void XMappingIter(int64_t& aVsize, int64_t& aResident)
   274 {
   275   aVsize = -1;
   276   aResident = -1;
   277   int mapfd = open("/proc/self/xmap", O_RDONLY);
   278   struct stat st;
   279   prxmap_t* prmapp = nullptr;
   280   if (mapfd >= 0) {
   281     if (!fstat(mapfd, &st)) {
   282       int nmap = st.st_size / sizeof(prxmap_t);
   283       while (1) {
   284         // stat(2) on /proc/<pid>/xmap returns an incorrect value,
   285         // prior to the release of Solaris 11.
   286         // Here is a workaround for it.
   287         nmap *= 2;
   288         prmapp = (prxmap_t*)malloc((nmap + 1) * sizeof(prxmap_t));
   289         if (!prmapp) {
   290           // out of memory
   291           break;
   292         }
   293         int n = pread(mapfd, prmapp, (nmap + 1) * sizeof(prxmap_t), 0);
   294         if (n < 0) {
   295           break;
   296         }
   297         if (nmap >= n / sizeof(prxmap_t)) {
   298           aVsize = 0;
   299           aResident = 0;
   300           for (int i = 0; i < n / sizeof(prxmap_t); i++) {
   301             aVsize += prmapp[i].pr_size;
   302             aResident += prmapp[i].pr_rss * prmapp[i].pr_pagesize;
   303           }
   304           break;
   305         }
   306         free(prmapp);
   307       }
   308       free(prmapp);
   309     }
   310     close(mapfd);
   311   }
   312 }
   314 #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
   315 static nsresult
   316 VsizeDistinguishedAmount(int64_t* aN)
   317 {
   318   int64_t vsize, resident;
   319   XMappingIter(vsize, resident);
   320   if (vsize == -1) {
   321     return NS_ERROR_FAILURE;
   322   }
   323   *aN = vsize;
   324   return NS_OK;
   325 }
   327 static nsresult
   328 ResidentDistinguishedAmount(int64_t* aN)
   329 {
   330   int64_t vsize, resident;
   331   XMappingIter(vsize, resident);
   332   if (resident == -1) {
   333     return NS_ERROR_FAILURE;
   334   }
   335   *aN = resident;
   336   return NS_OK;
   337 }
   339 static nsresult
   340 ResidentFastDistinguishedAmount(int64_t* aN)
   341 {
   342   return ResidentDistinguishedAmount(aN);
   343 }
   345 #elif defined(XP_MACOSX)
   347 #include <mach/mach_init.h>
   348 #include <mach/task.h>
   350 static bool
   351 GetTaskBasicInfo(struct task_basic_info* aTi)
   352 {
   353   mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
   354   kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO,
   355                                (task_info_t)aTi, &count);
   356   return kr == KERN_SUCCESS;
   357 }
   359 // The VSIZE figure on Mac includes huge amounts of shared memory and is always
   360 // absurdly high, eg. 2GB+ even at start-up.  But both 'top' and 'ps' report
   361 // it, so we might as well too.
   362 #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
   363 static nsresult
   364 VsizeDistinguishedAmount(int64_t* aN)
   365 {
   366   task_basic_info ti;
   367   if (!GetTaskBasicInfo(&ti)) {
   368     return NS_ERROR_FAILURE;
   369   }
   370   *aN = ti.virtual_size;
   371   return NS_OK;
   372 }
   374 // If we're using jemalloc on Mac, we need to instruct jemalloc to purge the
   375 // pages it has madvise(MADV_FREE)'d before we read our RSS in order to get
   376 // an accurate result.  The OS will take away MADV_FREE'd pages when there's
   377 // memory pressure, so ideally, they shouldn't count against our RSS.
   378 //
   379 // Purging these pages can take a long time for some users (see bug 789975),
   380 // so we provide the option to get the RSS without purging first.
   381 static nsresult
   382 ResidentDistinguishedAmountHelper(int64_t* aN, bool aDoPurge)
   383 {
   384 #ifdef HAVE_JEMALLOC_STATS
   385   if (aDoPurge) {
   386     Telemetry::AutoTimer<Telemetry::MEMORY_FREE_PURGED_PAGES_MS> timer;
   387     jemalloc_purge_freed_pages();
   388   }
   389 #endif
   391   task_basic_info ti;
   392   if (!GetTaskBasicInfo(&ti)) {
   393     return NS_ERROR_FAILURE;
   394   }
   395   *aN = ti.resident_size;
   396   return NS_OK;
   397 }
   399 static nsresult
   400 ResidentFastDistinguishedAmount(int64_t* aN)
   401 {
   402   return ResidentDistinguishedAmountHelper(aN, /* doPurge = */ false);
   403 }
   405 static nsresult
   406 ResidentDistinguishedAmount(int64_t* aN)
   407 {
   408   return ResidentDistinguishedAmountHelper(aN, /* doPurge = */ true);
   409 }
   411 #elif defined(XP_WIN)
   413 #include <windows.h>
   414 #include <psapi.h>
   415 #include <algorithm>
   417 #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
   418 static nsresult
   419 VsizeDistinguishedAmount(int64_t* aN)
   420 {
   421   MEMORYSTATUSEX s;
   422   s.dwLength = sizeof(s);
   424   if (!GlobalMemoryStatusEx(&s)) {
   425     return NS_ERROR_FAILURE;
   426   }
   428   *aN = s.ullTotalVirtual - s.ullAvailVirtual;
   429   return NS_OK;
   430 }
   432 static nsresult
   433 ResidentDistinguishedAmount(int64_t* aN)
   434 {
   435   PROCESS_MEMORY_COUNTERS pmc;
   436   pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
   438   if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
   439     return NS_ERROR_FAILURE;
   440   }
   442   *aN = pmc.WorkingSetSize;
   443   return NS_OK;
   444 }
   446 static nsresult
   447 ResidentFastDistinguishedAmount(int64_t* aN)
   448 {
   449   return ResidentDistinguishedAmount(aN);
   450 }
   452 #define HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER 1
   453 static nsresult
   454 VsizeMaxContiguousDistinguishedAmount(int64_t* aN)
   455 {
   456   SIZE_T biggestRegion = 0;
   457   MEMORY_BASIC_INFORMATION vmemInfo = { 0 };
   458   for (size_t currentAddress = 0; ; ) {
   459     if (!VirtualQuery((LPCVOID)currentAddress, &vmemInfo, sizeof(vmemInfo))) {
   460       // Something went wrong, just return whatever we've got already.
   461       break;
   462     }
   464     if (vmemInfo.State == MEM_FREE) {
   465       biggestRegion = std::max(biggestRegion, vmemInfo.RegionSize);
   466     }
   468     SIZE_T lastAddress = currentAddress;
   469     currentAddress += vmemInfo.RegionSize;
   471     // If we overflow, we've examined all of the address space.
   472     if (currentAddress < lastAddress) {
   473       break;
   474     }
   475   }
   477   *aN = biggestRegion;
   478   return NS_OK;
   479 }
   481 #define HAVE_PRIVATE_REPORTER
   482 static nsresult
   483 PrivateDistinguishedAmount(int64_t* aN)
   484 {
   485   PROCESS_MEMORY_COUNTERS_EX pmcex;
   486   pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
   488   if (!GetProcessMemoryInfo(GetCurrentProcess(),
   489                             (PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex))) {
   490     return NS_ERROR_FAILURE;
   491   }
   493   *aN = pmcex.PrivateUsage;
   494   return NS_OK;
   495 }
   496 #endif  // XP_<PLATFORM>
   498 #ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER
   499 class VsizeMaxContiguousReporter MOZ_FINAL : public nsIMemoryReporter
   500 {
   501 public:
   502   NS_DECL_ISUPPORTS
   504   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   505                            nsISupports* aData)
   506   {
   507     int64_t amount;
   508     nsresult rv = VsizeMaxContiguousDistinguishedAmount(&amount);
   509     NS_ENSURE_SUCCESS(rv, rv);
   510     return MOZ_COLLECT_REPORT(
   511       "vsize-max-contiguous", KIND_OTHER, UNITS_BYTES, amount,
   512       "Size of the maximum contiguous block of available virtual "
   513       "memory.");
   514   }
   515 };
   516 NS_IMPL_ISUPPORTS(VsizeMaxContiguousReporter, nsIMemoryReporter)
   517 #endif
   519 #ifdef HAVE_PRIVATE_REPORTER
   520 class PrivateReporter MOZ_FINAL : public nsIMemoryReporter
   521 {
   522 public:
   523   NS_DECL_ISUPPORTS
   525   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   526                            nsISupports* aData)
   527   {
   528     int64_t amount;
   529     nsresult rv = PrivateDistinguishedAmount(&amount);
   530     NS_ENSURE_SUCCESS(rv, rv);
   531     return MOZ_COLLECT_REPORT(
   532       "private", KIND_OTHER, UNITS_BYTES, amount,
   533 "Memory that cannot be shared with other processes, including memory that is "
   534 "committed and marked MEM_PRIVATE, data that is not mapped, and executable "
   535 "pages that have been written to.");
   536   }
   537 };
   538 NS_IMPL_ISUPPORTS(PrivateReporter, nsIMemoryReporter)
   539 #endif
   541 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
   542 class VsizeReporter MOZ_FINAL : public nsIMemoryReporter
   543 {
   544 public:
   545   NS_DECL_ISUPPORTS
   547   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   548                            nsISupports* aData)
   549   {
   550     int64_t amount;
   551     nsresult rv = VsizeDistinguishedAmount(&amount);
   552     NS_ENSURE_SUCCESS(rv, rv);
   554     return MOZ_COLLECT_REPORT(
   555       "vsize", KIND_OTHER, UNITS_BYTES, amount,
   556 "Memory mapped by the process, including code and data segments, the heap, "
   557 "thread stacks, memory explicitly mapped by the process via mmap and similar "
   558 "operations, and memory shared with other processes. This is the vsize figure "
   559 "as reported by 'top' and 'ps'.  This figure is of limited use on Mac, where "
   560 "processes share huge amounts of memory with one another.  But even on other "
   561 "operating systems, 'resident' is a much better measure of the memory "
   562 "resources used by the process.");
   563   }
   564 };
   565 NS_IMPL_ISUPPORTS(VsizeReporter, nsIMemoryReporter)
   567 class ResidentReporter MOZ_FINAL : public nsIMemoryReporter
   568 {
   569 public:
   570   NS_DECL_ISUPPORTS
   572   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   573                            nsISupports* aData)
   574   {
   575     int64_t amount;
   576     nsresult rv = ResidentDistinguishedAmount(&amount);
   577     NS_ENSURE_SUCCESS(rv, rv);
   579     return MOZ_COLLECT_REPORT(
   580       "resident", KIND_OTHER, UNITS_BYTES, amount,
   581 "Memory mapped by the process that is present in physical memory, also known "
   582 "as the resident set size (RSS).  This is the best single figure to use when "
   583 "considering the memory resources used by the process, but it depends both on "
   584 "other processes being run and details of the OS kernel and so is best used "
   585 "for comparing the memory usage of a single process at different points in "
   586 "time.");
   587     }
   588 };
   589 NS_IMPL_ISUPPORTS(ResidentReporter, nsIMemoryReporter)
   591 #endif  // HAVE_VSIZE_AND_RESIDENT_REPORTERS
   593 #ifdef XP_UNIX
   595 #include <sys/resource.h>
   597 #define HAVE_PAGE_FAULT_REPORTERS 1
   599 class PageFaultsSoftReporter MOZ_FINAL : public nsIMemoryReporter
   600 {
   601 public:
   602   NS_DECL_ISUPPORTS
   604   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   605                            nsISupports* aData)
   606   {
   607     struct rusage usage;
   608     int err = getrusage(RUSAGE_SELF, &usage);
   609     if (err != 0) {
   610       return NS_ERROR_FAILURE;
   611     }
   612     int64_t amount = usage.ru_minflt;
   614     return MOZ_COLLECT_REPORT(
   615       "page-faults-soft", KIND_OTHER, UNITS_COUNT_CUMULATIVE, amount,
   616 "The number of soft page faults (also known as 'minor page faults') that "
   617 "have occurred since the process started.  A soft page fault occurs when the "
   618 "process tries to access a page which is present in physical memory but is "
   619 "not mapped into the process's address space.  For instance, a process might "
   620 "observe soft page faults when it loads a shared library which is already "
   621 "present in physical memory. A process may experience many thousands of soft "
   622 "page faults even when the machine has plenty of available physical memory, "
   623 "and because the OS services a soft page fault without accessing the disk, "
   624 "they impact performance much less than hard page faults.");
   625   }
   626 };
   627 NS_IMPL_ISUPPORTS(PageFaultsSoftReporter, nsIMemoryReporter)
   629 static nsresult
   630 PageFaultsHardDistinguishedAmount(int64_t* aAmount)
   631 {
   632   struct rusage usage;
   633   int err = getrusage(RUSAGE_SELF, &usage);
   634   if (err != 0) {
   635     return NS_ERROR_FAILURE;
   636   }
   637   *aAmount = usage.ru_majflt;
   638   return NS_OK;
   639 }
   641 class PageFaultsHardReporter MOZ_FINAL : public nsIMemoryReporter
   642 {
   643 public:
   644   NS_DECL_ISUPPORTS
   646   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   647                            nsISupports* aData)
   648   {
   649     int64_t amount = 0;
   650     nsresult rv = PageFaultsHardDistinguishedAmount(&amount);
   651     NS_ENSURE_SUCCESS(rv, rv);
   653     return MOZ_COLLECT_REPORT(
   654       "page-faults-hard", KIND_OTHER, UNITS_COUNT_CUMULATIVE, amount,
   655 "The number of hard page faults (also known as 'major page faults') that have "
   656 "occurred since the process started.  A hard page fault occurs when a process "
   657 "tries to access a page which is not present in physical memory. The "
   658 "operating system must access the disk in order to fulfill a hard page fault. "
   659 "When memory is plentiful, you should see very few hard page faults. But if "
   660 "the process tries to use more memory than your machine has available, you "
   661 "may see many thousands of hard page faults. Because accessing the disk is up "
   662 "to a million times slower than accessing RAM, the program may run very "
   663 "slowly when it is experiencing more than 100 or so hard page faults a "
   664 "second.");
   665   }
   666 };
   667 NS_IMPL_ISUPPORTS(PageFaultsHardReporter, nsIMemoryReporter)
   669 #endif  // HAVE_PAGE_FAULT_REPORTERS
   671 /**
   672  ** memory reporter implementation for jemalloc and OSX malloc,
   673  ** to obtain info on total memory in use (that we know about,
   674  ** at least -- on OSX, there are sometimes other zones in use).
   675  **/
   677 #ifdef HAVE_JEMALLOC_STATS
   679 // This has UNITS_PERCENTAGE, so it is multiplied by 100.
   680 static int64_t
   681 HeapOverheadRatio(jemalloc_stats_t* aStats)
   682 {
   683   return (int64_t) 10000 *
   684     (aStats->waste + aStats->bookkeeping + aStats->page_cache) /
   685     ((double)aStats->allocated);
   686 }
   688 class JemallocHeapReporter MOZ_FINAL : public nsIMemoryReporter
   689 {
   690 public:
   691   NS_DECL_ISUPPORTS
   693   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   694                            nsISupports* aData)
   695   {
   696     jemalloc_stats_t stats;
   697     jemalloc_stats(&stats);
   699     nsresult rv;
   701     rv = MOZ_COLLECT_REPORT(
   702       "heap-allocated", KIND_OTHER, UNITS_BYTES, stats.allocated,
   703 "Memory mapped by the heap allocator that is currently allocated to the "
   704 "application.  This may exceed the amount of memory requested by the "
   705 "application because the allocator regularly rounds up request sizes. (The "
   706 "exact amount requested is not recorded.)");
   707     NS_ENSURE_SUCCESS(rv, rv);
   709     // We mark this and the other heap-overhead reporters as KIND_NONHEAP
   710     // because KIND_HEAP memory means "counted in heap-allocated", which
   711     // this is not.
   712     rv = MOZ_COLLECT_REPORT(
   713       "explicit/heap-overhead/waste", KIND_NONHEAP, UNITS_BYTES,
   714       stats.waste,
   715 "Committed bytes which do not correspond to an active allocation and which the "
   716 "allocator is not intentionally keeping alive (i.e., not 'heap-bookkeeping' or "
   717 "'heap-page-cache').  Although the allocator will waste some space under any "
   718 "circumstances, a large value here may indicate that the heap is highly "
   719 "fragmented, or that allocator is performing poorly for some other reason.");
   720     NS_ENSURE_SUCCESS(rv, rv);
   722     rv = MOZ_COLLECT_REPORT(
   723       "explicit/heap-overhead/bookkeeping", KIND_NONHEAP, UNITS_BYTES,
   724       stats.bookkeeping,
   725 "Committed bytes which the heap allocator uses for internal data structures.");
   726     NS_ENSURE_SUCCESS(rv, rv);
   728     rv = MOZ_COLLECT_REPORT(
   729       "explicit/heap-overhead/page-cache", KIND_NONHEAP, UNITS_BYTES,
   730       stats.page_cache,
   731 "Memory which the allocator could return to the operating system, but hasn't. "
   732 "The allocator keeps this memory around as an optimization, so it doesn't "
   733 "have to ask the OS the next time it needs to fulfill a request. This value "
   734 "is typically not larger than a few megabytes.");
   735     NS_ENSURE_SUCCESS(rv, rv);
   737     rv = MOZ_COLLECT_REPORT(
   738       "heap-committed", KIND_OTHER, UNITS_BYTES,
   739       stats.allocated + stats.waste + stats.bookkeeping + stats.page_cache,
   740 "Memory mapped by the heap allocator that is committed, i.e. in physical "
   741 "memory or paged to disk.  This value corresponds to 'heap-allocated' + "
   742 "'heap-waste' + 'heap-bookkeeping' + 'heap-page-cache', but because "
   743 "these values are read at different times, the result probably won't match "
   744 "exactly.");
   745     NS_ENSURE_SUCCESS(rv, rv);
   747     rv = MOZ_COLLECT_REPORT(
   748       "heap-overhead-ratio", KIND_OTHER, UNITS_PERCENTAGE,
   749       HeapOverheadRatio(&stats),
   750 "Ratio of committed, unused bytes to allocated bytes; i.e., "
   751 "'heap-overhead' / 'heap-allocated'.  This measures the overhead of "
   752 "the heap allocator relative to amount of memory allocated.");
   753     NS_ENSURE_SUCCESS(rv, rv);
   755     return NS_OK;
   756   }
   757 };
   758 NS_IMPL_ISUPPORTS(JemallocHeapReporter, nsIMemoryReporter)
   760 #endif  // HAVE_JEMALLOC_STATS
   762 // Why is this here?  At first glance, you'd think it could be defined and
   763 // registered with nsMemoryReporterManager entirely within nsAtomTable.cpp.
   764 // However, the obvious time to register it is when the table is initialized,
   765 // and that happens before XPCOM components are initialized, which means the
   766 // RegisterStrongMemoryReporter call fails.  So instead we do it here.
   767 class AtomTablesReporter MOZ_FINAL : public nsIMemoryReporter
   768 {
   769   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
   771 public:
   772   NS_DECL_ISUPPORTS
   774   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   775                            nsISupports* aData)
   776   {
   777     return MOZ_COLLECT_REPORT(
   778       "explicit/atom-tables", KIND_HEAP, UNITS_BYTES,
   779       NS_SizeOfAtomTablesIncludingThis(MallocSizeOf),
   780       "Memory used by the dynamic and static atoms tables.");
   781   }
   782 };
   783 NS_IMPL_ISUPPORTS(AtomTablesReporter, nsIMemoryReporter)
   785 #ifdef MOZ_DMD
   787 namespace mozilla {
   788 namespace dmd {
   790 class DMDReporter MOZ_FINAL : public nsIMemoryReporter
   791 {
   792 public:
   793   NS_DECL_ISUPPORTS
   795   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   796                             nsISupports* aData)
   797   {
   798     dmd::Sizes sizes;
   799     dmd::SizeOf(&sizes);
   801 #define REPORT(_path, _amount, _desc)                                         \
   802     do {                                                                      \
   803       nsresult rv;                                                            \
   804       rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
   805                                    KIND_HEAP, UNITS_BYTES, _amount,           \
   806                                    NS_LITERAL_CSTRING(_desc), aData);         \
   807       if (NS_WARN_IF(NS_FAILED(rv))) {                                        \
   808         return rv;                                                            \
   809       }                                                                       \
   810     } while (0)
   812     REPORT("explicit/dmd/stack-traces/used",
   813            sizes.mStackTracesUsed,
   814            "Memory used by stack traces which correspond to at least "
   815            "one heap block DMD is tracking.");
   817     REPORT("explicit/dmd/stack-traces/unused",
   818            sizes.mStackTracesUnused,
   819            "Memory used by stack traces which don't correspond to any heap "
   820            "blocks DMD is currently tracking.");
   822     REPORT("explicit/dmd/stack-traces/table",
   823            sizes.mStackTraceTable,
   824            "Memory used by DMD's stack trace table.");
   826     REPORT("explicit/dmd/block-table",
   827            sizes.mBlockTable,
   828            "Memory used by DMD's live block table.");
   830 #undef REPORT
   832     return NS_OK;
   833   }
   834 };
   835 NS_IMPL_ISUPPORTS(DMDReporter, nsIMemoryReporter)
   837 } // namespace dmd
   838 } // namespace mozilla
   840 #endif  // MOZ_DMD
   842 /**
   843  ** nsMemoryReporterManager implementation
   844  **/
   846 NS_IMPL_ISUPPORTS(nsMemoryReporterManager, nsIMemoryReporterManager)
   848 NS_IMETHODIMP
   849 nsMemoryReporterManager::Init()
   850 {
   851 #if defined(HAVE_JEMALLOC_STATS) && defined(XP_LINUX)
   852   if (!jemalloc_stats) {
   853     return NS_ERROR_FAILURE;
   854   }
   855 #endif
   857 #ifdef HAVE_JEMALLOC_STATS
   858   RegisterStrongReporter(new JemallocHeapReporter());
   859 #endif
   861 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
   862   RegisterStrongReporter(new VsizeReporter());
   863   RegisterStrongReporter(new ResidentReporter());
   864 #endif
   866 #ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER
   867   RegisterStrongReporter(new VsizeMaxContiguousReporter());
   868 #endif
   870 #ifdef HAVE_RESIDENT_UNIQUE_REPORTER
   871   RegisterStrongReporter(new ResidentUniqueReporter());
   872 #endif
   874 #ifdef HAVE_PAGE_FAULT_REPORTERS
   875   RegisterStrongReporter(new PageFaultsSoftReporter());
   876   RegisterStrongReporter(new PageFaultsHardReporter());
   877 #endif
   879 #ifdef HAVE_PRIVATE_REPORTER
   880   RegisterStrongReporter(new PrivateReporter());
   881 #endif
   883   RegisterStrongReporter(new AtomTablesReporter());
   885 #ifdef MOZ_DMD
   886   RegisterStrongReporter(new mozilla::dmd::DMDReporter());
   887 #endif
   889 #ifdef XP_UNIX
   890   nsMemoryInfoDumper::Initialize();
   891 #endif
   893   return NS_OK;
   894 }
   896 nsMemoryReporterManager::nsMemoryReporterManager()
   897   : mMutex("nsMemoryReporterManager::mMutex")
   898   , mIsRegistrationBlocked(false)
   899   , mStrongReporters(new StrongReportersTable())
   900   , mWeakReporters(new WeakReportersTable())
   901   , mSavedStrongReporters(nullptr)
   902   , mSavedWeakReporters(nullptr)
   903   , mNumChildProcesses(0)
   904   , mNextGeneration(1)
   905   , mGetReportsState(nullptr)
   906 {
   907 }
   909 nsMemoryReporterManager::~nsMemoryReporterManager()
   910 {
   911   delete mStrongReporters;
   912   delete mWeakReporters;
   913   NS_ASSERTION(!mSavedStrongReporters, "failed to restore strong reporters");
   914   NS_ASSERTION(!mSavedWeakReporters, "failed to restore weak reporters");
   915 }
   917 //#define DEBUG_CHILD_PROCESS_MEMORY_REPORTING 1
   919 #ifdef DEBUG_CHILD_PROCESS_MEMORY_REPORTING
   920 #define MEMORY_REPORTING_LOG(format, ...) \
   921   fprintf(stderr, "++++ MEMORY REPORTING: " format, ##__VA_ARGS__);
   922 #else
   923 #define MEMORY_REPORTING_LOG(...)
   924 #endif
   926 void
   927 nsMemoryReporterManager::IncrementNumChildProcesses()
   928 {
   929   if (!NS_IsMainThread()) {
   930     MOZ_CRASH();
   931   }
   932   mNumChildProcesses++;
   933   MEMORY_REPORTING_LOG("IncrementNumChildProcesses --> %d\n",
   934                        mNumChildProcesses);
   935 }
   937 void
   938 nsMemoryReporterManager::DecrementNumChildProcesses()
   939 {
   940   if (!NS_IsMainThread()) {
   941     MOZ_CRASH();
   942   }
   943   MOZ_ASSERT(mNumChildProcesses > 0);
   944   mNumChildProcesses--;
   945   MEMORY_REPORTING_LOG("DecrementNumChildProcesses --> %d\n",
   946                        mNumChildProcesses);
   947 }
   949 NS_IMETHODIMP
   950 nsMemoryReporterManager::GetReports(
   951   nsIHandleReportCallback* aHandleReport,
   952   nsISupports* aHandleReportData,
   953   nsIFinishReportingCallback* aFinishReporting,
   954   nsISupports* aFinishReportingData)
   955 {
   956   return GetReportsExtended(aHandleReport, aHandleReportData,
   957                             aFinishReporting, aFinishReportingData,
   958                             /* minimize = */ false,
   959                             /* DMDident = */ nsString());
   960 }
   962 NS_IMETHODIMP
   963 nsMemoryReporterManager::GetReportsExtended(
   964   nsIHandleReportCallback* aHandleReport,
   965   nsISupports* aHandleReportData,
   966   nsIFinishReportingCallback* aFinishReporting,
   967   nsISupports* aFinishReportingData,
   968   bool aMinimize,
   969   const nsAString& aDMDDumpIdent)
   970 {
   971   nsresult rv;
   973   // Memory reporters are not necessarily threadsafe, so this function must
   974   // be called from the main thread.
   975   if (!NS_IsMainThread()) {
   976     MOZ_CRASH();
   977   }
   979   uint32_t generation = mNextGeneration++;
   981   if (mGetReportsState) {
   982     // A request is in flight.  Don't start another one.  And don't report
   983     // an error;  just ignore it, and let the in-flight request finish.
   984     MEMORY_REPORTING_LOG("GetReports (gen=%u, s->gen=%u): abort\n",
   985                          generation, mGetReportsState->mGeneration);
   986     return NS_OK;
   987   }
   989   MEMORY_REPORTING_LOG("GetReports (gen=%u, %d child(ren) present)\n",
   990                        generation, mNumChildProcesses);
   992   if (mNumChildProcesses > 0) {
   993     // Request memory reports from child processes.  We do this *before*
   994     // collecting reports for this process so each process can collect
   995     // reports in parallel.
   996     nsCOMPtr<nsIObserverService> obs =
   997       do_GetService("@mozilla.org/observer-service;1");
   998     NS_ENSURE_STATE(obs);
  1000     nsPrintfCString genStr("generation=%x minimize=%d DMDident=",
  1001                            generation, aMinimize ? 1 : 0);
  1002     nsAutoString msg = NS_ConvertUTF8toUTF16(genStr);
  1003     msg += aDMDDumpIdent;
  1005     obs->NotifyObservers(nullptr, "child-memory-reporter-request",
  1006                          msg.get());
  1008     nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
  1009     NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
  1010     rv = timer->InitWithFuncCallback(TimeoutCallback,
  1011                                      this, kTimeoutLengthMS,
  1012                                      nsITimer::TYPE_ONE_SHOT);
  1013     NS_ENSURE_SUCCESS(rv, rv);
  1015     mGetReportsState = new GetReportsState(generation,
  1016                                            timer,
  1017                                            mNumChildProcesses,
  1018                                            aHandleReport,
  1019                                            aHandleReportData,
  1020                                            aFinishReporting,
  1021                                            aFinishReportingData,
  1022                                            aDMDDumpIdent);
  1023   } else {
  1024     mGetReportsState = new GetReportsState(generation,
  1025                                            nullptr,
  1026                                            /* mNumChildProcesses = */ 0,
  1027                                            aHandleReport,
  1028                                            aHandleReportData,
  1029                                            aFinishReporting,
  1030                                            aFinishReportingData,
  1031                                            aDMDDumpIdent);
  1034   if (aMinimize) {
  1035     rv = MinimizeMemoryUsage(NS_NewRunnableMethod(this, &nsMemoryReporterManager::StartGettingReports));
  1036   } else {
  1037     rv = StartGettingReports();
  1039   return rv;
  1042 nsresult
  1043 nsMemoryReporterManager::StartGettingReports()
  1045   GetReportsState *s = mGetReportsState;
  1047   // Get reports for this process.
  1048   GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData,
  1049                                    s->mDMDDumpIdent);
  1050   s->mParentDone = true;
  1052   // If there are no remaining child processes, we can finish up immediately.
  1053   return (s->mNumChildProcessesCompleted >= s->mNumChildProcesses)
  1054     ? FinishReporting()
  1055     : NS_OK;
  1058 typedef nsCOMArray<nsIMemoryReporter> MemoryReporterArray;
  1060 static PLDHashOperator
  1061 StrongEnumerator(nsRefPtrHashKey<nsIMemoryReporter>* aElem, void* aData)
  1063   MemoryReporterArray *allReporters = static_cast<MemoryReporterArray*>(aData);
  1064   allReporters->AppendElement(aElem->GetKey());
  1065   return PL_DHASH_NEXT;
  1068 static PLDHashOperator
  1069 WeakEnumerator(nsPtrHashKey<nsIMemoryReporter>* aElem, void* aData)
  1071   MemoryReporterArray *allReporters = static_cast<MemoryReporterArray*>(aData);
  1072   allReporters->AppendElement(aElem->GetKey());
  1073   return PL_DHASH_NEXT;
  1076 NS_IMETHODIMP
  1077 nsMemoryReporterManager::GetReportsForThisProcess(
  1078   nsIHandleReportCallback* aHandleReport,
  1079   nsISupports* aHandleReportData)
  1081   return GetReportsForThisProcessExtended(aHandleReport,
  1082                                           aHandleReportData,
  1083                                           nsString());
  1086 NS_IMETHODIMP
  1087 nsMemoryReporterManager::GetReportsForThisProcessExtended(
  1088   nsIHandleReportCallback* aHandleReport,
  1089   nsISupports* aHandleReportData,
  1090   const nsAString& aDMDDumpIdent)
  1092   // Memory reporters are not necessarily threadsafe, so this function must
  1093   // be called from the main thread.
  1094   if (!NS_IsMainThread()) {
  1095     MOZ_CRASH();
  1098 #ifdef MOZ_DMD
  1099   if (!aDMDDumpIdent.IsEmpty()) {
  1100     // Clear DMD's reportedness state before running the memory
  1101     // reporters, to avoid spurious twice-reported warnings.
  1102     dmd::ClearReports();
  1104 #endif
  1106   MemoryReporterArray allReporters;
  1108     mozilla::MutexAutoLock autoLock(mMutex);
  1109     mStrongReporters->EnumerateEntries(StrongEnumerator, &allReporters);
  1110     mWeakReporters->EnumerateEntries(WeakEnumerator, &allReporters);
  1112   for (uint32_t i = 0; i < allReporters.Length(); i++) {
  1113     allReporters[i]->CollectReports(aHandleReport, aHandleReportData);
  1116 #ifdef MOZ_DMD
  1117   if (!aDMDDumpIdent.IsEmpty()) {
  1118     return nsMemoryInfoDumper::DumpDMD(aDMDDumpIdent);
  1120 #endif
  1122   return NS_OK;
  1125 // This function has no return value.  If something goes wrong, there's no
  1126 // clear place to report the problem to, but that's ok -- we will end up
  1127 // hitting the timeout and executing TimeoutCallback().
  1128 void
  1129 nsMemoryReporterManager::HandleChildReports(
  1130   const uint32_t& aGeneration,
  1131   const InfallibleTArray<dom::MemoryReport>& aChildReports)
  1133   // Memory reporting only happens on the main thread.
  1134   if (!NS_IsMainThread()) {
  1135     MOZ_CRASH();
  1138   GetReportsState* s = mGetReportsState;
  1140   if (!s) {
  1141     // If we reach here, either:
  1142     //
  1143     // - A child process reported back too late, and no subsequent request
  1144     //   is in flight.
  1145     //
  1146     // - (Unlikely) A "child-memory-reporter-request" notification was
  1147     //   triggered from somewhere other than GetReports(), causing child
  1148     //   processes to report back when the nsMemoryReporterManager wasn't
  1149     //   expecting it.
  1150     //
  1151     // Either way, there's nothing to be done.  Just ignore it.
  1152     MEMORY_REPORTING_LOG(
  1153       "HandleChildReports: no request in flight (aGen=%u)\n",
  1154       aGeneration);
  1155     return;
  1158   if (aGeneration != s->mGeneration) {
  1159     // If we reach here, a child process must have reported back, too late,
  1160     // while a subsequent (higher-numbered) request is in flight.  Again,
  1161     // ignore it.
  1162     MOZ_ASSERT(aGeneration < s->mGeneration);
  1163     MEMORY_REPORTING_LOG(
  1164       "HandleChildReports: gen mismatch (aGen=%u, s->gen=%u)\n",
  1165       aGeneration, s->mGeneration);
  1166     return;
  1169   // Process the reports from the child process.
  1170   for (uint32_t i = 0; i < aChildReports.Length(); i++) {
  1171     const dom::MemoryReport& r = aChildReports[i];
  1173     // Child reports should have a non-empty process.
  1174     MOZ_ASSERT(!r.process().IsEmpty());
  1176     // If the call fails, ignore and continue.
  1177     s->mHandleReport->Callback(r.process(), r.path(), r.kind(),
  1178                                r.units(), r.amount(), r.desc(),
  1179                                s->mHandleReportData);
  1182   // If all the child processes have reported, we can cancel the timer and
  1183   // finish up.  Otherwise, just return.
  1185   s->mNumChildProcessesCompleted++;
  1186   MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): completed child %d\n",
  1187                        aGeneration, s->mNumChildProcessesCompleted);
  1189   if (s->mNumChildProcessesCompleted >= s->mNumChildProcesses &&
  1190       s->mParentDone) {
  1191     s->mTimer->Cancel();
  1192     FinishReporting();
  1196 /* static */ void
  1197 nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData)
  1199   nsMemoryReporterManager* mgr = static_cast<nsMemoryReporterManager*>(aData);
  1200   GetReportsState* s = mgr->mGetReportsState;
  1202   MOZ_ASSERT(mgr->mGetReportsState);
  1203   MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u)\n",
  1204                        s->mGeneration);
  1206   // We don't bother sending any kind of cancellation message to the child
  1207   // processes that haven't reported back.
  1209   if (s->mParentDone) {
  1210     mgr->FinishReporting();
  1211   } else {
  1212     // This is unlikely -- the timeout expired during MinimizeMemoryUsage.
  1213     MEMORY_REPORTING_LOG("Timeout expired before parent report started!");
  1214     // Let the parent continue with its report, but ensure that
  1215     // StartGettingReports gives up immediately after that.
  1216     s->mNumChildProcesses = s->mNumChildProcessesCompleted;
  1220 nsresult
  1221 nsMemoryReporterManager::FinishReporting()
  1223   // Memory reporting only happens on the main thread.
  1224   if (!NS_IsMainThread()) {
  1225     MOZ_CRASH();
  1228   MOZ_ASSERT(mGetReportsState);
  1229   MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u)\n",
  1230                        mGetReportsState->mGeneration);
  1232   // Call this before deleting |mGetReportsState|.  That way, if
  1233   // |mFinishReportData| calls GetReports(), it will silently abort, as
  1234   // required.
  1235   nsresult rv = mGetReportsState->mFinishReporting->Callback(
  1236     mGetReportsState->mFinishReportingData);
  1238   delete mGetReportsState;
  1239   mGetReportsState = nullptr;
  1240   return rv;
  1243 static void
  1244 CrashIfRefcountIsZero(nsISupports* aObj)
  1246   // This will probably crash if the object's refcount is 0.
  1247   uint32_t refcnt = NS_ADDREF(aObj);
  1248   if (refcnt <= 1) {
  1249     MOZ_CRASH("CrashIfRefcountIsZero: refcount is zero");
  1251   NS_RELEASE(aObj);
  1254 nsresult
  1255 nsMemoryReporterManager::RegisterReporterHelper(
  1256   nsIMemoryReporter* aReporter, bool aForce, bool aStrong)
  1258   // This method is thread-safe.
  1259   mozilla::MutexAutoLock autoLock(mMutex);
  1261   if (mIsRegistrationBlocked && !aForce) {
  1262     return NS_ERROR_FAILURE;
  1265   if (mStrongReporters->Contains(aReporter) ||
  1266       mWeakReporters->Contains(aReporter))
  1268     return NS_ERROR_FAILURE;
  1271   // If |aStrong| is true, |aReporter| may have a refcnt of 0, so we take
  1272   // a kung fu death grip before calling PutEntry.  Otherwise, if PutEntry
  1273   // addref'ed and released |aReporter| before finally addref'ing it for
  1274   // good, it would free aReporter!  The kung fu death grip could itself be
  1275   // problematic if PutEntry didn't addref |aReporter| (because then when the
  1276   // death grip goes out of scope, we would delete the reporter).  In debug
  1277   // mode, we check that this doesn't happen.
  1278   //
  1279   // If |aStrong| is false, we require that |aReporter| have a non-zero
  1280   // refcnt.
  1281   //
  1282   if (aStrong) {
  1283     nsCOMPtr<nsIMemoryReporter> kungFuDeathGrip = aReporter;
  1284     mStrongReporters->PutEntry(aReporter);
  1285     CrashIfRefcountIsZero(aReporter);
  1286   } else {
  1287     CrashIfRefcountIsZero(aReporter);
  1288     nsCOMPtr<nsIXPConnectWrappedJS> jsComponent = do_QueryInterface(aReporter);
  1289     if (jsComponent) {
  1290       // We cannot allow non-native reporters (WrappedJS), since we'll be
  1291       // holding onto a raw pointer, which would point to the wrapper,
  1292       // and that wrapper is likely to go away as soon as this register
  1293       // call finishes.  This would then lead to subsequent crashes in
  1294       // CollectReports().
  1295       return NS_ERROR_XPC_BAD_CONVERT_JS;
  1297     mWeakReporters->PutEntry(aReporter);
  1300   return NS_OK;
  1303 NS_IMETHODIMP
  1304 nsMemoryReporterManager::RegisterStrongReporter(nsIMemoryReporter* aReporter)
  1306   return RegisterReporterHelper(aReporter, /* force = */ false,
  1307                                 /* strong = */ true);
  1310 NS_IMETHODIMP
  1311 nsMemoryReporterManager::RegisterWeakReporter(nsIMemoryReporter* aReporter)
  1313   return RegisterReporterHelper(aReporter, /* force = */ false,
  1314                                 /* strong = */ false);
  1317 NS_IMETHODIMP
  1318 nsMemoryReporterManager::RegisterStrongReporterEvenIfBlocked(
  1319   nsIMemoryReporter* aReporter)
  1321   return RegisterReporterHelper(aReporter, /* force = */ true,
  1322                                 /* strong = */ true);
  1325 NS_IMETHODIMP
  1326 nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter)
  1328   // This method is thread-safe.
  1329   mozilla::MutexAutoLock autoLock(mMutex);
  1331   MOZ_ASSERT(!mWeakReporters->Contains(aReporter));
  1333   if (mStrongReporters->Contains(aReporter)) {
  1334     mStrongReporters->RemoveEntry(aReporter);
  1335     return NS_OK;
  1338   return NS_ERROR_FAILURE;
  1341 NS_IMETHODIMP
  1342 nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter)
  1344   // This method is thread-safe.
  1345   mozilla::MutexAutoLock autoLock(mMutex);
  1347   MOZ_ASSERT(!mStrongReporters->Contains(aReporter));
  1349   if (mWeakReporters->Contains(aReporter)) {
  1350     mWeakReporters->RemoveEntry(aReporter);
  1351     return NS_OK;
  1354   return NS_ERROR_FAILURE;
  1357 NS_IMETHODIMP
  1358 nsMemoryReporterManager::BlockRegistrationAndHideExistingReporters()
  1360   // This method is thread-safe.
  1361   mozilla::MutexAutoLock autoLock(mMutex);
  1362   if (mIsRegistrationBlocked) {
  1363     return NS_ERROR_FAILURE;
  1365   mIsRegistrationBlocked = true;
  1367   // Hide the existing reporters, saving them for later restoration.
  1368   MOZ_ASSERT(!mSavedStrongReporters);
  1369   MOZ_ASSERT(!mSavedWeakReporters);
  1370   mSavedStrongReporters = mStrongReporters;
  1371   mSavedWeakReporters = mWeakReporters;
  1372   mStrongReporters = new StrongReportersTable();
  1373   mWeakReporters = new WeakReportersTable();
  1375   return NS_OK;
  1378 NS_IMETHODIMP
  1379 nsMemoryReporterManager::UnblockRegistrationAndRestoreOriginalReporters()
  1381   // This method is thread-safe.
  1382   mozilla::MutexAutoLock autoLock(mMutex);
  1383   if (!mIsRegistrationBlocked) {
  1384     return NS_ERROR_FAILURE;
  1387   // Banish the current reporters, and restore the hidden ones.
  1388   delete mStrongReporters;
  1389   delete mWeakReporters;
  1390   mStrongReporters = mSavedStrongReporters;
  1391   mWeakReporters = mSavedWeakReporters;
  1392   mSavedStrongReporters = nullptr;
  1393   mSavedWeakReporters = nullptr;
  1395   mIsRegistrationBlocked = false;
  1396   return NS_OK;
  1399 // This is just a wrapper for int64_t that implements nsISupports, so it can be
  1400 // passed to nsIMemoryReporter::CollectReports.
  1401 class Int64Wrapper MOZ_FINAL : public nsISupports
  1403 public:
  1404   NS_DECL_ISUPPORTS
  1405   Int64Wrapper() : mValue(0) { }
  1406   int64_t mValue;
  1407 };
  1409 NS_IMPL_ISUPPORTS0(Int64Wrapper)
  1411 class ExplicitCallback MOZ_FINAL : public nsIHandleReportCallback
  1413 public:
  1414   NS_DECL_ISUPPORTS
  1416   NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath,
  1417                       int32_t aKind, int32_t aUnits, int64_t aAmount,
  1418                       const nsACString& aDescription,
  1419                       nsISupports* aWrappedExplicit)
  1421     // Using the "heap-allocated" reporter here instead of
  1422     // nsMemoryReporterManager.heapAllocated goes against the usual
  1423     // pattern.  But it's for a good reason:  in tests, we can easily
  1424     // create artificial (i.e. deterministic) reporters -- which allows us
  1425     // to precisely test nsMemoryReporterManager.explicit -- but we can't
  1426     // do that for distinguished amounts.
  1427     if (aPath.Equals("heap-allocated") ||
  1428         (aKind == nsIMemoryReporter::KIND_NONHEAP &&
  1429          PromiseFlatCString(aPath).Find("explicit") == 0))
  1431       Int64Wrapper* wrappedInt64 = static_cast<Int64Wrapper*>(aWrappedExplicit);
  1432       wrappedInt64->mValue += aAmount;
  1434     return NS_OK;
  1436 };
  1438 NS_IMPL_ISUPPORTS(ExplicitCallback, nsIHandleReportCallback)
  1440 NS_IMETHODIMP
  1441 nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
  1443   if (NS_WARN_IF(!aAmount)) {
  1444     return NS_ERROR_INVALID_ARG;
  1446   *aAmount = 0;
  1447 #ifndef HAVE_JEMALLOC_STATS
  1448   return NS_ERROR_NOT_AVAILABLE;
  1449 #else
  1451   // For each reporter we call CollectReports and filter out the
  1452   // non-explicit, non-NONHEAP measurements (except for "heap-allocated").
  1453   // That's lots of wasted work, and we used to have a GetExplicitNonHeap()
  1454   // method which did this more efficiently, but it ended up being more
  1455   // trouble than it was worth.
  1457   nsRefPtr<ExplicitCallback> handleReport = new ExplicitCallback();
  1458   nsRefPtr<Int64Wrapper> wrappedExplicitSize = new Int64Wrapper();
  1460   GetReportsForThisProcess(handleReport, wrappedExplicitSize);
  1462   *aAmount = wrappedExplicitSize->mValue;
  1464   return NS_OK;
  1465 #endif // HAVE_JEMALLOC_STATS
  1468 NS_IMETHODIMP
  1469 nsMemoryReporterManager::GetVsize(int64_t* aVsize)
  1471 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
  1472   return VsizeDistinguishedAmount(aVsize);
  1473 #else
  1474   *aVsize = 0;
  1475   return NS_ERROR_NOT_AVAILABLE;
  1476 #endif
  1479 NS_IMETHODIMP
  1480 nsMemoryReporterManager::GetVsizeMaxContiguous(int64_t* aAmount)
  1482 #ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER
  1483   return VsizeMaxContiguousDistinguishedAmount(aAmount);
  1484 #else
  1485   *aAmount = 0;
  1486   return NS_ERROR_NOT_AVAILABLE;
  1487 #endif
  1490 NS_IMETHODIMP
  1491 nsMemoryReporterManager::GetResident(int64_t* aAmount)
  1493 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
  1494   return ResidentDistinguishedAmount(aAmount);
  1495 #else
  1496   *aAmount = 0;
  1497   return NS_ERROR_NOT_AVAILABLE;
  1498 #endif
  1501 NS_IMETHODIMP
  1502 nsMemoryReporterManager::GetResidentFast(int64_t* aAmount)
  1504 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
  1505   return ResidentFastDistinguishedAmount(aAmount);
  1506 #else
  1507   *aAmount = 0;
  1508   return NS_ERROR_NOT_AVAILABLE;
  1509 #endif
  1512 /*static*/
  1513 int64_t nsMemoryReporterManager::ResidentFast()
  1515 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
  1516     int64_t amount;
  1517     ResidentFastDistinguishedAmount(&amount);
  1518     return amount;
  1519 #else
  1520     return 0;
  1521 #endif
  1524 NS_IMETHODIMP
  1525 nsMemoryReporterManager::GetHeapAllocated(int64_t* aAmount)
  1527 #ifdef HAVE_JEMALLOC_STATS
  1528   jemalloc_stats_t stats;
  1529   jemalloc_stats(&stats);
  1530   *aAmount = stats.allocated;
  1531   return NS_OK;
  1532 #else
  1533   *aAmount = 0;
  1534   return NS_ERROR_NOT_AVAILABLE;
  1535 #endif
  1538 // This has UNITS_PERCENTAGE, so it is multiplied by 100x.
  1539 NS_IMETHODIMP
  1540 nsMemoryReporterManager::GetHeapOverheadRatio(int64_t* aAmount)
  1542 #ifdef HAVE_JEMALLOC_STATS
  1543   jemalloc_stats_t stats;
  1544   jemalloc_stats(&stats);
  1545   *aAmount = HeapOverheadRatio(&stats);
  1546   return NS_OK;
  1547 #else
  1548   *aAmount = 0;
  1549   return NS_ERROR_NOT_AVAILABLE;
  1550 #endif
  1553 static nsresult
  1554 GetInfallibleAmount(InfallibleAmountFn aAmountFn, int64_t* aAmount)
  1556   if (aAmountFn) {
  1557     *aAmount = aAmountFn();
  1558     return NS_OK;
  1560   *aAmount = 0;
  1561   return NS_ERROR_NOT_AVAILABLE;
  1564 NS_IMETHODIMP
  1565 nsMemoryReporterManager::GetJSMainRuntimeGCHeap(int64_t* aAmount)
  1567   return GetInfallibleAmount(mAmountFns.mJSMainRuntimeGCHeap, aAmount);
  1570 NS_IMETHODIMP
  1571 nsMemoryReporterManager::GetJSMainRuntimeTemporaryPeak(int64_t* aAmount)
  1573   return GetInfallibleAmount(mAmountFns.mJSMainRuntimeTemporaryPeak, aAmount);
  1576 NS_IMETHODIMP
  1577 nsMemoryReporterManager::GetJSMainRuntimeCompartmentsSystem(int64_t* aAmount)
  1579   return GetInfallibleAmount(mAmountFns.mJSMainRuntimeCompartmentsSystem,
  1580                              aAmount);
  1583 NS_IMETHODIMP
  1584 nsMemoryReporterManager::GetJSMainRuntimeCompartmentsUser(int64_t* aAmount)
  1586   return GetInfallibleAmount(mAmountFns.mJSMainRuntimeCompartmentsUser,
  1587                              aAmount);
  1590 NS_IMETHODIMP
  1591 nsMemoryReporterManager::GetImagesContentUsedUncompressed(int64_t* aAmount)
  1593   return GetInfallibleAmount(mAmountFns.mImagesContentUsedUncompressed,
  1594                              aAmount);
  1597 NS_IMETHODIMP
  1598 nsMemoryReporterManager::GetStorageSQLite(int64_t* aAmount)
  1600   return GetInfallibleAmount(mAmountFns.mStorageSQLite, aAmount);
  1603 NS_IMETHODIMP
  1604 nsMemoryReporterManager::GetLowMemoryEventsVirtual(int64_t* aAmount)
  1606   return GetInfallibleAmount(mAmountFns.mLowMemoryEventsVirtual, aAmount);
  1609 NS_IMETHODIMP
  1610 nsMemoryReporterManager::GetLowMemoryEventsPhysical(int64_t* aAmount)
  1612   return GetInfallibleAmount(mAmountFns.mLowMemoryEventsPhysical, aAmount);
  1615 NS_IMETHODIMP
  1616 nsMemoryReporterManager::GetGhostWindows(int64_t* aAmount)
  1618   return GetInfallibleAmount(mAmountFns.mGhostWindows, aAmount);
  1621 NS_IMETHODIMP
  1622 nsMemoryReporterManager::GetPageFaultsHard(int64_t* aAmount)
  1624 #ifdef HAVE_PAGE_FAULT_REPORTERS
  1625   return PageFaultsHardDistinguishedAmount(aAmount);
  1626 #else
  1627   *aAmount = 0;
  1628   return NS_ERROR_NOT_AVAILABLE;
  1629 #endif
  1632 NS_IMETHODIMP
  1633 nsMemoryReporterManager::GetHasMozMallocUsableSize(bool* aHas)
  1635   void* p = malloc(16);
  1636   if (!p) {
  1637     return NS_ERROR_OUT_OF_MEMORY;
  1639   size_t usable = moz_malloc_usable_size(p);
  1640   free(p);
  1641   *aHas = !!(usable > 0);
  1642   return NS_OK;
  1645 namespace {
  1647 /**
  1648  * This runnable lets us implement
  1649  * nsIMemoryReporterManager::MinimizeMemoryUsage().  We fire a heap-minimize
  1650  * notification, spin the event loop, and repeat this process a few times.
  1652  * When this sequence finishes, we invoke the callback function passed to the
  1653  * runnable's constructor.
  1654  */
  1655 class MinimizeMemoryUsageRunnable : public nsRunnable
  1657 public:
  1658   MinimizeMemoryUsageRunnable(nsIRunnable* aCallback)
  1659     : mCallback(aCallback)
  1660     , mRemainingIters(sNumIters)
  1661   {}
  1663   NS_IMETHOD Run()
  1665     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1666     if (!os) {
  1667       return NS_ERROR_FAILURE;
  1670     if (mRemainingIters == 0) {
  1671       os->NotifyObservers(nullptr, "after-minimize-memory-usage",
  1672                           MOZ_UTF16("MinimizeMemoryUsageRunnable"));
  1673       if (mCallback) {
  1674         mCallback->Run();
  1676       return NS_OK;
  1679     os->NotifyObservers(nullptr, "memory-pressure",
  1680                         MOZ_UTF16("heap-minimize"));
  1681     mRemainingIters--;
  1682     NS_DispatchToMainThread(this);
  1684     return NS_OK;
  1687 private:
  1688   // Send sNumIters heap-minimize notifications, spinning the event
  1689   // loop after each notification (see bug 610166 comment 12 for an
  1690   // explanation), because one notification doesn't cut it.
  1691   static const uint32_t sNumIters = 3;
  1693   nsCOMPtr<nsIRunnable> mCallback;
  1694   uint32_t mRemainingIters;
  1695 };
  1697 } // anonymous namespace
  1699 NS_IMETHODIMP
  1700 nsMemoryReporterManager::MinimizeMemoryUsage(nsIRunnable* aCallback)
  1702   nsRefPtr<MinimizeMemoryUsageRunnable> runnable =
  1703     new MinimizeMemoryUsageRunnable(aCallback);
  1705   return NS_DispatchToMainThread(runnable);
  1708 NS_IMETHODIMP
  1709 nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow,
  1710                                    int64_t* aJSObjectsSize,
  1711                                    int64_t* aJSStringsSize,
  1712                                    int64_t* aJSOtherSize,
  1713                                    int64_t* aDomSize,
  1714                                    int64_t* aStyleSize,
  1715                                    int64_t* aOtherSize,
  1716                                    int64_t* aTotalSize,
  1717                                    double*  aJSMilliseconds,
  1718                                    double*  aNonJSMilliseconds)
  1720   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aTopWindow);
  1721   nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(aTopWindow);
  1722   if (NS_WARN_IF(!global) || NS_WARN_IF(!piWindow)) {
  1723     return NS_ERROR_FAILURE;
  1726   TimeStamp t1 = TimeStamp::Now();
  1728   // Measure JS memory consumption (and possibly some non-JS consumption, via
  1729   // |jsPrivateSize|).
  1730   size_t jsObjectsSize, jsStringsSize, jsPrivateSize, jsOtherSize;
  1731   nsresult rv = mSizeOfTabFns.mJS(global->GetGlobalJSObject(),
  1732                                   &jsObjectsSize, &jsStringsSize,
  1733                                   &jsPrivateSize, &jsOtherSize);
  1734   if (NS_WARN_IF(NS_FAILED(rv))) {
  1735     return rv;
  1738   TimeStamp t2 = TimeStamp::Now();
  1740   // Measure non-JS memory consumption.
  1741   size_t domSize, styleSize, otherSize;
  1742   mSizeOfTabFns.mNonJS(piWindow, &domSize, &styleSize, &otherSize);
  1744   TimeStamp t3 = TimeStamp::Now();
  1746   *aTotalSize = 0;
  1747   #define DO(aN, n) { *aN = (n); *aTotalSize += (n); }
  1748   DO(aJSObjectsSize, jsObjectsSize);
  1749   DO(aJSStringsSize, jsStringsSize);
  1750   DO(aJSOtherSize,   jsOtherSize);
  1751   DO(aDomSize,       jsPrivateSize + domSize);
  1752   DO(aStyleSize,     styleSize);
  1753   DO(aOtherSize,     otherSize);
  1754   #undef DO
  1756   *aJSMilliseconds    = (t2 - t1).ToMilliseconds();
  1757   *aNonJSMilliseconds = (t3 - t2).ToMilliseconds();
  1759   return NS_OK;
  1762 namespace mozilla {
  1764 nsresult
  1765 RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter)
  1767   // Hold a strong reference to the argument to make sure it gets released if
  1768   // we return early below.
  1769   nsCOMPtr<nsIMemoryReporter> reporter = aReporter;
  1771   nsCOMPtr<nsIMemoryReporterManager> mgr =
  1772     do_GetService("@mozilla.org/memory-reporter-manager;1");
  1773   if (!mgr) {
  1774     return NS_ERROR_FAILURE;
  1776   return mgr->RegisterStrongReporter(reporter);
  1779 nsresult
  1780 RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter)
  1782   nsCOMPtr<nsIMemoryReporterManager> mgr =
  1783     do_GetService("@mozilla.org/memory-reporter-manager;1");
  1784   if (!mgr) {
  1785     return NS_ERROR_FAILURE;
  1787   return mgr->RegisterWeakReporter(aReporter);
  1790 nsresult
  1791 UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter)
  1793   nsCOMPtr<nsIMemoryReporterManager> mgr =
  1794     do_GetService("@mozilla.org/memory-reporter-manager;1");
  1795   if (!mgr) {
  1796     return NS_ERROR_FAILURE;
  1798   return mgr->UnregisterWeakReporter(aReporter);
  1801 #define GET_MEMORY_REPORTER_MANAGER(mgr)                                      \
  1802   nsRefPtr<nsMemoryReporterManager> mgr =                                     \
  1803     nsMemoryReporterManager::GetOrCreate();                                   \
  1804   if (!mgr) {                                                                 \
  1805     return NS_ERROR_FAILURE;                                                  \
  1808 // Macro for generating functions that register distinguished amount functions
  1809 // with the memory reporter manager.
  1810 #define DEFINE_REGISTER_DISTINGUISHED_AMOUNT(kind, name)                      \
  1811   nsresult                                                                    \
  1812   Register##name##DistinguishedAmount(kind##AmountFn aAmountFn)               \
  1813   {                                                                           \
  1814     GET_MEMORY_REPORTER_MANAGER(mgr)                                          \
  1815     mgr->mAmountFns.m##name = aAmountFn;                                      \
  1816     return NS_OK;                                                             \
  1819 #define DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT(name)                          \
  1820   nsresult                                                                    \
  1821   Unregister##name##DistinguishedAmount()                                     \
  1822   {                                                                           \
  1823     GET_MEMORY_REPORTER_MANAGER(mgr)                                          \
  1824     mgr->mAmountFns.m##name = nullptr;                                        \
  1825     return NS_OK;                                                             \
  1828 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeGCHeap)
  1829 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeTemporaryPeak)
  1830 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
  1831 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
  1833 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, ImagesContentUsedUncompressed)
  1835 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, StorageSQLite)
  1836 DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT(StorageSQLite)
  1838 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsVirtual)
  1839 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsPhysical)
  1841 DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, GhostWindows)
  1843 #undef DEFINE_REGISTER_DISTINGUISHED_AMOUNT
  1844 #undef DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT
  1846 #define DEFINE_REGISTER_SIZE_OF_TAB(name)                                     \
  1847   nsresult                                                                    \
  1848   Register##name##SizeOfTab(name##SizeOfTabFn aSizeOfTabFn)                   \
  1849   {                                                                           \
  1850     GET_MEMORY_REPORTER_MANAGER(mgr)                                          \
  1851     mgr->mSizeOfTabFns.m##name = aSizeOfTabFn;                                \
  1852     return NS_OK;                                                             \
  1855 DEFINE_REGISTER_SIZE_OF_TAB(JS);
  1856 DEFINE_REGISTER_SIZE_OF_TAB(NonJS);
  1858 #undef DEFINE_REGISTER_SIZE_OF_TAB
  1860 #undef GET_MEMORY_REPORTER_MANAGER
  1864 #if defined(MOZ_DMD)
  1866 namespace mozilla {
  1867 namespace dmd {
  1869 class DoNothingCallback MOZ_FINAL : public nsIHandleReportCallback
  1871 public:
  1872   NS_DECL_ISUPPORTS
  1874   NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath,
  1875                       int32_t aKind, int32_t aUnits, int64_t aAmount,
  1876                       const nsACString& aDescription,
  1877                       nsISupports* aData)
  1879     // Do nothing;  the reporter has already reported to DMD.
  1880     return NS_OK;
  1882 };
  1884 NS_IMPL_ISUPPORTS(DoNothingCallback, nsIHandleReportCallback)
  1886 void
  1887 RunReportersForThisProcess()
  1889   nsCOMPtr<nsIMemoryReporterManager> mgr =
  1890     do_GetService("@mozilla.org/memory-reporter-manager;1");
  1892   nsRefPtr<DoNothingCallback> doNothing = new DoNothingCallback();
  1894   mgr->GetReportsForThisProcess(doNothing, nullptr);
  1897 } // namespace dmd
  1898 } // namespace mozilla
  1900 #endif  // defined(MOZ_DMD)

mercurial