| 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,
|
|
|