1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright 2015 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/process_memory_dump.h" 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 70d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <errno.h> 894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 90d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <vector> 100d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include "base/memory/ptr_util.h" 120d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/process/process_metrics.h" 1394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include "base/strings/stringprintf.h" 1494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include "base/trace_event/heap_profiler_heap_dump_writer.h" 150c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez#include "base/trace_event/memory_infra_background_whitelist.h" 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/process_memory_totals.h" 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/trace_event_argument.h" 180d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "build/build_config.h" 190d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 2045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#if defined(OS_IOS) 213a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli#include <mach/vm_page_size.h> 2245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#endif 2345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 240d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#if defined(OS_POSIX) 250d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <sys/mman.h> 260d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#endif 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 2845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#if defined(OS_WIN) 2945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include <Psapi.h> 3045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#endif 3145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace trace_event { 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 360d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratconst char kEdgeTypeOwnership[] = "ownership"; 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstd::string GetSharedGlobalAllocatorDumpName( 40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const MemoryAllocatorDumpGuid& guid) { 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return "global/" + guid.ToString(); 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 430d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 4445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#if defined(COUNT_RESIDENT_BYTES_SUPPORTED) 4545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkosize_t GetSystemPageCount(size_t mapped_size, size_t page_size) { 4645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko return (mapped_size + page_size - 1) / page_size; 4745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko} 4845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#endif 4945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 520c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez// static 530c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavezbool ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = false; 540c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez 550d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#if defined(COUNT_RESIDENT_BYTES_SUPPORTED) 560d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// static 5745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkosize_t ProcessMemoryDump::GetSystemPageSize() { 5845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#if defined(OS_IOS) 5945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // On iOS, getpagesize() returns the user page sizes, but for allocating 603a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // arrays for mincore(), kernel page sizes is needed. Use vm_kernel_page_size 613a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // as recommended by Apple, https://forums.developer.apple.com/thread/47532/. 623a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Refer to http://crbug.com/542671 and Apple rdar://23651782 633a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli return vm_kernel_page_size; 643a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli#else 65e5b2c6fa6f923f3a2f66346c2f169d9f0fceb3dcLuis Hector Chavez return base::GetPageSize(); 663a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli#endif // defined(OS_IOS) 6745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko} 6845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 6945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static 700d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkosize_t ProcessMemoryDump::CountResidentBytes(void* start_address, 710d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko size_t mapped_size) { 7245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko const size_t page_size = GetSystemPageSize(); 730d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address); 740d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko DCHECK_EQ(0u, start_pointer % page_size); 750d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 760d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko size_t offset = 0; 770d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko size_t total_resident_size = 0; 7845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko bool failure = false; 7945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 8045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // An array as large as number of pages in memory segment needs to be passed 8145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // to the query function. To avoid allocating a large array, the given block 8245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // of memory is split into chunks of size |kMaxChunkSize|. 8345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko const size_t kMaxChunkSize = 8 * 1024 * 1024; 8445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko size_t max_vec_size = 8545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko GetSystemPageCount(std::min(mapped_size, kMaxChunkSize), page_size); 8645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#if defined(OS_MACOSX) || defined(OS_IOS) 8794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez std::unique_ptr<char[]> vec(new char[max_vec_size]); 8845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#elif defined(OS_WIN) 8994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez std::unique_ptr<PSAPI_WORKING_SET_EX_INFORMATION[]> vec( 9045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko new PSAPI_WORKING_SET_EX_INFORMATION[max_vec_size]); 9145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#elif defined(OS_POSIX) 9294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez std::unique_ptr<unsigned char[]> vec(new unsigned char[max_vec_size]); 9345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#endif 9445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 950d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko while (offset < mapped_size) { 9645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko uintptr_t chunk_start = (start_pointer + offset); 970d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize); 9845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko const size_t page_count = GetSystemPageCount(chunk_size, page_size); 990d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko size_t resident_page_count = 0; 1000d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1010d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#if defined(OS_MACOSX) || defined(OS_IOS) 1020d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // mincore in MAC does not fail with EAGAIN. 10345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko failure = 10445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko !!mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get()); 1050d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko for (size_t i = 0; i < page_count; i++) 1060d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0; 10745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#elif defined(OS_WIN) 10845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko for (size_t i = 0; i < page_count; i++) { 10945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko vec[i].VirtualAddress = 11045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko reinterpret_cast<void*>(chunk_start + i * page_size); 11145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko } 11245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko DWORD vec_size = static_cast<DWORD>( 11345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko page_count * sizeof(PSAPI_WORKING_SET_EX_INFORMATION)); 11445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko failure = !QueryWorkingSetEx(GetCurrentProcess(), vec.get(), vec_size); 11545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 11645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko for (size_t i = 0; i < page_count; i++) 11745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko resident_page_count += vec[i].VirtualAttributes.Valid; 11845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#elif defined(OS_POSIX) 1190d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko int error_counter = 0; 12045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko int result = 0; 1210d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // HANDLE_EINTR tries for 100 times. So following the same pattern. 1220d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko do { 12345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko result = 12445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get()); 1250d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } while (result == -1 && errno == EAGAIN && error_counter++ < 100); 12645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko failure = !!result; 1270d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1280d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko for (size_t i = 0; i < page_count; i++) 12945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko resident_page_count += vec[i] & 1; 13045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#endif 13145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 13245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (failure) 13345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko break; 1340d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1350d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko total_resident_size += resident_page_count * page_size; 1360d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko offset += kMaxChunkSize; 1370d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 1380d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 13945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko DCHECK(!failure); 14045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (failure) { 1410d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko total_resident_size = 0; 14245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko LOG(ERROR) << "CountResidentBytes failed. The resident size is invalid"; 1430d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 1440d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko return total_resident_size; 1450d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} 1460d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) 1470d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratProcessMemoryDump::ProcessMemoryDump( 1490c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez scoped_refptr<MemoryDumpSessionState> session_state, 1500c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez const MemoryDumpArgs& dump_args) 151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat : has_process_totals_(false), 152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat has_process_mmaps_(false), 1530c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez session_state_(std::move(session_state)), 1540c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez dump_args_(dump_args) {} 155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 15645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoProcessMemoryDump::~ProcessMemoryDump() {} 157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( 159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const std::string& absolute_name) { 16045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko return AddAllocatorDumpInternal( 1613a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli MakeUnique<MemoryAllocatorDump>(absolute_name, this)); 162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( 165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const std::string& absolute_name, 166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const MemoryAllocatorDumpGuid& guid) { 16745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko return AddAllocatorDumpInternal( 1683a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli MakeUnique<MemoryAllocatorDump>(absolute_name, this, guid)); 169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 17145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoMemoryAllocatorDump* ProcessMemoryDump::AddAllocatorDumpInternal( 17294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez std::unique_ptr<MemoryAllocatorDump> mad) { 1730c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez // In background mode return the black hole dump, if invalid dump name is 1740c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez // given. 1750c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND && 1760c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez !IsMemoryAllocatorDumpNameWhitelisted(mad->absolute_name())) { 1770c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return GetBlackHoleMad(); 1780c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez } 1790c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez 18045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko auto insertion_result = allocator_dumps_.insert( 18145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko std::make_pair(mad->absolute_name(), std::move(mad))); 18294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez MemoryAllocatorDump* inserted_mad = insertion_result.first->second.get(); 18394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez DCHECK(insertion_result.second) << "Duplicate name: " 18494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez << inserted_mad->absolute_name(); 18594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez return inserted_mad; 186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump( 189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const std::string& absolute_name) const { 190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat auto it = allocator_dumps_.find(absolute_name); 1910c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez if (it != allocator_dumps_.end()) 1920c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return it->second.get(); 1930c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez if (black_hole_mad_) 1940c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return black_hole_mad_.get(); 1950c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return nullptr; 196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 1980d205d712abd16eeed2f5d5b1052a367d23a223fAlex VakulenkoMemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump( 1990d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko const std::string& absolute_name) { 2000d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name); 2010d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko return mad ? mad : CreateAllocatorDump(absolute_name); 2020d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} 2030d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 204b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump( 205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const MemoryAllocatorDumpGuid& guid) { 2060c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez // Global dumps are disabled in background mode. 2070c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) 2080c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return GetBlackHoleMad(); 2090c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez 2100d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // A shared allocator dump can be shared within a process and the guid could 2110d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // have been created already. 21245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); 21345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (mad) { 21445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // The weak flag is cleared because this method should create a non-weak 21545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // dump. 21645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko mad->clear_flags(MemoryAllocatorDump::Flags::WEAK); 21745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko return mad; 21845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko } 21945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); 22045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko} 22145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 22245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoMemoryAllocatorDump* ProcessMemoryDump::CreateWeakSharedGlobalAllocatorDump( 22345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko const MemoryAllocatorDumpGuid& guid) { 2240c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez // Global dumps are disabled in background mode. 2250c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) 2260c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return GetBlackHoleMad(); 2270c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez 22845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); 22945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (mad) 23045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko return mad; 23145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko mad = CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); 23245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko mad->set_flags(MemoryAllocatorDump::Flags::WEAK); 23345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko return mad; 234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump( 237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const MemoryAllocatorDumpGuid& guid) const { 238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid)); 239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 24194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid ProcessMemoryDump::DumpHeapUsage( 24294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez const base::hash_map<base::trace_event::AllocationContext, 24394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez base::trace_event::AllocationMetrics>& metrics_by_context, 24494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez base::trace_event::TraceEventMemoryOverhead& overhead, 24594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez const char* allocator_name) { 24694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez if (!metrics_by_context.empty()) { 2470c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez DCHECK_EQ(0ul, heap_dumps_.count(allocator_name)); 24894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez std::unique_ptr<TracedValue> heap_dump = ExportHeapDump( 24994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez metrics_by_context, *session_state()); 2500c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez heap_dumps_[allocator_name] = std::move(heap_dump); 25194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez } 25294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 25394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez std::string base_name = base::StringPrintf("tracing/heap_profiler_%s", 25494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez allocator_name); 25594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez overhead.DumpInto(base_name.c_str(), this); 25694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez} 25794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 258b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::Clear() { 259b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (has_process_totals_) { 260b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat process_totals_.Clear(); 261b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat has_process_totals_ = false; 262b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 263b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 264b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (has_process_mmaps_) { 265b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat process_mmaps_.Clear(); 266b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat has_process_mmaps_ = false; 267b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 268b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 269b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat allocator_dumps_.clear(); 270b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat allocator_dumps_edges_.clear(); 2710d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko heap_dumps_.clear(); 272b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 273b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 274b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) { 275b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK(!other->has_process_totals() && !other->has_process_mmaps()); 276b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 277b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Moves the ownership of all MemoryAllocatorDump(s) contained in |other| 27845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // into this ProcessMemoryDump, checking for duplicates. 27945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko for (auto& it : other->allocator_dumps_) 28045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko AddAllocatorDumpInternal(std::move(it.second)); 281b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat other->allocator_dumps_.clear(); 282b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 283b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Move all the edges. 284b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat allocator_dumps_edges_.insert(allocator_dumps_edges_.end(), 285b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat other->allocator_dumps_edges_.begin(), 286b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat other->allocator_dumps_edges_.end()); 287b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat other->allocator_dumps_edges_.clear(); 2880d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 28945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko for (auto& it : other->heap_dumps_) { 29045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko DCHECK_EQ(0ul, heap_dumps_.count(it.first)); 29145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko heap_dumps_.insert(std::make_pair(it.first, std::move(it.second))); 29245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko } 2930d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko other->heap_dumps_.clear(); 294b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 295b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 296b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AsValueInto(TracedValue* value) const { 297b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (has_process_totals_) { 298b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->BeginDictionary("process_totals"); 299b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat process_totals_.AsValueInto(value); 300b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->EndDictionary(); 301b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 302b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 303b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (has_process_mmaps_) { 304b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->BeginDictionary("process_mmaps"); 305b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat process_mmaps_.AsValueInto(value); 306b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->EndDictionary(); 307b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 308b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 30945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (allocator_dumps_.size() > 0) { 310b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->BeginDictionary("allocators"); 31145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko for (const auto& allocator_dump_it : allocator_dumps_) 31245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko allocator_dump_it.second->AsValueInto(value); 313b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->EndDictionary(); 314b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 315b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 3160d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (heap_dumps_.size() > 0) { 3170d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko value->BeginDictionary("heaps"); 3180d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko for (const auto& name_and_dump : heap_dumps_) 3190d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second); 3200d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko value->EndDictionary(); // "heaps" 3210d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 3220d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 323b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->BeginArray("allocators_graph"); 324b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) { 325b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->BeginDictionary(); 326b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->SetString("source", edge.source.ToString()); 327b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->SetString("target", edge.target.ToString()); 328b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->SetInteger("importance", edge.importance); 329b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->SetString("type", edge.type); 330b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->EndDictionary(); 331b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 332b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat value->EndArray(); 333b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 334b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 335b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AddOwnershipEdge(const MemoryAllocatorDumpGuid& source, 336b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const MemoryAllocatorDumpGuid& target, 337b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int importance) { 338b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat allocator_dumps_edges_.push_back( 339b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat {source, target, importance, kEdgeTypeOwnership}); 340b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 341b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 342b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AddOwnershipEdge( 343b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const MemoryAllocatorDumpGuid& source, 344b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const MemoryAllocatorDumpGuid& target) { 345b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AddOwnershipEdge(source, target, 0 /* importance */); 346b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 347b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 348b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source, 349b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const std::string& target_node_name) { 3500c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez // Do not create new dumps for suballocations in background mode. 3510c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) 3520c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return; 3530c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez 354b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat std::string child_mad_name = target_node_name + "/__" + source.ToString(); 355b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name); 356b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AddOwnershipEdge(source, target_child_mad->guid()); 357b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 358b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 3590c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector ChavezMemoryAllocatorDump* ProcessMemoryDump::GetBlackHoleMad() { 3600c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez DCHECK(is_black_hole_non_fatal_for_testing_); 3610c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez if (!black_hole_mad_) 3620c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez black_hole_mad_.reset(new MemoryAllocatorDump("discarded", this)); 3630c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez return black_hole_mad_.get(); 3640c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez} 3650c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez 366b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace trace_event 367b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 368