| 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 |