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