| 17 |
|
|
| 18 |
#include "base/file_util.h" |
#include "base/file_util.h" |
| 19 |
#include "base/logging.h" |
#include "base/logging.h" |
| 20 |
|
#include "base/string_number_conversions.h" |
| 21 |
#include "base/string_tokenizer.h" |
#include "base/string_tokenizer.h" |
| 22 |
#include "base/string_util.h" |
#include "base/string_util.h" |
| 23 |
#include "base/sys_info.h" |
#include "base/sys_info.h" |
| 33 |
// spaces. |
// spaces. |
| 34 |
void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { |
void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { |
| 35 |
FilePath stat_file("/proc"); |
FilePath stat_file("/proc"); |
| 36 |
stat_file = stat_file.Append(IntToString(pid)); |
stat_file = stat_file.Append(base::IntToString(pid)); |
| 37 |
stat_file = stat_file.Append("stat"); |
stat_file = stat_file.Append("stat"); |
| 38 |
std::string mem_stats; |
std::string mem_stats; |
| 39 |
if (!file_util::ReadFileToString(stat_file, &mem_stats)) |
if (!file_util::ReadFileToString(stat_file, &mem_stats)) |
| 47 |
|
|
| 48 |
ProcessId GetParentProcessId(ProcessHandle process) { |
ProcessId GetParentProcessId(ProcessHandle process) { |
| 49 |
FilePath stat_file("/proc"); |
FilePath stat_file("/proc"); |
| 50 |
stat_file = stat_file.Append(IntToString(process)); |
stat_file = stat_file.Append(base::IntToString(process)); |
| 51 |
stat_file = stat_file.Append("status"); |
stat_file = stat_file.Append("status"); |
| 52 |
std::string status; |
std::string status; |
| 53 |
if (!file_util::ReadFileToString(stat_file, &status)) |
if (!file_util::ReadFileToString(stat_file, &status)) |
| 65 |
case KEY_VALUE: |
case KEY_VALUE: |
| 66 |
DCHECK(!last_key_name.empty()); |
DCHECK(!last_key_name.empty()); |
| 67 |
if (last_key_name == "PPid") { |
if (last_key_name == "PPid") { |
| 68 |
pid_t ppid = StringToInt(tokenizer.token()); |
int ppid; |
| 69 |
|
base::StringToInt(tokenizer.token(), &ppid); |
| 70 |
return ppid; |
return ppid; |
| 71 |
} |
} |
| 72 |
state = KEY_NAME; |
state = KEY_NAME; |
| 79 |
|
|
| 80 |
FilePath GetProcessExecutablePath(ProcessHandle process) { |
FilePath GetProcessExecutablePath(ProcessHandle process) { |
| 81 |
FilePath stat_file("/proc"); |
FilePath stat_file("/proc"); |
| 82 |
stat_file = stat_file.Append(IntToString(process)); |
stat_file = stat_file.Append(base::IntToString(process)); |
| 83 |
stat_file = stat_file.Append("exe"); |
stat_file = stat_file.Append("exe"); |
| 84 |
char exename[2048]; |
char exename[2048]; |
| 85 |
ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename)); |
ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename)); |
| 207 |
std::vector<std::string> proc_stats; |
std::vector<std::string> proc_stats; |
| 208 |
GetProcStats(process_, &proc_stats); |
GetProcStats(process_, &proc_stats); |
| 209 |
const size_t kVmSize = 22; |
const size_t kVmSize = 22; |
| 210 |
if (proc_stats.size() > kVmSize) |
if (proc_stats.size() > kVmSize) { |
| 211 |
return static_cast<size_t>(StringToInt(proc_stats[kVmSize])); |
int vm_size; |
| 212 |
|
base::StringToInt(proc_stats[kVmSize], &vm_size); |
| 213 |
|
return static_cast<size_t>(vm_size); |
| 214 |
|
} |
| 215 |
return 0; |
return 0; |
| 216 |
} |
} |
| 217 |
|
|
| 220 |
std::vector<std::string> proc_stats; |
std::vector<std::string> proc_stats; |
| 221 |
GetProcStats(process_, &proc_stats); |
GetProcStats(process_, &proc_stats); |
| 222 |
const size_t kVmPeak = 21; |
const size_t kVmPeak = 21; |
| 223 |
if (proc_stats.size() > kVmPeak) |
if (proc_stats.size() > kVmPeak) { |
| 224 |
return static_cast<size_t>(StringToInt(proc_stats[kVmPeak])); |
int vm_peak; |
| 225 |
|
if (base::StringToInt(proc_stats[kVmPeak], &vm_peak)) |
| 226 |
|
return vm_peak; |
| 227 |
|
} |
| 228 |
return 0; |
return 0; |
| 229 |
} |
} |
| 230 |
|
|
| 234 |
GetProcStats(process_, &proc_stats); |
GetProcStats(process_, &proc_stats); |
| 235 |
const size_t kVmRss = 23; |
const size_t kVmRss = 23; |
| 236 |
if (proc_stats.size() > kVmRss) { |
if (proc_stats.size() > kVmRss) { |
| 237 |
size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmRss])); |
int num_pages; |
| 238 |
return num_pages * getpagesize(); |
if (base::StringToInt(proc_stats[kVmRss], &num_pages)) |
| 239 |
|
return static_cast<size_t>(num_pages) * getpagesize(); |
| 240 |
} |
} |
| 241 |
return 0; |
return 0; |
| 242 |
} |
} |
| 247 |
GetProcStats(process_, &proc_stats); |
GetProcStats(process_, &proc_stats); |
| 248 |
const size_t kVmHwm = 23; |
const size_t kVmHwm = 23; |
| 249 |
if (proc_stats.size() > kVmHwm) { |
if (proc_stats.size() > kVmHwm) { |
| 250 |
size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmHwm])); |
int num_pages; |
| 251 |
return num_pages * getpagesize(); |
base::StringToInt(proc_stats[kVmHwm], &num_pages); |
| 252 |
|
return static_cast<size_t>(num_pages) * getpagesize(); |
| 253 |
} |
} |
| 254 |
return 0; |
return 0; |
| 255 |
} |
} |
| 275 |
// See http://www.pixelbeat.org/scripts/ps_mem.py |
// See http://www.pixelbeat.org/scripts/ps_mem.py |
| 276 |
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
| 277 |
FilePath stat_file = |
FilePath stat_file = |
| 278 |
FilePath("/proc").Append(IntToString(process_)).Append("smaps"); |
FilePath("/proc").Append(base::IntToString(process_)).Append("smaps"); |
| 279 |
std::string smaps; |
std::string smaps; |
| 280 |
int private_kb = 0; |
int private_kb = 0; |
| 281 |
int pss_kb = 0; |
int pss_kb = 0; |
| 298 |
return false; |
return false; |
| 299 |
} |
} |
| 300 |
if (last_key_name.starts_with(private_prefix)) { |
if (last_key_name.starts_with(private_prefix)) { |
| 301 |
private_kb += StringToInt(tokenizer.token()); |
int cur; |
| 302 |
|
base::StringToInt(tokenizer.token(), &cur); |
| 303 |
|
private_kb += cur; |
| 304 |
} else if (last_key_name.starts_with(pss_prefix)) { |
} else if (last_key_name.starts_with(pss_prefix)) { |
| 305 |
have_pss = true; |
have_pss = true; |
| 306 |
pss_kb += StringToInt(tokenizer.token()); |
int cur; |
| 307 |
|
base::StringToInt(tokenizer.token(), &cur); |
| 308 |
|
pss_kb += cur; |
| 309 |
} |
} |
| 310 |
state = KEY_NAME; |
state = KEY_NAME; |
| 311 |
break; |
break; |
| 319 |
return false; |
return false; |
| 320 |
|
|
| 321 |
stat_file = |
stat_file = |
| 322 |
FilePath("/proc").Append(IntToString(process_)).Append("statm"); |
FilePath("/proc").Append(base::IntToString(process_)).Append("statm"); |
| 323 |
std::string statm; |
std::string statm; |
| 324 |
if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0) |
if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0) |
| 325 |
return false; |
return false; |
| 328 |
SplitString(statm, ' ', &statm_vec); |
SplitString(statm, ' ', &statm_vec); |
| 329 |
if (statm_vec.size() != 7) |
if (statm_vec.size() != 7) |
| 330 |
return false; // Not the format we expect. |
return false; // Not the format we expect. |
| 331 |
private_kb = StringToInt(statm_vec[1]) - StringToInt(statm_vec[2]); |
|
| 332 |
private_kb *= page_size_kb; |
int statm1, statm2; |
| 333 |
|
base::StringToInt(statm_vec[1], &statm1); |
| 334 |
|
base::StringToInt(statm_vec[2], &statm2); |
| 335 |
|
private_kb = (statm1 - statm2) * page_size_kb; |
| 336 |
} |
} |
| 337 |
ws_usage->priv = private_kb; |
ws_usage->priv = private_kb; |
| 338 |
// Sharable is not calculated, as it does not provide interesting data. |
// Sharable is not calculated, as it does not provide interesting data. |
| 349 |
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
| 350 |
std::string proc_io_contents; |
std::string proc_io_contents; |
| 351 |
FilePath io_file("/proc"); |
FilePath io_file("/proc"); |
| 352 |
io_file = io_file.Append(IntToString(process_)); |
io_file = io_file.Append(base::IntToString(process_)); |
| 353 |
io_file = io_file.Append("io"); |
io_file = io_file.Append("io"); |
| 354 |
if (!file_util::ReadFileToString(io_file, &proc_io_contents)) |
if (!file_util::ReadFileToString(io_file, &proc_io_contents)) |
| 355 |
return false; |
return false; |
| 369 |
case KEY_VALUE: |
case KEY_VALUE: |
| 370 |
DCHECK(!last_key_name.empty()); |
DCHECK(!last_key_name.empty()); |
| 371 |
if (last_key_name == "syscr") { |
if (last_key_name == "syscr") { |
| 372 |
(*io_counters).ReadOperationCount = StringToInt64(tokenizer.token()); |
base::StringToInt64(tokenizer.token(), |
| 373 |
|
reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount)); |
| 374 |
} else if (last_key_name == "syscw") { |
} else if (last_key_name == "syscw") { |
| 375 |
(*io_counters).WriteOperationCount = StringToInt64(tokenizer.token()); |
base::StringToInt64(tokenizer.token(), |
| 376 |
|
reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount)); |
| 377 |
} else if (last_key_name == "rchar") { |
} else if (last_key_name == "rchar") { |
| 378 |
(*io_counters).ReadTransferCount = StringToInt64(tokenizer.token()); |
base::StringToInt64(tokenizer.token(), |
| 379 |
|
reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount)); |
| 380 |
} else if (last_key_name == "wchar") { |
} else if (last_key_name == "wchar") { |
| 381 |
(*io_counters).WriteTransferCount = StringToInt64(tokenizer.token()); |
base::StringToInt64(tokenizer.token(), |
| 382 |
|
reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount)); |
| 383 |
} |
} |
| 384 |
state = KEY_NAME; |
state = KEY_NAME; |
| 385 |
break; |
break; |
| 405 |
if (fields.size() < 13) |
if (fields.size() < 13) |
| 406 |
return -1; // Output not in the format we expect. |
return -1; // Output not in the format we expect. |
| 407 |
|
|
| 408 |
return StringToInt(fields[11]) + StringToInt(fields[12]); |
int fields11, fields12; |
| 409 |
|
base::StringToInt(fields[11], &fields11); |
| 410 |
|
base::StringToInt(fields[12], &fields12); |
| 411 |
|
return fields11 + fields12; |
| 412 |
} |
} |
| 413 |
|
|
| 414 |
// Get the total CPU of a single process. Return value is number of jiffies |
// Get the total CPU of a single process. Return value is number of jiffies |
| 522 |
DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); |
DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); |
| 523 |
DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:"); |
DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:"); |
| 524 |
|
|
| 525 |
size_t result_in_kb; |
int mem_total, mem_free, mem_buffers, mem_cache; |
| 526 |
result_in_kb = StringToInt(meminfo_fields[kMemTotalIndex]); |
base::StringToInt(meminfo_fields[kMemTotalIndex], &mem_total); |
| 527 |
result_in_kb -= StringToInt(meminfo_fields[kMemFreeIndex]); |
base::StringToInt(meminfo_fields[kMemFreeIndex], &mem_free); |
| 528 |
result_in_kb -= StringToInt(meminfo_fields[kMemBuffersIndex]); |
base::StringToInt(meminfo_fields[kMemBuffersIndex], &mem_buffers); |
| 529 |
result_in_kb -= StringToInt(meminfo_fields[kMemCacheIndex]); |
base::StringToInt(meminfo_fields[kMemCacheIndex], &mem_cache); |
| 530 |
|
|
| 531 |
return result_in_kb; |
return mem_total - mem_free - mem_buffers - mem_cache; |
| 532 |
} |
} |
| 533 |
|
|
| 534 |
namespace { |
namespace { |
| 637 |
return false; |
return false; |
| 638 |
|
|
| 639 |
FilePath oom_adj("/proc"); |
FilePath oom_adj("/proc"); |
| 640 |
oom_adj = oom_adj.Append(Int64ToString(process)); |
oom_adj = oom_adj.Append(base::Int64ToString(process)); |
| 641 |
oom_adj = oom_adj.AppendASCII("oom_adj"); |
oom_adj = oom_adj.AppendASCII("oom_adj"); |
| 642 |
|
|
| 643 |
if (!file_util::PathExists(oom_adj)) |
if (!file_util::PathExists(oom_adj)) |
| 644 |
return false; |
return false; |
| 645 |
|
|
| 646 |
std::string score_str = IntToString(score); |
std::string score_str = base::IntToString(score); |
| 647 |
return (static_cast<int>(score_str.length()) == |
return (static_cast<int>(score_str.length()) == |
| 648 |
file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length())); |
file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length())); |
| 649 |
} |
} |