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

Side by Side Diff: base/process_util_linux.cc

Issue 12087091: Move string tokenizer to base/strings. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sort Created 7 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/debug/trace_event_impl.cc ('k') | base/string_tokenizer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/process_util.h" 5 #include "base/process_util.h"
6 6
7 #include <dirent.h> 7 #include <dirent.h>
8 #include <malloc.h> 8 #include <malloc.h>
9 #include <sys/time.h> 9 #include <sys/time.h>
10 #include <sys/types.h> 10 #include <sys/types.h>
11 #include <unistd.h> 11 #include <unistd.h>
12 12
13 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/string_number_conversions.h" 15 #include "base/string_number_conversions.h"
16 #include "base/string_split.h" 16 #include "base/string_split.h"
17 #include "base/string_tokenizer.h"
18 #include "base/string_util.h" 17 #include "base/string_util.h"
18 #include "base/strings/string_tokenizer.h"
19 #include "base/sys_info.h" 19 #include "base/sys_info.h"
20 #include "base/threading/thread_restrictions.h" 20 #include "base/threading/thread_restrictions.h"
21 21
22 namespace base {
23
22 namespace { 24 namespace {
23 25
24 enum ParsingState { 26 enum ParsingState {
25 KEY_NAME, 27 KEY_NAME,
26 KEY_VALUE 28 KEY_VALUE
27 }; 29 };
28 30
29 const char kProcDir[] = "/proc"; 31 const char kProcDir[] = "/proc";
30 const char kStatFile[] = "stat"; 32 const char kStatFile[] = "stat";
31 33
32 // Returns a FilePath to "/proc/pid". 34 // Returns a FilePath to "/proc/pid".
33 FilePath GetProcPidDir(pid_t pid) { 35 FilePath GetProcPidDir(pid_t pid) {
34 return FilePath(kProcDir).Append(base::IntToString(pid)); 36 return FilePath(kProcDir).Append(IntToString(pid));
35 } 37 }
36 38
37 // Fields from /proc/<pid>/stat, 0-based. See man 5 proc. 39 // Fields from /proc/<pid>/stat, 0-based. See man 5 proc.
38 // If the ordering ever changes, carefully review functions that use these 40 // If the ordering ever changes, carefully review functions that use these
39 // values. 41 // values.
40 enum ProcStatsFields { 42 enum ProcStatsFields {
41 VM_COMM = 1, // Filename of executable, without parentheses. 43 VM_COMM = 1, // Filename of executable, without parentheses.
42 VM_STATE = 2, // Letter indicating the state of the process. 44 VM_STATE = 2, // Letter indicating the state of the process.
43 VM_PPID = 3, // PID of the parent. 45 VM_PPID = 3, // PID of the parent.
44 VM_PGRP = 4, // Process group id. 46 VM_PGRP = 4, // Process group id.
45 VM_UTIME = 13, // Time scheduled in user mode in clock ticks. 47 VM_UTIME = 13, // Time scheduled in user mode in clock ticks.
46 VM_STIME = 14, // Time scheduled in kernel mode in clock ticks. 48 VM_STIME = 14, // Time scheduled in kernel mode in clock ticks.
47 VM_VSIZE = 22, // Virtual memory size in bytes. 49 VM_VSIZE = 22, // Virtual memory size in bytes.
48 VM_RSS = 23, // Resident Set Size in pages. 50 VM_RSS = 23, // Resident Set Size in pages.
49 }; 51 };
50 52
51 // Reads /proc/<pid>/stat into |buffer|. Returns true if the file can be read 53 // Reads /proc/<pid>/stat into |buffer|. Returns true if the file can be read
52 // and is non-empty. 54 // and is non-empty.
53 bool ReadProcStats(pid_t pid, std::string* buffer) { 55 bool ReadProcStats(pid_t pid, std::string* buffer) {
54 buffer->clear(); 56 buffer->clear();
55 // Synchronously reading files in /proc is safe. 57 // Synchronously reading files in /proc is safe.
56 base::ThreadRestrictions::ScopedAllowIO allow_io; 58 ThreadRestrictions::ScopedAllowIO allow_io;
57 59
58 FilePath stat_file = GetProcPidDir(pid).Append(kStatFile); 60 FilePath stat_file = GetProcPidDir(pid).Append(kStatFile);
59 if (!file_util::ReadFileToString(stat_file, buffer)) { 61 if (!file_util::ReadFileToString(stat_file, buffer)) {
60 DLOG(WARNING) << "Failed to get process stats."; 62 DLOG(WARNING) << "Failed to get process stats.";
61 return false; 63 return false;
62 } 64 }
63 return !buffer->empty(); 65 return !buffer->empty();
64 } 66 }
65 67
66 // Takes |stats_data| and populates |proc_stats| with the values split by 68 // Takes |stats_data| and populates |proc_stats| with the values split by
(...skipping 24 matching lines...) Expand all
91 proc_stats->clear(); 93 proc_stats->clear();
92 // PID. 94 // PID.
93 proc_stats->push_back(stats_data.substr(0, open_parens_idx)); 95 proc_stats->push_back(stats_data.substr(0, open_parens_idx));
94 // Process name without parentheses. 96 // Process name without parentheses.
95 proc_stats->push_back( 97 proc_stats->push_back(
96 stats_data.substr(open_parens_idx + 1, 98 stats_data.substr(open_parens_idx + 1,
97 close_parens_idx - (open_parens_idx + 1))); 99 close_parens_idx - (open_parens_idx + 1)));
98 100
99 // Split the rest. 101 // Split the rest.
100 std::vector<std::string> other_stats; 102 std::vector<std::string> other_stats;
101 base::SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats); 103 SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats);
102 for (size_t i = 0; i < other_stats.size(); ++i) 104 for (size_t i = 0; i < other_stats.size(); ++i)
103 proc_stats->push_back(other_stats[i]); 105 proc_stats->push_back(other_stats[i]);
104 return true; 106 return true;
105 } 107 }
106 108
107 // Reads the |field_num|th field from |proc_stats|. Returns 0 on failure. 109 // Reads the |field_num|th field from |proc_stats|. Returns 0 on failure.
108 // This version does not handle the first 3 values, since the first value is 110 // This version does not handle the first 3 values, since the first value is
109 // simply |pid|, and the next two values are strings. 111 // simply |pid|, and the next two values are strings.
110 int GetProcStatsFieldAsInt(const std::vector<std::string>& proc_stats, 112 int GetProcStatsFieldAsInt(const std::vector<std::string>& proc_stats,
111 ProcStatsFields field_num) { 113 ProcStatsFields field_num) {
112 DCHECK_GE(field_num, VM_PPID); 114 DCHECK_GE(field_num, VM_PPID);
113 CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); 115 CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
114 116
115 int value; 117 int value;
116 return base::StringToInt(proc_stats[field_num], &value) ? value : 0; 118 return StringToInt(proc_stats[field_num], &value) ? value : 0;
117 } 119 }
118 120
119 // Same as GetProcStatsFieldAsInt(), but for size_t values. 121 // Same as GetProcStatsFieldAsInt(), but for size_t values.
120 size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats, 122 size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
121 ProcStatsFields field_num) { 123 ProcStatsFields field_num) {
122 DCHECK_GE(field_num, VM_PPID); 124 DCHECK_GE(field_num, VM_PPID);
123 CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); 125 CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
124 126
125 size_t value; 127 size_t value;
126 return base::StringToSizeT(proc_stats[field_num], &value) ? value : 0; 128 return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
127 } 129 }
128 130
129 // Convenience wrapper around GetProcStatsFieldAsInt(), ParseProcStats() and 131 // Convenience wrapper around GetProcStatsFieldAsInt(), ParseProcStats() and
130 // ReadProcStats(). See GetProcStatsFieldAsInt() for details. 132 // ReadProcStats(). See GetProcStatsFieldAsInt() for details.
131 int ReadProcStatsAndGetFieldAsInt(pid_t pid, ProcStatsFields field_num) { 133 int ReadProcStatsAndGetFieldAsInt(pid_t pid, ProcStatsFields field_num) {
132 std::string stats_data; 134 std::string stats_data;
133 if (!ReadProcStats(pid, &stats_data)) 135 if (!ReadProcStats(pid, &stats_data))
134 return 0; 136 return 0;
135 std::vector<std::string> proc_stats; 137 std::vector<std::string> proc_stats;
136 if (!ParseProcStats(stats_data, &proc_stats)) 138 if (!ParseProcStats(stats_data, &proc_stats))
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 return 0; 170 return 0;
169 } 171 }
170 172
171 // Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command 173 // Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command
172 // line arguments. Returns true if successful. 174 // line arguments. Returns true if successful.
173 // Note: /proc/<pid>/cmdline contains command line arguments separated by single 175 // Note: /proc/<pid>/cmdline contains command line arguments separated by single
174 // null characters. We tokenize it into a vector of strings using '\0' as a 176 // null characters. We tokenize it into a vector of strings using '\0' as a
175 // delimiter. 177 // delimiter.
176 bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) { 178 bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
177 // Synchronously reading files in /proc is safe. 179 // Synchronously reading files in /proc is safe.
178 base::ThreadRestrictions::ScopedAllowIO allow_io; 180 ThreadRestrictions::ScopedAllowIO allow_io;
179 181
180 FilePath cmd_line_file = GetProcPidDir(pid).Append("cmdline"); 182 FilePath cmd_line_file = GetProcPidDir(pid).Append("cmdline");
181 std::string cmd_line; 183 std::string cmd_line;
182 if (!file_util::ReadFileToString(cmd_line_file, &cmd_line)) 184 if (!file_util::ReadFileToString(cmd_line_file, &cmd_line))
183 return false; 185 return false;
184 std::string delimiters; 186 std::string delimiters;
185 delimiters.push_back('\0'); 187 delimiters.push_back('\0');
186 Tokenize(cmd_line, delimiters, proc_cmd_line_args); 188 Tokenize(cmd_line, delimiters, proc_cmd_line_args);
187 return true; 189 return true;
188 } 190 }
189 191
190 // Take a /proc directory entry named |d_name|, and if it is the directory for 192 // Take a /proc directory entry named |d_name|, and if it is the directory for
191 // a process, convert it to a pid_t. 193 // a process, convert it to a pid_t.
192 // Returns 0 on failure. 194 // Returns 0 on failure.
193 // e.g. /proc/self/ will return 0, whereas /proc/1234 will return 1234. 195 // e.g. /proc/self/ will return 0, whereas /proc/1234 will return 1234.
194 pid_t ProcDirSlotToPid(const char* d_name) { 196 pid_t ProcDirSlotToPid(const char* d_name) {
195 int i; 197 int i;
196 for (i = 0; i < NAME_MAX && d_name[i]; ++i) { 198 for (i = 0; i < NAME_MAX && d_name[i]; ++i) {
197 if (!IsAsciiDigit(d_name[i])) { 199 if (!IsAsciiDigit(d_name[i])) {
198 return 0; 200 return 0;
199 } 201 }
200 } 202 }
201 if (i == NAME_MAX) 203 if (i == NAME_MAX)
202 return 0; 204 return 0;
203 205
204 // Read the process's command line. 206 // Read the process's command line.
205 pid_t pid; 207 pid_t pid;
206 std::string pid_string(d_name); 208 std::string pid_string(d_name);
207 if (!base::StringToInt(pid_string, &pid)) { 209 if (!StringToInt(pid_string, &pid)) {
208 NOTREACHED(); 210 NOTREACHED();
209 return 0; 211 return 0;
210 } 212 }
211 return pid; 213 return pid;
212 } 214 }
213 215
214 // Get the total CPU of a single process. Return value is number of jiffies 216 // Get the total CPU of a single process. Return value is number of jiffies
215 // on success or -1 on error. 217 // on success or -1 on error.
216 int GetProcessCPU(pid_t pid) { 218 int GetProcessCPU(pid_t pid) {
217 // Use /proc/<pid>/task to find all threads and parse their /stat file. 219 // Use /proc/<pid>/task to find all threads and parse their /stat file.
218 FilePath task_path = GetProcPidDir(pid).Append("task"); 220 FilePath task_path = GetProcPidDir(pid).Append("task");
219 221
220 DIR* dir = opendir(task_path.value().c_str()); 222 DIR* dir = opendir(task_path.value().c_str());
221 if (!dir) { 223 if (!dir) {
222 DPLOG(ERROR) << "opendir(" << task_path.value() << ")"; 224 DPLOG(ERROR) << "opendir(" << task_path.value() << ")";
223 return -1; 225 return -1;
224 } 226 }
225 227
226 int total_cpu = 0; 228 int total_cpu = 0;
227 while (struct dirent* ent = readdir(dir)) { 229 while (struct dirent* ent = readdir(dir)) {
228 pid_t tid = ProcDirSlotToPid(ent->d_name); 230 pid_t tid = ProcDirSlotToPid(ent->d_name);
229 if (!tid) 231 if (!tid)
230 continue; 232 continue;
231 233
232 // Synchronously reading files in /proc is safe. 234 // Synchronously reading files in /proc is safe.
233 base::ThreadRestrictions::ScopedAllowIO allow_io; 235 ThreadRestrictions::ScopedAllowIO allow_io;
234 236
235 std::string stat; 237 std::string stat;
236 FilePath stat_path = task_path.Append(ent->d_name).Append(kStatFile); 238 FilePath stat_path = task_path.Append(ent->d_name).Append(kStatFile);
237 if (file_util::ReadFileToString(stat_path, &stat)) { 239 if (file_util::ReadFileToString(stat_path, &stat)) {
238 int cpu = base::ParseProcStatCPU(stat); 240 int cpu = ParseProcStatCPU(stat);
239 if (cpu > 0) 241 if (cpu > 0)
240 total_cpu += cpu; 242 total_cpu += cpu;
241 } 243 }
242 } 244 }
243 closedir(dir); 245 closedir(dir);
244 246
245 return total_cpu; 247 return total_cpu;
246 } 248 }
247 249
248 // Read /proc/<pid>/status and returns the value for |field|, or 0 on failure. 250 // Read /proc/<pid>/status and returns the value for |field|, or 0 on failure.
249 // Only works for fields in the form of "Field: value kB". 251 // Only works for fields in the form of "Field: value kB".
250 size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) { 252 size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) {
251 FilePath stat_file = GetProcPidDir(pid).Append("status"); 253 FilePath stat_file = GetProcPidDir(pid).Append("status");
252 std::string status; 254 std::string status;
253 { 255 {
254 // Synchronously reading files in /proc is safe. 256 // Synchronously reading files in /proc is safe.
255 base::ThreadRestrictions::ScopedAllowIO allow_io; 257 ThreadRestrictions::ScopedAllowIO allow_io;
256 if (!file_util::ReadFileToString(stat_file, &status)) 258 if (!file_util::ReadFileToString(stat_file, &status))
257 return 0; 259 return 0;
258 } 260 }
259 261
260 StringTokenizer tokenizer(status, ":\n"); 262 StringTokenizer tokenizer(status, ":\n");
261 ParsingState state = KEY_NAME; 263 ParsingState state = KEY_NAME;
262 base::StringPiece last_key_name; 264 StringPiece last_key_name;
263 while (tokenizer.GetNext()) { 265 while (tokenizer.GetNext()) {
264 switch (state) { 266 switch (state) {
265 case KEY_NAME: 267 case KEY_NAME:
266 last_key_name = tokenizer.token_piece(); 268 last_key_name = tokenizer.token_piece();
267 state = KEY_VALUE; 269 state = KEY_VALUE;
268 break; 270 break;
269 case KEY_VALUE: 271 case KEY_VALUE:
270 DCHECK(!last_key_name.empty()); 272 DCHECK(!last_key_name.empty());
271 if (last_key_name == field) { 273 if (last_key_name == field) {
272 std::string value_str; 274 std::string value_str;
273 tokenizer.token_piece().CopyToString(&value_str); 275 tokenizer.token_piece().CopyToString(&value_str);
274 std::string value_str_trimmed; 276 std::string value_str_trimmed;
275 TrimWhitespaceASCII(value_str, TRIM_ALL, &value_str_trimmed); 277 TrimWhitespaceASCII(value_str, TRIM_ALL, &value_str_trimmed);
276 std::vector<std::string> split_value_str; 278 std::vector<std::string> split_value_str;
277 base::SplitString(value_str_trimmed, ' ', &split_value_str); 279 SplitString(value_str_trimmed, ' ', &split_value_str);
278 if (split_value_str.size() != 2 || split_value_str[1] != "kB") { 280 if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
279 NOTREACHED(); 281 NOTREACHED();
280 return 0; 282 return 0;
281 } 283 }
282 size_t value; 284 size_t value;
283 if (!base::StringToSizeT(split_value_str[0], &value)) { 285 if (!StringToSizeT(split_value_str[0], &value)) {
284 NOTREACHED(); 286 NOTREACHED();
285 return 0; 287 return 0;
286 } 288 }
287 return value; 289 return value;
288 } 290 }
289 state = KEY_NAME; 291 state = KEY_NAME;
290 break; 292 break;
291 } 293 }
292 } 294 }
293 NOTREACHED(); 295 NOTREACHED();
294 return 0; 296 return 0;
295 } 297 }
296 298
297 } // namespace 299 } // namespace
298 300
299 namespace base {
300
301 #if defined(USE_LINUX_BREAKPAD) 301 #if defined(USE_LINUX_BREAKPAD)
302 size_t g_oom_size = 0U; 302 size_t g_oom_size = 0U;
303 #endif 303 #endif
304 304
305 const char kProcSelfExe[] = "/proc/self/exe"; 305 const char kProcSelfExe[] = "/proc/self/exe";
306 306
307 ProcessId GetParentProcessId(ProcessHandle process) { 307 ProcessId GetParentProcessId(ProcessHandle process) {
308 ProcessId pid = ReadProcStatsAndGetFieldAsInt(process, VM_PPID); 308 ProcessId pid = ReadProcStatsAndGetFieldAsInt(process, VM_PPID);
309 if (pid) 309 if (pid)
310 return pid; 310 return pid;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 // First we need to get the page size, since everything is measured in pages. 453 // First we need to get the page size, since everything is measured in pages.
454 // For details, see: man 5 proc. 454 // For details, see: man 5 proc.
455 const int page_size_kb = getpagesize() / 1024; 455 const int page_size_kb = getpagesize() / 1024;
456 if (page_size_kb <= 0) 456 if (page_size_kb <= 0)
457 return false; 457 return false;
458 458
459 std::string statm; 459 std::string statm;
460 { 460 {
461 FilePath statm_file = GetProcPidDir(process_).Append("statm"); 461 FilePath statm_file = GetProcPidDir(process_).Append("statm");
462 // Synchronously reading files in /proc is safe. 462 // Synchronously reading files in /proc is safe.
463 base::ThreadRestrictions::ScopedAllowIO allow_io; 463 ThreadRestrictions::ScopedAllowIO allow_io;
464 bool ret = file_util::ReadFileToString(statm_file, &statm); 464 bool ret = file_util::ReadFileToString(statm_file, &statm);
465 if (!ret || statm.length() == 0) 465 if (!ret || statm.length() == 0)
466 return false; 466 return false;
467 } 467 }
468 468
469 std::vector<std::string> statm_vec; 469 std::vector<std::string> statm_vec;
470 base::SplitString(statm, ' ', &statm_vec); 470 SplitString(statm, ' ', &statm_vec);
471 if (statm_vec.size() != 7) 471 if (statm_vec.size() != 7)
472 return false; // Not the format we expect. 472 return false; // Not the format we expect.
473 473
474 int statm_rss, statm_shared; 474 int statm_rss, statm_shared;
475 base::StringToInt(statm_vec[1], &statm_rss); 475 StringToInt(statm_vec[1], &statm_rss);
476 base::StringToInt(statm_vec[2], &statm_shared); 476 StringToInt(statm_vec[2], &statm_shared);
477 477
478 ws_usage->priv = (statm_rss - statm_shared) * page_size_kb; 478 ws_usage->priv = (statm_rss - statm_shared) * page_size_kb;
479 ws_usage->shared = statm_shared * page_size_kb; 479 ws_usage->shared = statm_shared * page_size_kb;
480 480
481 // Sharable is not calculated, as it does not provide interesting data. 481 // Sharable is not calculated, as it does not provide interesting data.
482 ws_usage->shareable = 0; 482 ws_usage->shareable = 0;
483 483
484 return true; 484 return true;
485 } 485 }
486 486
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 last_time_ = time; 524 last_time_ = time;
525 last_cpu_ = cpu; 525 last_cpu_ = cpu;
526 526
527 return percentage; 527 return percentage;
528 } 528 }
529 529
530 // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING 530 // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
531 // in your kernel configuration. 531 // in your kernel configuration.
532 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { 532 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
533 // Synchronously reading files in /proc is safe. 533 // Synchronously reading files in /proc is safe.
534 base::ThreadRestrictions::ScopedAllowIO allow_io; 534 ThreadRestrictions::ScopedAllowIO allow_io;
535 535
536 std::string proc_io_contents; 536 std::string proc_io_contents;
537 FilePath io_file = GetProcPidDir(process_).Append("io"); 537 FilePath io_file = GetProcPidDir(process_).Append("io");
538 if (!file_util::ReadFileToString(io_file, &proc_io_contents)) 538 if (!file_util::ReadFileToString(io_file, &proc_io_contents))
539 return false; 539 return false;
540 540
541 (*io_counters).OtherOperationCount = 0; 541 (*io_counters).OtherOperationCount = 0;
542 (*io_counters).OtherTransferCount = 0; 542 (*io_counters).OtherTransferCount = 0;
543 543
544 StringTokenizer tokenizer(proc_io_contents, ": \n"); 544 StringTokenizer tokenizer(proc_io_contents, ": \n");
545 ParsingState state = KEY_NAME; 545 ParsingState state = KEY_NAME;
546 StringPiece last_key_name; 546 StringPiece last_key_name;
547 while (tokenizer.GetNext()) { 547 while (tokenizer.GetNext()) {
548 switch (state) { 548 switch (state) {
549 case KEY_NAME: 549 case KEY_NAME:
550 last_key_name = tokenizer.token_piece(); 550 last_key_name = tokenizer.token_piece();
551 state = KEY_VALUE; 551 state = KEY_VALUE;
552 break; 552 break;
553 case KEY_VALUE: 553 case KEY_VALUE:
554 DCHECK(!last_key_name.empty()); 554 DCHECK(!last_key_name.empty());
555 if (last_key_name == "syscr") { 555 if (last_key_name == "syscr") {
556 base::StringToInt64(tokenizer.token_piece(), 556 StringToInt64(tokenizer.token_piece(),
557 reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount)); 557 reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount));
558 } else if (last_key_name == "syscw") { 558 } else if (last_key_name == "syscw") {
559 base::StringToInt64(tokenizer.token_piece(), 559 StringToInt64(tokenizer.token_piece(),
560 reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount)); 560 reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount));
561 } else if (last_key_name == "rchar") { 561 } else if (last_key_name == "rchar") {
562 base::StringToInt64(tokenizer.token_piece(), 562 StringToInt64(tokenizer.token_piece(),
563 reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount)); 563 reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount));
564 } else if (last_key_name == "wchar") { 564 } else if (last_key_name == "wchar") {
565 base::StringToInt64(tokenizer.token_piece(), 565 StringToInt64(tokenizer.token_piece(),
566 reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount)); 566 reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount));
567 } 567 }
568 state = KEY_NAME; 568 state = KEY_NAME;
569 break; 569 break;
570 } 570 }
571 } 571 }
572 return true; 572 return true;
573 } 573 }
574 574
575 ProcessMetrics::ProcessMetrics(ProcessHandle process) 575 ProcessMetrics::ProcessMetrics(ProcessHandle process)
576 : process_(process), 576 : process_(process),
577 last_time_(0), 577 last_time_(0),
578 last_system_time_(0), 578 last_system_time_(0),
579 last_cpu_(0) { 579 last_cpu_(0) {
580 processor_count_ = base::SysInfo::NumberOfProcessors(); 580 processor_count_ = SysInfo::NumberOfProcessors();
581 } 581 }
582 582
583 583
584 // Exposed for testing. 584 // Exposed for testing.
585 int ParseProcStatCPU(const std::string& input) { 585 int ParseProcStatCPU(const std::string& input) {
586 std::vector<std::string> proc_stats; 586 std::vector<std::string> proc_stats;
587 if (!ParseProcStats(input, &proc_stats)) 587 if (!ParseProcStats(input, &proc_stats))
588 return -1; 588 return -1;
589 589
590 if (proc_stats.size() <= VM_STIME) 590 if (proc_stats.size() <= VM_STIME)
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 inactive_anon(0), 623 inactive_anon(0),
624 active_file(0), 624 active_file(0),
625 inactive_file(0), 625 inactive_file(0),
626 shmem(0), 626 shmem(0),
627 gem_objects(-1), 627 gem_objects(-1),
628 gem_size(-1) { 628 gem_size(-1) {
629 } 629 }
630 630
631 bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { 631 bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
632 // Synchronously reading files in /proc is safe. 632 // Synchronously reading files in /proc is safe.
633 base::ThreadRestrictions::ScopedAllowIO allow_io; 633 ThreadRestrictions::ScopedAllowIO allow_io;
634 634
635 // Used memory is: total - free - buffers - caches 635 // Used memory is: total - free - buffers - caches
636 FilePath meminfo_file("/proc/meminfo"); 636 FilePath meminfo_file("/proc/meminfo");
637 std::string meminfo_data; 637 std::string meminfo_data;
638 if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) { 638 if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) {
639 DLOG(WARNING) << "Failed to open " << meminfo_file.value(); 639 DLOG(WARNING) << "Failed to open " << meminfo_file.value();
640 return false; 640 return false;
641 } 641 }
642 std::vector<std::string> meminfo_fields; 642 std::vector<std::string> meminfo_fields;
643 SplitStringAlongWhitespace(meminfo_data, &meminfo_fields); 643 SplitStringAlongWhitespace(meminfo_data, &meminfo_fields);
644 644
645 if (meminfo_fields.size() < kMemCachedIndex) { 645 if (meminfo_fields.size() < kMemCachedIndex) {
646 DLOG(WARNING) << "Failed to parse " << meminfo_file.value() 646 DLOG(WARNING) << "Failed to parse " << meminfo_file.value()
647 << ". Only found " << meminfo_fields.size() << " fields."; 647 << ". Only found " << meminfo_fields.size() << " fields.";
648 return false; 648 return false;
649 } 649 }
650 650
651 DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:"); 651 DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:");
652 DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:"); 652 DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:");
653 DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); 653 DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:");
654 DCHECK_EQ(meminfo_fields[kMemCachedIndex-1], "Cached:"); 654 DCHECK_EQ(meminfo_fields[kMemCachedIndex-1], "Cached:");
655 DCHECK_EQ(meminfo_fields[kMemActiveAnonIndex-1], "Active(anon):"); 655 DCHECK_EQ(meminfo_fields[kMemActiveAnonIndex-1], "Active(anon):");
656 DCHECK_EQ(meminfo_fields[kMemInactiveAnonIndex-1], "Inactive(anon):"); 656 DCHECK_EQ(meminfo_fields[kMemInactiveAnonIndex-1], "Inactive(anon):");
657 DCHECK_EQ(meminfo_fields[kMemActiveFileIndex-1], "Active(file):"); 657 DCHECK_EQ(meminfo_fields[kMemActiveFileIndex-1], "Active(file):");
658 DCHECK_EQ(meminfo_fields[kMemInactiveFileIndex-1], "Inactive(file):"); 658 DCHECK_EQ(meminfo_fields[kMemInactiveFileIndex-1], "Inactive(file):");
659 659
660 base::StringToInt(meminfo_fields[kMemTotalIndex], &meminfo->total); 660 StringToInt(meminfo_fields[kMemTotalIndex], &meminfo->total);
661 base::StringToInt(meminfo_fields[kMemFreeIndex], &meminfo->free); 661 StringToInt(meminfo_fields[kMemFreeIndex], &meminfo->free);
662 base::StringToInt(meminfo_fields[kMemBuffersIndex], &meminfo->buffers); 662 StringToInt(meminfo_fields[kMemBuffersIndex], &meminfo->buffers);
663 base::StringToInt(meminfo_fields[kMemCachedIndex], &meminfo->cached); 663 StringToInt(meminfo_fields[kMemCachedIndex], &meminfo->cached);
664 base::StringToInt(meminfo_fields[kMemActiveAnonIndex], &meminfo->active_anon); 664 StringToInt(meminfo_fields[kMemActiveAnonIndex], &meminfo->active_anon);
665 base::StringToInt(meminfo_fields[kMemInactiveAnonIndex], 665 StringToInt(meminfo_fields[kMemInactiveAnonIndex],
666 &meminfo->inactive_anon); 666 &meminfo->inactive_anon);
667 base::StringToInt(meminfo_fields[kMemActiveFileIndex], &meminfo->active_file); 667 StringToInt(meminfo_fields[kMemActiveFileIndex], &meminfo->active_file);
668 base::StringToInt(meminfo_fields[kMemInactiveFileIndex], 668 StringToInt(meminfo_fields[kMemInactiveFileIndex],
669 &meminfo->inactive_file); 669 &meminfo->inactive_file);
670 #if defined(OS_CHROMEOS) 670 #if defined(OS_CHROMEOS)
671 // Chrome OS has a tweaked kernel that allows us to query Shmem, which is 671 // Chrome OS has a tweaked kernel that allows us to query Shmem, which is
672 // usually video memory otherwise invisible to the OS. Unfortunately, the 672 // usually video memory otherwise invisible to the OS. Unfortunately, the
673 // meminfo format varies on different hardware so we have to search for the 673 // meminfo format varies on different hardware so we have to search for the
674 // string. It always appears after "Cached:". 674 // string. It always appears after "Cached:".
675 for (size_t i = kMemCachedIndex+2; i < meminfo_fields.size(); i += 3) { 675 for (size_t i = kMemCachedIndex+2; i < meminfo_fields.size(); i += 3) {
676 if (meminfo_fields[i] == "Shmem:") { 676 if (meminfo_fields[i] == "Shmem:") {
677 base::StringToInt(meminfo_fields[i+1], &meminfo->shmem); 677 StringToInt(meminfo_fields[i+1], &meminfo->shmem);
678 break; 678 break;
679 } 679 }
680 } 680 }
681 #endif 681 #endif
682 682
683 // Check for graphics memory data and report if present. Synchronously 683 // Check for graphics memory data and report if present. Synchronously
684 // reading files in /sys is fast. 684 // reading files in /sys is fast.
685 #if defined(ARCH_CPU_ARM_FAMILY) 685 #if defined(ARCH_CPU_ARM_FAMILY)
686 FilePath geminfo_file("/sys/kernel/debug/dri/0/exynos_gem_objects"); 686 FilePath geminfo_file("/sys/kernel/debug/dri/0/exynos_gem_objects");
687 #else 687 #else
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
847 // also has its own C version. 847 // also has its own C version.
848 bool AdjustOOMScore(ProcessId process, int score) { 848 bool AdjustOOMScore(ProcessId process, int score) {
849 if (score < 0 || score > kMaxOomScore) 849 if (score < 0 || score > kMaxOomScore)
850 return false; 850 return false;
851 851
852 FilePath oom_path(GetProcPidDir(process)); 852 FilePath oom_path(GetProcPidDir(process));
853 853
854 // Attempt to write the newer oom_score_adj file first. 854 // Attempt to write the newer oom_score_adj file first.
855 FilePath oom_file = oom_path.AppendASCII("oom_score_adj"); 855 FilePath oom_file = oom_path.AppendASCII("oom_score_adj");
856 if (file_util::PathExists(oom_file)) { 856 if (file_util::PathExists(oom_file)) {
857 std::string score_str = base::IntToString(score); 857 std::string score_str = IntToString(score);
858 DVLOG(1) << "Adjusting oom_score_adj of " << process << " to " 858 DVLOG(1) << "Adjusting oom_score_adj of " << process << " to "
859 << score_str; 859 << score_str;
860 int score_len = static_cast<int>(score_str.length()); 860 int score_len = static_cast<int>(score_str.length());
861 return (score_len == file_util::WriteFile(oom_file, 861 return (score_len == file_util::WriteFile(oom_file,
862 score_str.c_str(), 862 score_str.c_str(),
863 score_len)); 863 score_len));
864 } 864 }
865 865
866 // If the oom_score_adj file doesn't exist, then we write the old 866 // If the oom_score_adj file doesn't exist, then we write the old
867 // style file and translate the oom_adj score to the range 0-15. 867 // style file and translate the oom_adj score to the range 0-15.
868 oom_file = oom_path.AppendASCII("oom_adj"); 868 oom_file = oom_path.AppendASCII("oom_adj");
869 if (file_util::PathExists(oom_file)) { 869 if (file_util::PathExists(oom_file)) {
870 // Max score for the old oom_adj range. Used for conversion of new 870 // Max score for the old oom_adj range. Used for conversion of new
871 // values to old values. 871 // values to old values.
872 const int kMaxOldOomScore = 15; 872 const int kMaxOldOomScore = 15;
873 873
874 int converted_score = score * kMaxOldOomScore / kMaxOomScore; 874 int converted_score = score * kMaxOldOomScore / kMaxOomScore;
875 std::string score_str = base::IntToString(converted_score); 875 std::string score_str = IntToString(converted_score);
876 DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str; 876 DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str;
877 int score_len = static_cast<int>(score_str.length()); 877 int score_len = static_cast<int>(score_str.length());
878 return (score_len == file_util::WriteFile(oom_file, 878 return (score_len == file_util::WriteFile(oom_file,
879 score_str.c_str(), 879 score_str.c_str(),
880 score_len)); 880 score_len));
881 } 881 }
882 882
883 return false; 883 return false;
884 } 884 }
885 885
886 } // namespace base 886 } // namespace base
OLDNEW
« no previous file with comments | « base/debug/trace_event_impl.cc ('k') | base/string_tokenizer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698