xpcom/base/nsIMemoryReporter.idl

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 #include "nsISupports.idl"
     9 interface nsIDOMWindow;
    10 interface nsIRunnable;
    11 interface nsISimpleEnumerator;
    13 /*
    14  * Memory reporters measure Firefox's memory usage.  They are primarily used to
    15  * generate the about:memory page.  You should read
    16  * https://wiki.mozilla.org/Memory_Reporting before writing a memory
    17  * reporter.
    18  */
    20 [scriptable, function, uuid(3a61be3b-b93b-461a-a4f8-388214f558b1)]
    21 interface nsIMemoryReporterCallback : nsISupports
    22 {
    23   /*
    24    * The arguments to the callback are as follows.
    25    *
    26    *
    27    * |process|  The name of the process containing this reporter.  Each
    28    * reporter initially has "" in this field, indicating that it applies to the
    29    * current process.  (This is true even for reporters in a child process.)
    30    * When a reporter from a child process is copied into the main process, the
    31    * copy has its 'process' field set appropriately.
    32    *
    33    *
    34    * |path|  The path that this memory usage should be reported under.  Paths
    35    * are '/'-delimited, eg. "a/b/c".
    36    *
    37    * Each reporter can be viewed as representing a leaf node in a tree.
    38    * Internal nodes of the tree don't have reporters.  So, for example, the
    39    * reporters "explicit/a/b", "explicit/a/c", "explicit/d/e", and
    40    * "explicit/d/f" define this tree:
    41    *
    42    *   explicit
    43    *   |--a
    44    *   |  |--b [*]
    45    *   |  \--c [*]
    46    *   \--d
    47    *      |--e [*]
    48    *      \--f [*]
    49    *
    50    * Nodes marked with a [*] have a reporter.  Notice that the internal
    51    * nodes are implicitly defined by the paths.
    52    *
    53    * Nodes within a tree should not overlap measurements, otherwise the
    54    * parent node measurements will be double-counted.  So in the example
    55    * above, |b| should not count any allocations counted by |c|, and vice
    56    * versa.
    57    *
    58    * All nodes within each tree must have the same units.
    59    *
    60    * If you want to include a '/' not as a path separator, e.g. because the
    61    * path contains a URL, you need to convert each '/' in the URL to a '\'.
    62    * Consumers of the path will undo this change.  Any other '\' character
    63    * in a path will also be changed.  This is clumsy but hasn't caused any
    64    * problems so far.
    65    *
    66    * The paths of all reporters form a set of trees.  Trees can be
    67    * "degenerate", i.e. contain a single entry with no '/'.
    68    *
    69    *
    70    * |kind|  There are three kinds of memory reporters.
    71    *
    72    *  - HEAP: reporters measuring memory allocated by the heap allocator,
    73    *    e.g. by calling malloc, calloc, realloc, memalign, operator new, or
    74    *    operator new[].  Reporters in this category must have units
    75    *    UNITS_BYTES.
    76    *
    77    *  - NONHEAP: reporters measuring memory which the program explicitly
    78    *    allocated, but does not live on the heap.  Such memory is commonly
    79    *    allocated by calling one of the OS's memory-mapping functions (e.g.
    80    *    mmap, VirtualAlloc, or vm_allocate).  Reporters in this category
    81    *    must have units UNITS_BYTES.
    82    *
    83    *  - OTHER: reporters which don't fit into either of these categories.
    84    *    They can have any units.
    85    *
    86    * The kind only matters for reporters in the "explicit" tree;
    87    * aboutMemory.js uses it to calculate "heap-unclassified".
    88    *
    89    *
    90    * |units|  The units on the reporter's amount.  One of the following.
    91    *
    92    *  - BYTES: The amount contains a number of bytes.
    93    *
    94    *  - COUNT: The amount is an instantaneous count of things currently in
    95    *    existence.  For instance, the number of tabs currently open would have
    96    *    units COUNT.
    97    *
    98    *  - COUNT_CUMULATIVE: The amount contains the number of times some event
    99    *    has occurred since the application started up.  For instance, the
   100    *    number of times the user has opened a new tab would have units
   101    *    COUNT_CUMULATIVE.
   102    *
   103    *    The amount returned by a reporter with units COUNT_CUMULATIVE must
   104    *    never decrease over the lifetime of the application.
   105    *
   106    *  - PERCENTAGE: The amount contains a fraction that should be expressed as
   107    *    a percentage.  NOTE!  The |amount| field should be given a value 100x
   108    *    the actual percentage;  this number will be divided by 100 when shown.
   109    *    This allows a fractional percentage to be shown even though |amount| is
   110    *    an integer.  E.g. if the actual percentage is 12.34%, |amount| should
   111    *    be 1234.
   112    *
   113    *    Values greater than 100% are allowed.
   114    *
   115    *
   116    * |amount|  The numeric value reported by this memory reporter.  Accesses
   117    * can fail if something goes wrong when getting the amount.
   118    *
   119    *
   120    * |description|  A human-readable description of this memory usage report.
   121    */
   122   void callback(in ACString process, in AUTF8String path, in int32_t kind,
   123                 in int32_t units, in int64_t amount,
   124                 in AUTF8String description, in nsISupports data);
   125 };
   127 /*
   128  * An nsIMemoryReporter reports one or more memory measurements via a
   129  * callback function which is called once for each measurement.
   130  *
   131  * An nsIMemoryReporter that reports a single measurement is sometimes called a
   132  * "uni-reporter".  One that reports multiple measurements is sometimes called
   133  * a "multi-reporter".
   134  *
   135  * aboutMemory.js is the most important consumer of memory reports.  It
   136  * places the following constraints on reports.
   137  *
   138  * - All reports within a single sub-tree must have the same units.
   139  *
   140  * - There may be an "explicit" tree.  If present, it represents
   141  *   non-overlapping regions of memory that have been explicitly allocated with
   142  *   an OS-level allocation (e.g. mmap/VirtualAlloc/vm_allocate) or a
   143  *   heap-level allocation (e.g. malloc/calloc/operator new).  Reporters in
   144  *   this tree must have kind HEAP or NONHEAP, units BYTES.
   145  *
   146  * It is preferred, but not required, that report descriptions use complete
   147  * sentences (i.e. start with a capital letter and end with a period, or
   148  * similar).
   149  */
   150 [scriptable, uuid(0884cd0f-5829-4381-979b-0f53904030ed)]
   151 interface nsIMemoryReporter : nsISupports
   152 {
   153   /*
   154    * Run the reporter.
   155    */
   156   void collectReports(in nsIMemoryReporterCallback callback,
   157                       in nsISupports data);
   159   /*
   160    * Kinds.  See the |kind| comment in nsIMemoryReporterCallback.
   161    */
   162   const int32_t KIND_NONHEAP = 0;
   163   const int32_t KIND_HEAP    = 1;
   164   const int32_t KIND_OTHER   = 2;
   166   /*
   167    * Units.  See the |units| comment in nsIMemoryReporterCallback.
   168    */
   169   const int32_t UNITS_BYTES = 0;
   170   const int32_t UNITS_COUNT = 1;
   171   const int32_t UNITS_COUNT_CUMULATIVE = 2;
   172   const int32_t UNITS_PERCENTAGE = 3;
   173 };
   175 [scriptable, function, uuid(548b3909-c04d-4ca6-8466-b8bee3837457)]
   176 interface nsIFinishReportingCallback : nsISupports
   177 {
   178   void callback(in nsISupports data);
   179 };
   181 [scriptable, builtinclass, uuid(b6e5ec8a-71d9-48db-8ae9-68b4c5bbf2c3)]
   182 interface nsIMemoryReporterManager : nsISupports
   183 {
   184   /*
   185    * Initialize.
   186    */
   187   void init();
   189   /*
   190    * Register the given nsIMemoryReporter.  The Manager service will hold a
   191    * strong reference to the given reporter, and will be responsible for freeing
   192    * the reporter at shutdown.  You may manually unregister the reporter with
   193    * unregisterStrongReporter() at any point.
   194    */
   195   void registerStrongReporter(in nsIMemoryReporter reporter);
   197   /*
   198    * Like registerReporter, but the Manager service will hold a weak reference
   199    * via a raw pointer to the given reporter.  The reporter should be
   200    * unregistered before shutdown.
   201    * You cannot register JavaScript components with this function!  Always
   202    * register your JavaScript components with registerStrongReporter().
   203    */
   204   void registerWeakReporter(in nsIMemoryReporter reporter);
   206   /*
   207    * Unregister the given memory reporter, which must have been registered with
   208    * registerStrongReporter().  You normally don't need to unregister your
   209    * strong reporters, as nsIMemoryReporterManager will take care of that at
   210    * shutdown.
   211    */
   212   void unregisterStrongReporter(in nsIMemoryReporter reporter);
   214   /*
   215    * Unregister the given memory reporter, which must have been registered with
   216    * registerWeakReporter().
   217    */
   218   void unregisterWeakReporter(in nsIMemoryReporter reporter);
   220   /*
   221    * These functions should only be used for testing purposes.
   222    */
   223   void blockRegistrationAndHideExistingReporters();
   224   void unblockRegistrationAndRestoreOriginalReporters();
   225   void registerStrongReporterEvenIfBlocked(in nsIMemoryReporter aReporter);
   227   /*
   228    * Get memory reports for the current process and all child processes.
   229    * |handleReport| is called for each report, and |finishReporting| is called
   230    * once all reports have been handled.
   231    *
   232    * |finishReporting| is called even if, for example, some child processes
   233    * fail to report back.  However, calls to this method will silently and
   234    * immediately abort -- and |finishReporting| will not be called -- if a
   235    * previous getReports() call is still in flight, i.e. if it has not yet
   236    * finished invoking |finishReporting|.  The silent abort is because the
   237    * in-flight request will finish soon, and the caller would very likely just
   238    * catch and ignore any error anyway.
   239    */
   240   void getReports(in nsIMemoryReporterCallback handleReport,
   241                   in nsISupports handleReportData,
   242                   in nsIFinishReportingCallback finishReporting,
   243                   in nsISupports finishReportingData);
   245   /*
   246    * As above, but: If |minimizeMemoryUsage| is true, then each process will
   247    * minimize its memory usage (see the |minimizeMemoryUsage| method) before
   248    * gathering its report.  If DMD is enabled and |DMDDumpIdent| is non-empty
   249    * then write a DMD report to a file in the usual temporary directory (see
   250    * |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.)
   251    */
   252   [noscript] void
   253     getReportsExtended(in nsIMemoryReporterCallback handleReport,
   254                        in nsISupports handleReportData,
   255                        in nsIFinishReportingCallback finishReporting,
   256                        in nsISupports finishReportingData,
   257                        in boolean minimizeMemoryUsage,
   258                        in AString DMDDumpIdent);
   260   /*
   261    * Get memory reports in the current process only.  |handleReport| is called
   262    * for each report.
   263    */
   264   void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport,
   265                                 in nsISupports handleReportData);
   267   /*
   268    * As above, but if DMD is enabled and |DMDDumpIdent| is non-empty
   269    * then write a DMD report to a file in the usual temporary directory (see
   270    * |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.)
   271    */
   272   [noscript] void
   273     getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport,
   274                                      in nsISupports handleReportData,
   275                                      in AString DMDDumpIdent);
   277   /*
   278    * The memory reporter manager, for the most part, treats reporters
   279    * registered with it as a black box.  However, there are some
   280    * "distinguished" amounts (as could be reported by a memory reporter) that
   281    * the manager provides as attributes, because they are sufficiently
   282    * interesting that we want external code (e.g. telemetry) to be able to rely
   283    * on them.
   284    *
   285    * Note that these are not reporters and so getReports() and
   286    * getReportsForThisProcess() do not look at them.  However, distinguished
   287    * amounts can be embedded in a reporter.
   288    *
   289    * Access to these attributes can fail.  In particular, some of them are not
   290    * available on all platforms.
   291    *
   292    * If you add a new distinguished amount, please update
   293    * toolkit/components/aboutmemory/tests/test_memoryReporters.xul.
   294    *
   295    * |explicit| (UNITS_BYTES)  The total size of explicit memory allocations,
   296    * both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level
   297    * (eg. via malloc, calloc, operator new).  It covers all heap allocations,
   298    * but will miss any OS-level ones not covered by memory reporters.
   299    *
   300    * |vsize| (UNITS_BYTES)  The virtual size, i.e. the amount of address space
   301    * taken up.
   302    *
   303    * |vsizeMaxContiguous| (UNITS_BYTES)  The size of the largest contiguous
   304    * block of virtual memory.
   305    *
   306    * |resident| (UNITS_BYTES)  The resident size (a.k.a. RSS or physical memory
   307    * used).
   308    *
   309    * |residentFast| (UNITS_BYTES)  This is like |resident|, but on Mac OS
   310    * |resident| can purge pages, which is slow.  It also affects the result of
   311    * |residentFast|, and so |resident| and |residentFast| should not be used
   312    * together.
   313    *
   314    * |heapAllocated| (UNITS_BYTES)  Memory mapped by the heap allocator.
   315    *
   316    * |heapOverheadRatio| (UNITS_PERCENTAGE)  In the heap allocator, this is the
   317    * ratio of committed, unused bytes to allocated bytes.  Like all
   318    * UNITS_PERCENTAGE measurements, its amount is multiplied by 100x so it can
   319    * be represented by an int64_t.
   320    *
   321    * |JSMainRuntimeGCHeap| (UNITS_BYTES)  Size of the main JS runtime's GC
   322    * heap.
   323    *
   324    * |JSMainRuntimeTemporaryPeak| (UNITS_BYTES)  Peak size of the transient
   325    * storage in the main JSRuntime.
   326    *
   327    * |JSMainRuntimeCompartments{System,User}| (UNITS_COUNT)  The number of
   328    * {system,user} compartments in the main JS runtime.
   329    *
   330    * |imagesContentUsedUncompressed| (UNITS_BYTES)  Memory used for decoded
   331    * images in content.
   332    *
   333    * |storageSQLite| (UNITS_BYTES)  Memory used by SQLite.
   334    *
   335    * |lowMemoryEvents{Virtual,Physical}| (UNITS_COUNT_CUMULATIVE)  The number
   336    * of low-{virtual,physical}-memory events that have occurred since the
   337    * process started.
   338    *
   339    * |ghostWindows| (UNITS_COUNT)  The number of ghost windows.
   340    *
   341    * |pageFaultsHard| (UNITS_COUNT_CUMULATIVE)  The number of hard (a.k.a.
   342    * major) page faults that have occurred since the process started.
   343    */
   344   readonly attribute int64_t explicit;
   345   readonly attribute int64_t vsize;
   346   readonly attribute int64_t vsizeMaxContiguous;
   347   readonly attribute int64_t resident;
   348   readonly attribute int64_t residentFast;
   350   readonly attribute int64_t heapAllocated;
   351   readonly attribute int64_t heapOverheadRatio;
   353   readonly attribute int64_t JSMainRuntimeGCHeap;
   354   readonly attribute int64_t JSMainRuntimeTemporaryPeak;
   355   readonly attribute int64_t JSMainRuntimeCompartmentsSystem;
   356   readonly attribute int64_t JSMainRuntimeCompartmentsUser;
   358   readonly attribute int64_t imagesContentUsedUncompressed;
   360   readonly attribute int64_t storageSQLite;
   362   readonly attribute int64_t lowMemoryEventsVirtual;
   363   readonly attribute int64_t lowMemoryEventsPhysical;
   365   readonly attribute int64_t ghostWindows;
   367   readonly attribute int64_t pageFaultsHard;
   369   /*
   370    * This attribute indicates if moz_malloc_usable_size() works.
   371    */
   372   [infallible] readonly attribute boolean hasMozMallocUsableSize;
   374   /*
   375    * Run a series of GC/CC's in an attempt to minimize the application's memory
   376    * usage.  When we're finished, we invoke the given runnable if it's not
   377    * null.
   378    */
   379   void minimizeMemoryUsage(in nsIRunnable callback);
   381   /*
   382    * Measure the memory that is known to be owned by this tab, split up into
   383    * several broad categories.  Note that this will be an underestimate of the
   384    * true number, due to imperfect memory reporter coverage (corresponding to
   385    * about:memory's "heap-unclassified"), and due to some memory shared between
   386    * tabs not being counted.
   387    *
   388    * The time taken for the measurement (split into JS and non-JS parts) is
   389    * also returned.
   390    */
   391   void sizeOfTab(in nsIDOMWindow window,
   392                  out int64_t jsObjectsSize, out int64_t jsStringsSize,
   393                  out int64_t jsOtherSize, out int64_t domSize,
   394                  out int64_t styleSize, out int64_t otherSize,
   395                  out int64_t totalSize,
   396                  out double jsMilliseconds, out double nonJSMilliseconds);
   397 };
   399 %{C++
   401 #include "js/TypeDecls.h"
   402 #include "nsStringGlue.h"
   403 #include "nsTArray.h"
   404 #include "mozilla/Atomics.h"
   406 class nsPIDOMWindow;
   408 // nsIHandleReportCallback is a better name, but keep nsIMemoryReporterCallback
   409 // around for backwards compatibility.
   410 typedef nsIMemoryReporterCallback nsIHandleReportCallback;
   412 namespace mozilla {
   414 // Register a memory reporter.  The manager service will hold a strong
   415 // reference to this reporter.
   416 XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter);
   418 // Register a memory reporter.  The manager service will hold a weak reference
   419 // to this reporter.
   420 XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter);
   422 // Unregister a weak memory reporter.
   423 XPCOM_API(nsresult) UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter);
   425 // The memory reporter manager provides access to several distinguished
   426 // amounts via attributes.  Some of these amounts are provided by Gecko
   427 // components that cannot be accessed directly from XPCOM code.  So we provide
   428 // the following functions for those components to be registered with the
   429 // manager.
   431 typedef int64_t (*InfallibleAmountFn)();
   432 typedef nsresult (*FallibleAmountFn)(int64_t* aAmount);
   434 #define DECL_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
   435     nsresult Register##name##DistinguishedAmount(kind##AmountFn aAmountFn);
   436 #define DECL_UNREGISTER_DISTINGUISHED_AMOUNT(name) \
   437     nsresult Unregister##name##DistinguishedAmount();
   439 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeGCHeap)
   440 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeTemporaryPeak)
   441 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
   442 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
   444 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, ImagesContentUsedUncompressed)
   446 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, StorageSQLite)
   447 DECL_UNREGISTER_DISTINGUISHED_AMOUNT(StorageSQLite)
   449 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsVirtual)
   450 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsPhysical)
   452 DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, GhostWindows)
   454 #undef DECL_REGISTER_DISTINGUISHED_AMOUNT
   455 #undef DECL_UNREGISTER_DISTINGUISHED_AMOUNT
   457 // Likewise for per-tab measurement.
   459 typedef nsresult (*JSSizeOfTabFn)(JSObject* aObj,
   460                                   size_t* aJsObjectsSize,
   461                                   size_t* aJsStringSize,
   462                                   size_t* aJsPrivateSize,
   463                                   size_t* aJsOtherSize);
   464 typedef nsresult (*NonJSSizeOfTabFn)(nsPIDOMWindow* aWindow,
   465                                      size_t* aDomSize,
   466                                      size_t* aStyleSize,
   467                                      size_t* aOtherSize);
   469 nsresult RegisterJSSizeOfTab(JSSizeOfTabFn aSizeOfTabFn);
   470 nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn);
   472 }
   474 #if defined(MOZ_DMD)
   475 namespace mozilla {
   476 namespace dmd {
   477 // This runs all the memory reporters in the current process but does nothing
   478 // with the results;  i.e. it does the minimal amount of work possible for DMD
   479 // to do its thing.  It does nothing with child processes.
   480 void RunReportersForThisProcess();
   481 }
   482 }
   484 #if !defined(MOZ_MEMORY)
   485 #error "MOZ_DMD requires MOZ_MEMORY"
   486 #endif
   488 #include "DMD.h"
   490 #define MOZ_REPORT(ptr)          mozilla::dmd::Report(ptr)
   491 #define MOZ_REPORT_ON_ALLOC(ptr) mozilla::dmd::ReportOnAlloc(ptr)
   493 #else
   495 #define MOZ_REPORT(ptr)
   496 #define MOZ_REPORT_ON_ALLOC(ptr)
   498 #endif  // defined(MOZ_DMD)
   500 // Functions generated via this macro should be used by all traversal-based
   501 // memory reporters.  Such functions return |moz_malloc_size_of(ptr)|;  this
   502 // will always be zero on some obscure platforms.
   503 //
   504 // You might be wondering why we have a macro that creates multiple functions
   505 // that differ only in their name, instead of a single MallocSizeOf function.
   506 // It's mostly to help with DMD integration, though it sometimes also helps
   507 // with debugging and temporary ad hoc profiling.  The function name chosen
   508 // doesn't matter greatly, but it's best to make it similar to the path used by
   509 // the relevant memory reporter(s).
   510 #define MOZ_DEFINE_MALLOC_SIZE_OF(fn)                                         \
   511   static size_t fn(const void* aPtr)                                          \
   512   {                                                                           \
   513       MOZ_REPORT(aPtr);                                                       \
   514       return moz_malloc_size_of(aPtr);                                        \
   515   }
   517 // Functions generated by the next two macros should be used by wrapping
   518 // allocators that report heap blocks as soon as they are allocated and
   519 // unreport them as soon as they are freed.  Such allocators are used in cases
   520 // where we have third-party code that we cannot modify.  The two functions
   521 // must always be used in tandem.
   522 #define MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(fn)                                \
   523   static size_t fn(const void* aPtr)                                          \
   524   {                                                                           \
   525       MOZ_REPORT_ON_ALLOC(aPtr);                                              \
   526       return moz_malloc_size_of(aPtr);                                        \
   527   }
   528 #define MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(fn)                                 \
   529   static size_t fn(const void* aPtr)                                          \
   530   {                                                                           \
   531       return moz_malloc_size_of(aPtr);                                        \
   532   }
   534 namespace mozilla {
   536 // This CRTP class handles several details of wrapping allocators and should
   537 // be preferred to manually counting with MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC
   538 // and MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE.  The typical use is in a memory
   539 // reporter for a particular third party library:
   540 //
   541 //   class MyMemoryReporter : public CountingAllocatorBase<MyMemoryReporter>
   542 //   {
   543 //     ...
   544 //     NS_IMETHODIMP
   545 //     CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
   546 //     {
   547 //        return MOZ_COLLECT_REPORTER(
   548 //          "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES,
   549 //          MemoryAllocated(),
   550 //          "A description of what we are reporting."
   551 //     }
   552 //   };
   553 //
   554 //   ...somewhere later in the code...
   555 //   SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc,
   556 //                                MyMemoryReporter::CountingFree);
   557 template<typename T>
   558 class CountingAllocatorBase
   559 {
   560 public:
   561   CountingAllocatorBase()
   562   {
   563 #ifdef DEBUG
   564     // There must be only one instance of this class, due to |sAmount| being
   565     // static.
   566     static bool hasRun = false;
   567     MOZ_ASSERT(!hasRun);
   568     hasRun = true;
   569 #endif
   570   }
   572   static size_t
   573   MemoryAllocated()
   574   {
   575     return sAmount;
   576   }
   578   static void*
   579   CountingMalloc(size_t size)
   580   {
   581     void* p = malloc(size);
   582     sAmount += MallocSizeOfOnAlloc(p);
   583     return p;
   584   }
   586   static void*
   587   CountingCalloc(size_t nmemb, size_t size)
   588   {
   589     void* p = calloc(nmemb, size);
   590     sAmount += MallocSizeOfOnAlloc(p);
   591     return p;
   592   }
   594   static void*
   595   CountingRealloc(void* p, size_t size)
   596   {
   597     size_t oldsize = MallocSizeOfOnFree(p);
   598     void *pnew = realloc(p, size);
   599     if (pnew) {
   600       size_t newsize = MallocSizeOfOnAlloc(pnew);
   601       sAmount += newsize - oldsize;
   602     } else if (size == 0) {
   603       // We asked for a 0-sized (re)allocation of some existing pointer
   604       // and received NULL in return.  0-sized allocations are permitted
   605       // to either return NULL or to allocate a unique object per call (!).
   606       // For a malloc implementation that chooses the second strategy,
   607       // that allocation may fail (unlikely, but possible).
   608       //
   609       // Given a NULL return value and an allocation size of 0, then, we
   610       // don't know if that means the original pointer was freed or if
   611       // the allocation of the unique object failed.  If the original
   612       // pointer was freed, then we have nothing to do here.  If the
   613       // allocation of the unique object failed, the original pointer is
   614       // still valid and we ought to undo the decrement from above.
   615       // However, we have no way of knowing how the underlying realloc
   616       // implementation is behaving.  Assuming that the original pointer
   617       // was freed is the safest course of action.  We do, however, need
   618       // to note that we freed memory.
   619       sAmount -= oldsize;
   620     } else {
   621       // realloc failed.  The amount allocated hasn't changed.
   622     }
   623     return pnew;
   624   }
   626   static void
   627   CountingFree(void* p)
   628   {
   629     sAmount -= MallocSizeOfOnFree(p);
   630     free(p);
   631   }
   633 private:
   634   // |sAmount| can be (implicitly) accessed by multiple threads, so it
   635   // must be thread-safe.
   636   static Atomic<size_t> sAmount;
   638   MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
   639   MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
   640 };
   642 }
   644 // This macro assumes the presence of appropriate |aHandleReport| and |aData|
   645 // variables.
   646 #define MOZ_COLLECT_REPORT(path, kind, units, amount, description)            \
   647   aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(path),           \
   648                           kind, units, amount,                                \
   649                           NS_LITERAL_CSTRING(description), aData)
   651 %}

mercurial