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

Side by Side Diff: base/process/process_metrics_linux.cc

Issue 2858213002: Clean up base/process/process_metrics_linux.cc. (Closed)
Patch Set: constexpr is too much Created 3 years, 7 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
« no previous file with comments | « base/process/process_metrics.h ('k') | no next file » | 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) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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/process_metrics.h" 5 #include "base/process/process_metrics.h"
6 6
7 #include <dirent.h> 7 #include <dirent.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <stddef.h> 9 #include <stddef.h>
10 #include <stdint.h> 10 #include <stdint.h>
(...skipping 14 matching lines...) Expand all
25 #include "base/strings/string_util.h" 25 #include "base/strings/string_util.h"
26 #include "base/sys_info.h" 26 #include "base/sys_info.h"
27 #include "base/threading/thread_restrictions.h" 27 #include "base/threading/thread_restrictions.h"
28 #include "build/build_config.h" 28 #include "build/build_config.h"
29 29
30 namespace base { 30 namespace base {
31 31
32 namespace { 32 namespace {
33 33
34 void TrimKeyValuePairs(StringPairs* pairs) { 34 void TrimKeyValuePairs(StringPairs* pairs) {
35 DCHECK(pairs); 35 for (auto& pair : *pairs) {
36 StringPairs& p_ref = *pairs; 36 TrimWhitespaceASCII(pair.first, TRIM_ALL, &pair.first);
37 for (size_t i = 0; i < p_ref.size(); ++i) { 37 TrimWhitespaceASCII(pair.second, TRIM_ALL, &pair.second);
38 TrimWhitespaceASCII(p_ref[i].first, TRIM_ALL, &p_ref[i].first);
39 TrimWhitespaceASCII(p_ref[i].second, TRIM_ALL, &p_ref[i].second);
40 } 38 }
41 } 39 }
42 40
43 #if defined(OS_CHROMEOS) 41 #if defined(OS_CHROMEOS)
44 // Read a file with a single number string and return the number as a uint64_t. 42 // Read a file with a single number string and return the number as a uint64_t.
45 static uint64_t ReadFileToUint64(const FilePath file) { 43 uint64_t ReadFileToUint64(const FilePath& file) {
46 std::string file_as_string; 44 std::string file_contents;
47 if (!ReadFileToString(file, &file_as_string)) 45 if (!ReadFileToString(file, &file_contents))
48 return 0; 46 return 0;
49 TrimWhitespaceASCII(file_as_string, TRIM_ALL, &file_as_string); 47 TrimWhitespaceASCII(file_contents, TRIM_ALL, &file_contents);
50 uint64_t file_as_uint64 = 0; 48 uint64_t file_contents_uint64 = 0;
51 if (!StringToUint64(file_as_string, &file_as_uint64)) 49 if (!StringToUint64(file_contents, &file_contents_uint64))
52 return 0; 50 return 0;
53 return file_as_uint64; 51 return file_contents_uint64;
54 } 52 }
55 #endif 53 #endif
56 54
57 // Read /proc/<pid>/status and return the value for |field|, or 0 on failure. 55 // Read |filename| in /proc/<pid>/, split the entries into key/value pairs, and
58 // Only works for fields in the form of "Field: value kB". 56 // trim the key and value. On success, return true and write the trimmed
59 size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) { 57 // key/value pairs into |key_value_pairs|.
58 bool ReadProcFileToTrimmedStringPairs(pid_t pid,
59 StringPiece filename,
60 StringPairs* key_value_pairs) {
60 std::string status_data; 61 std::string status_data;
61 { 62 {
62 // Synchronously reading files in /proc does not hit the disk. 63 // Synchronously reading files in /proc does not hit the disk.
63 ThreadRestrictions::ScopedAllowIO allow_io; 64 ThreadRestrictions::ScopedAllowIO allow_io;
64 FilePath status_file = internal::GetProcPidDir(pid).Append("status"); 65 FilePath status_file = internal::GetProcPidDir(pid).Append(filename);
65 if (!ReadFileToString(status_file, &status_data)) 66 if (!ReadFileToString(status_file, &status_data))
67 return false;
68 }
69 SplitStringIntoKeyValuePairs(status_data, ':', '\n', key_value_pairs);
70 TrimKeyValuePairs(key_value_pairs);
71 return true;
72 }
73
74 // Read /proc/<pid>/status and return the value for |field|, or 0 on failure.
75 // Only works for fields in the form of "Field: value kB".
76 size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, StringPiece field) {
77 StringPairs pairs;
78 if (!ReadProcFileToTrimmedStringPairs(pid, "status", &pairs))
79 return 0;
80
81 for (const auto& pair : pairs) {
82 const std::string& key = pair.first;
83 const std::string& value_str = pair.second;
84 if (key != field)
85 continue;
86
87 std::vector<StringPiece> split_value_str =
88 SplitStringPiece(value_str, " ", TRIM_WHITESPACE, SPLIT_WANT_ALL);
89 if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
90 NOTREACHED();
66 return 0; 91 return 0;
67 }
68
69 StringPairs pairs;
70 SplitStringIntoKeyValuePairs(status_data, ':', '\n', &pairs);
71 TrimKeyValuePairs(&pairs);
72 for (size_t i = 0; i < pairs.size(); ++i) {
73 const std::string& key = pairs[i].first;
74 const std::string& value_str = pairs[i].second;
75 if (key == field) {
76 std::vector<StringPiece> split_value_str =
77 SplitStringPiece(value_str, " ", TRIM_WHITESPACE, SPLIT_WANT_ALL);
78 if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
79 NOTREACHED();
80 return 0;
81 }
82 size_t value;
83 if (!StringToSizeT(split_value_str[0], &value)) {
84 NOTREACHED();
85 return 0;
86 }
87 return value;
88 } 92 }
93 size_t value;
94 if (!StringToSizeT(split_value_str[0], &value)) {
95 NOTREACHED();
96 return 0;
97 }
98 return value;
89 } 99 }
90 // This can be reached if the process dies when proc is read -- in that case, 100 // This can be reached if the process dies when proc is read -- in that case,
91 // the kernel can return missing fields. 101 // the kernel can return missing fields.
92 return 0; 102 return 0;
93 } 103 }
94 104
95 #if defined(OS_LINUX) || defined(OS_AIX) 105 #if defined(OS_LINUX) || defined(OS_AIX)
96 // Read /proc/<pid>/status and look for |field|. On success, return true and 106 // Read /proc/<pid>/status and look for |field|. On success, return true and
97 // write the value for |field| into |result|. 107 // write the value for |field| into |result|.
98 // Only works for fields in the form of "field : uint_value" 108 // Only works for fields in the form of "field : uint_value"
99 bool ReadProcStatusAndGetFieldAsUint64(pid_t pid, 109 bool ReadProcStatusAndGetFieldAsUint64(pid_t pid,
100 const std::string& field, 110 StringPiece field,
101 uint64_t* result) { 111 uint64_t* result) {
102 std::string status_data; 112 StringPairs pairs;
103 { 113 if (!ReadProcFileToTrimmedStringPairs(pid, "status", &pairs))
104 // Synchronously reading files in /proc does not hit the disk. 114 return false;
105 ThreadRestrictions::ScopedAllowIO allow_io; 115
106 FilePath status_file = internal::GetProcPidDir(pid).Append("status"); 116 for (const auto& pair : pairs) {
107 if (!ReadFileToString(status_file, &status_data)) 117 const std::string& key = pair.first;
118 const std::string& value_str = pair.second;
119 if (key != field)
120 continue;
121
122 uint64_t value;
123 if (!StringToUint64(value_str, &value))
108 return false; 124 return false;
109 } 125 *result = value;
110 126 return true;
111 StringPairs pairs;
112 SplitStringIntoKeyValuePairs(status_data, ':', '\n', &pairs);
113 TrimKeyValuePairs(&pairs);
114 for (size_t i = 0; i < pairs.size(); ++i) {
115 const std::string& key = pairs[i].first;
116 const std::string& value_str = pairs[i].second;
117 if (key == field) {
118 uint64_t value;
119 if (!StringToUint64(value_str, &value))
120 return false;
121 *result = value;
122 return true;
123 }
124 } 127 }
125 return false; 128 return false;
126 } 129 }
127 #endif // defined(OS_LINUX) || defined(OS_AIX) 130 #endif // defined(OS_LINUX) || defined(OS_AIX)
128 131
129 // Get the total CPU of a single process. Return value is number of jiffies 132 // Get the total CPU of a single process. Return value is number of jiffies
130 // on success or -1 on error. 133 // on success or -1 on error.
131 int GetProcessCPU(pid_t pid) { 134 int GetProcessCPU(pid_t pid) {
132 // Use /proc/<pid>/task to find all threads and parse their /stat file. 135 // Use /proc/<pid>/task to find all threads and parse their /stat file.
133 FilePath task_path = internal::GetProcPidDir(pid).Append("task"); 136 FilePath task_path = internal::GetProcPidDir(pid).Append("task");
(...skipping 28 matching lines...) Expand all
162 } 165 }
163 166
164 } // namespace 167 } // namespace
165 168
166 // static 169 // static
167 std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( 170 std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
168 ProcessHandle process) { 171 ProcessHandle process) {
169 return WrapUnique(new ProcessMetrics(process)); 172 return WrapUnique(new ProcessMetrics(process));
170 } 173 }
171 174
172 // On linux, we return vsize. 175 // On Linux, return vsize.
173 size_t ProcessMetrics::GetPagefileUsage() const { 176 size_t ProcessMetrics::GetPagefileUsage() const {
174 return internal::ReadProcStatsAndGetFieldAsSizeT(process_, 177 return internal::ReadProcStatsAndGetFieldAsSizeT(process_,
175 internal::VM_VSIZE); 178 internal::VM_VSIZE);
176 } 179 }
177 180
178 // On linux, we return the high water mark of vsize. 181 // On Linux, return the high water mark of vsize.
179 size_t ProcessMetrics::GetPeakPagefileUsage() const { 182 size_t ProcessMetrics::GetPeakPagefileUsage() const {
180 return ReadProcStatusAndGetFieldAsSizeT(process_, "VmPeak") * 1024; 183 return ReadProcStatusAndGetFieldAsSizeT(process_, "VmPeak") * 1024;
181 } 184 }
182 185
183 // On linux, we return RSS. 186 // On Linux, return RSS.
184 size_t ProcessMetrics::GetWorkingSetSize() const { 187 size_t ProcessMetrics::GetWorkingSetSize() const {
185 return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) * 188 return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) *
186 getpagesize(); 189 getpagesize();
187 } 190 }
188 191
189 // On linux, we return the high water mark of RSS. 192 // On Linux, return the high water mark of RSS.
190 size_t ProcessMetrics::GetPeakWorkingSetSize() const { 193 size_t ProcessMetrics::GetPeakWorkingSetSize() const {
191 return ReadProcStatusAndGetFieldAsSizeT(process_, "VmHWM") * 1024; 194 return ReadProcStatusAndGetFieldAsSizeT(process_, "VmHWM") * 1024;
192 } 195 }
193 196
194 bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, 197 bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
195 size_t* shared_bytes) const { 198 size_t* shared_bytes) const {
196 WorkingSetKBytes ws_usage; 199 WorkingSetKBytes ws_usage;
197 if (!GetWorkingSetKBytes(&ws_usage)) 200 if (!GetWorkingSetKBytes(&ws_usage))
198 return false; 201 return false;
199 202
(...skipping 25 matching lines...) Expand all
225 } 228 }
226 229
227 TimeDelta time_delta = time - last_cpu_time_; 230 TimeDelta time_delta = time - last_cpu_time_;
228 if (time_delta.is_zero()) { 231 if (time_delta.is_zero()) {
229 NOTREACHED(); 232 NOTREACHED();
230 return 0.0; 233 return 0.0;
231 } 234 }
232 235
233 int cpu = GetProcessCPU(process_); 236 int cpu = GetProcessCPU(process_);
234 237
235 // We have the number of jiffies in the time period. Convert to percentage. 238 // The number of jiffies in the time period. Convert to percentage.
236 // Note this means we will go *over* 100 in the case where multiple threads 239 // Note: this means this will go *over* 100 in the case where multiple threads
237 // are together adding to more than one CPU's worth. 240 // are together adding to more than one CPU's worth.
238 TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu); 241 TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu);
239 TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_); 242 TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_);
240 243
241 // If the number of threads running in the process has decreased since the 244 // If the number of threads running in the process has decreased since the
242 // last time this function was called, |last_cpu_time| will be greater than 245 // last time this function was called, |last_cpu_time| will be greater than
243 // |cpu_time| which will result in a negative value in the below percentage 246 // |cpu_time| which will result in a negative value in the below percentage
244 // calculation. We prevent this by clamping to 0. crbug.com/546565. 247 // calculation. Prevent this by clamping to 0. https://crbug.com/546565.
245 // This computation is known to be shaky when threads are destroyed between 248 // This computation is known to be shaky when threads are destroyed between
246 // "last" and "now", but for our current purposes, it's all right. 249 // "last" and "now", but for our current purposes, it's all right.
247 double percentage = 0.0; 250 double percentage = 0.0;
248 if (last_cpu_time < cpu_time) { 251 if (last_cpu_time < cpu_time) {
249 percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() / 252 percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
250 time_delta.InSecondsF(); 253 time_delta.InSecondsF();
251 } 254 }
252 255
253 last_cpu_time_ = time; 256 last_cpu_time_ = time;
254 last_cpu_ = cpu; 257 last_cpu_ = cpu;
255 258
256 return percentage; 259 return percentage;
257 } 260 }
258 261
259 // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING 262 // For the /proc/self/io file to exist, the Linux kernel must have
260 // in your kernel configuration. 263 // CONFIG_TASK_IO_ACCOUNTING enabled.
261 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { 264 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
262 // Synchronously reading files in /proc does not hit the disk. 265 StringPairs pairs;
263 ThreadRestrictions::ScopedAllowIO allow_io; 266 if (!ReadProcFileToTrimmedStringPairs(process_, "io", &pairs))
264
265 std::string proc_io_contents;
266 FilePath io_file = internal::GetProcPidDir(process_).Append("io");
267 if (!ReadFileToString(io_file, &proc_io_contents))
268 return false; 267 return false;
269 268
270 io_counters->OtherOperationCount = 0; 269 io_counters->OtherOperationCount = 0;
271 io_counters->OtherTransferCount = 0; 270 io_counters->OtherTransferCount = 0;
272 271
273 StringPairs pairs; 272 for (const auto& pair : pairs) {
274 SplitStringIntoKeyValuePairs(proc_io_contents, ':', '\n', &pairs); 273 const std::string& key = pair.first;
275 TrimKeyValuePairs(&pairs); 274 const std::string& value_str = pair.second;
276 for (size_t i = 0; i < pairs.size(); ++i) { 275 uint64_t* target_counter = nullptr;
277 const std::string& key = pairs[i].first;
278 const std::string& value_str = pairs[i].second;
279 uint64_t* target_counter = NULL;
280 if (key == "syscr") 276 if (key == "syscr")
281 target_counter = &io_counters->ReadOperationCount; 277 target_counter = &io_counters->ReadOperationCount;
282 else if (key == "syscw") 278 else if (key == "syscw")
283 target_counter = &io_counters->WriteOperationCount; 279 target_counter = &io_counters->WriteOperationCount;
284 else if (key == "rchar") 280 else if (key == "rchar")
285 target_counter = &io_counters->ReadTransferCount; 281 target_counter = &io_counters->ReadTransferCount;
286 else if (key == "wchar") 282 else if (key == "wchar")
287 target_counter = &io_counters->WriteTransferCount; 283 target_counter = &io_counters->WriteTransferCount;
288 if (!target_counter) 284 if (!target_counter)
289 continue; 285 continue;
(...skipping 23 matching lines...) Expand all
313 } 309 }
314 310
315 int ProcessMetrics::GetOpenFdSoftLimit() const { 311 int ProcessMetrics::GetOpenFdSoftLimit() const {
316 // Use /proc/<pid>/limits to read the open fd limit. 312 // Use /proc/<pid>/limits to read the open fd limit.
317 FilePath fd_path = internal::GetProcPidDir(process_).Append("limits"); 313 FilePath fd_path = internal::GetProcPidDir(process_).Append("limits");
318 314
319 std::string limits_contents; 315 std::string limits_contents;
320 if (!ReadFileToString(fd_path, &limits_contents)) 316 if (!ReadFileToString(fd_path, &limits_contents))
321 return -1; 317 return -1;
322 318
323 for (const auto& line : 319 for (const auto& line : SplitStringPiece(
324 base::SplitStringPiece(limits_contents, "\n", base::KEEP_WHITESPACE, 320 limits_contents, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
325 base::SPLIT_WANT_NONEMPTY)) { 321 if (!line.starts_with("Max open files"))
326 if (line.starts_with("Max open files")) { 322 continue;
327 auto tokens = base::SplitStringPiece(line, " ", base::TRIM_WHITESPACE, 323
328 base::SPLIT_WANT_NONEMPTY); 324 auto tokens =
329 if (tokens.size() > 3) { 325 SplitStringPiece(line, " ", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
330 int limit = -1; 326 if (tokens.size() > 3) {
331 if (StringToInt(tokens[3], &limit)) 327 int limit = -1;
332 return limit; 328 if (!StringToInt(tokens[3], &limit))
333 return -1; 329 return -1;
334 } 330 return limit;
335 } 331 }
336 } 332 }
337 return -1; 333 return -1;
338 } 334 }
339
340 #endif // defined(OS_LINUX) || defined(OS_AIX) 335 #endif // defined(OS_LINUX) || defined(OS_AIX)
341 336
342 ProcessMetrics::ProcessMetrics(ProcessHandle process) 337 ProcessMetrics::ProcessMetrics(ProcessHandle process)
343 : process_(process), 338 : process_(process),
344 last_system_time_(0), 339 last_system_time_(0),
345 #if defined(OS_LINUX) || defined(OS_AIX) 340 #if defined(OS_LINUX) || defined(OS_AIX)
346 last_absolute_idle_wakeups_(0), 341 last_absolute_idle_wakeups_(0),
347 #endif 342 #endif
348 last_cpu_(0) { 343 last_cpu_(0) {
349 processor_count_ = SysInfo::NumberOfProcessors(); 344 processor_count_ = SysInfo::NumberOfProcessors();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 int pss = 0; 387 int pss = 0;
393 int private_clean = 0; 388 int private_clean = 0;
394 int private_dirty = 0; 389 int private_dirty = 0;
395 int swap = 0; 390 int swap = 0;
396 bool ret = true; 391 bool ret = true;
397 ret &= StringToInt(totmaps_fields[kPssIndex], &pss); 392 ret &= StringToInt(totmaps_fields[kPssIndex], &pss);
398 ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean); 393 ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean);
399 ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty); 394 ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty);
400 ret &= StringToInt(totmaps_fields[kSwapIndex], &swap); 395 ret &= StringToInt(totmaps_fields[kSwapIndex], &swap);
401 396
402 // On ChromeOS swap is to zram. We count this as private / shared, as 397 // On ChromeOS, swap goes to zram. Count this as private / shared, as
403 // increased swap decreases available RAM to user processes, which would 398 // increased swap decreases available RAM to user processes, which would
404 // otherwise create surprising results. 399 // otherwise create surprising results.
405 ws_usage->priv = private_clean + private_dirty + swap; 400 ws_usage->priv = private_clean + private_dirty + swap;
406 ws_usage->shared = pss + swap; 401 ws_usage->shared = pss + swap;
407 ws_usage->shareable = 0; 402 ws_usage->shareable = 0;
408 ws_usage->swapped = swap; 403 ws_usage->swapped = swap;
409 return ret; 404 return ret;
410 } 405 }
411 #endif 406 #endif
412 407
413 // Private and Shared working set sizes are obtained from /proc/<pid>/statm. 408 // Private and Shared working set sizes are obtained from /proc/<pid>/statm.
414 bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) 409 bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage)
415 const { 410 const {
416 // Use statm instead of smaps because smaps is: 411 // Use statm instead of smaps because smaps is:
417 // a) Large and slow to parse. 412 // a) Large and slow to parse.
418 // b) Unavailable in the SUID sandbox. 413 // b) Unavailable in the SUID sandbox.
419 414
420 // First we need to get the page size, since everything is measured in pages. 415 // First get the page size, since everything is measured in pages.
421 // For details, see: man 5 proc. 416 // For details, see: man 5 proc.
422 const int page_size_kb = getpagesize() / 1024; 417 const int page_size_kb = getpagesize() / 1024;
423 if (page_size_kb <= 0) 418 if (page_size_kb <= 0)
424 return false; 419 return false;
425 420
426 std::string statm; 421 std::string statm;
427 { 422 {
428 FilePath statm_file = internal::GetProcPidDir(process_).Append("statm"); 423 FilePath statm_file = internal::GetProcPidDir(process_).Append("statm");
429 // Synchronously reading files in /proc does not hit the disk. 424 // Synchronously reading files in /proc does not hit the disk.
430 ThreadRestrictions::ScopedAllowIO allow_io; 425 ThreadRestrictions::ScopedAllowIO allow_io;
431 bool ret = ReadFileToString(statm_file, &statm); 426 bool ret = ReadFileToString(statm_file, &statm);
432 if (!ret || statm.length() == 0) 427 if (!ret || statm.length() == 0)
433 return false; 428 return false;
434 } 429 }
435 430
436 std::vector<StringPiece> statm_vec = 431 std::vector<StringPiece> statm_vec =
437 SplitStringPiece(statm, " ", TRIM_WHITESPACE, SPLIT_WANT_ALL); 432 SplitStringPiece(statm, " ", TRIM_WHITESPACE, SPLIT_WANT_ALL);
438 if (statm_vec.size() != 7) 433 if (statm_vec.size() != 7)
439 return false; // Not the format we expect. 434 return false; // Not the expected format.
440 435
441 int statm_rss, statm_shared; 436 int statm_rss;
437 int statm_shared;
442 bool ret = true; 438 bool ret = true;
443 ret &= StringToInt(statm_vec[1], &statm_rss); 439 ret &= StringToInt(statm_vec[1], &statm_rss);
444 ret &= StringToInt(statm_vec[2], &statm_shared); 440 ret &= StringToInt(statm_vec[2], &statm_shared);
445 441
446 ws_usage->priv = (statm_rss - statm_shared) * page_size_kb; 442 ws_usage->priv = (statm_rss - statm_shared) * page_size_kb;
447 ws_usage->shared = statm_shared * page_size_kb; 443 ws_usage->shared = statm_shared * page_size_kb;
448 444
449 // Sharable is not calculated, as it does not provide interesting data. 445 // Sharable is not calculated, as it does not provide interesting data.
450 ws_usage->shareable = 0; 446 ws_usage->shareable = 0;
451 447
452 #if defined(OS_CHROMEOS) 448 #if defined(OS_CHROMEOS)
453 // Can't get swapped memory from statm. 449 // Can't get swapped memory from statm.
454 ws_usage->swapped = 0; 450 ws_usage->swapped = 0;
455 #endif 451 #endif
456 452
457 return ret; 453 return ret;
458 } 454 }
459 455
460 size_t GetSystemCommitCharge() { 456 size_t GetSystemCommitCharge() {
461 SystemMemoryInfoKB meminfo; 457 SystemMemoryInfoKB meminfo;
462 if (!GetSystemMemoryInfo(&meminfo)) 458 if (!GetSystemMemoryInfo(&meminfo))
463 return 0; 459 return 0;
464 return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached; 460 return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached;
465 } 461 }
466 462
467 int ParseProcStatCPU(const std::string& input) { 463 int ParseProcStatCPU(StringPiece input) {
468 // |input| may be empty if the process disappeared somehow. 464 // |input| may be empty if the process disappeared somehow.
469 // e.g. http://crbug.com/145811. 465 // e.g. http://crbug.com/145811.
470 if (input.empty()) 466 if (input.empty())
471 return -1; 467 return -1;
472 468
473 size_t start = input.find_last_of(')'); 469 size_t start = input.find_last_of(')');
474 if (start == input.npos) 470 if (start == input.npos)
475 return -1; 471 return -1;
476 472
477 // Number of spaces remaining until reaching utime's index starting after the 473 // Number of spaces remaining until reaching utime's index starting after the
(...skipping 11 matching lines...) Expand all
489 if (sscanf(&input.data()[i], "%d %d", &utime, &stime) != 2) 485 if (sscanf(&input.data()[i], "%d %d", &utime, &stime) != 2)
490 return -1; 486 return -1;
491 487
492 return utime + stime; 488 return utime + stime;
493 } 489 }
494 } 490 }
495 491
496 return -1; 492 return -1;
497 } 493 }
498 494
499 const char kProcSelfExe[] = "/proc/self/exe";
500
501 int GetNumberOfThreads(ProcessHandle process) { 495 int GetNumberOfThreads(ProcessHandle process) {
502 return internal::ReadProcStatsAndGetFieldAsInt64(process, 496 return internal::ReadProcStatsAndGetFieldAsInt64(process,
503 internal::VM_NUMTHREADS); 497 internal::VM_NUMTHREADS);
504 } 498 }
505 499
500 const char kProcSelfExe[] = "/proc/self/exe";
501
506 namespace { 502 namespace {
507 503
508 // The format of /proc/diskstats is: 504 // The format of /proc/diskstats is:
509 // Device major number 505 // Device major number
510 // Device minor number 506 // Device minor number
511 // Device name 507 // Device name
512 // Field 1 -- # of reads completed 508 // Field 1 -- # of reads completed
513 // This is the total number of reads completed successfully. 509 // This is the total number of reads completed successfully.
514 // Field 2 -- # of reads merged, field 6 -- # of writes merged 510 // Field 2 -- # of reads merged, field 6 -- # of writes merged
515 // Reads and writes which are adjacent to each other may be merged for 511 // Reads and writes which are adjacent to each other may be merged for
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 const size_t kDiskWritesMerged = 8; 548 const size_t kDiskWritesMerged = 8;
553 const size_t kDiskSectorsWritten = 9; 549 const size_t kDiskSectorsWritten = 9;
554 const size_t kDiskWriteTime = 10; 550 const size_t kDiskWriteTime = 10;
555 const size_t kDiskIO = 11; 551 const size_t kDiskIO = 11;
556 const size_t kDiskIOTime = 12; 552 const size_t kDiskIOTime = 12;
557 const size_t kDiskWeightedIOTime = 13; 553 const size_t kDiskWeightedIOTime = 13;
558 554
559 } // namespace 555 } // namespace
560 556
561 std::unique_ptr<Value> SystemMemoryInfoKB::ToValue() const { 557 std::unique_ptr<Value> SystemMemoryInfoKB::ToValue() const {
562 std::unique_ptr<DictionaryValue> res(new DictionaryValue()); 558 auto res = base::MakeUnique<DictionaryValue>();
563
564 res->SetInteger("total", total); 559 res->SetInteger("total", total);
565 res->SetInteger("free", free); 560 res->SetInteger("free", free);
566 res->SetInteger("available", available); 561 res->SetInteger("available", available);
567 res->SetInteger("buffers", buffers); 562 res->SetInteger("buffers", buffers);
568 res->SetInteger("cached", cached); 563 res->SetInteger("cached", cached);
569 res->SetInteger("active_anon", active_anon); 564 res->SetInteger("active_anon", active_anon);
570 res->SetInteger("inactive_anon", inactive_anon); 565 res->SetInteger("inactive_anon", inactive_anon);
571 res->SetInteger("active_file", active_file); 566 res->SetInteger("active_file", active_file);
572 res->SetInteger("inactive_file", inactive_file); 567 res->SetInteger("inactive_file", inactive_file);
573 res->SetInteger("swap_total", swap_total); 568 res->SetInteger("swap_total", swap_total);
574 res->SetInteger("swap_free", swap_free); 569 res->SetInteger("swap_free", swap_free);
575 res->SetInteger("swap_used", swap_total - swap_free); 570 res->SetInteger("swap_used", swap_total - swap_free);
576 res->SetInteger("dirty", dirty); 571 res->SetInteger("dirty", dirty);
577 res->SetInteger("reclaimable", reclaimable); 572 res->SetInteger("reclaimable", reclaimable);
578 res->SetInteger("pswpin", pswpin); 573 res->SetInteger("pswpin", pswpin);
579 res->SetInteger("pswpout", pswpout); 574 res->SetInteger("pswpout", pswpout);
580 res->SetInteger("pgmajfault", pgmajfault); 575 res->SetInteger("pgmajfault", pgmajfault);
581 #ifdef OS_CHROMEOS 576 #ifdef OS_CHROMEOS
582 res->SetInteger("shmem", shmem); 577 res->SetInteger("shmem", shmem);
583 res->SetInteger("slab", slab); 578 res->SetInteger("slab", slab);
584 res->SetInteger("gem_objects", gem_objects); 579 res->SetInteger("gem_objects", gem_objects);
585 res->SetInteger("gem_size", gem_size); 580 res->SetInteger("gem_size", gem_size);
586 #endif 581 #endif
587 582
588 return std::move(res); 583 return std::move(res);
589 } 584 }
590 585
591 // exposed for testing 586 bool ParseProcMeminfo(StringPiece meminfo_data, SystemMemoryInfoKB* meminfo) {
592 bool ParseProcMeminfo(const std::string& meminfo_data,
593 SystemMemoryInfoKB* meminfo) {
594 // The format of /proc/meminfo is: 587 // The format of /proc/meminfo is:
595 // 588 //
596 // MemTotal: 8235324 kB 589 // MemTotal: 8235324 kB
597 // MemFree: 1628304 kB 590 // MemFree: 1628304 kB
598 // Buffers: 429596 kB 591 // Buffers: 429596 kB
599 // Cached: 4728232 kB 592 // Cached: 4728232 kB
600 // ... 593 // ...
601 // There is no guarantee on the ordering or position 594 // There is no guarantee on the ordering or position
602 // though it doesn't appear to change very often 595 // though it doesn't appear to change very often
603 596
604 // As a basic sanity check, let's make sure we at least get non-zero 597 // As a basic sanity check at the end, make sure the MemTotal value will be at
605 // MemTotal value 598 // least non-zero. So start off with a zero total.
606 meminfo->total = 0; 599 meminfo->total = 0;
607 600
608 for (const StringPiece& line : SplitStringPiece( 601 for (const StringPiece& line : SplitStringPiece(
609 meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) { 602 meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
610 std::vector<StringPiece> tokens = SplitStringPiece( 603 std::vector<StringPiece> tokens = SplitStringPiece(
611 line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); 604 line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
612 // HugePages_* only has a number and no suffix so we can't rely on 605 // HugePages_* only has a number and no suffix so there may not be exactly 3
613 // there being exactly 3 tokens. 606 // tokens.
614 if (tokens.size() <= 1) { 607 if (tokens.size() <= 1) {
615 DLOG(WARNING) << "meminfo: tokens: " << tokens.size() 608 DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
616 << " malformed line: " << line.as_string(); 609 << " malformed line: " << line.as_string();
617 continue; 610 continue;
618 } 611 }
619 612
620 int* target = NULL; 613 int* target = nullptr;
621 if (tokens[0] == "MemTotal:") 614 if (tokens[0] == "MemTotal:")
622 target = &meminfo->total; 615 target = &meminfo->total;
623 else if (tokens[0] == "MemFree:") 616 else if (tokens[0] == "MemFree:")
624 target = &meminfo->free; 617 target = &meminfo->free;
625 else if (tokens[0] == "MemAvailable:") 618 else if (tokens[0] == "MemAvailable:")
626 target = &meminfo->available; 619 target = &meminfo->available;
627 else if (tokens[0] == "Buffers:") 620 else if (tokens[0] == "Buffers:")
628 target = &meminfo->buffers; 621 target = &meminfo->buffers;
629 else if (tokens[0] == "Cached:") 622 else if (tokens[0] == "Cached:")
630 target = &meminfo->cached; 623 target = &meminfo->cached;
631 else if (tokens[0] == "Active(anon):") 624 else if (tokens[0] == "Active(anon):")
632 target = &meminfo->active_anon; 625 target = &meminfo->active_anon;
633 else if (tokens[0] == "Inactive(anon):") 626 else if (tokens[0] == "Inactive(anon):")
634 target = &meminfo->inactive_anon; 627 target = &meminfo->inactive_anon;
635 else if (tokens[0] == "Active(file):") 628 else if (tokens[0] == "Active(file):")
636 target = &meminfo->active_file; 629 target = &meminfo->active_file;
637 else if (tokens[0] == "Inactive(file):") 630 else if (tokens[0] == "Inactive(file):")
638 target = &meminfo->inactive_file; 631 target = &meminfo->inactive_file;
639 else if (tokens[0] == "SwapTotal:") 632 else if (tokens[0] == "SwapTotal:")
640 target = &meminfo->swap_total; 633 target = &meminfo->swap_total;
641 else if (tokens[0] == "SwapFree:") 634 else if (tokens[0] == "SwapFree:")
642 target = &meminfo->swap_free; 635 target = &meminfo->swap_free;
643 else if (tokens[0] == "Dirty:") 636 else if (tokens[0] == "Dirty:")
644 target = &meminfo->dirty; 637 target = &meminfo->dirty;
645 else if (tokens[0] == "SReclaimable:") 638 else if (tokens[0] == "SReclaimable:")
646 target = &meminfo->reclaimable; 639 target = &meminfo->reclaimable;
647 #if defined(OS_CHROMEOS) 640 #if defined(OS_CHROMEOS)
648 // Chrome OS has a tweaked kernel that allows us to query Shmem, which is 641 // Chrome OS has a tweaked kernel that allows querying Shmem, which is
649 // usually video memory otherwise invisible to the OS. 642 // usually video memory otherwise invisible to the OS.
650 else if (tokens[0] == "Shmem:") 643 else if (tokens[0] == "Shmem:")
651 target = &meminfo->shmem; 644 target = &meminfo->shmem;
652 else if (tokens[0] == "Slab:") 645 else if (tokens[0] == "Slab:")
653 target = &meminfo->slab; 646 target = &meminfo->slab;
654 #endif 647 #endif
655 if (target) 648 if (target)
656 StringToInt(tokens[1], target); 649 StringToInt(tokens[1], target);
657 } 650 }
658 651
659 // Make sure we got a valid MemTotal. 652 // Make sure the MemTotal is valid.
660 return meminfo->total > 0; 653 return meminfo->total > 0;
661 } 654 }
662 655
663 // exposed for testing 656 bool ParseProcVmstat(StringPiece vmstat_data, SystemMemoryInfoKB* meminfo) {
664 bool ParseProcVmstat(const std::string& vmstat_data,
665 SystemMemoryInfoKB* meminfo) {
666 // The format of /proc/vmstat is: 657 // The format of /proc/vmstat is:
667 // 658 //
668 // nr_free_pages 299878 659 // nr_free_pages 299878
669 // nr_inactive_anon 239863 660 // nr_inactive_anon 239863
670 // nr_active_anon 1318966 661 // nr_active_anon 1318966
671 // nr_inactive_file 2015629 662 // nr_inactive_file 2015629
672 // ... 663 // ...
673 // 664 //
674 // We iterate through the whole file because the position of the 665 // Iterate through the whole file because the position of the
675 // fields are dependent on the kernel version and configuration. 666 // fields are dependent on the kernel version and configuration.
676
677 for (const StringPiece& line : SplitStringPiece( 667 for (const StringPiece& line : SplitStringPiece(
678 vmstat_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) { 668 vmstat_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
679 std::vector<StringPiece> tokens = SplitStringPiece( 669 std::vector<StringPiece> tokens = SplitStringPiece(
680 line, " ", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); 670 line, " ", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
681 if (tokens.size() != 2) 671 if (tokens.size() != 2)
682 continue; 672 continue;
683 673
684 uint64_t val; 674 uint64_t val;
685 if (!StringToUint64(tokens[1], &val)) 675 if (!StringToUint64(tokens[1], &val))
686 continue; 676 continue;
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
775 sectors_written = 0; 765 sectors_written = 0;
776 write_time = 0; 766 write_time = 0;
777 io = 0; 767 io = 0;
778 io_time = 0; 768 io_time = 0;
779 weighted_io_time = 0; 769 weighted_io_time = 0;
780 } 770 }
781 771
782 SystemDiskInfo::SystemDiskInfo(const SystemDiskInfo& other) = default; 772 SystemDiskInfo::SystemDiskInfo(const SystemDiskInfo& other) = default;
783 773
784 std::unique_ptr<Value> SystemDiskInfo::ToValue() const { 774 std::unique_ptr<Value> SystemDiskInfo::ToValue() const {
785 std::unique_ptr<DictionaryValue> res(new DictionaryValue()); 775 auto res = base::MakeUnique<DictionaryValue>();
786 776
787 // Write out uint64_t variables as doubles. 777 // Write out uint64_t variables as doubles.
788 // Note: this may discard some precision, but for JS there's no other option. 778 // Note: this may discard some precision, but for JS there's no other option.
789 res->SetDouble("reads", static_cast<double>(reads)); 779 res->SetDouble("reads", static_cast<double>(reads));
790 res->SetDouble("reads_merged", static_cast<double>(reads_merged)); 780 res->SetDouble("reads_merged", static_cast<double>(reads_merged));
791 res->SetDouble("sectors_read", static_cast<double>(sectors_read)); 781 res->SetDouble("sectors_read", static_cast<double>(sectors_read));
792 res->SetDouble("read_time", static_cast<double>(read_time)); 782 res->SetDouble("read_time", static_cast<double>(read_time));
793 res->SetDouble("writes", static_cast<double>(writes)); 783 res->SetDouble("writes", static_cast<double>(writes));
794 res->SetDouble("writes_merged", static_cast<double>(writes_merged)); 784 res->SetDouble("writes_merged", static_cast<double>(writes_merged));
795 res->SetDouble("sectors_written", static_cast<double>(sectors_written)); 785 res->SetDouble("sectors_written", static_cast<double>(sectors_written));
796 res->SetDouble("write_time", static_cast<double>(write_time)); 786 res->SetDouble("write_time", static_cast<double>(write_time));
797 res->SetDouble("io", static_cast<double>(io)); 787 res->SetDouble("io", static_cast<double>(io));
798 res->SetDouble("io_time", static_cast<double>(io_time)); 788 res->SetDouble("io_time", static_cast<double>(io_time));
799 res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time)); 789 res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
800 790
801 return std::move(res); 791 return std::move(res);
802 } 792 }
803 793
804 bool IsValidDiskName(const std::string& candidate) { 794 bool IsValidDiskName(StringPiece candidate) {
805 if (candidate.length() < 3) 795 if (candidate.length() < 3)
806 return false; 796 return false;
797
807 if (candidate[1] == 'd' && 798 if (candidate[1] == 'd' &&
808 (candidate[0] == 'h' || candidate[0] == 's' || candidate[0] == 'v')) { 799 (candidate[0] == 'h' || candidate[0] == 's' || candidate[0] == 'v')) {
809 // [hsv]d[a-z]+ case 800 // [hsv]d[a-z]+ case
810 for (size_t i = 2; i < candidate.length(); ++i) { 801 for (size_t i = 2; i < candidate.length(); ++i) {
811 if (!islower(candidate[i])) 802 if (!islower(candidate[i]))
812 return false; 803 return false;
813 } 804 }
814 return true; 805 return true;
815 } 806 }
816 807
817 const char kMMCName[] = "mmcblk"; 808 const char kMMCName[] = "mmcblk";
818 const size_t kMMCNameLen = strlen(kMMCName); 809 if (!candidate.starts_with(kMMCName))
819 if (candidate.length() < kMMCNameLen + 1)
820 return false;
821 if (candidate.compare(0, kMMCNameLen, kMMCName) != 0)
822 return false; 810 return false;
823 811
824 // mmcblk[0-9]+ case 812 // mmcblk[0-9]+ case
825 for (size_t i = kMMCNameLen; i < candidate.length(); ++i) { 813 for (size_t i = strlen(kMMCName); i < candidate.length(); ++i) {
826 if (!isdigit(candidate[i])) 814 if (!isdigit(candidate[i]))
827 return false; 815 return false;
828 } 816 }
829 return true; 817 return true;
830 } 818 }
831 819
832 bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) { 820 bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
833 // Synchronously reading files in /proc does not hit the disk. 821 // Synchronously reading files in /proc does not hit the disk.
834 ThreadRestrictions::ScopedAllowIO allow_io; 822 ThreadRestrictions::ScopedAllowIO allow_io;
835 823
836 FilePath diskinfo_file("/proc/diskstats"); 824 FilePath diskinfo_file("/proc/diskstats");
837 std::string diskinfo_data; 825 std::string diskinfo_data;
838 if (!ReadFileToString(diskinfo_file, &diskinfo_data)) { 826 if (!ReadFileToString(diskinfo_file, &diskinfo_data)) {
839 DLOG(WARNING) << "Failed to open " << diskinfo_file.value(); 827 DLOG(WARNING) << "Failed to open " << diskinfo_file.value();
840 return false; 828 return false;
841 } 829 }
842 830
843 std::vector<StringPiece> diskinfo_lines = SplitStringPiece( 831 std::vector<StringPiece> diskinfo_lines = SplitStringPiece(
844 diskinfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); 832 diskinfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
845 if (diskinfo_lines.size() == 0) { 833 if (diskinfo_lines.empty()) {
846 DLOG(WARNING) << "No lines found"; 834 DLOG(WARNING) << "No lines found";
847 return false; 835 return false;
848 } 836 }
849 837
850 diskinfo->reads = 0; 838 diskinfo->reads = 0;
851 diskinfo->reads_merged = 0; 839 diskinfo->reads_merged = 0;
852 diskinfo->sectors_read = 0; 840 diskinfo->sectors_read = 0;
853 diskinfo->read_time = 0; 841 diskinfo->read_time = 0;
854 diskinfo->writes = 0; 842 diskinfo->writes = 0;
855 diskinfo->writes_merged = 0; 843 diskinfo->writes_merged = 0;
(...skipping 13 matching lines...) Expand all
869 uint64_t write_time = 0; 857 uint64_t write_time = 0;
870 uint64_t io = 0; 858 uint64_t io = 0;
871 uint64_t io_time = 0; 859 uint64_t io_time = 0;
872 uint64_t weighted_io_time = 0; 860 uint64_t weighted_io_time = 0;
873 861
874 for (const StringPiece& line : diskinfo_lines) { 862 for (const StringPiece& line : diskinfo_lines) {
875 std::vector<StringPiece> disk_fields = SplitStringPiece( 863 std::vector<StringPiece> disk_fields = SplitStringPiece(
876 line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); 864 line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
877 865
878 // Fields may have overflowed and reset to zero. 866 // Fields may have overflowed and reset to zero.
879 if (IsValidDiskName(disk_fields[kDiskDriveName].as_string())) { 867 if (!IsValidDiskName(disk_fields[kDiskDriveName].as_string()))
880 StringToUint64(disk_fields[kDiskReads], &reads); 868 continue;
881 StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
882 StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
883 StringToUint64(disk_fields[kDiskReadTime], &read_time);
884 StringToUint64(disk_fields[kDiskWrites], &writes);
885 StringToUint64(disk_fields[kDiskWritesMerged], &writes_merged);
886 StringToUint64(disk_fields[kDiskSectorsWritten], &sectors_written);
887 StringToUint64(disk_fields[kDiskWriteTime], &write_time);
888 StringToUint64(disk_fields[kDiskIO], &io);
889 StringToUint64(disk_fields[kDiskIOTime], &io_time);
890 StringToUint64(disk_fields[kDiskWeightedIOTime], &weighted_io_time);
891 869
892 diskinfo->reads += reads; 870 StringToUint64(disk_fields[kDiskReads], &reads);
893 diskinfo->reads_merged += reads_merged; 871 StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
894 diskinfo->sectors_read += sectors_read; 872 StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
895 diskinfo->read_time += read_time; 873 StringToUint64(disk_fields[kDiskReadTime], &read_time);
896 diskinfo->writes += writes; 874 StringToUint64(disk_fields[kDiskWrites], &writes);
897 diskinfo->writes_merged += writes_merged; 875 StringToUint64(disk_fields[kDiskWritesMerged], &writes_merged);
898 diskinfo->sectors_written += sectors_written; 876 StringToUint64(disk_fields[kDiskSectorsWritten], &sectors_written);
899 diskinfo->write_time += write_time; 877 StringToUint64(disk_fields[kDiskWriteTime], &write_time);
900 diskinfo->io += io; 878 StringToUint64(disk_fields[kDiskIO], &io);
901 diskinfo->io_time += io_time; 879 StringToUint64(disk_fields[kDiskIOTime], &io_time);
902 diskinfo->weighted_io_time += weighted_io_time; 880 StringToUint64(disk_fields[kDiskWeightedIOTime], &weighted_io_time);
903 } 881
882 diskinfo->reads += reads;
883 diskinfo->reads_merged += reads_merged;
884 diskinfo->sectors_read += sectors_read;
885 diskinfo->read_time += read_time;
886 diskinfo->writes += writes;
887 diskinfo->writes_merged += writes_merged;
888 diskinfo->sectors_written += sectors_written;
889 diskinfo->write_time += write_time;
890 diskinfo->io += io;
891 diskinfo->io_time += io_time;
892 diskinfo->weighted_io_time += weighted_io_time;
904 } 893 }
905 894
906 return true; 895 return true;
907 } 896 }
908 897
909 TimeDelta GetUserCpuTimeSinceBoot() { 898 TimeDelta GetUserCpuTimeSinceBoot() {
910 return internal::GetUserCpuTimeSinceBoot(); 899 return internal::GetUserCpuTimeSinceBoot();
911 } 900 }
912 901
913 #if defined(OS_CHROMEOS) 902 #if defined(OS_CHROMEOS)
914 std::unique_ptr<Value> SwapInfo::ToValue() const { 903 std::unique_ptr<Value> SwapInfo::ToValue() const {
915 std::unique_ptr<DictionaryValue> res(new DictionaryValue()); 904 auto res = base::MakeUnique<DictionaryValue>();
916 905
917 // Write out uint64_t variables as doubles. 906 // Write out uint64_t variables as doubles.
918 // Note: this may discard some precision, but for JS there's no other option. 907 // Note: this may discard some precision, but for JS there's no other option.
919 res->SetDouble("num_reads", static_cast<double>(num_reads)); 908 res->SetDouble("num_reads", static_cast<double>(num_reads));
920 res->SetDouble("num_writes", static_cast<double>(num_writes)); 909 res->SetDouble("num_writes", static_cast<double>(num_writes));
921 res->SetDouble("orig_data_size", static_cast<double>(orig_data_size)); 910 res->SetDouble("orig_data_size", static_cast<double>(orig_data_size));
922 res->SetDouble("compr_data_size", static_cast<double>(compr_data_size)); 911 res->SetDouble("compr_data_size", static_cast<double>(compr_data_size));
923 res->SetDouble("mem_used_total", static_cast<double>(mem_used_total)); 912 res->SetDouble("mem_used_total", static_cast<double>(mem_used_total));
924 if (compr_data_size > 0) 913 double ratio = compr_data_size ? static_cast<double>(orig_data_size) /
925 res->SetDouble("compression_ratio", static_cast<double>(orig_data_size) / 914 static_cast<double>(compr_data_size)
926 static_cast<double>(compr_data_size)); 915 : 0;
927 else 916 res->SetDouble("compression_ratio", ratio);
928 res->SetDouble("compression_ratio", 0);
929 917
930 return std::move(res); 918 return std::move(res);
931 } 919 }
932 920
933 void GetSwapInfo(SwapInfo* swap_info) { 921 void GetSwapInfo(SwapInfo* swap_info) {
934 // Synchronously reading files in /sys/block/zram0 does not hit the disk. 922 // Synchronously reading files in /sys/block/zram0 does not hit the disk.
935 ThreadRestrictions::ScopedAllowIO allow_io; 923 ThreadRestrictions::ScopedAllowIO allow_io;
936 924
937 FilePath zram_path("/sys/block/zram0"); 925 FilePath zram_path("/sys/block/zram0");
938 uint64_t orig_data_size = 926 uint64_t orig_data_size =
939 ReadFileToUint64(zram_path.Append("orig_data_size")); 927 ReadFileToUint64(zram_path.Append("orig_data_size"));
940 if (orig_data_size <= 4096) { 928 if (orig_data_size <= 4096) {
941 // A single page is compressed at startup, and has a high compression 929 // A single page is compressed at startup, and has a high compression
942 // ratio. We ignore this as it doesn't indicate any real swapping. 930 // ratio. Ignore this as it doesn't indicate any real swapping.
943 swap_info->orig_data_size = 0; 931 swap_info->orig_data_size = 0;
944 swap_info->num_reads = 0; 932 swap_info->num_reads = 0;
945 swap_info->num_writes = 0; 933 swap_info->num_writes = 0;
946 swap_info->compr_data_size = 0; 934 swap_info->compr_data_size = 0;
947 swap_info->mem_used_total = 0; 935 swap_info->mem_used_total = 0;
948 return; 936 return;
949 } 937 }
950 swap_info->orig_data_size = orig_data_size; 938 swap_info->orig_data_size = orig_data_size;
951 swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads")); 939 swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads"));
952 swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes")); 940 swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes"));
953 swap_info->compr_data_size = 941 swap_info->compr_data_size =
954 ReadFileToUint64(zram_path.Append("compr_data_size")); 942 ReadFileToUint64(zram_path.Append("compr_data_size"));
955 swap_info->mem_used_total = 943 swap_info->mem_used_total =
956 ReadFileToUint64(zram_path.Append("mem_used_total")); 944 ReadFileToUint64(zram_path.Append("mem_used_total"));
957 } 945 }
958 #endif // defined(OS_CHROMEOS) 946 #endif // defined(OS_CHROMEOS)
959 947
960 #if defined(OS_LINUX) || defined(OS_AIX) 948 #if defined(OS_LINUX) || defined(OS_AIX)
961 int ProcessMetrics::GetIdleWakeupsPerSecond() { 949 int ProcessMetrics::GetIdleWakeupsPerSecond() {
962 uint64_t num_switches; 950 uint64_t num_switches;
963 static const char kSwitchStat[] = "voluntary_ctxt_switches"; 951 static const char kSwitchStat[] = "voluntary_ctxt_switches";
964 return ReadProcStatusAndGetFieldAsUint64(process_, kSwitchStat, &num_switches) 952 return ReadProcStatusAndGetFieldAsUint64(process_, kSwitchStat, &num_switches)
965 ? CalculateIdleWakeupsPerSecond(num_switches) 953 ? CalculateIdleWakeupsPerSecond(num_switches)
966 : 0; 954 : 0;
967 } 955 }
968 #endif // defined(OS_LINUX) || defined(OS_AIX) 956 #endif // defined(OS_LINUX) || defined(OS_AIX)
969 957
970 } // namespace base 958 } // namespace base
OLDNEW
« no previous file with comments | « base/process/process_metrics.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698