Use totmaps if available on chromeos

We currently use statm on linux. This provides less than great results.
We take total resident memory and subtract "shared pages" from it instead of
using a count of pages that only this process has mapped.

On chromeos we've added totmaps which sums up the fields from the process'
smaps.

BUG=125150
TEST=Examine memory reports from about:memory and task manager, and compare
     them to the sums of the results in the smaps.

R=thestig@chromium.org, willchan@chromium.org

Review URL: https://codereview.chromium.org/15779007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202639 0039d316-1c4b-4281-b951-d872f2087c98
parent d39e1c84
...@@ -170,6 +170,14 @@ class BASE_EXPORT ProcessMetrics { ...@@ -170,6 +170,14 @@ class BASE_EXPORT ProcessMetrics {
ProcessMetrics(ProcessHandle process, PortProvider* port_provider); ProcessMetrics(ProcessHandle process, PortProvider* port_provider);
#endif // !defined(OS_MACOSX) || defined(OS_IOS) #endif // !defined(OS_MACOSX) || defined(OS_IOS)
#if defined(OS_LINUX)
bool GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) const;
#endif
#if defined(OS_CHROMEOS)
bool GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) const;
#endif
ProcessHandle process_; ProcessHandle process_;
int processor_count_; int processor_count_;
......
...@@ -5,11 +5,14 @@ ...@@ -5,11 +5,14 @@
#include "base/process/process_metrics.h" #include "base/process/process_metrics.h"
#include <dirent.h> #include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "base/file_util.h" #include "base/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/process/internal_linux.h" #include "base/process/internal_linux.h"
#include "base/string_util.h" #include "base/string_util.h"
...@@ -156,44 +159,12 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, ...@@ -156,44 +159,12 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
return true; return true;
} }
// Private and Shared working set sizes are obtained from /proc/<pid>/statm.
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
// Use statm instead of smaps because smaps is: #if defined(OS_CHROMEOS)
// a) Large and slow to parse. if (GetWorkingSetKBytesTotmaps(ws_usage))
// b) Unavailable in the SUID sandbox. return true;
#endif
// First we need to get the page size, since everything is measured in pages. return GetWorkingSetKBytesStatm(ws_usage);
// For details, see: man 5 proc.
const int page_size_kb = getpagesize() / 1024;
if (page_size_kb <= 0)
return false;
std::string statm;
{
FilePath statm_file = internal::GetProcPidDir(process_).Append("statm");
// Synchronously reading files in /proc is safe.
ThreadRestrictions::ScopedAllowIO allow_io;
bool ret = file_util::ReadFileToString(statm_file, &statm);
if (!ret || 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.
int statm_rss, statm_shared;
StringToInt(statm_vec[1], &statm_rss);
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;
return true;
} }
double ProcessMetrics::GetCPUUsage() { double ProcessMetrics::GetCPUUsage() {
...@@ -292,6 +263,96 @@ ProcessMetrics::ProcessMetrics(ProcessHandle process) ...@@ -292,6 +263,96 @@ ProcessMetrics::ProcessMetrics(ProcessHandle process)
processor_count_ = base::SysInfo::NumberOfProcessors(); processor_count_ = base::SysInfo::NumberOfProcessors();
} }
#if defined(OS_CHROMEOS)
// Private, Shared and Proportional working set sizes are obtained from
// /proc/<pid>/totmaps
bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage)
const {
// The format of /proc/<pid>/totmaps is:
//
// Rss: 6120 kB
// Pss: 3335 kB
// Shared_Clean: 1008 kB
// Shared_Dirty: 4012 kB
// Private_Clean: 4 kB
// Private_Dirty: 1096 kB
// ...
const size_t kPssIndex = 4;
const size_t kPrivate_CleanIndex = 13;
const size_t kPrivate_DirtyIndex = 16;
std::string totmaps_data;
{
FilePath totmaps_file = internal::GetProcPidDir(process_).Append("totmaps");
ThreadRestrictions::ScopedAllowIO allow_io;
bool ret = file_util::ReadFileToString(totmaps_file, &totmaps_data);
if (!ret || totmaps_data.length() == 0)
return false;
}
std::vector<std::string> totmaps_fields;
SplitStringAlongWhitespace(totmaps_data, &totmaps_fields);
DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]);
DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex-1]);
DCHECK_EQ("Private_Dirty:", totmaps_fields[kPrivate_DirtyIndex-1]);
int pss, private_clean, private_dirty;
bool ret = true;
ret &= StringToInt(totmaps_fields[kPssIndex], &pss);
ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean);
ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty);
ws_usage->priv = private_clean + private_dirty;
ws_usage->shared = pss;
ws_usage->shareable = 0;
return ret;
}
#endif
// Private and Shared working set sizes are obtained from /proc/<pid>/statm.
bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage)
const {
// Use statm instead of smaps because smaps is:
// a) Large and slow to parse.
// b) Unavailable in the SUID sandbox.
// 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 = getpagesize() / 1024;
if (page_size_kb <= 0)
return false;
std::string statm;
{
FilePath statm_file = internal::GetProcPidDir(process_).Append("statm");
// Synchronously reading files in /proc is safe.
ThreadRestrictions::ScopedAllowIO allow_io;
bool ret = file_util::ReadFileToString(statm_file, &statm);
if (!ret || 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.
int statm_rss, statm_shared;
bool ret = true;
ret &= StringToInt(statm_vec[1], &statm_rss);
ret &= 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;
return ret;
}
size_t GetSystemCommitCharge() { size_t GetSystemCommitCharge() {
SystemMemoryInfoKB meminfo; SystemMemoryInfoKB meminfo;
if (!GetSystemMemoryInfo(&meminfo)) if (!GetSystemMemoryInfo(&meminfo))
......
...@@ -586,11 +586,16 @@ bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const { ...@@ -586,11 +586,16 @@ bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
!iter->second->GetWorkingSetKBytes(&ws_usage)) !iter->second->GetWorkingSetKBytes(&ws_usage))
return false; return false;
values.is_physical_memory_valid = true;
#if defined(OS_LINUX)
// On Linux private memory is also resident. Just use it.
values.physical_memory = ws_usage.priv * 1024;
#else
// Memory = working_set.private + working_set.shareable. // Memory = working_set.private + working_set.shareable.
// We exclude the shared memory. // We exclude the shared memory.
values.is_physical_memory_valid = true;
values.physical_memory = iter->second->GetWorkingSetSize(); values.physical_memory = iter->second->GetWorkingSetSize();
values.physical_memory -= ws_usage.shared * 1024; values.physical_memory -= ws_usage.shared * 1024;
#endif
} }
*result = values.physical_memory; *result = values.physical_memory;
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment