Bug 1035396 - Make Linux USS reporting 2x faster. r=nbp, r=njn
☠☠ backed out by 9396c2c95b00 ☠ ☠
authorJan Keromnes <janx@linux.com>
Fri, 11 Jul 2014 05:03:00 -0400
changeset 193591 d89a7ed61c1924133e5e70633dd5ff9a25a8b4b7
parent 193590 6808a2c6eab4d647e66afa872a831ec392d456cc
child 193592 673ad6aa248df39a782794180387b5379c2bc575
push idunknown
push userunknown
push dateunknown
reviewersnbp, njn
bugs1035396
milestone33.0a1
Bug 1035396 - Make Linux USS reporting 2x faster. r=nbp, r=njn
xpcom/base/nsMemoryReporterManager.cpp
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -40,16 +40,19 @@ using namespace mozilla;
 
 #if defined(MOZ_MEMORY)
 #  define HAVE_JEMALLOC_STATS 1
 #  include "mozmemory.h"
 #endif  // MOZ_MEMORY
 
 #if defined(XP_LINUX)
 
+#include <string.h>
+#include <stdlib.h>
+
 static nsresult
 GetProcSelfStatmField(int aField, int64_t* aN)
 {
   // There are more than two fields, but we're only interested in the first
   // two.
   static const int MAX_FIELD = 2;
   size_t fields[MAX_FIELD];
   MOZ_ASSERT(aField < MAX_FIELD, "bad field number");
@@ -63,40 +66,58 @@ GetProcSelfStatmField(int aField, int64_
     }
   }
   return NS_ERROR_FAILURE;
 }
 
 static nsresult
 GetProcSelfSmapsPrivate(int64_t* aN)
 {
-  // You might be tempted to calculate USS by subtracting the "shared"
-  // value from the "resident" value in /proc/<pid>/statm. But at least
-  // on Linux, statm's "shared" value actually counts pages backed by
-  // files, which has little to do with whether the pages are actually
-  // shared. /proc/self/smaps on the other hand appears to give us the
-  // correct information.
+  // You might be tempted to calculate USS by subtracting the "shared" value
+  // from the "resident" value in /proc/<pid>/statm. But at least on Linux,
+  // statm's "shared" value actually counts pages backed by files, which has
+  // little to do with whether the pages are actually shared. /proc/self/smaps
+  // on the other hand appears to give us the correct information.
 
   FILE* f = fopen("/proc/self/smaps", "r");
   if (NS_WARN_IF(!f)) {
     return NS_ERROR_UNEXPECTED;
   }
 
+  // We carry over the end of the buffer to make sure we don't accidentally
+  // break on an interesting line.
+  static const uint32_t carryOver = 32;
+  static const uint32_t readSize = 4096;
+
   int64_t amount = 0;
-  char line[256];
-  while (fgets(line, sizeof(line), f)) {
-    long long val = 0;
-    if (sscanf(line, "Private_Dirty: %lld kB", &val) == 1 ||
-        sscanf(line, "Private_Clean: %lld kB", &val) == 1) {
-      amount += val * 1024; // convert from kB to bytes
+  char buffer[carryOver + readSize + 1];
+  memset(buffer, ' ', carryOver);
+
+  for (;;) {
+    size_t bytes = fread(buffer + carryOver, sizeof(*buffer), readSize, f);
+    char* end = buffer + bytes;
+    char* ptr = buffer;
+    end[carryOver] = '\0';
+    // We are looking for lines like "Private_{Clean,Dirty}: 4 kB".
+    while (ptr = strstr(ptr, "Private")) {
+      ptr += sizeof("Private_Xxxxx:");
+      amount += atoi(ptr);
+      if (ptr >= end) {
+        break;
+      }
     }
+    if (bytes < readSize) {
+      break;
+    }
+    memcpy(buffer, end, carryOver);
   }
 
   fclose(f);
-  *aN = amount;
+  // Convert from kB to bytes.
+  *aN = amount * 1024;
   return NS_OK;
 }
 
 #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1
 static nsresult
 VsizeDistinguishedAmount(int64_t* aN)
 {
   return GetProcSelfStatmField(0, aN);