Bug 789975 - Disable purging of MADV_FREE'd pages on MacOS when collecting RSS from Telemetry. r=njn, a=akeybl
authorJustin Lebar <justin.lebar@gmail.com>
Tue, 15 Jan 2013 09:14:36 -0500
changeset 127251 c635335afd9f57366202214a7628fd7b853dfdc5
parent 127250 6ee29f8c87d7ace927c827bb5042dc76452c52ea
child 127252 6624fe215f6d15e7784e9aa0d52df7ee37eb67a0
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn, akeybl
bugs789975
milestone20.0a2
Bug 789975 - Disable purging of MADV_FREE'd pages on MacOS when collecting RSS from Telemetry. r=njn, a=akeybl
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/telemetry/TelemetryPing.js
xpcom/base/nsMemoryReporterManager.cpp
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -715,22 +715,33 @@ function getTreesByProcess(aProcessMemor
                            aDegeneratesByProcess, aHeapTotalByProcess,
                            aForceShowSmaps)
 {
   // Ignore the "smaps" multi-reporter in non-verbose mode unless we're reading
   // from a file or the clipboard, and ignore the "compartments" and
   // "ghost-windows" multi-reporters all the time.  (Note that reports from
   // these multi-reporters can reach here as single reports if they were in the
   // child process.)
+  //
+  // Also ignore the resident-fast reporter; we use the vanilla resident
+  // reporter because it's more important that we get accurate results than
+  // that we avoid the (small) possibility of a long pause when loading
+  // about:memory.
+  //
+  // We don't show both resident and resident-fast because running the resident
+  // reporter can purge pages on MacOS, which affects the results of the
+  // resident-fast reporter.  We don't want about:memory's results to be
+  // affected by the order of memory reporter execution.
 
   function ignoreSingle(aUnsafePath)
   {
     return (isSmapsPath(aUnsafePath) && !gVerbose && !aForceShowSmaps) ||
            aUnsafePath.startsWith("compartments/") ||
-           aUnsafePath.startsWith("ghost-windows/");
+           aUnsafePath.startsWith("ghost-windows/") ||
+           aUnsafePath == "resident-fast";
   }
 
   function ignoreMulti(aMRName)
   {
     return (aMRName === "smaps" && !gVerbose && !aForceShowSmaps) ||
             aMRName === "compartments" ||
             aMRName === "ghost-windows";
   }
--- a/toolkit/components/telemetry/TelemetryPing.js
+++ b/toolkit/components/telemetry/TelemetryPing.js
@@ -51,17 +51,17 @@ const RWX_OWNER = 0700;
 //   * MEMORY_JS_GC_HEAP, and
 //   * MEMORY_JS_COMPARTMENTS_SYSTEM.
 //
 const MEM_HISTOGRAMS = {
   "js-gc-heap": "MEMORY_JS_GC_HEAP",
   "js-compartments/system": "MEMORY_JS_COMPARTMENTS_SYSTEM",
   "js-compartments/user": "MEMORY_JS_COMPARTMENTS_USER",
   "explicit": "MEMORY_EXPLICIT",
-  "resident": "MEMORY_RESIDENT",
+  "resident-fast": "MEMORY_RESIDENT",
   "vsize": "MEMORY_VSIZE",
   "storage-sqlite": "MEMORY_STORAGE_SQLITE",
   "images-content-used-uncompressed":
     "MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED",
   "heap-allocated": "MEMORY_HEAP_ALLOCATED",
   "heap-committed-unused": "MEMORY_HEAP_COMMITTED_UNUSED",
   "heap-committed-unused-ratio": "MEMORY_HEAP_COMMITTED_UNUSED_RATIO",
   "page-faults-hard": "PAGE_FAULTS_HARD",
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -92,16 +92,21 @@ static nsresult GetVsize(int64_t *n)
     return GetProcSelfStatmField(0, n);
 }
 
 static nsresult GetResident(int64_t *n)
 {
     return GetProcSelfStatmField(1, n);
 }
 
+static nsresult GetResidentFast(int64_t *n)
+{
+    return GetResident(n);
+}
+
 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
     || defined(__NetBSD__) || defined(__OpenBSD__)
 
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #if defined(__DragonFly__) || defined(__FreeBSD__)
 #include <sys/user.h>
 #endif
@@ -167,16 +172,21 @@ static nsresult GetResident(int64_t *n)
     KINFO_PROC proc;
     nsresult rv = GetKinfoProcSelf(&proc);
     if (NS_SUCCEEDED(rv))
         *n = KP_RSS(proc);
 
     return rv;
 }
 
+static nsresult GetResidentFast(int64_t *n)
+{
+    return GetResident(n);
+}
+
 #elif defined(SOLARIS)
 
 #include <procfs.h>
 #include <fcntl.h>
 #include <unistd.h>
 
 static void XMappingIter(int64_t& vsize, int64_t& resident)
 {
@@ -237,16 +247,21 @@ static nsresult GetResident(int64_t *n)
     XMappingIter(vsize, resident);
     if (resident == -1) {
         return NS_ERROR_FAILURE;
     }
     *n = resident;
     return NS_OK;
 }
 
+static nsresult GetResidentFast(int64_t *n)
+{
+    return GetResident(n);
+}
+
 #elif defined(XP_MACOSX)
 
 #include <mach/mach_init.h>
 #include <mach/task.h>
 
 static bool GetTaskBasicInfo(struct task_basic_info *ti)
 {
     mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
@@ -264,40 +279,50 @@ static nsresult GetVsize(int64_t *n)
     task_basic_info ti;
     if (!GetTaskBasicInfo(&ti))
         return NS_ERROR_FAILURE;
 
     *n = ti.virtual_size;
     return NS_OK;
 }
 
-static nsresult GetResident(int64_t *n)
+// If we're using jemalloc on Mac, we need to instruct jemalloc to purge the
+// pages it has madvise(MADV_FREE)'d before we read our RSS in order to get
+// an accurate result.  The OS will take away MADV_FREE'd pages when there's
+// memory pressure, so ideally, they shouldn't count against our RSS.
+//
+// Purging these pages can take a long time for some users (see bug 789975),
+// so we provide the option to get the RSS without purging first.
+static nsresult GetResident(int64_t *n, bool aDoPurge)
 {
 #ifdef HAVE_JEMALLOC_STATS
-    // If we're using jemalloc on Mac, we need to instruct jemalloc to purge
-    // the pages it has madvise(MADV_FREE)'d before we read our RSS.  The OS
-    // will take away MADV_FREE'd pages when there's memory pressure, so they
-    // shouldn't count against our RSS.
-    //
-    // Purging these pages shouldn't take more than 10ms or so, but we want to
-    // keep an eye on it since GetResident() is called on each Telemetry ping.
-    {
+    if (aDoPurge) {
       Telemetry::AutoTimer<Telemetry::MEMORY_FREE_PURGED_PAGES_MS> timer;
       jemalloc_purge_freed_pages();
     }
 #endif
 
     task_basic_info ti;
     if (!GetTaskBasicInfo(&ti))
         return NS_ERROR_FAILURE;
 
     *n = ti.resident_size;
     return NS_OK;
 }
 
+static nsresult GetResidentFast(int64_t *n)
+{
+    return GetResident(n, /* doPurge = */ false);
+}
+
+static nsresult GetResident(int64_t *n)
+{
+    return GetResident(n, /* doPurge = */ true);
+}
+
 #elif defined(XP_WIN)
 
 #include <windows.h>
 #include <psapi.h>
 
 #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
 static nsresult GetVsize(int64_t *n)
 {
@@ -320,16 +345,21 @@ static nsresult GetResident(int64_t *n)
     if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
         return NS_ERROR_FAILURE;
     }
 
     *n = pmc.WorkingSetSize;
     return NS_OK;
 }
 
+static nsresult GetResidentFast(int64_t *n)
+{
+    return GetResident(n);
+}
+
 #define HAVE_PRIVATE_REPORTER
 static nsresult GetPrivate(int64_t *n)
 {
     PROCESS_MEMORY_COUNTERS_EX pmcex;
     pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
 
     if (!GetProcessMemoryInfo(GetCurrentProcess(),
                               (PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex)))
@@ -372,16 +402,27 @@ NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(Re
     UNITS_BYTES,
     GetResident,
     "Memory mapped by the process that is present in physical memory, "
     "also known as the resident set size (RSS).  This is the best single "
     "figure to use when considering the memory resources used by the process, "
     "but it depends both on other processes being run and details of the OS "
     "kernel and so is best used for comparing the memory usage of a single "
     "process at different points in time.")
+
+NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(ResidentFast,
+    "resident-fast",
+    KIND_OTHER,
+    UNITS_BYTES,
+    GetResidentFast,
+    "This is the same measurement as 'resident', but it tries to be as fast as "
+    "possible at the expense of accuracy.  On most platforms this is identical to "
+    "the 'resident' measurement, but on Mac it may over-count.  You should use "
+    "'resident-fast' where you care about latency of collection (e.g. in "
+    "telemetry).  Otherwise you should use 'resident'.")
 #endif  // HAVE_VSIZE_AND_RESIDENT_REPORTERS
 
 #ifdef HAVE_PAGE_FAULT_REPORTERS
 NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT(PageFaultsSoft,
     "page-faults-soft",
     KIND_OTHER,
     UNITS_COUNT_CUMULATIVE,
     GetSoftPageFaults,
@@ -660,16 +701,17 @@ nsMemoryReporterManager::Init()
     REGISTER(HeapCommittedUnusedRatio);
     REGISTER(HeapDirty);
     REGISTER(Explicit);
 #endif
 
 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
     REGISTER(Vsize);
     REGISTER(Resident);
+    REGISTER(ResidentFast);
 #endif
 
 #ifdef HAVE_PAGE_FAULT_REPORTERS
     REGISTER(PageFaultsSoft);
     REGISTER(PageFaultsHard);
 #endif
 
 #ifdef HAVE_PRIVATE_REPORTER