Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(481)

Side by Side Diff: components/tracing/common/process_metrics_memory_dump_provider.cc

Issue 2601193002: Emit VMRegions for macOS when doing process memory dumps. (Closed)
Patch Set: Update test. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #endif // defined(OS_MACOSX)
33
27 namespace tracing { 34 namespace tracing {
28 35
29 namespace { 36 namespace {
30 37
31 base::LazyInstance< 38 base::LazyInstance<
32 std::map<base::ProcessId, 39 std::map<base::ProcessId,
33 std::unique_ptr<ProcessMetricsMemoryDumpProvider>>>::Leaky 40 std::unique_ptr<ProcessMetricsMemoryDumpProvider>>>::Leaky
34 g_dump_providers_map = LAZY_INSTANCE_INITIALIZER; 41 g_dump_providers_map = LAZY_INSTANCE_INITIALIZER;
35 42
36 #if defined(OS_LINUX) || defined(OS_ANDROID) 43 #if defined(OS_LINUX) || defined(OS_ANDROID)
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 base::ScopedFILE smaps_file(fopen(file_name.c_str(), "r")); 219 base::ScopedFILE smaps_file(fopen(file_name.c_str(), "r"));
213 res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps()); 220 res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps());
214 } 221 }
215 222
216 if (res) 223 if (res)
217 pmd->set_has_process_mmaps(); 224 pmd->set_has_process_mmaps();
218 return res; 225 return res;
219 } 226 }
220 #endif // defined(OS_LINUX) || defined(OS_ANDROID) 227 #endif // defined(OS_LINUX) || defined(OS_ANDROID)
221 228
229 #if defined(OS_MACOSX)
230 bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
231 const base::trace_event::MemoryDumpArgs& args,
232 base::trace_event::ProcessMemoryDump* pmd) {
233 int pid = getpid();
Mark Mentovai 2017/01/31 17:49:21 Optional: lately, I’ve enjoyed marking things like
erikchen 2017/01/31 20:01:18 Done.
234 uint64_t kPageSize = 4096;
Mark Mentovai 2017/01/31 17:49:21 Don’t define this yourself. Use PAGE_SIZE.
erikchen 2017/01/31 20:01:18 Done.
235 using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
236 typedef vm_region_submap_info_64 RegionInfo;
Mark Mentovai 2017/01/31 17:49:21 Since you used new-style “using” on the line befor
erikchen 2017/01/31 20:01:17 *cough* I copy pasted some code.
237 mach_vm_address_t address = 0;
238 mach_vm_size_t vmsize = 0;
239 natural_t depth = 0;
240 RegionInfo vminfo;
241 mach_msg_type_number_t count = sizeof(RegionInfo);
242 kern_return_t kr = KERN_SUCCESS;
Mark Mentovai 2017/01/31 17:49:21 You can move this inside the loop. There’s no need
erikchen 2017/01/31 20:01:17 Done.
243 while (true) {
244 kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,
245 (vm_region_info_t)&vminfo, &count);
Mark Mentovai 2017/01/31 17:49:21 Use cplusplus<style>(casts).
erikchen 2017/01/31 20:01:17 Done.
246 if (kr != KERN_SUCCESS)
Mark Mentovai 2017/01/31 17:49:21 I think that this should be if (kr == KERN_INVA
erikchen 2017/01/31 20:01:17 Done.
247 break;
248
249 if ((int)vminfo.is_submap) {
Mark Mentovai 2017/01/31 17:49:21 Lose the cast.
erikchen 2017/01/31 20:01:18 Done.
250 ++depth;
251 continue;
252 }
253
254 VMRegion region;
255
256 // See vm_map_region_walk and vm_map_region_look_for_page in
257 // osfmk/vm/vm_map.c for more details.
258 if (vminfo.share_mode == SM_EMPTY || vminfo.share_mode == SM_LARGE_PAGE) {
Mark Mentovai 2017/01/31 17:49:21 Is there really nothing that we can fill out for S
erikchen 2017/01/31 20:01:17 Hm. In https://llvm.org/svn/llvm-project/lldb/trun
259 } else if (vminfo.share_mode == SM_COW) {
260 region.byte_stats_private_dirty_resident =
261 vminfo.pages_shared_now_private * kPageSize;
262 region.byte_stats_shared_clean_resident =
263 (vminfo.pages_resident - vminfo.pages_shared_now_private) *
264 kPageSize;
265 } else if (vminfo.share_mode == SM_PRIVATE) {
266 region.byte_stats_private_dirty_resident =
267 vminfo.pages_dirtied * kPageSize;
268 region.byte_stats_private_clean_resident =
269 (vminfo.pages_resident - vminfo.pages_dirtied) * kPageSize;
270 } else if (vminfo.share_mode == SM_SHARED ||
271 vminfo.share_mode == SM_PRIVATE_ALIASED ||
272 vminfo.share_mode == SM_TRUESHARED ||
273 vminfo.share_mode == SM_SHARED_ALIASED) {
274 region.byte_stats_shared_dirty_resident =
275 vminfo.pages_dirtied * kPageSize;
276 region.byte_stats_shared_clean_resident =
277 (vminfo.pages_resident - vminfo.pages_dirtied) * kPageSize;
278 } else {
279 NOTREACHED();
280 }
281
282 if (vminfo.protection & VM_PROT_READ)
283 region.protection_flags |= VMRegion::kProtectionFlagsRead;
284 if (vminfo.protection & VM_PROT_WRITE)
285 region.protection_flags |= VMRegion::kProtectionFlagsWrite;
286 if (vminfo.protection & VM_PROT_EXECUTE)
287 region.protection_flags |= VMRegion::kProtectionFlagsExec;
288
289 char buffer[MAXPATHLEN];
290 int length = proc_regionfilename(pid, address, buffer, MAXPATHLEN);
Mark Mentovai 2017/01/31 17:49:21 A problem here is that you get a couple of giganti
erikchen 2017/01/31 20:01:17 Noted. We can add more information when we decide
291 if (length != 0)
292 region.mapped_file = std::string(buffer, length);
Mark Mentovai 2017/01/31 17:49:21 I don’t know if the compiler can always optimize a
erikchen 2017/01/31 20:01:18 Done.
293
294 region.byte_stats_swapped = vminfo.pages_swapped_out * kPageSize;
295 region.start_address = address;
296 region.size_in_bytes = vmsize;
297 pmd->process_mmaps()->AddVMRegion(region);
298
299 address = address + vmsize;
Mark Mentovai 2017/01/31 17:49:21 +=
erikchen 2017/01/31 20:01:17 Done.
300 if (address == 0u)
Mark Mentovai 2017/01/31 17:49:21 I think you want to test whether address overflowe
erikchen 2017/01/31 20:01:17 Done.
301 break;
302 }
303
304 pmd->set_has_process_mmaps();
305 return true;
306 }
307 #endif // defined(OS_MACOSX)
308
222 // static 309 // static
223 void ProcessMetricsMemoryDumpProvider::RegisterForProcess( 310 void ProcessMetricsMemoryDumpProvider::RegisterForProcess(
224 base::ProcessId process) { 311 base::ProcessId process) {
225 std::unique_ptr<ProcessMetricsMemoryDumpProvider> metrics_provider( 312 std::unique_ptr<ProcessMetricsMemoryDumpProvider> metrics_provider(
226 new ProcessMetricsMemoryDumpProvider(process)); 313 new ProcessMetricsMemoryDumpProvider(process));
227 base::trace_event::MemoryDumpProvider::Options options; 314 base::trace_event::MemoryDumpProvider::Options options;
228 options.target_pid = process; 315 options.target_pid = process;
229 options.is_fast_polling_supported = true; 316 options.is_fast_polling_supported = true;
230 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( 317 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
231 metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options); 318 metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options);
(...skipping 28 matching lines...) Expand all
260 347
261 ProcessMetricsMemoryDumpProvider::~ProcessMetricsMemoryDumpProvider() {} 348 ProcessMetricsMemoryDumpProvider::~ProcessMetricsMemoryDumpProvider() {}
262 349
263 // Called at trace dump point time. Creates a snapshot of the memory maps for 350 // Called at trace dump point time. Creates a snapshot of the memory maps for
264 // the current process. 351 // the current process.
265 bool ProcessMetricsMemoryDumpProvider::OnMemoryDump( 352 bool ProcessMetricsMemoryDumpProvider::OnMemoryDump(
266 const base::trace_event::MemoryDumpArgs& args, 353 const base::trace_event::MemoryDumpArgs& args,
267 base::trace_event::ProcessMemoryDump* pmd) { 354 base::trace_event::ProcessMemoryDump* pmd) {
268 bool res = DumpProcessTotals(args, pmd); 355 bool res = DumpProcessTotals(args, pmd);
269 356
270 #if defined(OS_LINUX) || defined(OS_ANDROID) 357 #if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX)
271 if (args.level_of_detail == 358 if (args.level_of_detail ==
272 base::trace_event::MemoryDumpLevelOfDetail::DETAILED) 359 base::trace_event::MemoryDumpLevelOfDetail::DETAILED)
273 res &= DumpProcessMemoryMaps(args, pmd); 360 res &= DumpProcessMemoryMaps(args, pmd);
274 #endif 361 #endif // defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX)
275 return res; 362 return res;
276 } 363 }
277 364
278 bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals( 365 bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals(
279 const base::trace_event::MemoryDumpArgs& args, 366 const base::trace_event::MemoryDumpArgs& args,
280 base::trace_event::ProcessMemoryDump* pmd) { 367 base::trace_event::ProcessMemoryDump* pmd) {
281 const uint64_t rss_bytes = rss_bytes_for_testing 368 const uint64_t rss_bytes = rss_bytes_for_testing
282 ? rss_bytes_for_testing 369 ? rss_bytes_for_testing
283 : process_metrics_->GetWorkingSetSize(); 370 : process_metrics_->GetWorkingSetSize();
284 371
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 #endif 454 #endif
368 } 455 }
369 456
370 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { 457 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() {
371 #if defined(OS_LINUX) || defined(OS_ANDROID) 458 #if defined(OS_LINUX) || defined(OS_ANDROID)
372 fast_polling_statm_fd_.reset(); 459 fast_polling_statm_fd_.reset();
373 #endif 460 #endif
374 } 461 }
375 462
376 } // namespace tracing 463 } // namespace tracing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698