OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/tracing/common/process_metrics_memory_dump_provider.h" | 5 #include "components/tracing/common/process_metrics_memory_dump_provider.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <map> | 10 #include <map> |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include <mach/mach.h> | 29 #include <mach/mach.h> |
30 #include <mach/mach_vm.h> | 30 #include <mach/mach_vm.h> |
31 #include <mach/shared_region.h> | 31 #include <mach/shared_region.h> |
32 #include <sys/param.h> | 32 #include <sys/param.h> |
33 | 33 |
34 #include <mach-o/dyld_images.h> | 34 #include <mach-o/dyld_images.h> |
35 #include <mach-o/loader.h> | 35 #include <mach-o/loader.h> |
36 #include <mach/mach.h> | 36 #include <mach/mach.h> |
37 | 37 |
38 #include "base/numerics/safe_math.h" | 38 #include "base/numerics/safe_math.h" |
| 39 #include "base/process/process_metrics.h" |
39 #endif // defined(OS_MACOSX) | 40 #endif // defined(OS_MACOSX) |
40 | 41 |
41 #if defined(OS_WIN) | 42 #if defined(OS_WIN) |
42 #include <psapi.h> | 43 #include <psapi.h> |
43 #include <tchar.h> | 44 #include <tchar.h> |
44 #include <windows.h> | 45 #include <windows.h> |
45 | 46 |
46 #include <base/strings/sys_string_conversions.h> | 47 #include <base/strings/sys_string_conversions.h> |
47 #include <base/win/win_util.h> | 48 #include <base/win/win_util.h> |
48 #endif // defined(OS_WIN) | 49 #endif // defined(OS_WIN) |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 | 381 |
381 // We intentionally avoid setting any page information, which is not | 382 // We intentionally avoid setting any page information, which is not |
382 // available from dyld. The fields will be populated later. | 383 // available from dyld. The fields will be populated later. |
383 regions->push_back(region); | 384 regions->push_back(region); |
384 } | 385 } |
385 } | 386 } |
386 } | 387 } |
387 return true; | 388 return true; |
388 } | 389 } |
389 | 390 |
390 void PopulateByteStats(VMRegion* region, const vm_region_submap_info_64& info) { | 391 void PopulateByteStats(VMRegion* region, |
391 uint32_t share_mode = info.share_mode; | 392 const vm_region_top_info_data_t& info) { |
392 if (share_mode == SM_COW && info.ref_count == 1) | 393 uint64_t dirty_bytes = |
393 share_mode = SM_PRIVATE; | 394 (info.private_pages_resident + info.shared_pages_resident) * PAGE_SIZE; |
394 | 395 switch (info.share_mode) { |
395 uint64_t dirty_bytes = info.pages_dirtied * PAGE_SIZE; | |
396 uint64_t clean_bytes = | |
397 (info.pages_resident - info.pages_reusable - info.pages_dirtied) * | |
398 PAGE_SIZE; | |
399 switch (share_mode) { | |
400 case SM_LARGE_PAGE: | 396 case SM_LARGE_PAGE: |
401 case SM_PRIVATE: | 397 case SM_PRIVATE: |
402 region->byte_stats_private_dirty_resident = dirty_bytes; | |
403 region->byte_stats_private_clean_resident = clean_bytes; | |
404 break; | |
405 case SM_COW: | 398 case SM_COW: |
406 region->byte_stats_private_dirty_resident = dirty_bytes; | 399 region->byte_stats_private_dirty_resident = dirty_bytes; |
407 region->byte_stats_shared_clean_resident = clean_bytes; | |
408 break; | |
409 case SM_SHARED: | 400 case SM_SHARED: |
410 case SM_PRIVATE_ALIASED: | 401 case SM_PRIVATE_ALIASED: |
411 case SM_TRUESHARED: | 402 case SM_TRUESHARED: |
412 case SM_SHARED_ALIASED: | 403 case SM_SHARED_ALIASED: |
413 region->byte_stats_shared_dirty_resident = dirty_bytes; | 404 region->byte_stats_shared_dirty_resident = dirty_bytes; |
414 region->byte_stats_shared_clean_resident = clean_bytes; | |
415 break; | 405 break; |
416 case SM_EMPTY: | 406 case SM_EMPTY: |
417 break; | 407 break; |
418 default: | 408 default: |
419 NOTREACHED(); | 409 NOTREACHED(); |
420 break; | 410 break; |
421 } | 411 } |
422 } | 412 } |
423 | 413 |
424 // Creates VMRegions from mach_vm_region_recurse. Returns whether the operation | 414 // Creates VMRegions using mach vm syscalls. Returns whether the operation |
425 // succeeded. | 415 // succeeded. |
426 bool GetAllRegions(std::vector<VMRegion>* regions) { | 416 bool GetAllRegions(std::vector<VMRegion>* regions) { |
427 const int pid = getpid(); | 417 const int pid = getpid(); |
428 task_t task = mach_task_self(); | 418 task_t task = mach_task_self(); |
429 mach_vm_size_t size = 0; | 419 mach_vm_size_t size = 0; |
430 vm_region_submap_info_64 info; | |
431 natural_t depth = 1; | |
432 mach_msg_type_number_t count = sizeof(info); | |
433 mach_vm_address_t address = MACH_VM_MIN_ADDRESS; | 420 mach_vm_address_t address = MACH_VM_MIN_ADDRESS; |
434 while (true) { | 421 while (true) { |
435 memset(&info, 0, sizeof(info)); | 422 base::CheckedNumeric<mach_vm_address_t> next_address(address); |
436 kern_return_t kr = mach_vm_region_recurse( | 423 next_address += size; |
437 task, &address, &size, &depth, | 424 if (!next_address.IsValid()) |
438 reinterpret_cast<vm_region_info_t>(&info), &count); | 425 return false; |
439 if (kr == KERN_INVALID_ADDRESS) // nothing else left | 426 address = next_address.ValueOrDie(); |
| 427 mach_vm_address_t address_copy = address; |
| 428 |
| 429 vm_region_top_info_data_t info; |
| 430 base::MachVMRegionResult result = |
| 431 base::GetTopInfo(task, &size, &address, &info); |
| 432 if (result == base::MachVMRegionResult::Error) |
| 433 return false; |
| 434 if (result == base::MachVMRegionResult::Finished) |
440 break; | 435 break; |
441 if (kr != KERN_SUCCESS) // something bad | 436 |
| 437 vm_region_basic_info_64 basic_info; |
| 438 mach_vm_size_t dummy_size = 0; |
| 439 result = base::GetBasicInfo(task, &dummy_size, &address_copy, &basic_info); |
| 440 if (result == base::MachVMRegionResult::Error) |
442 return false; | 441 return false; |
443 if (info.is_submap) { | 442 if (result == base::MachVMRegionResult::Finished) |
444 size = 0; | 443 break; |
445 ++depth; | |
446 continue; | |
447 } | |
448 | 444 |
449 VMRegion region; | 445 VMRegion region; |
450 PopulateByteStats(®ion, info); | 446 PopulateByteStats(®ion, info); |
451 | 447 |
452 if (info.protection & VM_PROT_READ) | 448 if (basic_info.protection & VM_PROT_READ) |
453 region.protection_flags |= VMRegion::kProtectionFlagsRead; | 449 region.protection_flags |= VMRegion::kProtectionFlagsRead; |
454 if (info.protection & VM_PROT_WRITE) | 450 if (basic_info.protection & VM_PROT_WRITE) |
455 region.protection_flags |= VMRegion::kProtectionFlagsWrite; | 451 region.protection_flags |= VMRegion::kProtectionFlagsWrite; |
456 if (info.protection & VM_PROT_EXECUTE) | 452 if (basic_info.protection & VM_PROT_EXECUTE) |
457 region.protection_flags |= VMRegion::kProtectionFlagsExec; | 453 region.protection_flags |= VMRegion::kProtectionFlagsExec; |
458 | 454 |
459 char buffer[MAXPATHLEN]; | 455 char buffer[MAXPATHLEN]; |
460 int length = proc_regionfilename(pid, address, buffer, MAXPATHLEN); | 456 int length = proc_regionfilename(pid, address, buffer, MAXPATHLEN); |
461 if (length != 0) | 457 if (length != 0) |
462 region.mapped_file.assign(buffer, length); | 458 region.mapped_file.assign(buffer, length); |
463 | 459 |
464 region.byte_stats_swapped = info.pages_swapped_out * PAGE_SIZE; | 460 // There's no way to get swapped or clean bytes without doing a |
| 461 // very expensive syscalls that crawls every single page in the memory |
| 462 // object. |
465 region.start_address = address; | 463 region.start_address = address; |
466 region.size_in_bytes = size; | 464 region.size_in_bytes = size; |
467 regions->push_back(region); | 465 regions->push_back(region); |
468 | |
469 base::CheckedNumeric<mach_vm_address_t> numeric(address); | |
470 numeric += size; | |
471 if (!numeric.IsValid()) | |
472 return false; | |
473 address = numeric.ValueOrDie(); | |
474 } | 466 } |
475 return true; | 467 return true; |
476 } | 468 } |
477 | 469 |
478 void AddRegionByteStats(VMRegion* dest, const VMRegion& source) { | 470 void AddRegionByteStats(VMRegion* dest, const VMRegion& source) { |
479 dest->byte_stats_private_dirty_resident += | 471 dest->byte_stats_private_dirty_resident += |
480 source.byte_stats_private_dirty_resident; | 472 source.byte_stats_private_dirty_resident; |
481 dest->byte_stats_private_clean_resident += | 473 dest->byte_stats_private_clean_resident += |
482 source.byte_stats_private_clean_resident; | 474 source.byte_stats_private_clean_resident; |
483 dest->byte_stats_shared_dirty_resident += | 475 dest->byte_stats_shared_dirty_resident += |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 #endif | 699 #endif |
708 } | 700 } |
709 | 701 |
710 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { | 702 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { |
711 #if defined(OS_LINUX) || defined(OS_ANDROID) | 703 #if defined(OS_LINUX) || defined(OS_ANDROID) |
712 fast_polling_statm_fd_.reset(); | 704 fast_polling_statm_fd_.reset(); |
713 #endif | 705 #endif |
714 } | 706 } |
715 | 707 |
716 } // namespace tracing | 708 } // namespace tracing |
OLD | NEW |