Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3779)

Unified Diff: base/process_util_linux.cc

Issue 9568046: Linux: Stop using /proc/pid/smaps to calculate memory usage. It's too slow. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: grammar Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/process_util_linux.cc
===================================================================
--- base/process_util_linux.cc (revision 124488)
+++ base/process_util_linux.cc (working copy)
@@ -17,7 +17,6 @@
#include "base/file_util.h"
#include "base/logging.h"
-#include "base/stringprintf.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "base/string_tokenizer.h"
@@ -27,24 +26,25 @@
namespace {
-// Max score for the old oom_adj range. Used for conversion of new
-// values to old values.
-const int kMaxOldOomScore = 15;
-
enum ParsingState {
KEY_NAME,
KEY_VALUE
};
+const char kProcDir[] = "/proc";
+
+// Returns a FilePath to "/proc/pid".
+FilePath GetProcPidDir(pid_t pid) {
+ return FilePath(kProcDir).Append(base::Int64ToString(pid));
+}
+
// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by
// spaces. Returns true if successful.
bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
// Synchronously reading files in /proc is safe.
base::ThreadRestrictions::ScopedAllowIO allow_io;
- FilePath stat_file("/proc");
- stat_file = stat_file.Append(base::IntToString(pid));
- stat_file = stat_file.Append("stat");
+ FilePath stat_file = GetProcPidDir(pid).Append("stat");
std::string mem_stats;
if (!file_util::ReadFileToString(stat_file, &mem_stats))
return false;
@@ -61,9 +61,7 @@
// Synchronously reading files in /proc is safe.
base::ThreadRestrictions::ScopedAllowIO allow_io;
- FilePath cmd_line_file("/proc");
- cmd_line_file = cmd_line_file.Append(base::IntToString(pid));
- cmd_line_file = cmd_line_file.Append("cmdline");
+ FilePath cmd_line_file = GetProcPidDir(pid).Append("cmdline");
std::string cmd_line;
if (!file_util::ReadFileToString(cmd_line_file, &cmd_line))
return false;
@@ -80,7 +78,7 @@
base::ThreadRestrictions::ScopedAllowIO allow_io;
// Use /proc/<pid>/task to find all threads and parse their /stat file.
- FilePath path = FilePath(base::StringPrintf("/proc/%d/task/", pid));
+ FilePath path = GetProcPidDir(pid).Append("task");
DIR* dir = opendir(path.value().c_str());
if (!dir) {
@@ -114,9 +112,7 @@
// Synchronously reading files in /proc is safe.
base::ThreadRestrictions::ScopedAllowIO allow_io;
- FilePath stat_file("/proc");
- stat_file = stat_file.Append(base::IntToString(process));
- stat_file = stat_file.Append("status");
+ FilePath stat_file = GetProcPidDir(process).Append("status");
std::string status;
if (!file_util::ReadFileToString(stat_file, &status))
return -1;
@@ -146,9 +142,7 @@
}
FilePath GetProcessExecutablePath(ProcessHandle process) {
- FilePath stat_file("/proc");
- stat_file = stat_file.Append(base::IntToString(process));
- stat_file = stat_file.Append("exe");
+ FilePath stat_file = GetProcPidDir(process).Append("exe");
FilePath exe_name;
if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) {
// No such process. Happens frequently in e.g. TerminateAllChromeProcesses
@@ -159,7 +153,7 @@
ProcessIterator::ProcessIterator(const ProcessFilter* filter)
: filter_(filter) {
- procfs_dir_ = opendir("/proc");
+ procfs_dir_ = opendir(kProcDir);
}
ProcessIterator::~ProcessIterator() {
@@ -210,7 +204,7 @@
// Read the process's status.
char buf[NAME_MAX + 12];
sprintf(buf, "/proc/%s/stat", slot->d_name);
- FILE *fp = fopen(buf, "r");
+ FILE* fp = fopen(buf, "r");
if (!fp)
continue;
const char* result = fgets(buf, sizeof(buf), fp);
@@ -340,92 +334,43 @@
return true;
}
-// 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
+// Private and Shared working set sizes are obtained from /proc/<pid>/statm.
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
- // Synchronously reading files in /proc is safe.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
+ // Use statm instead of smaps because smaps is:
+ // a) Large and slow to parse.
+ // b) Unavailable in the SUID sandbox.
- FilePath proc_dir = FilePath("/proc").Append(base::IntToString(process_));
- std::string smaps;
- int private_kb = 0;
- int pss_kb = 0;
- bool have_pss = false;
- bool ret;
+ // First we need to get the page size, since everything is measured in pages.
+ // For details, see: man 5 proc.
+ const int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024;
+ if (page_size_kb <= 0)
+ return false;
+ std::string statm;
{
- FilePath smaps_file = proc_dir.Append("smaps");
+ FilePath statm_file = GetProcPidDir(process_).Append("statm");
// Synchronously reading files in /proc is safe.
base::ThreadRestrictions::ScopedAllowIO allow_io;
- ret = file_util::ReadFileToString(smaps_file, &smaps);
- }
- if (ret && smaps.length() > 0) {
- const std::string private_prefix = "Private_";
- const std::string pss_prefix = "Pss";
- StringTokenizer tokenizer(smaps, ":\n");
- StringPiece last_key_name;
- ParsingState state = KEY_NAME;
- while (tokenizer.GetNext()) {
- switch (state) {
- case KEY_NAME:
- last_key_name = tokenizer.token_piece();
- state = KEY_VALUE;
- break;
- case KEY_VALUE:
- if (last_key_name.empty()) {
- NOTREACHED();
- return false;
- }
- if (last_key_name.starts_with(private_prefix)) {
- int cur;
- base::StringToInt(tokenizer.token_piece(), &cur);
- private_kb += cur;
- } else if (last_key_name.starts_with(pss_prefix)) {
- have_pss = true;
- int cur;
- base::StringToInt(tokenizer.token_piece(), &cur);
- pss_kb += cur;
- }
- 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;
-
- std::string statm;
- {
- FilePath statm_file = proc_dir.Append("statm");
- // Synchronously reading files in /proc is safe.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- ret = file_util::ReadFileToString(statm_file, &statm);
- }
+ bool ret = file_util::ReadFileToString(statm_file, &statm);
if (!ret || statm.length() == 0)
return false;
+ }
- std::vector<std::string> statm_vec;
- base::SplitString(statm, ' ', &statm_vec);
- if (statm_vec.size() != 7)
- return false; // Not the format we expect.
+ std::vector<std::string> statm_vec;
+ base::SplitString(statm, ' ', &statm_vec);
+ if (statm_vec.size() != 7)
+ return false; // Not the format we expect.
- int statm1, statm2;
- base::StringToInt(statm_vec[1], &statm1);
- base::StringToInt(statm_vec[2], &statm2);
- private_kb = (statm1 - statm2) * page_size_kb;
- }
- ws_usage->priv = private_kb;
+ int statm_rss, statm_shared;
+ base::StringToInt(statm_vec[1], &statm_rss);
+ base::StringToInt(statm_vec[2], &statm_shared);
+
+ ws_usage->priv = (statm_rss - statm_shared) * page_size_kb;
+ ws_usage->shared = statm_shared * page_size_kb;
+
// Sharable is not calculated, as it does not provide interesting data.
ws_usage->shareable = 0;
- ws_usage->shared = 0;
- if (have_pss)
- ws_usage->shared = pss_kb;
return true;
}
@@ -479,9 +424,7 @@
base::ThreadRestrictions::ScopedAllowIO allow_io;
std::string proc_io_contents;
- FilePath io_file("/proc");
- io_file = io_file.Append(base::IntToString(process_));
- io_file = io_file.Append("io");
+ FilePath io_file = GetProcPidDir(process_).Append("io");
if (!file_util::ReadFileToString(io_file, &proc_io_contents))
return false;
@@ -745,8 +688,7 @@
if (score < 0 || score > kMaxOomScore)
return false;
- FilePath oom_path("/proc");
- oom_path = oom_path.Append(base::Int64ToString(process));
+ FilePath oom_path(GetProcPidDir(process));
// Attempt to write the newer oom_score_adj file first.
FilePath oom_file = oom_path.AppendASCII("oom_score_adj");
@@ -764,8 +706,12 @@
// style file and translate the oom_adj score to the range 0-15.
oom_file = oom_path.AppendASCII("oom_adj");
if (file_util::PathExists(oom_file)) {
- std::string score_str = base::IntToString(
- score * kMaxOldOomScore / kMaxOomScore);
+ // Max score for the old oom_adj range. Used for conversion of new
+ // values to old values.
+ const int kMaxOldOomScore = 15;
+
+ int converted_score = score * kMaxOldOomScore / kMaxOomScore;
+ std::string score_str = base::IntToString(converted_score);
DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str;
int score_len = static_cast<int>(score_str.length());
return (score_len == file_util::WriteFile(oom_file,
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698