blob: 4c034c429fbabe2739637d1cd86538d723fd6964 [file] [log] [blame]
[email protected]655750cb2009-09-14 17:46:151// Copyright (c) 2009 The Chromium Authors. All rights reserved.
[email protected]0b100bc8b2008-10-14 20:49:162// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/process_util.h"
6
[email protected]ab0e2222008-10-31 20:19:437#include <ctype.h>
8#include <dirent.h>
[email protected]9be42c82009-11-18 21:10:579#include <dlfcn.h>
[email protected]d2ed23832009-09-19 01:57:3910#include <errno.h>
[email protected]fa3097a6a52008-12-17 22:41:5011#include <fcntl.h>
[email protected]d2ed23832009-09-19 01:57:3912#include <sys/time.h>
[email protected]fb7f9be2008-10-22 01:15:4713#include <sys/types.h>
14#include <sys/wait.h>
[email protected]d2ed23832009-09-19 01:57:3915#include <time.h>
[email protected]78c6dd62009-06-08 23:29:1116#include <unistd.h>
[email protected]0b100bc8b2008-10-14 20:49:1617
18#include "base/file_util.h"
19#include "base/logging.h"
[email protected]528c56d2010-07-30 19:28:4420#include "base/string_number_conversions.h"
[email protected]4e5ae20f2010-09-24 04:52:1121#include "base/string_split.h"
[email protected]0b100bc8b2008-10-14 20:49:1622#include "base/string_tokenizer.h"
23#include "base/string_util.h"
[email protected]b6128aa2010-04-29 17:44:4224#include "base/sys_info.h"
[email protected]0b100bc8b2008-10-14 20:49:1625
26namespace {
27
28enum ParsingState {
29 KEY_NAME,
30 KEY_VALUE
31};
32
[email protected]0c557f12009-05-11 23:35:5233// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by
[email protected]c47d81d2010-10-05 23:41:0434// spaces. Returns true if successful.
35bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
[email protected]0c557f12009-05-11 23:35:5236 FilePath stat_file("/proc");
[email protected]528c56d2010-07-30 19:28:4437 stat_file = stat_file.Append(base::IntToString(pid));
[email protected]0c557f12009-05-11 23:35:5238 stat_file = stat_file.Append("stat");
39 std::string mem_stats;
40 if (!file_util::ReadFileToString(stat_file, &mem_stats))
[email protected]c47d81d2010-10-05 23:41:0441 return false;
[email protected]0c557f12009-05-11 23:35:5242 SplitString(mem_stats, ' ', proc_stats);
[email protected]c47d81d2010-10-05 23:41:0443 return true;
44}
45
46// Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command
47// line arguments. Returns true if successful.
48// Note: /proc/<pid>/cmdline contains command line arguments separated by single
49// null characters. We tokenize it into a vector of strings using '\0' as a
50// delimiter.
51bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
52 FilePath cmd_line_file("/proc");
53 cmd_line_file = cmd_line_file.Append(base::IntToString(pid));
54 cmd_line_file = cmd_line_file.Append("cmdline");
55 std::string cmd_line;
56 if (!file_util::ReadFileToString(cmd_line_file, &cmd_line))
57 return false;
58 std::string delimiters;
59 delimiters.push_back('\0');
60 Tokenize(cmd_line, delimiters, proc_cmd_line_args);
61 return true;
[email protected]0c557f12009-05-11 23:35:5262}
63
[email protected]0b100bc8b2008-10-14 20:49:1664} // namespace
65
[email protected]176aa482008-11-14 03:25:1566namespace base {
[email protected]0b100bc8b2008-10-14 20:49:1667
[email protected]78c6dd62009-06-08 23:29:1168ProcessId GetParentProcessId(ProcessHandle process) {
69 FilePath stat_file("/proc");
[email protected]528c56d2010-07-30 19:28:4470 stat_file = stat_file.Append(base::IntToString(process));
[email protected]78c6dd62009-06-08 23:29:1171 stat_file = stat_file.Append("status");
72 std::string status;
73 if (!file_util::ReadFileToString(stat_file, &status))
74 return -1;
75
76 StringTokenizer tokenizer(status, ":\n");
77 ParsingState state = KEY_NAME;
78 std::string last_key_name;
79 while (tokenizer.GetNext()) {
80 switch (state) {
81 case KEY_NAME:
82 last_key_name = tokenizer.token();
83 state = KEY_VALUE;
84 break;
85 case KEY_VALUE:
86 DCHECK(!last_key_name.empty());
87 if (last_key_name == "PPid") {
[email protected]528c56d2010-07-30 19:28:4488 int ppid;
89 base::StringToInt(tokenizer.token(), &ppid);
[email protected]78c6dd62009-06-08 23:29:1190 return ppid;
91 }
92 state = KEY_NAME;
93 break;
94 }
95 }
96 NOTREACHED();
97 return -1;
98}
99
100FilePath GetProcessExecutablePath(ProcessHandle process) {
101 FilePath stat_file("/proc");
[email protected]528c56d2010-07-30 19:28:44102 stat_file = stat_file.Append(base::IntToString(process));
[email protected]78c6dd62009-06-08 23:29:11103 stat_file = stat_file.Append("exe");
104 char exename[2048];
105 ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename));
106 if (len < 1) {
107 // No such process. Happens frequently in e.g. TerminateAllChromeProcesses
108 return FilePath();
109 }
110 return FilePath(std::string(exename, len));
111}
112
[email protected]b6128aa2010-04-29 17:44:42113ProcessIterator::ProcessIterator(const ProcessFilter* filter)
114 : filter_(filter) {
[email protected]99c062e2009-01-21 13:41:42115 procfs_dir_ = opendir("/proc");
116}
[email protected]ab0e2222008-10-31 20:19:43117
[email protected]b6128aa2010-04-29 17:44:42118ProcessIterator::~ProcessIterator() {
[email protected]ab0e2222008-10-31 20:19:43119 if (procfs_dir_) {
120 closedir(procfs_dir_);
[email protected]99c062e2009-01-21 13:41:42121 procfs_dir_ = NULL;
[email protected]ab0e2222008-10-31 20:19:43122 }
123}
124
[email protected]b6128aa2010-04-29 17:44:42125bool ProcessIterator::CheckForNextProcess() {
[email protected]ab0e2222008-10-31 20:19:43126 // TODO(port): skip processes owned by different UID
127
128 dirent* slot = 0;
129 const char* openparen;
130 const char* closeparen;
[email protected]c47d81d2010-10-05 23:41:04131 std::vector<std::string> cmd_line_args;
[email protected]ab0e2222008-10-31 20:19:43132
[email protected]99c062e2009-01-21 13:41:42133 // Arbitrarily guess that there will never be more than 200 non-process
134 // files in /proc. Hardy has 53.
[email protected]ab0e2222008-10-31 20:19:43135 int skipped = 0;
136 const int kSkipLimit = 200;
137 while (skipped < kSkipLimit) {
138 slot = readdir(procfs_dir_);
139 // all done looking through /proc?
140 if (!slot)
141 return false;
142
143 // If not a process, keep looking for one.
144 bool notprocess = false;
145 int i;
[email protected]99c062e2009-01-21 13:41:42146 for (i = 0; i < NAME_MAX && slot->d_name[i]; ++i) {
[email protected]ab0e2222008-10-31 20:19:43147 if (!isdigit(slot->d_name[i])) {
148 notprocess = true;
149 break;
150 }
151 }
152 if (i == NAME_MAX || notprocess) {
153 skipped++;
154 continue;
155 }
156
[email protected]c47d81d2010-10-05 23:41:04157 // Read the process's command line.
158 std::string pid_string(slot->d_name);
159 int pid;
160 if (StringToInt(pid_string, &pid) && !GetProcCmdline(pid, &cmd_line_args))
161 return false;
162
[email protected]ab0e2222008-10-31 20:19:43163 // Read the process's status.
164 char buf[NAME_MAX + 12];
165 sprintf(buf, "/proc/%s/stat", slot->d_name);
166 FILE *fp = fopen(buf, "r");
167 if (!fp)
168 return false;
169 const char* result = fgets(buf, sizeof(buf), fp);
170 fclose(fp);
171 if (!result)
172 return false;
173
174 // Parse the status. It is formatted like this:
[email protected]b6128aa2010-04-29 17:44:42175 // %d (%s) %c %d %d ...
176 // pid (name) runstate ppid gid
[email protected]99c062e2009-01-21 13:41:42177 // To avoid being fooled by names containing a closing paren, scan
178 // backwards.
[email protected]ab0e2222008-10-31 20:19:43179 openparen = strchr(buf, '(');
180 closeparen = strrchr(buf, ')');
181 if (!openparen || !closeparen)
182 return false;
183 char runstate = closeparen[2];
184
185 // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
186 // Allowed values: D R S T Z
187 if (runstate != 'Z')
188 break;
189
190 // Nope, it's a zombie; somebody isn't cleaning up after their children.
191 // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
192 // There could be a lot of zombies, can't really decrement i here.
193 }
194 if (skipped >= kSkipLimit) {
195 NOTREACHED();
196 return false;
197 }
198
[email protected]b6128aa2010-04-29 17:44:42199 // This seems fragile.
200 entry_.pid_ = atoi(slot->d_name);
201 entry_.ppid_ = atoi(closeparen + 3);
202 entry_.gid_ = atoi(strchr(closeparen + 4, ' '));
[email protected]ab0e2222008-10-31 20:19:43203
[email protected]c47d81d2010-10-05 23:41:04204 entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
205
[email protected]99c062e2009-01-21 13:41:42206 // TODO(port): read pid's commandline's $0, like killall does. Using the
207 // short name between openparen and closeparen won't work for long names!
[email protected]ab0e2222008-10-31 20:19:43208 int len = closeparen - openparen - 1;
[email protected]b6128aa2010-04-29 17:44:42209 entry_.exe_file_.assign(openparen + 1, len);
[email protected]ab0e2222008-10-31 20:19:43210 return true;
211}
212
213bool NamedProcessIterator::IncludeEntry() {
214 // TODO(port): make this also work for non-ASCII filenames
[email protected]b6128aa2010-04-29 17:44:42215 if (WideToASCII(executable_name_) != entry().exe_file())
[email protected]99c062e2009-01-21 13:41:42216 return false;
[email protected]b6128aa2010-04-29 17:44:42217 return ProcessIterator::IncludeEntry();
218}
219
220
221ProcessMetrics::ProcessMetrics(ProcessHandle process)
222 : process_(process),
223 last_time_(0),
224 last_system_time_(0),
225 last_cpu_(0) {
226 processor_count_ = base::SysInfo::NumberOfProcessors();
227}
228
229// static
230ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
231 return new ProcessMetrics(process);
[email protected]ab0e2222008-10-31 20:19:43232}
233
[email protected]0c557f12009-05-11 23:35:52234// On linux, we return vsize.
235size_t ProcessMetrics::GetPagefileUsage() const {
236 std::vector<std::string> proc_stats;
[email protected]c47d81d2010-10-05 23:41:04237 if (!GetProcStats(process_, &proc_stats))
238 LOG(WARNING) << "Failed to get process stats.";
[email protected]0c557f12009-05-11 23:35:52239 const size_t kVmSize = 22;
[email protected]528c56d2010-07-30 19:28:44240 if (proc_stats.size() > kVmSize) {
241 int vm_size;
242 base::StringToInt(proc_stats[kVmSize], &vm_size);
243 return static_cast<size_t>(vm_size);
244 }
[email protected]0c557f12009-05-11 23:35:52245 return 0;
246}
247
[email protected]1d775f62009-07-22 13:44:48248// On linux, we return the high water mark of vsize.
[email protected]0c557f12009-05-11 23:35:52249size_t ProcessMetrics::GetPeakPagefileUsage() const {
[email protected]1d775f62009-07-22 13:44:48250 std::vector<std::string> proc_stats;
[email protected]c47d81d2010-10-05 23:41:04251 if (!GetProcStats(process_, &proc_stats))
252 LOG(WARNING) << "Failed to get process stats.";
[email protected]1d775f62009-07-22 13:44:48253 const size_t kVmPeak = 21;
[email protected]528c56d2010-07-30 19:28:44254 if (proc_stats.size() > kVmPeak) {
255 int vm_peak;
256 if (base::StringToInt(proc_stats[kVmPeak], &vm_peak))
257 return vm_peak;
258 }
[email protected]0c557f12009-05-11 23:35:52259 return 0;
260}
261
262// On linux, we return RSS.
263size_t ProcessMetrics::GetWorkingSetSize() const {
264 std::vector<std::string> proc_stats;
[email protected]c47d81d2010-10-05 23:41:04265 if (!GetProcStats(process_, &proc_stats))
266 LOG(WARNING) << "Failed to get process stats.";
[email protected]0c557f12009-05-11 23:35:52267 const size_t kVmRss = 23;
268 if (proc_stats.size() > kVmRss) {
[email protected]528c56d2010-07-30 19:28:44269 int num_pages;
270 if (base::StringToInt(proc_stats[kVmRss], &num_pages))
271 return static_cast<size_t>(num_pages) * getpagesize();
[email protected]0c557f12009-05-11 23:35:52272 }
273 return 0;
274}
275
[email protected]1d775f62009-07-22 13:44:48276// On linux, we return the high water mark of RSS.
[email protected]0c557f12009-05-11 23:35:52277size_t ProcessMetrics::GetPeakWorkingSetSize() const {
[email protected]1d775f62009-07-22 13:44:48278 std::vector<std::string> proc_stats;
[email protected]c47d81d2010-10-05 23:41:04279 if (!GetProcStats(process_, &proc_stats))
280 LOG(WARNING) << "Failed to get process stats.";
[email protected]1d775f62009-07-22 13:44:48281 const size_t kVmHwm = 23;
282 if (proc_stats.size() > kVmHwm) {
[email protected]528c56d2010-07-30 19:28:44283 int num_pages;
284 base::StringToInt(proc_stats[kVmHwm], &num_pages);
285 return static_cast<size_t>(num_pages) * getpagesize();
[email protected]1d775f62009-07-22 13:44:48286 }
[email protected]0c557f12009-05-11 23:35:52287 return 0;
288}
289
[email protected]98947a02010-05-11 17:46:08290bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
291 size_t* shared_bytes) {
[email protected]9bb48aa2009-10-07 22:54:48292 WorkingSetKBytes ws_usage;
[email protected]98947a02010-05-11 17:46:08293 if (!GetWorkingSetKBytes(&ws_usage))
294 return false;
295
296 if (private_bytes)
297 *private_bytes = ws_usage.priv << 10;
298
299 if (shared_bytes)
300 *shared_bytes = ws_usage.shared * 1024;
301
302 return true;
[email protected]0da192212009-05-14 14:01:58303}
304
[email protected]7dcac982009-11-04 22:26:03305// Private and Shared working set sizes are obtained from /proc/<pid>/smaps.
306// When that's not available, use the values from /proc<pid>/statm as a
307// close approximation.
308// See http://www.pixelbeat.org/scripts/ps_mem.py
[email protected]0da192212009-05-14 14:01:58309bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
[email protected]1d775f62009-07-22 13:44:48310 FilePath stat_file =
[email protected]528c56d2010-07-30 19:28:44311 FilePath("/proc").Append(base::IntToString(process_)).Append("smaps");
[email protected]1d775f62009-07-22 13:44:48312 std::string smaps;
[email protected]1d775f62009-07-22 13:44:48313 int private_kb = 0;
314 int pss_kb = 0;
315 bool have_pss = false;
[email protected]7dcac982009-11-04 22:26:03316 if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) {
[email protected]3b6711ea2010-05-12 16:49:35317 const std::string private_prefix = "Private_";
318 const std::string pss_prefix = "Pss";
[email protected]7dcac982009-11-04 22:26:03319 StringTokenizer tokenizer(smaps, ":\n");
[email protected]3b6711ea2010-05-12 16:49:35320 StringPiece last_key_name;
[email protected]7dcac982009-11-04 22:26:03321 ParsingState state = KEY_NAME;
[email protected]7dcac982009-11-04 22:26:03322 while (tokenizer.GetNext()) {
323 switch (state) {
324 case KEY_NAME:
[email protected]3b6711ea2010-05-12 16:49:35325 last_key_name = tokenizer.token_piece();
[email protected]7dcac982009-11-04 22:26:03326 state = KEY_VALUE;
327 break;
328 case KEY_VALUE:
329 if (last_key_name.empty()) {
330 NOTREACHED();
331 return false;
332 }
[email protected]3b6711ea2010-05-12 16:49:35333 if (last_key_name.starts_with(private_prefix)) {
[email protected]528c56d2010-07-30 19:28:44334 int cur;
335 base::StringToInt(tokenizer.token(), &cur);
336 private_kb += cur;
[email protected]3b6711ea2010-05-12 16:49:35337 } else if (last_key_name.starts_with(pss_prefix)) {
[email protected]7dcac982009-11-04 22:26:03338 have_pss = true;
[email protected]528c56d2010-07-30 19:28:44339 int cur;
340 base::StringToInt(tokenizer.token(), &cur);
341 pss_kb += cur;
[email protected]7dcac982009-11-04 22:26:03342 }
343 state = KEY_NAME;
344 break;
345 }
[email protected]1d775f62009-07-22 13:44:48346 }
[email protected]7dcac982009-11-04 22:26:03347 } else {
348 // Try statm if smaps is empty because of the SUID sandbox.
349 // First we need to get the page size though.
350 int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024;
351 if (page_size_kb <= 0)
352 return false;
353
354 stat_file =
[email protected]528c56d2010-07-30 19:28:44355 FilePath("/proc").Append(base::IntToString(process_)).Append("statm");
[email protected]7dcac982009-11-04 22:26:03356 std::string statm;
357 if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0)
358 return false;
359
360 std::vector<std::string> statm_vec;
361 SplitString(statm, ' ', &statm_vec);
362 if (statm_vec.size() != 7)
363 return false; // Not the format we expect.
[email protected]528c56d2010-07-30 19:28:44364
365 int statm1, statm2;
366 base::StringToInt(statm_vec[1], &statm1);
367 base::StringToInt(statm_vec[2], &statm2);
368 private_kb = (statm1 - statm2) * page_size_kb;
[email protected]1d775f62009-07-22 13:44:48369 }
370 ws_usage->priv = private_kb;
371 // Sharable is not calculated, as it does not provide interesting data.
372 ws_usage->shareable = 0;
[email protected]54fd1d32009-09-01 00:12:58373
374 ws_usage->shared = 0;
375 if (have_pss)
376 ws_usage->shared = pss_kb;
[email protected]1d775f62009-07-22 13:44:48377 return true;
[email protected]0da192212009-05-14 14:01:58378}
379
[email protected]0b100bc8b2008-10-14 20:49:16380// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
381// in your kernel configuration.
[email protected]d043c2cc2009-03-25 18:30:45382bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
[email protected]0b100bc8b2008-10-14 20:49:16383 std::string proc_io_contents;
[email protected]0c557f12009-05-11 23:35:52384 FilePath io_file("/proc");
[email protected]528c56d2010-07-30 19:28:44385 io_file = io_file.Append(base::IntToString(process_));
[email protected]0c557f12009-05-11 23:35:52386 io_file = io_file.Append("io");
387 if (!file_util::ReadFileToString(io_file, &proc_io_contents))
[email protected]0b100bc8b2008-10-14 20:49:16388 return false;
389
390 (*io_counters).OtherOperationCount = 0;
391 (*io_counters).OtherTransferCount = 0;
392
393 StringTokenizer tokenizer(proc_io_contents, ": \n");
394 ParsingState state = KEY_NAME;
395 std::string last_key_name;
396 while (tokenizer.GetNext()) {
397 switch (state) {
398 case KEY_NAME:
399 last_key_name = tokenizer.token();
400 state = KEY_VALUE;
401 break;
402 case KEY_VALUE:
403 DCHECK(!last_key_name.empty());
404 if (last_key_name == "syscr") {
[email protected]528c56d2010-07-30 19:28:44405 base::StringToInt64(tokenizer.token(),
406 reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount));
[email protected]0b100bc8b2008-10-14 20:49:16407 } else if (last_key_name == "syscw") {
[email protected]528c56d2010-07-30 19:28:44408 base::StringToInt64(tokenizer.token(),
409 reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount));
[email protected]0b100bc8b2008-10-14 20:49:16410 } else if (last_key_name == "rchar") {
[email protected]528c56d2010-07-30 19:28:44411 base::StringToInt64(tokenizer.token(),
412 reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount));
[email protected]0b100bc8b2008-10-14 20:49:16413 } else if (last_key_name == "wchar") {
[email protected]528c56d2010-07-30 19:28:44414 base::StringToInt64(tokenizer.token(),
415 reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount));
[email protected]0b100bc8b2008-10-14 20:49:16416 }
417 state = KEY_NAME;
418 break;
419 }
420 }
421 return true;
422}
423
[email protected]d2ed23832009-09-19 01:57:39424
425// Exposed for testing.
426int ParseProcStatCPU(const std::string& input) {
427 // /proc/<pid>/stat contains the process name in parens. In case the
428 // process name itself contains parens, skip past them.
429 std::string::size_type rparen = input.rfind(')');
430 if (rparen == std::string::npos)
431 return -1;
432
433 // From here, we expect a bunch of space-separated fields, where the
434 // 0-indexed 11th and 12th are utime and stime. On two different machines
435 // I found 42 and 39 fields, so let's just expect the ones we need.
436 std::vector<std::string> fields;
437 SplitString(input.substr(rparen + 2), ' ', &fields);
438 if (fields.size() < 13)
439 return -1; // Output not in the format we expect.
440
[email protected]528c56d2010-07-30 19:28:44441 int fields11, fields12;
442 base::StringToInt(fields[11], &fields11);
443 base::StringToInt(fields[12], &fields12);
444 return fields11 + fields12;
[email protected]d2ed23832009-09-19 01:57:39445}
446
447// Get the total CPU of a single process. Return value is number of jiffies
448// on success or -1 on error.
449static int GetProcessCPU(pid_t pid) {
450 // Use /proc/<pid>/task to find all threads and parse their /stat file.
451 FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid));
452
453 DIR* dir = opendir(path.value().c_str());
454 if (!dir) {
[email protected]57b765672009-10-13 18:27:40455 PLOG(ERROR) << "opendir(" << path.value() << ")";
[email protected]d2ed23832009-09-19 01:57:39456 return -1;
457 }
458
459 int total_cpu = 0;
460 while (struct dirent* ent = readdir(dir)) {
461 if (ent->d_name[0] == '.')
462 continue;
463
464 FilePath stat_path = path.AppendASCII(ent->d_name).AppendASCII("stat");
465 std::string stat;
466 if (file_util::ReadFileToString(stat_path, &stat)) {
467 int cpu = ParseProcStatCPU(stat);
468 if (cpu > 0)
469 total_cpu += cpu;
470 }
471 }
472 closedir(dir);
473
474 return total_cpu;
475}
476
[email protected]022eab62010-01-13 04:55:06477double ProcessMetrics::GetCPUUsage() {
[email protected]d2ed23832009-09-19 01:57:39478 // This queries the /proc-specific scaling factor which is
479 // conceptually the system hertz. To dump this value on another
480 // system, try
481 // od -t dL /proc/self/auxv
482 // and look for the number after 17 in the output; mine is
483 // 0000040 17 100 3 134512692
484 // which means the answer is 100.
485 // It may be the case that this value is always 100.
486 static const int kHertz = sysconf(_SC_CLK_TCK);
487
488 struct timeval now;
489 int retval = gettimeofday(&now, NULL);
490 if (retval)
491 return 0;
492 int64 time = TimeValToMicroseconds(now);
493
494 if (last_time_ == 0) {
495 // First call, just set the last values.
496 last_time_ = time;
497 last_cpu_ = GetProcessCPU(process_);
498 return 0;
499 }
500
501 int64 time_delta = time - last_time_;
[email protected]7dcac982009-11-04 22:26:03502 DCHECK_NE(time_delta, 0);
[email protected]d2ed23832009-09-19 01:57:39503 if (time_delta == 0)
504 return 0;
505
506 int cpu = GetProcessCPU(process_);
507
508 // We have the number of jiffies in the time period. Convert to percentage.
509 // Note this means we will go *over* 100 in the case where multiple threads
510 // are together adding to more than one CPU's worth.
511 int percentage = 100 * (cpu - last_cpu_) /
512 (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF());
513
514 last_time_ = time;
515 last_cpu_ = cpu;
516
517 return percentage;
518}
519
[email protected]ed26d942009-11-09 06:57:28520namespace {
521
522// The format of /proc/meminfo is:
523//
524// MemTotal: 8235324 kB
525// MemFree: 1628304 kB
526// Buffers: 429596 kB
527// Cached: 4728232 kB
528// ...
529const size_t kMemTotalIndex = 1;
530const size_t kMemFreeIndex = 4;
531const size_t kMemBuffersIndex = 7;
532const size_t kMemCacheIndex = 10;
533
534} // namespace
535
536size_t GetSystemCommitCharge() {
537 // Used memory is: total - free - buffers - caches
538 FilePath meminfo_file("/proc/meminfo");
539 std::string meminfo_data;
[email protected]66d0a942009-11-13 22:55:29540 if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) {
541 LOG(WARNING) << "Failed to open /proc/meminfo.";
[email protected]ed26d942009-11-09 06:57:28542 return 0;
[email protected]66d0a942009-11-13 22:55:29543 }
[email protected]ed26d942009-11-09 06:57:28544 std::vector<std::string> meminfo_fields;
545 SplitStringAlongWhitespace(meminfo_data, &meminfo_fields);
546
547 if (meminfo_fields.size() < kMemCacheIndex) {
[email protected]66d0a942009-11-13 22:55:29548 LOG(WARNING) << "Failed to parse /proc/meminfo. Only found " <<
[email protected]ed26d942009-11-09 06:57:28549 meminfo_fields.size() << " fields.";
550 return 0;
551 }
552
553 DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:");
554 DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:");
555 DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:");
556 DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:");
557
[email protected]528c56d2010-07-30 19:28:44558 int mem_total, mem_free, mem_buffers, mem_cache;
559 base::StringToInt(meminfo_fields[kMemTotalIndex], &mem_total);
560 base::StringToInt(meminfo_fields[kMemFreeIndex], &mem_free);
561 base::StringToInt(meminfo_fields[kMemBuffersIndex], &mem_buffers);
562 base::StringToInt(meminfo_fields[kMemCacheIndex], &mem_cache);
[email protected]ed26d942009-11-09 06:57:28563
[email protected]528c56d2010-07-30 19:28:44564 return mem_total - mem_free - mem_buffers - mem_cache;
[email protected]ed26d942009-11-09 06:57:28565}
566
[email protected]9be42c82009-11-18 21:10:57567namespace {
568
569void OnNoMemorySize(size_t size) {
570 if (size != 0)
[email protected]8e6b2c1c2010-05-05 00:43:22571 LOG(FATAL) << "Out of memory, size = " << size;
572 LOG(FATAL) << "Out of memory.";
[email protected]9be42c82009-11-18 21:10:57573}
574
575void OnNoMemory() {
576 OnNoMemorySize(0);
577}
578
579} // namespace
580
581extern "C" {
[email protected]61a9b2d82010-02-26 00:31:08582#if !defined(USE_TCMALLOC)
[email protected]9be42c82009-11-18 21:10:57583
[email protected]78711ce42010-01-08 21:28:27584extern "C" {
585void* __libc_malloc(size_t size);
586void* __libc_realloc(void* ptr, size_t size);
587void* __libc_calloc(size_t nmemb, size_t size);
588void* __libc_valloc(size_t size);
589void* __libc_pvalloc(size_t size);
590void* __libc_memalign(size_t alignment, size_t size);
591} // extern "C"
[email protected]9be42c82009-11-18 21:10:57592
[email protected]78711ce42010-01-08 21:28:27593// Overriding the system memory allocation functions:
594//
595// For security reasons, we want malloc failures to be fatal. Too much code
596// doesn't check for a NULL return value from malloc and unconditionally uses
597// the resulting pointer. If the first offset that they try to access is
598// attacker controlled, then the attacker can direct the code to access any
599// part of memory.
600//
601// Thus, we define all the standard malloc functions here and mark them as
602// visibility 'default'. This means that they replace the malloc functions for
603// all Chromium code and also for all code in shared libraries. There are tests
604// for this in process_util_unittest.cc.
605//
606// If we are using tcmalloc, then the problem is moot since tcmalloc handles
[email protected]61a9b2d82010-02-26 00:31:08607// this for us. Thus this code is in a !defined(USE_TCMALLOC) block.
[email protected]78711ce42010-01-08 21:28:27608//
609// We call the real libc functions in this code by using __libc_malloc etc.
610// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on
611// the link order. Since ld.so needs calloc during symbol resolution, it
612// defines its own versions of several of these functions in dl-minimal.c.
613// Depending on the runtime library order, dlsym ended up giving us those
614// functions and bad things happened. See crbug.com/31809
615//
616// This means that any code which calls __libc_* gets the raw libc versions of
617// these functions.
[email protected]9be42c82009-11-18 21:10:57618
[email protected]9be42c82009-11-18 21:10:57619#define DIE_ON_OOM_1(function_name) \
[email protected]78711ce42010-01-08 21:28:27620 void* function_name(size_t) __attribute__ ((visibility("default"))); \
621 \
[email protected]9be42c82009-11-18 21:10:57622 void* function_name(size_t size) { \
[email protected]78711ce42010-01-08 21:28:27623 void* ret = __libc_##function_name(size); \
[email protected]9be42c82009-11-18 21:10:57624 if (ret == NULL && size != 0) \
625 OnNoMemorySize(size); \
626 return ret; \
627 }
628
[email protected]78711ce42010-01-08 21:28:27629#define DIE_ON_OOM_2(function_name, arg1_type) \
630 void* function_name(arg1_type, size_t) \
631 __attribute__ ((visibility("default"))); \
632 \
[email protected]9be42c82009-11-18 21:10:57633 void* function_name(arg1_type arg1, size_t size) { \
[email protected]78711ce42010-01-08 21:28:27634 void* ret = __libc_##function_name(arg1, size); \
[email protected]9be42c82009-11-18 21:10:57635 if (ret == NULL && size != 0) \
636 OnNoMemorySize(size); \
637 return ret; \
638 }
639
[email protected]9be42c82009-11-18 21:10:57640DIE_ON_OOM_1(malloc)
641DIE_ON_OOM_1(valloc)
642DIE_ON_OOM_1(pvalloc)
643
[email protected]78711ce42010-01-08 21:28:27644DIE_ON_OOM_2(calloc, size_t)
[email protected]9be42c82009-11-18 21:10:57645DIE_ON_OOM_2(realloc, void*)
646DIE_ON_OOM_2(memalign, size_t)
647
[email protected]7dcd4d52009-11-24 19:34:35648// posix_memalign has a unique signature and doesn't have a __libc_ variant.
[email protected]78711ce42010-01-08 21:28:27649int posix_memalign(void** ptr, size_t alignment, size_t size)
650 __attribute__ ((visibility("default")));
651
[email protected]7dcd4d52009-11-24 19:34:35652int posix_memalign(void** ptr, size_t alignment, size_t size) {
[email protected]78711ce42010-01-08 21:28:27653 // This will use the safe version of memalign, above.
654 *ptr = memalign(alignment, size);
655 return 0;
[email protected]7dcd4d52009-11-24 19:34:35656}
[email protected]9be42c82009-11-18 21:10:57657
[email protected]61a9b2d82010-02-26 00:31:08658#endif // !defined(USE_TCMALLOC)
[email protected]9be42c82009-11-18 21:10:57659} // extern C
660
[email protected]cccb21212009-11-12 20:39:56661void EnableTerminationOnOutOfMemory() {
[email protected]9be42c82009-11-18 21:10:57662 // Set the new-out of memory handler.
663 std::set_new_handler(&OnNoMemory);
664 // If we're using glibc's allocator, the above functions will override
665 // malloc and friends and make them die on out of memory.
[email protected]cccb21212009-11-12 20:39:56666}
667
[email protected]e5856a7a2009-12-10 02:08:10668bool AdjustOOMScore(ProcessId process, int score) {
669 if (score < 0 || score > 15)
670 return false;
671
672 FilePath oom_adj("/proc");
[email protected]528c56d2010-07-30 19:28:44673 oom_adj = oom_adj.Append(base::Int64ToString(process));
[email protected]e5856a7a2009-12-10 02:08:10674 oom_adj = oom_adj.AppendASCII("oom_adj");
675
676 if (!file_util::PathExists(oom_adj))
677 return false;
678
[email protected]528c56d2010-07-30 19:28:44679 std::string score_str = base::IntToString(score);
[email protected]e5856a7a2009-12-10 02:08:10680 return (static_cast<int>(score_str.length()) ==
681 file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length()));
682}
683
[email protected]176aa482008-11-14 03:25:15684} // namespace base