Index: base/process_util_linux.cc |
=================================================================== |
--- base/process_util_linux.cc (revision 31001) |
+++ base/process_util_linux.cc (working copy) |
@@ -14,8 +14,6 @@ |
#include <time.h> |
#include <unistd.h> |
-#include <string> |
- |
#include "base/file_util.h" |
#include "base/logging.h" |
#include "base/string_tokenizer.h" |
@@ -253,8 +251,10 @@ |
return ws_usage.priv << 10; |
} |
-// Private and Shared working set sizes are obtained from /proc/<pid>/smaps, |
-// as in http://www.pixelbeat.org/scripts/ps_mem.py |
+// Private and Shared working set sizes are obtained from /proc/<pid>/smaps. |
+// When that's not available, use the values from /proc<pid>/statm as a |
+// close approximation. |
+// See http://www.pixelbeat.org/scripts/ps_mem.py |
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
FilePath stat_file = |
FilePath("/proc").Append(IntToString(process_)).Append("smaps"); |
@@ -262,32 +262,50 @@ |
int private_kb = 0; |
int pss_kb = 0; |
bool have_pss = false; |
- if (!file_util::ReadFileToString(stat_file, &smaps) || smaps.length() == 0) |
- return false; |
+ if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) { |
+ StringTokenizer tokenizer(smaps, ":\n"); |
+ ParsingState state = KEY_NAME; |
+ std::string last_key_name; |
+ while (tokenizer.GetNext()) { |
+ switch (state) { |
+ case KEY_NAME: |
+ last_key_name = tokenizer.token(); |
+ state = KEY_VALUE; |
+ break; |
+ case KEY_VALUE: |
+ if (last_key_name.empty()) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ if (StartsWithASCII(last_key_name, "Private_", 1)) { |
+ private_kb += StringToInt(tokenizer.token()); |
+ } else if (StartsWithASCII(last_key_name, "Pss", 1)) { |
+ have_pss = true; |
+ pss_kb += StringToInt(tokenizer.token()); |
+ } |
+ state = KEY_NAME; |
+ break; |
+ } |
+ } |
+ } else { |
+ // Try statm if smaps is empty because of the SUID sandbox. |
+ // First we need to get the page size though. |
+ int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; |
+ if (page_size_kb <= 0) |
+ return false; |
- StringTokenizer tokenizer(smaps, ":\n"); |
- ParsingState state = KEY_NAME; |
- std::string last_key_name; |
- while (tokenizer.GetNext()) { |
- switch (state) { |
- case KEY_NAME: |
- last_key_name = tokenizer.token(); |
- state = KEY_VALUE; |
- break; |
- case KEY_VALUE: |
- if (last_key_name.empty()) { |
- NOTREACHED(); |
- return false; |
- } |
- if (StartsWithASCII(last_key_name, "Private_", 1)) { |
- private_kb += StringToInt(tokenizer.token()); |
- } else if (StartsWithASCII(last_key_name, "Pss", 1)) { |
- have_pss = true; |
- pss_kb += StringToInt(tokenizer.token()); |
- } |
- state = KEY_NAME; |
- break; |
- } |
+ stat_file = |
+ FilePath("/proc").Append(IntToString(process_)).Append("statm"); |
+ std::string statm; |
+ if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0) |
+ return false; |
+ |
+ std::vector<std::string> statm_vec; |
+ SplitString(statm, ' ', &statm_vec); |
+ if (statm_vec.size() != 7) |
+ return false; // Not the format we expect. |
+ private_kb = StringToInt(statm_vec[1]) - StringToInt(statm_vec[2]); |
+ private_kb *= page_size_kb; |
} |
ws_usage->priv = private_kb; |
// Sharable is not calculated, as it does not provide interesting data. |
@@ -414,7 +432,7 @@ |
} |
int64 time_delta = time - last_time_; |
- DCHECK(time_delta != 0); |
+ DCHECK_NE(time_delta, 0); |
if (time_delta == 0) |
return 0; |