Chromium Code Reviews| Index: components/tracing/common/process_metrics_memory_dump_provider.cc |
| diff --git a/components/tracing/common/process_metrics_memory_dump_provider.cc b/components/tracing/common/process_metrics_memory_dump_provider.cc |
| index 593755bada11899c83bd93f32689d819cd09fae7..a95722d7283611a1d5816b0da8ee1efa774b1de7 100644 |
| --- a/components/tracing/common/process_metrics_memory_dump_provider.cc |
| +++ b/components/tracing/common/process_metrics_memory_dump_provider.cc |
| @@ -24,6 +24,13 @@ |
| #include "base/trace_event/process_memory_totals.h" |
| #include "build/build_config.h" |
| +#if defined(OS_MACOSX) |
| +#include <libproc.h> |
| +#include <mach/mach.h> |
| +#include <mach/mach_vm.h> |
| +#include <sys/param.h> |
| +#endif // defined(OS_MACOSX) |
| + |
| namespace tracing { |
| namespace { |
| @@ -219,6 +226,88 @@ bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps( |
| } |
| #endif // defined(OS_LINUX) || defined(OS_ANDROID) |
| +#if defined(OS_MACOSX) |
| +bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps( |
| + const base::trace_event::MemoryDumpArgs& args, |
| + base::trace_event::ProcessMemoryDump* pmd) { |
| + const int pid = getpid(); |
| + using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion; |
| + using RegionInfo = vm_region_submap_info_64; |
| + mach_vm_address_t address = 0; |
| + mach_vm_size_t vmsize = 0; |
| + natural_t depth = 0; |
| + RegionInfo vminfo; |
| + mach_msg_type_number_t count = sizeof(RegionInfo); |
| + while (true) { |
| + kern_return_t kr = mach_vm_region_recurse(mach_task_self(), &address, |
| + &vmsize, &depth, reinterpret_cast<vm_region_info_t>(&vminfo), &count); |
| + if (kr == KERN_INVALID_ADDRESS) // nothing else left |
| + break; |
| + if (kr != KERN_SUCCESS) // something bad |
| + return false; |
| + |
| + if (vminfo.is_submap) { |
| + ++depth; |
| + continue; |
| + } |
| + |
| + VMRegion region; |
| + |
| + // See vm_map_region_walk and vm_map_region_look_for_page in |
| + // osfmk/vm/vm_map.c for more details. |
| + if (vminfo.share_mode == SM_EMPTY) { |
| + if (vminfo.share_mode == SM_LARGE_PAGE) |
|
Mark Mentovai
2017/01/31 20:29:13
How can share_mode be both SM_EMPTY and SM_LARGE_P
erikchen
2017/01/31 20:54:10
whoops, left over debugging that wasn't even in th
|
| + LOG(ERROR) << "large page"; |
| + } else if (vminfo.share_mode == SM_COW) { |
| + region.byte_stats_private_dirty_resident = |
| + vminfo.pages_shared_now_private * PAGE_SIZE; |
| + region.byte_stats_shared_clean_resident = |
| + (vminfo.pages_resident - vminfo.pages_shared_now_private) * |
| + PAGE_SIZE; |
| + } else if (vminfo.share_mode == SM_PRIVATE || |
| + vminfo.share_mode == SM_LARGE_PAGE) { |
| + region.byte_stats_private_dirty_resident = |
| + vminfo.pages_dirtied * PAGE_SIZE; |
| + region.byte_stats_private_clean_resident = |
| + (vminfo.pages_resident - vminfo.pages_dirtied) * PAGE_SIZE; |
| + } else if (vminfo.share_mode == SM_SHARED || |
| + vminfo.share_mode == SM_PRIVATE_ALIASED || |
| + vminfo.share_mode == SM_TRUESHARED || |
| + vminfo.share_mode == SM_SHARED_ALIASED) { |
| + region.byte_stats_shared_dirty_resident = |
| + vminfo.pages_dirtied * PAGE_SIZE; |
| + region.byte_stats_shared_clean_resident = |
| + (vminfo.pages_resident - vminfo.pages_dirtied) * PAGE_SIZE; |
| + } else { |
| + NOTREACHED(); |
| + } |
| + |
| + if (vminfo.protection & VM_PROT_READ) |
| + region.protection_flags |= VMRegion::kProtectionFlagsRead; |
| + if (vminfo.protection & VM_PROT_WRITE) |
| + region.protection_flags |= VMRegion::kProtectionFlagsWrite; |
| + if (vminfo.protection & VM_PROT_EXECUTE) |
| + region.protection_flags |= VMRegion::kProtectionFlagsExec; |
| + |
| + char buffer[MAXPATHLEN]; |
| + int length = proc_regionfilename(pid, address, buffer, MAXPATHLEN); |
| + if (length != 0) |
| + region.mapped_file.assign(buffer, length); |
| + |
| + region.byte_stats_swapped = vminfo.pages_swapped_out * PAGE_SIZE; |
| + region.start_address = address; |
| + region.size_in_bytes = vmsize; |
| + pmd->process_mmaps()->AddVMRegion(region); |
| + |
| + if (__builtin_add_overflow(address, vmsize, &address)) |
| + break; |
| + } |
| + |
| + pmd->set_has_process_mmaps(); |
| + return true; |
| +} |
| +#endif // defined(OS_MACOSX) |
| + |
| // static |
| void ProcessMetricsMemoryDumpProvider::RegisterForProcess( |
| base::ProcessId process) { |
| @@ -267,11 +356,11 @@ bool ProcessMetricsMemoryDumpProvider::OnMemoryDump( |
| base::trace_event::ProcessMemoryDump* pmd) { |
| bool res = DumpProcessTotals(args, pmd); |
| -#if defined(OS_LINUX) || defined(OS_ANDROID) |
| +#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) |
| if (args.level_of_detail == |
| base::trace_event::MemoryDumpLevelOfDetail::DETAILED) |
| res &= DumpProcessMemoryMaps(args, pmd); |
| -#endif |
| +#endif // defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) |
| return res; |
| } |