OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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], §ors_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], §ors_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], §ors_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], §ors_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 |
OLD | NEW |