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> |
| 9 #include <sys/stat.h> |
8 #include <sys/time.h> | 10 #include <sys/time.h> |
9 #include <sys/types.h> | 11 #include <sys/types.h> |
10 #include <unistd.h> | 12 #include <unistd.h> |
11 | 13 |
12 #include "base/file_util.h" | 14 #include "base/file_util.h" |
| 15 #include "base/files/memory_mapped_file.h" |
13 #include "base/logging.h" | 16 #include "base/logging.h" |
14 #include "base/process/internal_linux.h" | 17 #include "base/process/internal_linux.h" |
15 #include "base/string_util.h" | 18 #include "base/string_util.h" |
16 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/string_split.h" | 20 #include "base/strings/string_split.h" |
18 #include "base/strings/string_tokenizer.h" | 21 #include "base/strings/string_tokenizer.h" |
19 #include "base/sys_info.h" | 22 #include "base/sys_info.h" |
20 #include "base/threading/thread_restrictions.h" | 23 #include "base/threading/thread_restrictions.h" |
21 | 24 |
22 namespace base { | 25 namespace base { |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 | 152 |
150 if (private_bytes) | 153 if (private_bytes) |
151 *private_bytes = ws_usage.priv * 1024; | 154 *private_bytes = ws_usage.priv * 1024; |
152 | 155 |
153 if (shared_bytes) | 156 if (shared_bytes) |
154 *shared_bytes = ws_usage.shared * 1024; | 157 *shared_bytes = ws_usage.shared * 1024; |
155 | 158 |
156 return true; | 159 return true; |
157 } | 160 } |
158 | 161 |
159 // Private and Shared working set sizes are obtained from /proc/<pid>/statm. | |
160 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { | 162 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
161 // Use statm instead of smaps because smaps is: | 163 #if defined(OS_CHROMEOS) |
162 // a) Large and slow to parse. | 164 if (GetWorkingSetKBytesTotmaps(ws_usage)) |
163 // b) Unavailable in the SUID sandbox. | 165 return true; |
164 | 166 #endif |
165 // First we need to get the page size, since everything is measured in pages. | 167 return GetWorkingSetKBytesStatm(ws_usage); |
166 // For details, see: man 5 proc. | |
167 const int page_size_kb = getpagesize() / 1024; | |
168 if (page_size_kb <= 0) | |
169 return false; | |
170 | |
171 std::string statm; | |
172 { | |
173 FilePath statm_file = internal::GetProcPidDir(process_).Append("statm"); | |
174 // Synchronously reading files in /proc is safe. | |
175 ThreadRestrictions::ScopedAllowIO allow_io; | |
176 bool ret = file_util::ReadFileToString(statm_file, &statm); | |
177 if (!ret || statm.length() == 0) | |
178 return false; | |
179 } | |
180 | |
181 std::vector<std::string> statm_vec; | |
182 SplitString(statm, ' ', &statm_vec); | |
183 if (statm_vec.size() != 7) | |
184 return false; // Not the format we expect. | |
185 | |
186 int statm_rss, statm_shared; | |
187 StringToInt(statm_vec[1], &statm_rss); | |
188 StringToInt(statm_vec[2], &statm_shared); | |
189 | |
190 ws_usage->priv = (statm_rss - statm_shared) * page_size_kb; | |
191 ws_usage->shared = statm_shared * page_size_kb; | |
192 | |
193 // Sharable is not calculated, as it does not provide interesting data. | |
194 ws_usage->shareable = 0; | |
195 | |
196 return true; | |
197 } | 168 } |
198 | 169 |
199 double ProcessMetrics::GetCPUUsage() { | 170 double ProcessMetrics::GetCPUUsage() { |
200 // This queries the /proc-specific scaling factor which is | 171 // This queries the /proc-specific scaling factor which is |
201 // conceptually the system hertz. To dump this value on another | 172 // conceptually the system hertz. To dump this value on another |
202 // system, try | 173 // system, try |
203 // od -t dL /proc/self/auxv | 174 // od -t dL /proc/self/auxv |
204 // and look for the number after 17 in the output; mine is | 175 // and look for the number after 17 in the output; mine is |
205 // 0000040 17 100 3 134512692 | 176 // 0000040 17 100 3 134512692 |
206 // which means the answer is 100. | 177 // which means the answer is 100. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 } | 256 } |
286 | 257 |
287 ProcessMetrics::ProcessMetrics(ProcessHandle process) | 258 ProcessMetrics::ProcessMetrics(ProcessHandle process) |
288 : process_(process), | 259 : process_(process), |
289 last_time_(0), | 260 last_time_(0), |
290 last_system_time_(0), | 261 last_system_time_(0), |
291 last_cpu_(0) { | 262 last_cpu_(0) { |
292 processor_count_ = base::SysInfo::NumberOfProcessors(); | 263 processor_count_ = base::SysInfo::NumberOfProcessors(); |
293 } | 264 } |
294 | 265 |
| 266 #if defined(OS_CHROMEOS) |
| 267 // Private, Shared and Proportional working set sizes are obtained from |
| 268 // /proc/<pid>/totmaps |
| 269 bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) |
| 270 const { |
| 271 // The format of /proc/<pid>/totmaps is: |
| 272 // |
| 273 // Rss: 6120 kB |
| 274 // Pss: 3335 kB |
| 275 // Shared_Clean: 1008 kB |
| 276 // Shared_Dirty: 4012 kB |
| 277 // Private_Clean: 4 kB |
| 278 // Private_Dirty: 1096 kB |
| 279 // ... |
| 280 const size_t kPssIndex = 4; |
| 281 const size_t kPrivate_CleanIndex = 13; |
| 282 const size_t kPrivate_DirtyIndex = 16; |
| 283 |
| 284 std::string totmaps_data; |
| 285 { |
| 286 FilePath totmaps_file = internal::GetProcPidDir(process_).Append("totmaps"); |
| 287 ThreadRestrictions::ScopedAllowIO allow_io; |
| 288 bool ret = file_util::ReadFileToString(totmaps_file, &totmaps_data); |
| 289 if (!ret || totmaps_data.length() == 0) |
| 290 return false; |
| 291 } |
| 292 |
| 293 std::vector<std::string> totmaps_fields; |
| 294 SplitStringAlongWhitespace(totmaps_data, &totmaps_fields); |
| 295 |
| 296 DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]); |
| 297 DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex-1]); |
| 298 DCHECK_EQ("Private_Dirty:", totmaps_fields[kPrivate_DirtyIndex-1]); |
| 299 |
| 300 int pss, private_clean, private_dirty; |
| 301 bool ret = true; |
| 302 ret &= StringToInt(totmaps_fields[kPssIndex], &pss); |
| 303 ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean); |
| 304 ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty); |
| 305 |
| 306 ws_usage->priv = private_clean + private_dirty; |
| 307 ws_usage->shared = pss; |
| 308 ws_usage->shareable = 0; |
| 309 |
| 310 return ret; |
| 311 } |
| 312 #endif |
| 313 |
| 314 // Private and Shared working set sizes are obtained from /proc/<pid>/statm. |
| 315 bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) |
| 316 const { |
| 317 // Use statm instead of smaps because smaps is: |
| 318 // a) Large and slow to parse. |
| 319 // b) Unavailable in the SUID sandbox. |
| 320 |
| 321 // First we need to get the page size, since everything is measured in pages. |
| 322 // For details, see: man 5 proc. |
| 323 const int page_size_kb = getpagesize() / 1024; |
| 324 if (page_size_kb <= 0) |
| 325 return false; |
| 326 |
| 327 std::string statm; |
| 328 { |
| 329 FilePath statm_file = internal::GetProcPidDir(process_).Append("statm"); |
| 330 // Synchronously reading files in /proc is safe. |
| 331 ThreadRestrictions::ScopedAllowIO allow_io; |
| 332 bool ret = file_util::ReadFileToString(statm_file, &statm); |
| 333 if (!ret || statm.length() == 0) |
| 334 return false; |
| 335 } |
| 336 |
| 337 std::vector<std::string> statm_vec; |
| 338 SplitString(statm, ' ', &statm_vec); |
| 339 if (statm_vec.size() != 7) |
| 340 return false; // Not the format we expect. |
| 341 |
| 342 int statm_rss, statm_shared; |
| 343 bool ret = true; |
| 344 ret &= StringToInt(statm_vec[1], &statm_rss); |
| 345 ret &= StringToInt(statm_vec[2], &statm_shared); |
| 346 |
| 347 ws_usage->priv = (statm_rss - statm_shared) * page_size_kb; |
| 348 ws_usage->shared = statm_shared * page_size_kb; |
| 349 |
| 350 // Sharable is not calculated, as it does not provide interesting data. |
| 351 ws_usage->shareable = 0; |
| 352 |
| 353 return ret; |
| 354 } |
| 355 |
295 size_t GetSystemCommitCharge() { | 356 size_t GetSystemCommitCharge() { |
296 SystemMemoryInfoKB meminfo; | 357 SystemMemoryInfoKB meminfo; |
297 if (!GetSystemMemoryInfo(&meminfo)) | 358 if (!GetSystemMemoryInfo(&meminfo)) |
298 return 0; | 359 return 0; |
299 return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached; | 360 return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached; |
300 } | 361 } |
301 | 362 |
302 // Exposed for testing. | 363 // Exposed for testing. |
303 int ParseProcStatCPU(const std::string& input) { | 364 int ParseProcStatCPU(const std::string& input) { |
304 std::vector<std::string> proc_stats; | 365 std::vector<std::string> proc_stats; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 if (num_res == 1) | 491 if (num_res == 1) |
431 meminfo->gem_size += mali_size; | 492 meminfo->gem_size += mali_size; |
432 } | 493 } |
433 #endif // defined(ARCH_CPU_ARM_FAMILY) | 494 #endif // defined(ARCH_CPU_ARM_FAMILY) |
434 #endif // defined(OS_CHROMEOS) | 495 #endif // defined(OS_CHROMEOS) |
435 | 496 |
436 return true; | 497 return true; |
437 } | 498 } |
438 | 499 |
439 } // namespace base | 500 } // namespace base |
OLD | NEW |