LCOV - code coverage report
Current view: directory - xpcom/base - nsMemoryReporterManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 236 160 67.8 %
Date: 2012-06-02 Functions: 163 103 63.2 %

       1                 : /* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * mozilla.org
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2008
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Vladimir Vukicevic <vladimir@pobox.com> (original author)
      24                 :  *   Nicholas Nethercote <nnethercote@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsAtomTable.h"
      41                 : #include "nsAutoPtr.h"
      42                 : #include "nsCOMPtr.h"
      43                 : #include "nsServiceManagerUtils.h"
      44                 : #include "nsMemoryReporterManager.h"
      45                 : #include "nsArrayEnumerator.h"
      46                 : #include "nsISimpleEnumerator.h"
      47                 : #include "mozilla/Telemetry.h"
      48                 : 
      49                 : using namespace mozilla;
      50                 : 
      51               3 : static PRInt64 GetExplicit()
      52                 : {
      53               6 :     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
      54               3 :     if (mgr == nsnull)
      55               0 :         return (PRInt64)-1;
      56                 : 
      57                 :     PRInt64 n;
      58               3 :     nsresult rv = mgr->GetExplicit(&n);
      59               3 :     NS_ENSURE_SUCCESS(rv, rv);
      60                 : 
      61               3 :     return n;
      62                 : }
      63                 : 
      64                 : #if defined(MOZ_MEMORY)
      65                 : #  if defined(XP_WIN) || defined(SOLARIS) || defined(ANDROID) || defined(XP_MACOSX)
      66                 : #    define HAVE_JEMALLOC_STATS 1
      67                 : #    include "jemalloc.h"
      68                 : #  elif defined(XP_LINUX)
      69                 : #    define HAVE_JEMALLOC_STATS 1
      70                 : #    include "jemalloc_types.h"
      71                 : // jemalloc is directly linked into firefox-bin; libxul doesn't link
      72                 : // with it.  So if we tried to use jemalloc_stats directly here, it
      73                 : // wouldn't be defined.  Instead, we don't include the jemalloc header
      74                 : // and weakly link against jemalloc_stats.
      75                 : extern "C" {
      76                 : extern void jemalloc_stats(jemalloc_stats_t* stats)
      77                 :   NS_VISIBILITY_DEFAULT __attribute__((weak));
      78                 : }
      79                 : #  endif  // XP_LINUX
      80                 : #endif  // MOZ_MEMORY
      81                 : 
      82                 : #if defined(XP_LINUX) || defined(XP_MACOSX) || defined(SOLARIS)
      83                 : 
      84                 : #include <sys/time.h>
      85                 : #include <sys/resource.h>
      86                 : 
      87               3 : static PRInt64 GetHardPageFaults()
      88                 : {
      89                 :   struct rusage usage;
      90               3 :   int err = getrusage(RUSAGE_SELF, &usage);
      91               3 :   if (err != 0) {
      92               0 :     return PRInt64(-1);
      93                 :   }
      94                 : 
      95               3 :   return usage.ru_majflt;
      96                 : }
      97                 : 
      98               0 : static PRInt64 GetSoftPageFaults()
      99                 : {
     100                 :   struct rusage usage;
     101               0 :   int err = getrusage(RUSAGE_SELF, &usage);
     102               0 :   if (err != 0) {
     103               0 :     return PRInt64(-1);
     104                 :   }
     105                 : 
     106               0 :   return usage.ru_minflt;
     107                 : }
     108                 : 
     109                 : #endif
     110                 : 
     111                 : #if defined(XP_LINUX)
     112                 : 
     113                 : #include <unistd.h>
     114               3 : static PRInt64 GetProcSelfStatmField(int n)
     115                 : {
     116                 :     // There are more than two fields, but we're only interested in the first
     117                 :     // two.
     118                 :     static const int MAX_FIELD = 2;
     119                 :     size_t fields[MAX_FIELD];
     120               3 :     NS_ASSERTION(n < MAX_FIELD, "bad field number");
     121               3 :     FILE *f = fopen("/proc/self/statm", "r");
     122               3 :     if (f) {
     123               3 :         int nread = fscanf(f, "%zu %zu", &fields[0], &fields[1]);
     124               3 :         fclose(f);
     125               3 :         return (PRInt64) ((nread == MAX_FIELD) ? fields[n]*getpagesize() : -1);
     126                 :     }
     127               0 :     return (PRInt64) -1;
     128                 : }
     129                 : 
     130               0 : static PRInt64 GetVsize()
     131                 : {
     132               0 :     return GetProcSelfStatmField(0);
     133                 : }
     134                 : 
     135               3 : static PRInt64 GetResident()
     136                 : {
     137               3 :     return GetProcSelfStatmField(1);
     138                 : }
     139                 : 
     140                 : #elif defined(SOLARIS)
     141                 : 
     142                 : #include <procfs.h>
     143                 : #include <fcntl.h>
     144                 : #include <unistd.h>
     145                 : 
     146                 : static void XMappingIter(PRInt64& Vsize, PRInt64& Resident)
     147                 : {
     148                 :     Vsize = -1;
     149                 :     Resident = -1;
     150                 :     int mapfd = open("/proc/self/xmap", O_RDONLY);
     151                 :     struct stat st;
     152                 :     prxmap_t *prmapp = NULL;
     153                 :     if (mapfd >= 0) {
     154                 :         if (!fstat(mapfd, &st)) {
     155                 :             int nmap = st.st_size / sizeof(prxmap_t);
     156                 :             while (1) {
     157                 :                 // stat(2) on /proc/<pid>/xmap returns an incorrect value,
     158                 :                 // prior to the release of Solaris 11.
     159                 :                 // Here is a workaround for it.
     160                 :                 nmap *= 2;
     161                 :                 prmapp = (prxmap_t*)malloc((nmap + 1) * sizeof(prxmap_t));
     162                 :                 if (!prmapp) {
     163                 :                     // out of memory
     164                 :                     break;
     165                 :                 }
     166                 :                 int n = pread(mapfd, prmapp, (nmap + 1) * sizeof(prxmap_t), 0);
     167                 :                 if (n < 0) {
     168                 :                     break;
     169                 :                 }
     170                 :                 if (nmap >= n / sizeof (prxmap_t)) {
     171                 :                     Vsize = 0;
     172                 :                     Resident = 0;
     173                 :                     for (int i = 0; i < n / sizeof (prxmap_t); i++) {
     174                 :                         Vsize += prmapp[i].pr_size;
     175                 :                         Resident += prmapp[i].pr_rss * prmapp[i].pr_pagesize;
     176                 :                     }
     177                 :                     break;
     178                 :                 }
     179                 :                 free(prmapp);
     180                 :             }
     181                 :             free(prmapp);
     182                 :         }
     183                 :         close(mapfd);
     184                 :     }
     185                 : }
     186                 : 
     187                 : static PRInt64 GetVsize()
     188                 : {
     189                 :     PRInt64 Vsize, Resident;
     190                 :     XMappingIter(Vsize, Resident);
     191                 :     return Vsize;
     192                 : }
     193                 : 
     194                 : static PRInt64 GetResident()
     195                 : {
     196                 :     PRInt64 Vsize, Resident;
     197                 :     XMappingIter(Vsize, Resident);
     198                 :     return Resident;
     199                 : }
     200                 : 
     201                 : #elif defined(XP_MACOSX)
     202                 : 
     203                 : #include <mach/mach_init.h>
     204                 : #include <mach/task.h>
     205                 : 
     206                 : static bool GetTaskBasicInfo(struct task_basic_info *ti)
     207                 : {
     208                 :     mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
     209                 :     kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO,
     210                 :                                  (task_info_t)ti, &count);
     211                 :     return kr == KERN_SUCCESS;
     212                 : }
     213                 : 
     214                 : // The VSIZE figure on Mac includes huge amounts of shared memory and is always
     215                 : // absurdly high, eg. 2GB+ even at start-up.  But both 'top' and 'ps' report
     216                 : // it, so we might as well too.
     217                 : static PRInt64 GetVsize()
     218                 : {
     219                 :     task_basic_info ti;
     220                 :     return (PRInt64) (GetTaskBasicInfo(&ti) ? ti.virtual_size : -1);
     221                 : }
     222                 : 
     223                 : static PRInt64 GetResident()
     224                 : {
     225                 : #ifdef HAVE_JEMALLOC_STATS
     226                 :     // If we're using jemalloc on Mac, we need to instruct jemalloc to purge
     227                 :     // the pages it has madvise(MADV_FREE)'d before we read our RSS.  The OS
     228                 :     // will take away MADV_FREE'd pages when there's memory pressure, so they
     229                 :     // shouldn't count against our RSS.
     230                 :     //
     231                 :     // Purging these pages shouldn't take more than 10ms or so, but we want to
     232                 :     // keep an eye on it since GetResident() is called on each Telemetry ping.
     233                 :     {
     234                 :       Telemetry::AutoTimer<Telemetry::MEMORY_FREE_PURGED_PAGES_MS> timer;
     235                 :       jemalloc_purge_freed_pages();
     236                 :     }
     237                 : #endif
     238                 : 
     239                 :     task_basic_info ti;
     240                 :     return (PRInt64) (GetTaskBasicInfo(&ti) ? ti.resident_size : -1);
     241                 : }
     242                 : 
     243                 : #elif defined(XP_WIN)
     244                 : 
     245                 : #include <windows.h>
     246                 : #include <psapi.h>
     247                 : 
     248                 : static PRInt64 GetVsize()
     249                 : {
     250                 :   MEMORYSTATUSEX s;
     251                 :   s.dwLength = sizeof(s);
     252                 : 
     253                 :   bool success = GlobalMemoryStatusEx(&s);
     254                 :   if (!success)
     255                 :     return -1;
     256                 : 
     257                 :   return s.ullTotalVirtual - s.ullAvailVirtual;
     258                 : }
     259                 : 
     260                 : static PRInt64 GetPrivate()
     261                 : {
     262                 :     PROCESS_MEMORY_COUNTERS_EX pmcex;
     263                 :     pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
     264                 : 
     265                 :     if (!GetProcessMemoryInfo(GetCurrentProcess(),
     266                 :                               (PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex)))
     267                 :     return (PRInt64) -1;
     268                 : 
     269                 :     return pmcex.PrivateUsage;
     270                 : }
     271                 : 
     272                 : NS_MEMORY_REPORTER_IMPLEMENT(Private,
     273                 :     "private",
     274                 :     KIND_OTHER,
     275                 :     UNITS_BYTES,
     276                 :     GetPrivate,
     277                 :     "Memory that cannot be shared with other processes, including memory that "
     278                 :     "is committed and marked MEM_PRIVATE, data that is not mapped, and "
     279                 :     "executable pages that have been written to.")
     280                 : 
     281                 : static PRInt64 GetResident()
     282                 : {
     283                 :   PROCESS_MEMORY_COUNTERS pmc;
     284                 :   pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
     285                 : 
     286                 :   if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
     287                 :       return (PRInt64) -1;
     288                 : 
     289                 :   return pmc.WorkingSetSize;
     290                 : }
     291                 : 
     292                 : #else
     293                 : 
     294                 : static PRInt64 GetResident()
     295                 : {
     296                 :     return (PRInt64) -1;
     297                 : }
     298                 : 
     299                 : #endif
     300                 : 
     301                 : #if defined(XP_LINUX) || defined(XP_MACOSX) || defined(XP_WIN) || defined(SOLARIS)
     302            1428 : NS_MEMORY_REPORTER_IMPLEMENT(Vsize,
     303                 :     "vsize",
     304                 :     KIND_OTHER,
     305                 :     UNITS_BYTES,
     306                 :     GetVsize,
     307                 :     "Memory mapped by the process, including code and data segments, the "
     308                 :     "heap, thread stacks, memory explicitly mapped by the process via mmap "
     309                 :     "and similar operations, and memory shared with other processes. "
     310                 :     "This is the vsize figure as reported by 'top' and 'ps'.  This figure is of "
     311                 :     "limited use on Mac, where processes share huge amounts of memory with one "
     312                 :     "another.  But even on other operating systems, 'resident' is a much better "
     313            4323 :     "measure of the memory resources used by the process.")
     314                 : #endif
     315                 : 
     316                 : #if defined(XP_LINUX) || defined(XP_MACOSX) || defined(SOLARIS)
     317            1428 : NS_MEMORY_REPORTER_IMPLEMENT(PageFaultsSoft,
     318                 :     "page-faults-soft",
     319                 :     KIND_OTHER,
     320                 :     UNITS_COUNT_CUMULATIVE,
     321                 :     GetSoftPageFaults,
     322                 :     "The number of soft page faults (also known as \"minor page faults\") that "
     323                 :     "have occurred since the process started.  A soft page fault occurs when the "
     324                 :     "process tries to access a page which is present in physical memory but is "
     325                 :     "not mapped into the process's address space.  For instance, a process might "
     326                 :     "observe soft page faults when it loads a shared library which is already "
     327                 :     "present in physical memory. A process may experience many thousands of soft "
     328                 :     "page faults even when the machine has plenty of available physical memory, "
     329                 :     "and because the OS services a soft page fault without accessing the disk, "
     330            4323 :     "they impact performance much less than hard page faults.")
     331                 : 
     332            1450 : NS_MEMORY_REPORTER_IMPLEMENT(PageFaultsHard,
     333                 :     "page-faults-hard",
     334                 :     KIND_OTHER,
     335                 :     UNITS_COUNT_CUMULATIVE,
     336                 :     GetHardPageFaults,
     337                 :     "The number of hard page faults (also known as \"major page faults\") that "
     338                 :     "have occurred since the process started.  A hard page fault occurs when a "
     339                 :     "process tries to access a page which is not present in physical memory. "
     340                 :     "The operating system must access the disk in order to fulfill a hard page "
     341                 :     "fault. When memory is plentiful, you should see very few hard page faults. "
     342                 :     "But if the process tries to use more memory than your machine has "
     343                 :     "available, you may see many thousands of hard page faults. Because "
     344                 :     "accessing the disk is up to a million times slower than accessing RAM, "
     345                 :     "the program may run very slowly when it is experiencing more than 100 or "
     346            4323 :     "so hard page faults a second.")
     347                 : #endif
     348                 : 
     349            1437 : NS_MEMORY_REPORTER_IMPLEMENT(Explicit,
     350                 :     "explicit",
     351                 :     KIND_OTHER,
     352                 :     UNITS_BYTES,
     353                 :     GetExplicit,
     354                 :     "This is the same measurement as the root of the 'explicit' tree.  "
     355                 :     "However, it is measured at a different time and so gives slightly "
     356            4323 :     "different results.")
     357                 : 
     358            1437 : NS_MEMORY_REPORTER_IMPLEMENT(Resident,
     359                 :     "resident",
     360                 :     KIND_OTHER,
     361                 :     UNITS_BYTES,
     362                 :     GetResident,
     363                 :     "Memory mapped by the process that is present in physical memory, "
     364                 :     "also known as the resident set size (RSS).  This is the best single "
     365                 :     "figure to use when considering the memory resources used by the process, "
     366                 :     "but it depends both on other processes being run and details of the OS "
     367                 :     "kernel and so is best used for comparing the memory usage of a single "
     368            4323 :     "process at different points in time.")
     369                 : 
     370                 : /**
     371                 :  ** memory reporter implementation for jemalloc and OSX malloc,
     372                 :  ** to obtain info on total memory in use (that we know about,
     373                 :  ** at least -- on OSX, there are sometimes other zones in use).
     374                 :  **/
     375                 : 
     376                 : #if HAVE_JEMALLOC_STATS
     377                 : 
     378               0 : static PRInt64 GetHeapUnallocated()
     379                 : {
     380                 :     jemalloc_stats_t stats;
     381               0 :     jemalloc_stats(&stats);
     382               0 :     return (PRInt64) stats.mapped - stats.allocated;
     383                 : }
     384                 : 
     385               6 : static PRInt64 GetHeapAllocated()
     386                 : {
     387                 :     jemalloc_stats_t stats;
     388               6 :     jemalloc_stats(&stats);
     389               6 :     return (PRInt64) stats.allocated;
     390                 : }
     391                 : 
     392               0 : static PRInt64 GetHeapCommitted()
     393                 : {
     394                 :     jemalloc_stats_t stats;
     395               0 :     jemalloc_stats(&stats);
     396               0 :     return (PRInt64) stats.committed;
     397                 : }
     398                 : 
     399               0 : static PRInt64 GetHeapCommittedFragmentation()
     400                 : {
     401                 :     jemalloc_stats_t stats;
     402               0 :     jemalloc_stats(&stats);
     403               0 :     return (PRInt64) 10000 * (1 - stats.allocated / (double)stats.committed);
     404                 : }
     405                 : 
     406               0 : static PRInt64 GetHeapDirty()
     407                 : {
     408                 :     jemalloc_stats_t stats;
     409               0 :     jemalloc_stats(&stats);
     410               0 :     return (PRInt64) stats.dirty;
     411                 : }
     412                 : 
     413            1428 : NS_MEMORY_REPORTER_IMPLEMENT(HeapCommitted,
     414                 :     "heap-committed",
     415                 :     KIND_OTHER,
     416                 :     UNITS_BYTES,
     417                 :     GetHeapCommitted,
     418                 :     "Memory mapped by the heap allocator that is committed, i.e. in physical "
     419                 :     "memory or paged to disk.  When heap-committed is larger than "
     420                 :     "heap-allocated, the difference between the two values is likely due to "
     421                 :     "external fragmentation; that is, the allocator allocated a large block of "
     422                 :     "memory and is unable to decommit it because a small part of that block is "
     423            4323 :     "currently in use.")
     424                 : 
     425            1428 : NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedFragmentation,
     426                 :     "heap-committed-fragmentation",
     427                 :     KIND_OTHER,
     428                 :     UNITS_PERCENTAGE,
     429                 :     GetHeapCommittedFragmentation,
     430                 :     "Fraction of committed bytes which do not correspond to an active "
     431                 :     "allocation; i.e., 1 - (heap-allocated / heap-committed).  Although the "
     432                 :     "allocator will waste some space under any circumstances, a large value here "
     433            4323 :     "may indicate that the heap is highly fragmented.")
     434                 : 
     435            1428 : NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty,
     436                 :     "heap-dirty",
     437                 :     KIND_OTHER,
     438                 :     UNITS_BYTES,
     439                 :     GetHeapDirty,
     440                 :     "Memory which the allocator could return to the operating system, but "
     441                 :     "hasn't.  The allocator keeps this memory around as an optimization, so it "
     442                 :     "doesn't have to ask the OS the next time it needs to fulfill a request. "
     443            4323 :     "This value is typically not larger than a few megabytes.")
     444                 : 
     445                 : #elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
     446                 : #include <malloc/malloc.h>
     447                 : 
     448                 : static PRInt64 GetHeapUnallocated()
     449                 : {
     450                 :     struct mstats stats = mstats();
     451                 :     return (PRInt64) (stats.bytes_total - stats.bytes_used);
     452                 : }
     453                 : 
     454                 : static PRInt64 GetHeapAllocated()
     455                 : {
     456                 :     struct mstats stats = mstats();
     457                 :     return (PRInt64) stats.bytes_used;
     458                 : }
     459                 : 
     460                 : static PRInt64 GetHeapZone0Committed()
     461                 : {
     462                 : #ifdef MOZ_DMD
     463                 :     // malloc_zone_statistics() crashes when run under DMD because Valgrind
     464                 :     // doesn't intercept it.  This measurement isn't important for DMD, so
     465                 :     // don't even try.
     466                 :     return (PRInt64) -1;
     467                 : #else
     468                 :     malloc_statistics_t stats;
     469                 :     malloc_zone_statistics(malloc_default_zone(), &stats);
     470                 :     return stats.size_in_use;
     471                 : #endif
     472                 : }
     473                 : 
     474                 : static PRInt64 GetHeapZone0Used()
     475                 : {
     476                 : #ifdef MOZ_DMD
     477                 :     // See comment in GetHeapZone0Committed above.
     478                 :     return (PRInt64) -1;
     479                 : #else
     480                 :     malloc_statistics_t stats;
     481                 :     malloc_zone_statistics(malloc_default_zone(), &stats);
     482                 :     return stats.size_allocated;
     483                 : #endif
     484                 : }
     485                 : 
     486                 : NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Committed,
     487                 :     "heap-zone0-committed",
     488                 :     KIND_OTHER,
     489                 :     UNITS_BYTES,
     490                 :     GetHeapZone0Committed,
     491                 :     "Memory mapped by the heap allocator that is committed in the default "
     492                 :     "zone.")
     493                 : 
     494                 : NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Used,
     495                 :     "heap-zone0-used",
     496                 :     KIND_OTHER,
     497                 :     UNITS_BYTES,
     498                 :     GetHeapZone0Used,
     499                 :     "Memory mapped by the heap allocator in the default zone that is "
     500                 :     "allocated to the application.")
     501                 : 
     502                 : #else
     503                 : 
     504                 : static PRInt64 GetHeapAllocated()
     505                 : {
     506                 :     return (PRInt64) -1;
     507                 : }
     508                 : 
     509                 : static PRInt64 GetHeapUnallocated()
     510                 : {
     511                 :   return (PRInt64) -1;
     512                 : }
     513                 : 
     514                 : #endif
     515                 : 
     516            1428 : NS_MEMORY_REPORTER_IMPLEMENT(HeapUnallocated,
     517                 :     "heap-unallocated",
     518                 :     KIND_OTHER,
     519                 :     UNITS_BYTES,
     520                 :     GetHeapUnallocated,
     521                 :     "Memory mapped by the heap allocator that is not part of an active "
     522                 :     "allocation. Much of this memory may be uncommitted -- that is, it does not "
     523            4323 :     "take up space in physical memory or in the swap file.")
     524                 : 
     525            1440 : NS_MEMORY_REPORTER_IMPLEMENT(HeapAllocated,
     526                 :     "heap-allocated",
     527                 :     KIND_OTHER,
     528                 :     UNITS_BYTES,
     529                 :     GetHeapAllocated,
     530                 :     "Memory mapped by the heap allocator that is currently allocated to the "
     531                 :     "application.  This may exceed the amount of memory requested by the "
     532                 :     "application because the allocator regularly rounds up request sizes. (The "
     533            4323 :     "exact amount requested is not recorded.)")
     534                 : 
     535               0 : NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(AtomTableMallocSizeOf, "atom-table")
     536                 : 
     537               0 : static PRInt64 GetAtomTableSize() {
     538               0 :   return NS_SizeOfAtomTableIncludingThis(AtomTableMallocSizeOf);
     539                 : }
     540                 : 
     541                 : // Why is this here?  At first glance, you'd think it could be defined and
     542                 : // registered with nsMemoryReporterManager entirely within nsAtomTable.cpp.
     543                 : // However, the obvious time to register it is when the table is initialized,
     544                 : // and that happens before XPCOM components are initialized, which means the
     545                 : // NS_RegisterMemoryReporter call fails.  So instead we do it here.
     546            1428 : NS_MEMORY_REPORTER_IMPLEMENT(AtomTable,
     547                 :     "explicit/atom-table",
     548                 :     KIND_HEAP,
     549                 :     UNITS_BYTES,
     550                 :     GetAtomTableSize,
     551            4323 :     "Memory used by the atoms table.")
     552                 : 
     553                 : /**
     554                 :  ** nsMemoryReporterManager implementation
     555                 :  **/
     556                 : 
     557          152571 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsMemoryReporterManager, nsIMemoryReporterManager)
     558                 : 
     559                 : NS_IMETHODIMP
     560            1419 : nsMemoryReporterManager::Init()
     561                 : {
     562                 : #if HAVE_JEMALLOC_STATS && defined(XP_LINUX)
     563            1419 :     if (!jemalloc_stats)
     564               0 :         return NS_ERROR_FAILURE;
     565                 : #endif
     566                 : 
     567                 : #define REGISTER(_x)  RegisterReporter(new NS_MEMORY_REPORTER_NAME(_x))
     568                 : 
     569            2838 :     REGISTER(HeapAllocated);
     570            2838 :     REGISTER(HeapUnallocated);
     571            2838 :     REGISTER(Explicit);
     572            2838 :     REGISTER(Resident);
     573                 : 
     574                 : #if defined(XP_LINUX) || defined(XP_MACOSX) || defined(XP_WIN) || defined(SOLARIS)
     575            2838 :     REGISTER(Vsize);
     576                 : #endif
     577                 : 
     578                 : #if defined(XP_LINUX) || defined(XP_MACOSX) || defined(SOLARIS)
     579            2838 :     REGISTER(PageFaultsSoft);
     580            2838 :     REGISTER(PageFaultsHard);
     581                 : #endif
     582                 : 
     583                 : #if defined(XP_WIN)
     584                 :     REGISTER(Private);
     585                 : #endif
     586                 : 
     587                 : #if defined(HAVE_JEMALLOC_STATS)
     588            2838 :     REGISTER(HeapCommitted);
     589            2838 :     REGISTER(HeapCommittedFragmentation);
     590            2838 :     REGISTER(HeapDirty);
     591                 : #elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
     592                 :     REGISTER(HeapZone0Committed);
     593                 :     REGISTER(HeapZone0Used);
     594                 : #endif
     595                 : 
     596            2838 :     REGISTER(AtomTable);
     597                 : 
     598            1419 :     return NS_OK;
     599                 : }
     600                 : 
     601            1419 : nsMemoryReporterManager::nsMemoryReporterManager()
     602            1419 :   : mMutex("nsMemoryReporterManager::mMutex")
     603                 : {
     604            1419 : }
     605                 : 
     606            2838 : nsMemoryReporterManager::~nsMemoryReporterManager()
     607                 : {
     608            5676 : }
     609                 : 
     610                 : NS_IMETHODIMP
     611               6 : nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator **result)
     612                 : {
     613                 :     nsresult rv;
     614              12 :     mozilla::MutexAutoLock autoLock(mMutex);
     615               6 :     rv = NS_NewArrayEnumerator(result, mReporters);
     616               6 :     return rv;
     617                 : }
     618                 : 
     619                 : NS_IMETHODIMP
     620               6 : nsMemoryReporterManager::EnumerateMultiReporters(nsISimpleEnumerator **result)
     621                 : {
     622                 :     nsresult rv;
     623              12 :     mozilla::MutexAutoLock autoLock(mMutex);
     624               6 :     rv = NS_NewArrayEnumerator(result, mMultiReporters);
     625               6 :     return rv;
     626                 : }
     627                 : 
     628                 : NS_IMETHODIMP
     629           25146 : nsMemoryReporterManager::RegisterReporter(nsIMemoryReporter *reporter)
     630                 : {
     631           50292 :     mozilla::MutexAutoLock autoLock(mMutex);
     632           25146 :     if (mReporters.IndexOf(reporter) != -1)
     633               0 :         return NS_ERROR_FAILURE;
     634                 : 
     635           25146 :     mReporters.AppendObject(reporter);
     636           25146 :     return NS_OK;
     637                 : }
     638                 : 
     639                 : NS_IMETHODIMP
     640            6527 : nsMemoryReporterManager::RegisterMultiReporter(nsIMemoryMultiReporter *reporter)
     641                 : {
     642           13054 :     mozilla::MutexAutoLock autoLock(mMutex);
     643            6527 :     if (mMultiReporters.IndexOf(reporter) != -1)
     644               0 :         return NS_ERROR_FAILURE;
     645                 : 
     646            6527 :     mMultiReporters.AppendObject(reporter);
     647            6527 :     return NS_OK;
     648                 : }
     649                 : 
     650                 : NS_IMETHODIMP
     651           13305 : nsMemoryReporterManager::UnregisterReporter(nsIMemoryReporter *reporter)
     652                 : {
     653           26610 :     mozilla::MutexAutoLock autoLock(mMutex);
     654           13305 :     if (!mReporters.RemoveObject(reporter))
     655           11835 :         return NS_ERROR_FAILURE;
     656                 : 
     657            1470 :     return NS_OK;
     658                 : }
     659                 : 
     660                 : NS_IMETHODIMP
     661               0 : nsMemoryReporterManager::UnregisterMultiReporter(nsIMemoryMultiReporter *reporter)
     662                 : {
     663               0 :     mozilla::MutexAutoLock autoLock(mMutex);
     664               0 :     if (!mMultiReporters.RemoveObject(reporter))
     665               0 :         return NS_ERROR_FAILURE;
     666                 : 
     667               0 :     return NS_OK;
     668                 : }
     669                 : 
     670                 : NS_IMETHODIMP
     671               0 : nsMemoryReporterManager::GetResident(PRInt64 *aResident)
     672                 : {
     673               0 :     *aResident = ::GetResident();
     674               0 :     return NS_OK;
     675                 : }
     676                 : 
     677                 : struct MemoryReport {
     678                 :     MemoryReport(const nsACString &path, PRInt64 amount) 
     679                 :     : path(path), amount(amount)
     680                 :     {
     681                 :         MOZ_COUNT_CTOR(MemoryReport);
     682                 :     }
     683                 :     MemoryReport(const MemoryReport& rhs)
     684                 :     : path(rhs.path), amount(rhs.amount)
     685                 :     {
     686                 :         MOZ_COUNT_CTOR(MemoryReport);
     687                 :     }
     688                 :     ~MemoryReport() 
     689                 :     {
     690                 :         MOZ_COUNT_DTOR(MemoryReport);
     691                 :     }
     692                 :     const nsCString path;
     693                 :     PRInt64 amount;
     694                 : };
     695                 : 
     696                 : #ifdef DEBUG
     697                 : // This is just a wrapper for PRInt64 that implements nsISupports, so it can be
     698                 : // passed to nsIMemoryMultiReporter::CollectReports.
     699                 : class PRInt64Wrapper : public nsISupports {
     700                 : public:
     701                 :     NS_DECL_ISUPPORTS
     702               3 :     PRInt64Wrapper() : mValue(0) { }
     703                 :     PRInt64 mValue;
     704                 : };
     705               9 : NS_IMPL_ISUPPORTS0(PRInt64Wrapper)
     706                 : 
     707                 : class ExplicitNonHeapCountingCallback : public nsIMemoryMultiReporterCallback
     708               3 : {
     709                 : public:
     710                 :     NS_DECL_ISUPPORTS
     711                 : 
     712            1703 :     NS_IMETHOD Callback(const nsACString &aProcess, const nsACString &aPath,
     713                 :                         PRInt32 aKind, PRInt32 aUnits, PRInt64 aAmount,
     714                 :                         const nsACString &aDescription,
     715                 :                         nsISupports *aWrappedExplicitNonHeap)
     716                 :     {
     717            6476 :         if (aKind == nsIMemoryReporter::KIND_NONHEAP &&
     718            4773 :             PromiseFlatCString(aPath).Find("explicit") == 0 &&
     719                 :             aAmount != PRInt64(-1))
     720                 :         {
     721                 :             PRInt64Wrapper *wrappedPRInt64 =
     722              96 :                 static_cast<PRInt64Wrapper *>(aWrappedExplicitNonHeap);
     723              96 :             wrappedPRInt64->mValue += aAmount;
     724                 :         }
     725            1703 :         return NS_OK;
     726                 :     }
     727                 : };
     728               9 : NS_IMPL_ISUPPORTS1(
     729                 :   ExplicitNonHeapCountingCallback
     730                 : , nsIMemoryMultiReporterCallback
     731                 : )
     732                 : #endif
     733                 : 
     734                 : NS_IMETHODIMP
     735               3 : nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
     736                 : {
     737               3 :     NS_ENSURE_ARG_POINTER(aExplicit);
     738               3 :     *aExplicit = 0;
     739                 : 
     740                 :     nsresult rv;
     741                 :     bool more;
     742                 : 
     743                 :     // Get "heap-allocated" and all the KIND_NONHEAP measurements from normal
     744                 :     // (i.e. non-multi) "explicit" reporters.
     745               3 :     PRInt64 heapAllocated = PRInt64(-1);
     746               3 :     PRInt64 explicitNonHeapNormalSize = 0;
     747               6 :     nsCOMPtr<nsISimpleEnumerator> e;
     748               3 :     EnumerateReporters(getter_AddRefs(e));
     749              63 :     while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
     750             114 :         nsCOMPtr<nsIMemoryReporter> r;
     751              57 :         e->GetNext(getter_AddRefs(r));
     752                 : 
     753                 :         PRInt32 kind;
     754              57 :         rv = r->GetKind(&kind);
     755              57 :         NS_ENSURE_SUCCESS(rv, rv);
     756                 : 
     757             114 :         nsCString path;
     758              57 :         rv = r->GetPath(path);
     759              57 :         NS_ENSURE_SUCCESS(rv, rv);
     760                 : 
     761                 :         // We're only interested in NONHEAP explicit reporters and
     762                 :         // the 'heap-allocated' reporter.
     763              60 :         if (kind == nsIMemoryReporter::KIND_NONHEAP &&
     764               3 :             path.Find("explicit") == 0)
     765                 :         {
     766                 :             PRInt64 amount;
     767               3 :             rv = r->GetAmount(&amount);
     768               3 :             NS_ENSURE_SUCCESS(rv, rv);
     769                 : 
     770                 :             // Just skip any NONHEAP reporters that fail, because
     771                 :             // "heap-allocated" is the most important one.
     772               3 :             if (amount != PRInt64(-1)) {
     773               3 :                 explicitNonHeapNormalSize += amount;
     774                 :             }
     775              54 :         } else if (path.Equals("heap-allocated")) {
     776               3 :             rv = r->GetAmount(&heapAllocated);
     777               3 :             NS_ENSURE_SUCCESS(rv, rv);
     778                 : 
     779                 :             // If we don't have "heap-allocated", give up, because the result would be
     780                 :             // horribly inaccurate.
     781               3 :             if (heapAllocated == PRInt64(-1)) {
     782               0 :                 *aExplicit = PRInt64(-1);
     783               0 :                 return NS_OK;
     784                 :             }
     785                 :         }
     786                 :     }
     787                 : 
     788                 :     // For each multi-reporter we could call CollectReports and filter out the
     789                 :     // non-explicit, non-NONHEAP measurements.  But that's lots of wasted work,
     790                 :     // so we instead use GetExplicitNonHeap() which exists purely for this
     791                 :     // purpose.
     792                 :     //
     793                 :     // (Actually, in debug builds we also do it the slow way and compare the
     794                 :     // result to the result obtained from GetExplicitNonHeap().  This
     795                 :     // guarantees the two measurement paths are equivalent.  This is wise
     796                 :     // because it's easy for memory reporters to have bugs.)
     797                 : 
     798               3 :     PRInt64 explicitNonHeapMultiSize = 0;
     799               6 :     nsCOMPtr<nsISimpleEnumerator> e2;
     800               3 :     EnumerateMultiReporters(getter_AddRefs(e2));
     801              21 :     while (NS_SUCCEEDED(e2->HasMoreElements(&more)) && more) {
     802              30 :       nsCOMPtr<nsIMemoryMultiReporter> r;
     803              15 :       e2->GetNext(getter_AddRefs(r));
     804                 :       PRInt64 n;
     805              15 :       rv = r->GetExplicitNonHeap(&n);
     806              15 :       NS_ENSURE_SUCCESS(rv, rv);
     807              30 :       explicitNonHeapMultiSize += n;
     808                 :     }
     809                 : 
     810                 : #ifdef DEBUG
     811                 :     nsRefPtr<ExplicitNonHeapCountingCallback> cb =
     812               6 :       new ExplicitNonHeapCountingCallback();
     813                 :     nsRefPtr<PRInt64Wrapper> wrappedExplicitNonHeapMultiSize2 =
     814               6 :       new PRInt64Wrapper();
     815               6 :     nsCOMPtr<nsISimpleEnumerator> e3;
     816               3 :     EnumerateMultiReporters(getter_AddRefs(e3));
     817              21 :     while (NS_SUCCEEDED(e3->HasMoreElements(&more)) && more) {
     818              30 :       nsCOMPtr<nsIMemoryMultiReporter> r;
     819              15 :       e3->GetNext(getter_AddRefs(r));
     820              15 :       r->CollectReports(cb, wrappedExplicitNonHeapMultiSize2);
     821                 :     }
     822               3 :     PRInt64 explicitNonHeapMultiSize2 = wrappedExplicitNonHeapMultiSize2->mValue;
     823                 : 
     824                 :     // Check the two measurements give the same result.  This was an
     825                 :     // NS_ASSERTION but they occasionally don't match due to races (bug
     826                 :     // 728990).
     827               3 :     if (explicitNonHeapMultiSize != explicitNonHeapMultiSize2) {
     828                 :         char *msg = PR_smprintf("The two measurements of 'explicit' memory "
     829                 :                                 "usage don't match (%lld vs %lld)",
     830                 :                                 explicitNonHeapMultiSize,
     831               0 :                                 explicitNonHeapMultiSize2);
     832               0 :         NS_WARNING(msg);
     833               0 :         PR_smprintf_free(msg);
     834                 :     }
     835                 : #endif
     836                 : 
     837               3 :     *aExplicit = heapAllocated + explicitNonHeapNormalSize + explicitNonHeapMultiSize;
     838               3 :     return NS_OK;
     839                 : }
     840                 : 
     841                 : NS_IMETHODIMP
     842               0 : nsMemoryReporterManager::GetHasMozMallocUsableSize(bool *aHas)
     843                 : {
     844               0 :     void *p = malloc(16);
     845               0 :     if (!p) {
     846               0 :         return NS_ERROR_OUT_OF_MEMORY;
     847                 :     }
     848               0 :     size_t usable = moz_malloc_usable_size(p);
     849               0 :     free(p);
     850               0 :     *aHas = !!(usable > 0);
     851               0 :     return NS_OK;
     852                 : }
     853                 : 
     854               0 : NS_IMPL_ISUPPORTS1(nsMemoryReporter, nsIMemoryReporter)
     855                 : 
     856               0 : nsMemoryReporter::nsMemoryReporter(nsACString& process,
     857                 :                                    nsACString& path,
     858                 :                                    PRInt32 kind,
     859                 :                                    PRInt32 units,
     860                 :                                    PRInt64 amount,
     861                 :                                    nsACString& desc)
     862                 : : mProcess(process)
     863                 : , mPath(path)
     864                 : , mKind(kind)
     865                 : , mUnits(units)
     866                 : , mAmount(amount)
     867               0 : , mDesc(desc)
     868                 : {
     869               0 : }
     870                 : 
     871               0 : nsMemoryReporter::~nsMemoryReporter()
     872                 : {
     873               0 : }
     874                 : 
     875               0 : NS_IMETHODIMP nsMemoryReporter::GetProcess(nsACString &aProcess)
     876                 : {
     877               0 :     aProcess.Assign(mProcess);
     878               0 :     return NS_OK;
     879                 : }
     880                 : 
     881               0 : NS_IMETHODIMP nsMemoryReporter::GetPath(nsACString &aPath)
     882                 : {
     883               0 :     aPath.Assign(mPath);
     884               0 :     return NS_OK;
     885                 : }
     886                 : 
     887               0 : NS_IMETHODIMP nsMemoryReporter::GetKind(PRInt32 *aKind)
     888                 : {
     889               0 :     *aKind = mKind;
     890               0 :     return NS_OK;
     891                 : }
     892                 : 
     893               0 : NS_IMETHODIMP nsMemoryReporter::GetUnits(PRInt32 *aUnits)
     894                 : {
     895               0 :   *aUnits = mUnits;
     896               0 :   return NS_OK;
     897                 : }
     898                 : 
     899               0 : NS_IMETHODIMP nsMemoryReporter::GetAmount(PRInt64 *aAmount)
     900                 : {
     901               0 :     *aAmount = mAmount;
     902               0 :     return NS_OK;
     903                 : }
     904                 : 
     905               0 : NS_IMETHODIMP nsMemoryReporter::GetDescription(nsACString &aDescription)
     906                 : {
     907               0 :     aDescription.Assign(mDesc);
     908               0 :     return NS_OK;
     909                 : }
     910                 : 
     911                 : nsresult
     912            9537 : NS_RegisterMemoryReporter (nsIMemoryReporter *reporter)
     913                 : {
     914           19074 :     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
     915            9537 :     if (mgr == nsnull)
     916               0 :         return NS_ERROR_FAILURE;
     917            9537 :     return mgr->RegisterReporter(reporter);
     918                 : }
     919                 : 
     920                 : nsresult
     921            6527 : NS_RegisterMemoryMultiReporter (nsIMemoryMultiReporter *reporter)
     922                 : {
     923           13054 :     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
     924            6527 :     if (mgr == nsnull)
     925               0 :         return NS_ERROR_FAILURE;
     926            6527 :     return mgr->RegisterMultiReporter(reporter);
     927                 : }
     928                 : 
     929                 : nsresult
     930           14108 : NS_UnregisterMemoryReporter (nsIMemoryReporter *reporter)
     931                 : {
     932           28216 :     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
     933           14108 :     if (mgr == nsnull)
     934             803 :         return NS_ERROR_FAILURE;
     935           13305 :     return mgr->UnregisterReporter(reporter);
     936                 : }
     937                 : 
     938                 : nsresult
     939             794 : NS_UnregisterMemoryMultiReporter (nsIMemoryMultiReporter *reporter)
     940                 : {
     941            1588 :     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
     942             794 :     if (mgr == nsnull)
     943             794 :         return NS_ERROR_FAILURE;
     944               0 :     return mgr->UnregisterMultiReporter(reporter);
     945                 : }
     946                 : 
     947                 : namespace mozilla {
     948                 : 
     949                 : #ifdef MOZ_DMD
     950                 : 
     951                 : class NullMultiReporterCallback : public nsIMemoryMultiReporterCallback
     952                 : {
     953                 : public:
     954                 :     NS_DECL_ISUPPORTS
     955                 : 
     956                 :     NS_IMETHOD Callback(const nsACString &aProcess, const nsACString &aPath,
     957                 :                         PRInt32 aKind, PRInt32 aUnits, PRInt64 aAmount,
     958                 :                         const nsACString &aDescription,
     959                 :                         nsISupports *aData)
     960                 :     {
     961                 :         // Do nothing;  the reporter has already reported to DMD.
     962                 :         return NS_OK;
     963                 :     }
     964                 : };
     965                 : NS_IMPL_ISUPPORTS1(
     966                 :   NullMultiReporterCallback
     967                 : , nsIMemoryMultiReporterCallback
     968                 : )
     969                 : 
     970                 : void
     971                 : DMDCheckAndDump()
     972                 : {
     973                 :     nsCOMPtr<nsIMemoryReporterManager> mgr =
     974                 :         do_GetService("@mozilla.org/memory-reporter-manager;1");
     975                 : 
     976                 :     // Do vanilla reporters.
     977                 :     nsCOMPtr<nsISimpleEnumerator> e;
     978                 :     mgr->EnumerateReporters(getter_AddRefs(e));
     979                 :     bool more;
     980                 :     while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
     981                 :         nsCOMPtr<nsIMemoryReporter> r;
     982                 :         e->GetNext(getter_AddRefs(r));
     983                 : 
     984                 :         // Just getting the amount is enough for the reporter to report to DMD.
     985                 :         PRInt64 amount;
     986                 :         (void)r->GetAmount(&amount);
     987                 :     }
     988                 : 
     989                 :     // Do multi-reporters.
     990                 :     nsCOMPtr<nsISimpleEnumerator> e2;
     991                 :     mgr->EnumerateMultiReporters(getter_AddRefs(e2));
     992                 :     nsRefPtr<NullMultiReporterCallback> cb = new NullMultiReporterCallback();
     993                 :     while (NS_SUCCEEDED(e2->HasMoreElements(&more)) && more) {
     994                 :       nsCOMPtr<nsIMemoryMultiReporter> r;
     995                 :       e2->GetNext(getter_AddRefs(r));
     996                 :       r->CollectReports(cb, nsnull);
     997                 :     }
     998                 : 
     999                 :     VALGRIND_DMD_CHECK_REPORTING;
    1000                 : }
    1001                 : 
    1002                 : #endif  /* defined(MOZ_DMD) */
    1003                 : 
    1004                 : }

Generated by: LCOV version 1.7