xpcom/base/nsMemoryReporterManager.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 #ifndef nsMemoryReporterManager_h__
     8 #define nsMemoryReporterManager_h__
    10 #include "nsIMemoryReporter.h"
    11 #include "nsITimer.h"
    12 #include "nsServiceManagerUtils.h"
    13 #include "mozilla/Mutex.h"
    14 #include "nsTHashtable.h"
    15 #include "nsHashKeys.h"
    17 class nsITimer;
    19 namespace mozilla {
    20 namespace dom {
    21 class MemoryReport;
    22 }
    23 }
    25 class nsMemoryReporterManager : public nsIMemoryReporterManager
    26 {
    27 public:
    28   NS_DECL_THREADSAFE_ISUPPORTS
    29   NS_DECL_NSIMEMORYREPORTERMANAGER
    31   nsMemoryReporterManager();
    32   virtual ~nsMemoryReporterManager();
    34   // Gets the memory reporter manager service.
    35   static nsMemoryReporterManager* GetOrCreate()
    36   {
    37     nsCOMPtr<nsIMemoryReporterManager> imgr =
    38       do_GetService("@mozilla.org/memory-reporter-manager;1");
    39     return static_cast<nsMemoryReporterManager*>(imgr.get());
    40   }
    42   typedef nsTHashtable<nsRefPtrHashKey<nsIMemoryReporter> > StrongReportersTable;
    43   typedef nsTHashtable<nsPtrHashKey<nsIMemoryReporter> > WeakReportersTable;
    45   void IncrementNumChildProcesses();
    46   void DecrementNumChildProcesses();
    48   // Inter-process memory reporting proceeds as follows.
    49   //
    50   // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER)
    51   //   synchronously gets memory reports for the current process, tells all
    52   //   child processes to get memory reports, and sets up some state
    53   //   (mGetReportsState) for when the child processes report back, including a
    54   //   timer.  Control then returns to the main event loop.
    55   //
    56   // - HandleChildReports() is called (asynchronously) once per child process
    57   //   that reports back.  If all child processes report back before time-out,
    58   //   the timer is cancelled.  (The number of child processes is part of the
    59   //   saved request state.)
    60   //
    61   // - TimeoutCallback() is called (asynchronously) if all the child processes
    62   //   don't respond within the time threshold.
    63   //
    64   // - FinishReporting() finishes things off.  It is *always* called -- either
    65   //   from HandleChildReports() (if all child processes have reported back) or
    66   //   from TimeoutCallback() (if time-out occurs).
    67   //
    68   // All operations occur on the main thread.
    69   //
    70   // The above sequence of steps is a "request".  A partially-completed request
    71   // is described as "in flight".
    72   //
    73   // Each request has a "generation", a unique number that identifies it.  This
    74   // is used to ensure that each reports from a child process corresponds to
    75   // the appropriate request from the parent process.  (It's easier to
    76   // implement a generation system than to implement a child report request
    77   // cancellation mechanism.)
    78   //
    79   // Failures are mostly ignored, because it's (a) typically the most sensible
    80   // thing to do, and (b) often hard to do anything else.  The following are
    81   // the failure cases of note.
    82   //
    83   // - If a request is made while the previous request is in flight, the new
    84   //   request is ignored, as per getReports()'s specification.  No error is
    85   //   reported, because the previous request will complete soon enough.
    86   //
    87   // - If one or more child processes fail to respond within the time limit,
    88   //   things will proceed as if they don't exist.  No error is reported,
    89   //   because partial information is better than nothing.
    90   //
    91   // - If a child process reports after the time-out occurs, it is ignored.
    92   //   (Generation checking will ensure it is ignored even if a subsequent
    93   //   request is in flight;  this is the main use of generations.)  No error
    94   //   is reported, because there's nothing sensible to be done about it at
    95   //   this late stage.
    96   //
    97   // Now, what what happens if a child process is created/destroyed in the
    98   // middle of a request?  Well, GetReportsState contains a copy of
    99   // mNumChildProcesses which it uses to determine finished-ness.  So...
   100   //
   101   // - If a process is created, it won't have received the request for reports,
   102   //   and the GetReportsState's mNumChildProcesses won't account for it.  So
   103   //   the reported data will reflect how things were when the request began.
   104   //
   105   // - If a process is destroyed before reporting back, we'll just hit the
   106   //   time-out, because we'll have received reports (barring other errors)
   107   //   from N-1 child process.  So the reported data will reflect how things
   108   //   are when the request ends.
   109   //
   110   // - If a process is destroyed after reporting back, but before all other
   111   //   child processes have reported back, it will be included in the reported
   112   //   data.  So the reported data will reflect how things were when the
   113   //   request began.
   114   //
   115   // The inconsistencies between these three cases are unfortunate but
   116   // difficult to avoid.  It's enough of an edge case to not be worth doing
   117   // more.
   118   //
   119   void HandleChildReports(
   120     const uint32_t& generation,
   121     const InfallibleTArray<mozilla::dom::MemoryReport>& aChildReports);
   122   nsresult FinishReporting();
   124   // Functions that (a) implement distinguished amounts, and (b) are outside of
   125   // this module.
   126   struct AmountFns
   127   {
   128     mozilla::InfallibleAmountFn mJSMainRuntimeGCHeap;
   129     mozilla::InfallibleAmountFn mJSMainRuntimeTemporaryPeak;
   130     mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsSystem;
   131     mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsUser;
   133     mozilla::InfallibleAmountFn mImagesContentUsedUncompressed;
   135     mozilla::InfallibleAmountFn mStorageSQLite;
   137     mozilla::InfallibleAmountFn mLowMemoryEventsVirtual;
   138     mozilla::InfallibleAmountFn mLowMemoryEventsPhysical;
   140     mozilla::InfallibleAmountFn mGhostWindows;
   142     AmountFns() { mozilla::PodZero(this); }
   143   };
   144   AmountFns mAmountFns;
   146   // Convenience function to get RSS easily from other code.  This is useful
   147   // when debugging transient memory spikes with printf instrumentation.
   148   static int64_t ResidentFast();
   150   // Functions that measure per-tab memory consumption.
   151   struct SizeOfTabFns
   152   {
   153     mozilla::JSSizeOfTabFn    mJS;
   154     mozilla::NonJSSizeOfTabFn mNonJS;
   156     SizeOfTabFns()
   157     {
   158       mozilla::PodZero(this);
   159     }
   160   };
   161   SizeOfTabFns mSizeOfTabFns;
   163 private:
   164   nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter,
   165                                   bool aForce, bool aStrongRef);
   166   nsresult StartGettingReports();
   168   static void TimeoutCallback(nsITimer* aTimer, void* aData);
   169   // Note: this timeout needs to be long enough to allow for the
   170   // possibility of DMD reports and/or running on a low-end phone.
   171   static const uint32_t kTimeoutLengthMS = 50000;
   173   mozilla::Mutex mMutex;
   174   bool mIsRegistrationBlocked;
   176   StrongReportersTable* mStrongReporters;
   177   WeakReportersTable* mWeakReporters;
   179   // These two are only used for testing purposes.
   180   StrongReportersTable* mSavedStrongReporters;
   181   WeakReportersTable* mSavedWeakReporters;
   183   uint32_t mNumChildProcesses;
   184   uint32_t mNextGeneration;
   186   struct GetReportsState
   187   {
   188     uint32_t                             mGeneration;
   189     nsCOMPtr<nsITimer>                   mTimer;
   190     uint32_t                             mNumChildProcesses;
   191     uint32_t                             mNumChildProcessesCompleted;
   192     bool                                 mParentDone;
   193     nsCOMPtr<nsIHandleReportCallback>    mHandleReport;
   194     nsCOMPtr<nsISupports>                mHandleReportData;
   195     nsCOMPtr<nsIFinishReportingCallback> mFinishReporting;
   196     nsCOMPtr<nsISupports>                mFinishReportingData;
   197     nsString                             mDMDDumpIdent;
   199     GetReportsState(uint32_t aGeneration, nsITimer* aTimer,
   200                     uint32_t aNumChildProcesses,
   201                     nsIHandleReportCallback* aHandleReport,
   202                     nsISupports* aHandleReportData,
   203                     nsIFinishReportingCallback* aFinishReporting,
   204                     nsISupports* aFinishReportingData,
   205                     const nsAString &aDMDDumpIdent)
   206       : mGeneration(aGeneration)
   207       , mTimer(aTimer)
   208       , mNumChildProcesses(aNumChildProcesses)
   209       , mNumChildProcessesCompleted(0)
   210       , mParentDone(false)
   211       , mHandleReport(aHandleReport)
   212       , mHandleReportData(aHandleReportData)
   213       , mFinishReporting(aFinishReporting)
   214       , mFinishReportingData(aFinishReportingData)
   215       , mDMDDumpIdent(aDMDDumpIdent)
   216     {
   217     }
   218   };
   220   // When this is non-null, a request is in flight.  Note: We use manual
   221   // new/delete for this because its lifetime doesn't match block scope or
   222   // anything like that.
   223   GetReportsState* mGetReportsState;
   224 };
   226 #define NS_MEMORY_REPORTER_MANAGER_CID \
   227 { 0xfb97e4f5, 0x32dd, 0x497a, \
   228 { 0xba, 0xa2, 0x7d, 0x1e, 0x55, 0x7, 0x99, 0x10 } }
   230 #endif // nsMemoryReporterManager_h__

mercurial