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
7cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <errno.h>
8cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <vector>
9cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
10cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "base/process/process_metrics.h"
11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/process_memory_totals.h"
12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/trace_event_argument.h"
13cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "build/build_config.h"
14cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
15cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#if defined(OS_POSIX)
16cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <sys/mman.h>
17cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#endif
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace trace_event {
21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace {
23cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratconst char kEdgeTypeOwnership[] = "ownership";
25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstd::string GetSharedGlobalAllocatorDumpName(
27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const MemoryAllocatorDumpGuid& guid) {
28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return "global/" + guid.ToString();
29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
30cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace
32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
33cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
34cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko// static
35cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenkosize_t ProcessMemoryDump::CountResidentBytes(void* start_address,
36cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko                                             size_t mapped_size) {
37cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  const size_t page_size = GetPageSize();
38cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address);
39cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  DCHECK_EQ(0u, start_pointer % page_size);
40cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
41cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  // This function allocates a char vector of size number of pages in the given
42cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  // mapped_size. To avoid allocating a large array, the memory is split into
43cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  // chunks. Maximum size of vector allocated, will be
44cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  // kPageChunkSize / page_size.
45cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  const size_t kMaxChunkSize = 32 * 1024 * 1024;
46cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  size_t offset = 0;
47cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  size_t total_resident_size = 0;
48cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  int result = 0;
49cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  while (offset < mapped_size) {
50cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    void* chunk_start = reinterpret_cast<void*>(start_pointer + offset);
51cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize);
52cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    const size_t page_count = (chunk_size + page_size - 1) / page_size;
53cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    size_t resident_page_count = 0;
54cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
55cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#if defined(OS_MACOSX) || defined(OS_IOS)
56cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    std::vector<char> vec(page_count + 1);
57cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    // mincore in MAC does not fail with EAGAIN.
58cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    result = mincore(chunk_start, chunk_size, vec.data());
59cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    if (result)
60cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko      break;
61cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
62cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    for (size_t i = 0; i < page_count; i++)
63cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko      resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0;
64cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#else   // defined(OS_MACOSX) || defined(OS_IOS)
65cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    std::vector<unsigned char> vec(page_count + 1);
66cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    int error_counter = 0;
67cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    // HANDLE_EINTR tries for 100 times. So following the same pattern.
68cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    do {
69cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko      result = mincore(chunk_start, chunk_size, vec.data());
70cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    } while (result == -1 && errno == EAGAIN && error_counter++ < 100);
71cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    if (result)
72cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko      break;
73cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
74cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    for (size_t i = 0; i < page_count; i++)
75cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko      resident_page_count += vec[i];
76cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#endif  // defined(OS_MACOSX) || defined(OS_IOS)
77cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
78cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    total_resident_size += resident_page_count * page_size;
79cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    offset += kMaxChunkSize;
80cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  }
81cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
82cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  DCHECK_EQ(0, result);
83cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  if (result) {
84cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    total_resident_size = 0;
85cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    LOG(ERROR) << "mincore() call failed. The resident size is invalid";
86cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  }
87cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  return total_resident_size;
88cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko}
89cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#endif  // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
90cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratProcessMemoryDump::ProcessMemoryDump(
92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const scoped_refptr<MemoryDumpSessionState>& session_state)
93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    : has_process_totals_(false),
94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      has_process_mmaps_(false),
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      session_state_(session_state) {
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratProcessMemoryDump::~ProcessMemoryDump() {
99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const std::string& absolute_name) {
103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this);
104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  AddAllocatorDumpInternal(mad);  // Takes ownership of |mad|.
105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return mad;
106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const std::string& absolute_name,
110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const MemoryAllocatorDumpGuid& guid) {
111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this, guid);
112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  AddAllocatorDumpInternal(mad);  // Takes ownership of |mad|.
113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return mad;
114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AddAllocatorDumpInternal(MemoryAllocatorDump* mad) {
117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK_EQ(0ul, allocator_dumps_.count(mad->absolute_name()));
118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  allocator_dumps_storage_.push_back(mad);
119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  allocator_dumps_[mad->absolute_name()] = mad;
120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const std::string& absolute_name) const {
124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  auto it = allocator_dumps_.find(absolute_name);
125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return it == allocator_dumps_.end() ? nullptr : it->second;
126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
128cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex VakulenkoMemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump(
129cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    const std::string& absolute_name) {
130cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name);
131cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  return mad ? mad : CreateAllocatorDump(absolute_name);
132cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko}
133cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump(
135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const MemoryAllocatorDumpGuid& guid) {
136cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  // A shared allocator dump can be shared within a process and the guid could
137cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  // have been created already.
138cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  MemoryAllocatorDump* allocator_dump = GetSharedGlobalAllocatorDump(guid);
139cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  return allocator_dump ? allocator_dump
140cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko                        : CreateAllocatorDump(
141cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko                              GetSharedGlobalAllocatorDumpName(guid), guid);
142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratMemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const MemoryAllocatorDumpGuid& guid) const {
146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid));
147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
149cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenkovoid ProcessMemoryDump::AddHeapDump(const std::string& absolute_name,
150cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko                                    scoped_refptr<TracedValue> heap_dump) {
151cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  DCHECK_EQ(0ul, heap_dumps_.count(absolute_name));
152cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  heap_dumps_[absolute_name] = heap_dump;
153cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko}
154cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::Clear() {
156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (has_process_totals_) {
157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    process_totals_.Clear();
158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    has_process_totals_ = false;
159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (has_process_mmaps_) {
162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    process_mmaps_.Clear();
163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    has_process_mmaps_ = false;
164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  allocator_dumps_storage_.clear();
167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  allocator_dumps_.clear();
168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  allocator_dumps_edges_.clear();
169cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  heap_dumps_.clear();
170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(!other->has_process_totals() && !other->has_process_mmaps());
174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Moves the ownership of all MemoryAllocatorDump(s) contained in |other|
176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // into this ProcessMemoryDump.
177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (MemoryAllocatorDump* mad : other->allocator_dumps_storage_) {
178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Check that we don't merge duplicates.
179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DCHECK_EQ(0ul, allocator_dumps_.count(mad->absolute_name()));
180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    allocator_dumps_storage_.push_back(mad);
181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    allocator_dumps_[mad->absolute_name()] = mad;
182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
183b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  other->allocator_dumps_storage_.weak_clear();
184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  other->allocator_dumps_.clear();
185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Move all the edges.
187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  allocator_dumps_edges_.insert(allocator_dumps_edges_.end(),
188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                other->allocator_dumps_edges_.begin(),
189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                other->allocator_dumps_edges_.end());
190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  other->allocator_dumps_edges_.clear();
191cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
192cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  heap_dumps_.insert(other->heap_dumps_.begin(), other->heap_dumps_.end());
193cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  other->heap_dumps_.clear();
194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AsValueInto(TracedValue* value) const {
197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (has_process_totals_) {
198b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->BeginDictionary("process_totals");
199b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    process_totals_.AsValueInto(value);
200b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->EndDictionary();
201b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
202b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
203b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (has_process_mmaps_) {
204b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->BeginDictionary("process_mmaps");
205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    process_mmaps_.AsValueInto(value);
206b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->EndDictionary();
207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
208b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
209b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (allocator_dumps_storage_.size() > 0) {
210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->BeginDictionary("allocators");
211b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    for (const MemoryAllocatorDump* allocator_dump : allocator_dumps_storage_)
212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      allocator_dump->AsValueInto(value);
213b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->EndDictionary();
214b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
215b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
216cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  if (heap_dumps_.size() > 0) {
217cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    value->BeginDictionary("heaps");
218cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    for (const auto& name_and_dump : heap_dumps_)
219cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko      value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second);
220cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko    value->EndDictionary();  // "heaps"
221cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  }
222cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko
223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  value->BeginArray("allocators_graph");
224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) {
225b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->BeginDictionary();
226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->SetString("source", edge.source.ToString());
227b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->SetString("target", edge.target.ToString());
228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->SetInteger("importance", edge.importance);
229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->SetString("type", edge.type);
230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    value->EndDictionary();
231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
232b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  value->EndArray();
233b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                         const MemoryAllocatorDumpGuid& target,
237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                         int importance) {
238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  allocator_dumps_edges_.push_back(
239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      {source, target, importance, kEdgeTypeOwnership});
240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
241b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
242b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AddOwnershipEdge(
243b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const MemoryAllocatorDumpGuid& source,
244b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const MemoryAllocatorDumpGuid& target) {
245b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  AddOwnershipEdge(source, target, 0 /* importance */);
246b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
247b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
248b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source,
249b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                         const std::string& target_node_name) {
250b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  std::string child_mad_name = target_node_name + "/__" + source.ToString();
251b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name);
252b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  AddOwnershipEdge(source, target_child_mad->guid());
253b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
254b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
255b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace trace_event
256b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
257