| 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> |
| 11 | 11 |
| 12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
| 13 #include "base/files/scoped_file.h" | 13 #include "base/files/scoped_file.h" |
| 14 #include "base/format_macros.h" | 14 #include "base/format_macros.h" |
| 15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/ptr_util.h" | 17 #include "base/memory/ptr_util.h" |
| 18 #include "base/process/process_metrics.h" | 18 #include "base/process/process_metrics.h" |
| 19 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 21 #include "base/trace_event/memory_dump_manager.h" | 21 #include "base/trace_event/memory_dump_manager.h" |
| 22 #include "base/trace_event/process_memory_dump.h" | 22 #include "base/trace_event/process_memory_dump.h" |
| 23 #include "base/trace_event/process_memory_maps.h" | 23 #include "base/trace_event/process_memory_maps.h" |
| 24 #include "base/trace_event/process_memory_totals.h" | 24 #include "base/trace_event/process_memory_totals.h" |
| 25 #include "build/build_config.h" | 25 #include "build/build_config.h" |
| 26 | 26 |
| 27 #if defined(OS_MACOSX) |
| 28 #include <libproc.h> |
| 29 #include <mach/mach.h> |
| 30 #include <mach/mach_vm.h> |
| 31 #include <sys/param.h> |
| 32 |
| 33 #include "base/numerics/safe_math.h" |
| 34 #endif // defined(OS_MACOSX) |
| 35 |
| 27 namespace tracing { | 36 namespace tracing { |
| 28 | 37 |
| 29 namespace { | 38 namespace { |
| 30 | 39 |
| 31 base::LazyInstance< | 40 base::LazyInstance< |
| 32 std::map<base::ProcessId, | 41 std::map<base::ProcessId, |
| 33 std::unique_ptr<ProcessMetricsMemoryDumpProvider>>>::Leaky | 42 std::unique_ptr<ProcessMetricsMemoryDumpProvider>>>::Leaky |
| 34 g_dump_providers_map = LAZY_INSTANCE_INITIALIZER; | 43 g_dump_providers_map = LAZY_INSTANCE_INITIALIZER; |
| 35 | 44 |
| 36 #if defined(OS_LINUX) || defined(OS_ANDROID) | 45 #if defined(OS_LINUX) || defined(OS_ANDROID) |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 base::ScopedFILE smaps_file(fopen(file_name.c_str(), "r")); | 221 base::ScopedFILE smaps_file(fopen(file_name.c_str(), "r")); |
| 213 res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps()); | 222 res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps()); |
| 214 } | 223 } |
| 215 | 224 |
| 216 if (res) | 225 if (res) |
| 217 pmd->set_has_process_mmaps(); | 226 pmd->set_has_process_mmaps(); |
| 218 return res; | 227 return res; |
| 219 } | 228 } |
| 220 #endif // defined(OS_LINUX) || defined(OS_ANDROID) | 229 #endif // defined(OS_LINUX) || defined(OS_ANDROID) |
| 221 | 230 |
| 231 #if defined(OS_MACOSX) |
| 232 bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps( |
| 233 const base::trace_event::MemoryDumpArgs& args, |
| 234 base::trace_event::ProcessMemoryDump* pmd) { |
| 235 const int pid = getpid(); |
| 236 task_t task = mach_task_self(); |
| 237 using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion; |
| 238 mach_vm_size_t size = 0; |
| 239 vm_region_submap_info_64 info; |
| 240 natural_t depth = 1; |
| 241 mach_msg_type_number_t count = sizeof(info); |
| 242 for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) { |
| 243 memset(&info, 0, sizeof(info)); |
| 244 kern_return_t kr = mach_vm_region_recurse( |
| 245 task, &address, &size, &depth, |
| 246 reinterpret_cast<vm_region_info_t>(&info), &count); |
| 247 if (kr == KERN_INVALID_ADDRESS) // nothing else left |
| 248 break; |
| 249 if (kr != KERN_SUCCESS) // something bad |
| 250 return false; |
| 251 if (info.is_submap) { |
| 252 size = 0; |
| 253 ++depth; |
| 254 continue; |
| 255 } |
| 256 |
| 257 if (info.share_mode == SM_COW && info.ref_count == 1) |
| 258 info.share_mode = SM_PRIVATE; |
| 259 |
| 260 VMRegion region; |
| 261 uint64_t dirty_bytes = info.pages_dirtied * PAGE_SIZE; |
| 262 uint64_t clean_bytes = |
| 263 (info.pages_resident - info.pages_reusable - info.pages_dirtied) * |
| 264 PAGE_SIZE; |
| 265 switch (info.share_mode) { |
| 266 case SM_LARGE_PAGE: |
| 267 case SM_PRIVATE: |
| 268 region.byte_stats_private_dirty_resident = dirty_bytes; |
| 269 region.byte_stats_private_clean_resident = clean_bytes; |
| 270 break; |
| 271 case SM_COW: |
| 272 region.byte_stats_private_dirty_resident = dirty_bytes; |
| 273 region.byte_stats_shared_clean_resident = clean_bytes; |
| 274 break; |
| 275 case SM_SHARED: |
| 276 case SM_PRIVATE_ALIASED: |
| 277 case SM_TRUESHARED: |
| 278 case SM_SHARED_ALIASED: |
| 279 region.byte_stats_shared_dirty_resident = dirty_bytes; |
| 280 region.byte_stats_shared_clean_resident = clean_bytes; |
| 281 break; |
| 282 case SM_EMPTY: |
| 283 break; |
| 284 default: |
| 285 NOTREACHED(); |
| 286 break; |
| 287 } |
| 288 |
| 289 if (info.protection & VM_PROT_READ) |
| 290 region.protection_flags |= VMRegion::kProtectionFlagsRead; |
| 291 if (info.protection & VM_PROT_WRITE) |
| 292 region.protection_flags |= VMRegion::kProtectionFlagsWrite; |
| 293 if (info.protection & VM_PROT_EXECUTE) |
| 294 region.protection_flags |= VMRegion::kProtectionFlagsExec; |
| 295 |
| 296 char buffer[MAXPATHLEN]; |
| 297 int length = proc_regionfilename(pid, address, buffer, MAXPATHLEN); |
| 298 if (length != 0) |
| 299 region.mapped_file.assign(buffer, length); |
| 300 |
| 301 region.byte_stats_swapped = info.pages_swapped_out * PAGE_SIZE; |
| 302 region.start_address = address; |
| 303 region.size_in_bytes = size; |
| 304 pmd->process_mmaps()->AddVMRegion(region); |
| 305 |
| 306 base::CheckedNumeric<mach_vm_address_t> numeric(address); |
| 307 numeric += size; |
| 308 if (!numeric.IsValid()) |
| 309 break; |
| 310 address = numeric.ValueOrDie(); |
| 311 } |
| 312 |
| 313 pmd->set_has_process_mmaps(); |
| 314 return true; |
| 315 } |
| 316 #endif // defined(OS_MACOSX) |
| 317 |
| 222 // static | 318 // static |
| 223 void ProcessMetricsMemoryDumpProvider::RegisterForProcess( | 319 void ProcessMetricsMemoryDumpProvider::RegisterForProcess( |
| 224 base::ProcessId process) { | 320 base::ProcessId process) { |
| 225 std::unique_ptr<ProcessMetricsMemoryDumpProvider> metrics_provider( | 321 std::unique_ptr<ProcessMetricsMemoryDumpProvider> metrics_provider( |
| 226 new ProcessMetricsMemoryDumpProvider(process)); | 322 new ProcessMetricsMemoryDumpProvider(process)); |
| 227 base::trace_event::MemoryDumpProvider::Options options; | 323 base::trace_event::MemoryDumpProvider::Options options; |
| 228 options.target_pid = process; | 324 options.target_pid = process; |
| 229 options.is_fast_polling_supported = true; | 325 options.is_fast_polling_supported = true; |
| 230 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | 326 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
| 231 metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options); | 327 metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 260 | 356 |
| 261 ProcessMetricsMemoryDumpProvider::~ProcessMetricsMemoryDumpProvider() {} | 357 ProcessMetricsMemoryDumpProvider::~ProcessMetricsMemoryDumpProvider() {} |
| 262 | 358 |
| 263 // Called at trace dump point time. Creates a snapshot of the memory maps for | 359 // Called at trace dump point time. Creates a snapshot of the memory maps for |
| 264 // the current process. | 360 // the current process. |
| 265 bool ProcessMetricsMemoryDumpProvider::OnMemoryDump( | 361 bool ProcessMetricsMemoryDumpProvider::OnMemoryDump( |
| 266 const base::trace_event::MemoryDumpArgs& args, | 362 const base::trace_event::MemoryDumpArgs& args, |
| 267 base::trace_event::ProcessMemoryDump* pmd) { | 363 base::trace_event::ProcessMemoryDump* pmd) { |
| 268 bool res = DumpProcessTotals(args, pmd); | 364 bool res = DumpProcessTotals(args, pmd); |
| 269 | 365 |
| 270 #if defined(OS_LINUX) || defined(OS_ANDROID) | 366 #if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) |
| 271 if (args.level_of_detail == | 367 if (args.level_of_detail == |
| 272 base::trace_event::MemoryDumpLevelOfDetail::DETAILED) | 368 base::trace_event::MemoryDumpLevelOfDetail::DETAILED) |
| 273 res &= DumpProcessMemoryMaps(args, pmd); | 369 res &= DumpProcessMemoryMaps(args, pmd); |
| 274 #endif | 370 #endif // defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) |
| 275 return res; | 371 return res; |
| 276 } | 372 } |
| 277 | 373 |
| 278 bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals( | 374 bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals( |
| 279 const base::trace_event::MemoryDumpArgs& args, | 375 const base::trace_event::MemoryDumpArgs& args, |
| 280 base::trace_event::ProcessMemoryDump* pmd) { | 376 base::trace_event::ProcessMemoryDump* pmd) { |
| 281 const uint64_t rss_bytes = rss_bytes_for_testing | 377 const uint64_t rss_bytes = rss_bytes_for_testing |
| 282 ? rss_bytes_for_testing | 378 ? rss_bytes_for_testing |
| 283 : process_metrics_->GetWorkingSetSize(); | 379 : process_metrics_->GetWorkingSetSize(); |
| 284 | 380 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 #endif | 463 #endif |
| 368 } | 464 } |
| 369 | 465 |
| 370 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { | 466 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { |
| 371 #if defined(OS_LINUX) || defined(OS_ANDROID) | 467 #if defined(OS_LINUX) || defined(OS_ANDROID) |
| 372 fast_polling_statm_fd_.reset(); | 468 fast_polling_statm_fd_.reset(); |
| 373 #endif | 469 #endif |
| 374 } | 470 } |
| 375 | 471 |
| 376 } // namespace tracing | 472 } // namespace tracing |
| OLD | NEW |