primiano | f11ccf5 | 2015-02-17 23:21:19 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/trace_event/process_memory_dump.h" |
| 6 | |
mostynb | d0170823 | 2015-11-05 11:03:06 | [diff] [blame] | 7 | #include <errno.h> |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 8 | |
thestig | db54eaf | 2015-10-13 06:19:28 | [diff] [blame] | 9 | #include <vector> |
| 10 | |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 11 | #include "base/memory/ptr_util.h" |
jbroman | 59915fe | 2015-10-22 18:11:33 | [diff] [blame] | 12 | #include "base/process/process_metrics.h" |
bashi | b873c0d4 | 2016-05-12 05:41:04 | [diff] [blame] | 13 | #include "base/strings/stringprintf.h" |
| 14 | #include "base/trace_event/heap_profiler_heap_dump_writer.h" |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 15 | #include "base/trace_event/memory_infra_background_whitelist.h" |
primiano | c96eca7 | 2015-02-20 16:41:14 | [diff] [blame] | 16 | #include "base/trace_event/process_memory_totals.h" |
| 17 | #include "base/trace_event/trace_event_argument.h" |
avi | bd1ed05 | 2015-12-24 04:03:44 | [diff] [blame] | 18 | #include "build/build_config.h" |
primiano | f11ccf5 | 2015-02-17 23:21:19 | [diff] [blame] | 19 | |
pkl | 0b19e32e | 2016-03-16 16:57:29 | [diff] [blame] | 20 | #if defined(OS_IOS) |
sdefresne | 8bb015f | 2016-09-27 14:39:37 | [diff] [blame] | 21 | #include <mach/vm_page_size.h> |
pkl | 0b19e32e | 2016-03-16 16:57:29 | [diff] [blame] | 22 | #endif |
| 23 | |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 24 | #if defined(OS_POSIX) |
| 25 | #include <sys/mman.h> |
| 26 | #endif |
| 27 | |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 28 | #if defined(OS_WIN) |
| 29 | #include <Psapi.h> |
| 30 | #endif |
| 31 | |
primiano | f11ccf5 | 2015-02-17 23:21:19 | [diff] [blame] | 32 | namespace base { |
| 33 | namespace trace_event { |
| 34 | |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 35 | namespace { |
thestig | db54eaf | 2015-10-13 06:19:28 | [diff] [blame] | 36 | |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 37 | const char kEdgeTypeOwnership[] = "ownership"; |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 38 | |
| 39 | std::string GetSharedGlobalAllocatorDumpName( |
| 40 | const MemoryAllocatorDumpGuid& guid) { |
| 41 | return "global/" + guid.ToString(); |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 42 | } |
thestig | db54eaf | 2015-10-13 06:19:28 | [diff] [blame] | 43 | |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 44 | #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
| 45 | size_t GetSystemPageCount(size_t mapped_size, size_t page_size) { |
| 46 | return (mapped_size + page_size - 1) / page_size; |
| 47 | } |
| 48 | #endif |
| 49 | |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 50 | } // namespace |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 51 | |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 52 | // static |
| 53 | bool ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = false; |
| 54 | |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 55 | #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
| 56 | // static |
pkl | 0b19e32e | 2016-03-16 16:57:29 | [diff] [blame] | 57 | size_t ProcessMemoryDump::GetSystemPageSize() { |
| 58 | #if defined(OS_IOS) |
| 59 | // On iOS, getpagesize() returns the user page sizes, but for allocating |
sdefresne | 8bb015f | 2016-09-27 14:39:37 | [diff] [blame] | 60 | // arrays for mincore(), kernel page sizes is needed. Use vm_kernel_page_size |
| 61 | // as recommended by Apple, https://forums.developer.apple.com/thread/47532/. |
| 62 | // Refer to http://crbug.com/542671 and Apple rdar://23651782 |
| 63 | return vm_kernel_page_size; |
| 64 | #else |
pkl | 0b19e32e | 2016-03-16 16:57:29 | [diff] [blame] | 65 | return base::GetPageSize(); |
sdefresne | 8bb015f | 2016-09-27 14:39:37 | [diff] [blame] | 66 | #endif // defined(OS_IOS) |
pkl | 0b19e32e | 2016-03-16 16:57:29 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | // static |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 70 | size_t ProcessMemoryDump::CountResidentBytes(void* start_address, |
| 71 | size_t mapped_size) { |
pkl | 0b19e32e | 2016-03-16 16:57:29 | [diff] [blame] | 72 | const size_t page_size = GetSystemPageSize(); |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 73 | const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address); |
| 74 | DCHECK_EQ(0u, start_pointer % page_size); |
| 75 | |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 76 | size_t offset = 0; |
| 77 | size_t total_resident_size = 0; |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 78 | bool failure = false; |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 79 | |
| 80 | // An array as large as number of pages in memory segment needs to be passed |
| 81 | // to the query function. To avoid allocating a large array, the given block |
| 82 | // of memory is split into chunks of size |kMaxChunkSize|. |
| 83 | const size_t kMaxChunkSize = 8 * 1024 * 1024; |
| 84 | size_t max_vec_size = |
| 85 | GetSystemPageCount(std::min(mapped_size, kMaxChunkSize), page_size); |
| 86 | #if defined(OS_MACOSX) || defined(OS_IOS) |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 87 | std::unique_ptr<char[]> vec(new char[max_vec_size]); |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 88 | #elif defined(OS_WIN) |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 89 | std::unique_ptr<PSAPI_WORKING_SET_EX_INFORMATION[]> vec( |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 90 | new PSAPI_WORKING_SET_EX_INFORMATION[max_vec_size]); |
| 91 | #elif defined(OS_POSIX) |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 92 | std::unique_ptr<unsigned char[]> vec(new unsigned char[max_vec_size]); |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 93 | #endif |
| 94 | |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 95 | while (offset < mapped_size) { |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 96 | uintptr_t chunk_start = (start_pointer + offset); |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 97 | const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize); |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 98 | const size_t page_count = GetSystemPageCount(chunk_size, page_size); |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 99 | size_t resident_page_count = 0; |
| 100 | |
| 101 | #if defined(OS_MACOSX) || defined(OS_IOS) |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 102 | // mincore in MAC does not fail with EAGAIN. |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 103 | failure = |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 104 | !!mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get()); |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 105 | for (size_t i = 0; i < page_count; i++) |
| 106 | resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0; |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 107 | #elif defined(OS_WIN) |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 108 | for (size_t i = 0; i < page_count; i++) { |
| 109 | vec[i].VirtualAddress = |
| 110 | reinterpret_cast<void*>(chunk_start + i * page_size); |
| 111 | } |
| 112 | DWORD vec_size = static_cast<DWORD>( |
| 113 | page_count * sizeof(PSAPI_WORKING_SET_EX_INFORMATION)); |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 114 | failure = !QueryWorkingSetEx(GetCurrentProcess(), vec.get(), vec_size); |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 115 | |
| 116 | for (size_t i = 0; i < page_count; i++) |
| 117 | resident_page_count += vec[i].VirtualAttributes.Valid; |
| 118 | #elif defined(OS_POSIX) |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 119 | int error_counter = 0; |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 120 | int result = 0; |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 121 | // HANDLE_EINTR tries for 100 times. So following the same pattern. |
| 122 | do { |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 123 | result = |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 124 | mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get()); |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 125 | } while (result == -1 && errno == EAGAIN && error_counter++ < 100); |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 126 | failure = !!result; |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 127 | |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 128 | for (size_t i = 0; i < page_count; i++) |
ssid | 22b5016 | 2016-02-02 14:33:17 | [diff] [blame] | 129 | resident_page_count += vec[i] & 1; |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 130 | #endif |
| 131 | |
| 132 | if (failure) |
| 133 | break; |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 134 | |
| 135 | total_resident_size += resident_page_count * page_size; |
| 136 | offset += kMaxChunkSize; |
| 137 | } |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 138 | |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 139 | DCHECK(!failure); |
| 140 | if (failure) { |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 141 | total_resident_size = 0; |
ssid | b39972df | 2016-01-21 13:58:55 | [diff] [blame] | 142 | LOG(ERROR) << "CountResidentBytes failed. The resident size is invalid"; |
ssid | 999ca54e | 2015-10-15 15:26:41 | [diff] [blame] | 143 | } |
ssid | a3fc37f | 2015-10-12 17:36:55 | [diff] [blame] | 144 | return total_resident_size; |
| 145 | } |
| 146 | #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
| 147 | |
primiano | 2de25ee6 | 2015-04-21 06:09:08 | [diff] [blame] | 148 | ProcessMemoryDump::ProcessMemoryDump( |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 149 | scoped_refptr<MemoryDumpSessionState> session_state, |
| 150 | const MemoryDumpArgs& dump_args) |
primiano | 2de25ee6 | 2015-04-21 06:09:08 | [diff] [blame] | 151 | : has_process_totals_(false), |
| 152 | has_process_mmaps_(false), |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 153 | session_state_(std::move(session_state)), |
| 154 | dump_args_(dump_args) {} |
primiano | f11ccf5 | 2015-02-17 23:21:19 | [diff] [blame] | 155 | |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 156 | ProcessMemoryDump::~ProcessMemoryDump() {} |
primiano | f11ccf5 | 2015-02-17 23:21:19 | [diff] [blame] | 157 | |
primiano | 13cf4d0 | 2015-03-19 16:24:38 | [diff] [blame] | 158 | MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( |
primiano | 0842511 | 2015-04-28 17:10:39 | [diff] [blame] | 159 | const std::string& absolute_name) { |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 160 | return AddAllocatorDumpInternal( |
ricea | ec7c3997e | 2016-09-13 04:10:11 | [diff] [blame] | 161 | MakeUnique<MemoryAllocatorDump>(absolute_name, this)); |
primiano | 13cf4d0 | 2015-03-19 16:24:38 | [diff] [blame] | 162 | } |
| 163 | |
primiano | 673eda6 | 2015-05-29 13:55:31 | [diff] [blame] | 164 | MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( |
| 165 | const std::string& absolute_name, |
| 166 | const MemoryAllocatorDumpGuid& guid) { |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 167 | return AddAllocatorDumpInternal( |
ricea | ec7c3997e | 2016-09-13 04:10:11 | [diff] [blame] | 168 | MakeUnique<MemoryAllocatorDump>(absolute_name, this, guid)); |
primiano | 673eda6 | 2015-05-29 13:55:31 | [diff] [blame] | 169 | } |
| 170 | |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 171 | MemoryAllocatorDump* ProcessMemoryDump::AddAllocatorDumpInternal( |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 172 | std::unique_ptr<MemoryAllocatorDump> mad) { |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 173 | // In background mode return the black hole dump, if invalid dump name is |
| 174 | // given. |
| 175 | if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND && |
| 176 | !IsMemoryAllocatorDumpNameWhitelisted(mad->absolute_name())) { |
| 177 | return GetBlackHoleMad(); |
| 178 | } |
| 179 | |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 180 | auto insertion_result = allocator_dumps_.insert( |
| 181 | std::make_pair(mad->absolute_name(), std::move(mad))); |
dskiba | d20680c | 2016-04-29 20:40:52 | [diff] [blame] | 182 | MemoryAllocatorDump* inserted_mad = insertion_result.first->second.get(); |
| 183 | DCHECK(insertion_result.second) << "Duplicate name: " |
| 184 | << inserted_mad->absolute_name(); |
| 185 | return inserted_mad; |
primiano | 673eda6 | 2015-05-29 13:55:31 | [diff] [blame] | 186 | } |
| 187 | |
primiano | 13cf4d0 | 2015-03-19 16:24:38 | [diff] [blame] | 188 | MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump( |
primiano | 0842511 | 2015-04-28 17:10:39 | [diff] [blame] | 189 | const std::string& absolute_name) const { |
| 190 | auto it = allocator_dumps_.find(absolute_name); |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 191 | if (it != allocator_dumps_.end()) |
| 192 | return it->second.get(); |
| 193 | if (black_hole_mad_) |
| 194 | return black_hole_mad_.get(); |
| 195 | return nullptr; |
primiano | 13cf4d0 | 2015-03-19 16:24:38 | [diff] [blame] | 196 | } |
| 197 | |
primiano | 96baab5e | 2015-10-05 22:49:10 | [diff] [blame] | 198 | MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump( |
| 199 | const std::string& absolute_name) { |
| 200 | MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name); |
thestig | db54eaf | 2015-10-13 06:19:28 | [diff] [blame] | 201 | return mad ? mad : CreateAllocatorDump(absolute_name); |
primiano | 96baab5e | 2015-10-05 22:49:10 | [diff] [blame] | 202 | } |
| 203 | |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 204 | MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump( |
| 205 | const MemoryAllocatorDumpGuid& guid) { |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 206 | // Global dumps are disabled in background mode. |
| 207 | if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) |
| 208 | return GetBlackHoleMad(); |
| 209 | |
ssid | 1050d80 | 2015-07-28 20:28:14 | [diff] [blame] | 210 | // A shared allocator dump can be shared within a process and the guid could |
| 211 | // have been created already. |
ssid | a937635d | 2016-01-21 13:41:35 | [diff] [blame] | 212 | MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); |
| 213 | if (mad) { |
| 214 | // The weak flag is cleared because this method should create a non-weak |
| 215 | // dump. |
| 216 | mad->clear_flags(MemoryAllocatorDump::Flags::WEAK); |
| 217 | return mad; |
| 218 | } |
| 219 | return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); |
| 220 | } |
| 221 | |
| 222 | MemoryAllocatorDump* ProcessMemoryDump::CreateWeakSharedGlobalAllocatorDump( |
| 223 | const MemoryAllocatorDumpGuid& guid) { |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 224 | // Global dumps are disabled in background mode. |
| 225 | if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) |
| 226 | return GetBlackHoleMad(); |
| 227 | |
ssid | a937635d | 2016-01-21 13:41:35 | [diff] [blame] | 228 | MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); |
| 229 | if (mad) |
| 230 | return mad; |
| 231 | mad = CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); |
| 232 | mad->set_flags(MemoryAllocatorDump::Flags::WEAK); |
| 233 | return mad; |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 234 | } |
| 235 | |
| 236 | MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump( |
| 237 | const MemoryAllocatorDumpGuid& guid) const { |
| 238 | return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid)); |
| 239 | } |
| 240 | |
bashi | b873c0d4 | 2016-05-12 05:41:04 | [diff] [blame] | 241 | void ProcessMemoryDump::DumpHeapUsage( |
| 242 | const base::hash_map<base::trace_event::AllocationContext, |
| 243 | base::trace_event::AllocationMetrics>& metrics_by_context, |
| 244 | base::trace_event::TraceEventMemoryOverhead& overhead, |
| 245 | const char* allocator_name) { |
| 246 | if (!metrics_by_context.empty()) { |
bashi | fa5b57e | 2016-05-30 01:51:57 | [diff] [blame] | 247 | DCHECK_EQ(0ul, heap_dumps_.count(allocator_name)); |
bashi | b873c0d4 | 2016-05-12 05:41:04 | [diff] [blame] | 248 | std::unique_ptr<TracedValue> heap_dump = ExportHeapDump( |
| 249 | metrics_by_context, *session_state()); |
bashi | fa5b57e | 2016-05-30 01:51:57 | [diff] [blame] | 250 | heap_dumps_[allocator_name] = std::move(heap_dump); |
bashi | b873c0d4 | 2016-05-12 05:41:04 | [diff] [blame] | 251 | } |
| 252 | |
| 253 | std::string base_name = base::StringPrintf("tracing/heap_profiler_%s", |
| 254 | allocator_name); |
| 255 | overhead.DumpInto(base_name.c_str(), this); |
| 256 | } |
| 257 | |
primiano | 139c6fe | 2015-05-26 19:27:04 | [diff] [blame] | 258 | void ProcessMemoryDump::Clear() { |
| 259 | if (has_process_totals_) { |
| 260 | process_totals_.Clear(); |
| 261 | has_process_totals_ = false; |
| 262 | } |
| 263 | |
| 264 | if (has_process_mmaps_) { |
| 265 | process_mmaps_.Clear(); |
| 266 | has_process_mmaps_ = false; |
| 267 | } |
| 268 | |
primiano | 139c6fe | 2015-05-26 19:27:04 | [diff] [blame] | 269 | allocator_dumps_.clear(); |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 270 | allocator_dumps_edges_.clear(); |
ruuda | 51d9e66 | 2015-10-27 13:20:12 | [diff] [blame] | 271 | heap_dumps_.clear(); |
primiano | 139c6fe | 2015-05-26 19:27:04 | [diff] [blame] | 272 | } |
| 273 | |
primiano | c733608 | 2015-05-21 10:07:28 | [diff] [blame] | 274 | void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) { |
primiano | c733608 | 2015-05-21 10:07:28 | [diff] [blame] | 275 | DCHECK(!other->has_process_totals() && !other->has_process_mmaps()); |
| 276 | |
| 277 | // Moves the ownership of all MemoryAllocatorDump(s) contained in |other| |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 278 | // into this ProcessMemoryDump, checking for duplicates. |
| 279 | for (auto& it : other->allocator_dumps_) |
| 280 | AddAllocatorDumpInternal(std::move(it.second)); |
primiano | c733608 | 2015-05-21 10:07:28 | [diff] [blame] | 281 | other->allocator_dumps_.clear(); |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 282 | |
| 283 | // Move all the edges. |
| 284 | allocator_dumps_edges_.insert(allocator_dumps_edges_.end(), |
| 285 | other->allocator_dumps_edges_.begin(), |
| 286 | other->allocator_dumps_edges_.end()); |
| 287 | other->allocator_dumps_edges_.clear(); |
ruuda | 51d9e66 | 2015-10-27 13:20:12 | [diff] [blame] | 288 | |
primiano | cb1afb3 | 2016-02-29 20:46:05 | [diff] [blame] | 289 | for (auto& it : other->heap_dumps_) { |
| 290 | DCHECK_EQ(0ul, heap_dumps_.count(it.first)); |
| 291 | heap_dumps_.insert(std::make_pair(it.first, std::move(it.second))); |
| 292 | } |
ruuda | 51d9e66 | 2015-10-27 13:20:12 | [diff] [blame] | 293 | other->heap_dumps_.clear(); |
primiano | c733608 | 2015-05-21 10:07:28 | [diff] [blame] | 294 | } |
| 295 | |
primiano | c96eca7 | 2015-02-20 16:41:14 | [diff] [blame] | 296 | void ProcessMemoryDump::AsValueInto(TracedValue* value) const { |
primiano | c96eca7 | 2015-02-20 16:41:14 | [diff] [blame] | 297 | if (has_process_totals_) { |
| 298 | value->BeginDictionary("process_totals"); |
| 299 | process_totals_.AsValueInto(value); |
| 300 | value->EndDictionary(); |
| 301 | } |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 302 | |
primiano | 5a489957 | 2015-02-24 17:52:32 | [diff] [blame] | 303 | if (has_process_mmaps_) { |
| 304 | value->BeginDictionary("process_mmaps"); |
| 305 | process_mmaps_.AsValueInto(value); |
| 306 | value->EndDictionary(); |
| 307 | } |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 308 | |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 309 | if (allocator_dumps_.size() > 0) { |
primiano | 13cf4d0 | 2015-03-19 16:24:38 | [diff] [blame] | 310 | value->BeginDictionary("allocators"); |
primiano | fbc6978 | 2016-02-22 17:23:34 | [diff] [blame] | 311 | for (const auto& allocator_dump_it : allocator_dumps_) |
| 312 | allocator_dump_it.second->AsValueInto(value); |
primiano | 13cf4d0 | 2015-03-19 16:24:38 | [diff] [blame] | 313 | value->EndDictionary(); |
| 314 | } |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 315 | |
ruuda | 51d9e66 | 2015-10-27 13:20:12 | [diff] [blame] | 316 | if (heap_dumps_.size() > 0) { |
| 317 | value->BeginDictionary("heaps"); |
| 318 | for (const auto& name_and_dump : heap_dumps_) |
| 319 | value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second); |
| 320 | value->EndDictionary(); // "heaps" |
| 321 | } |
| 322 | |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 323 | value->BeginArray("allocators_graph"); |
| 324 | for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) { |
| 325 | value->BeginDictionary(); |
| 326 | value->SetString("source", edge.source.ToString()); |
| 327 | value->SetString("target", edge.target.ToString()); |
| 328 | value->SetInteger("importance", edge.importance); |
| 329 | value->SetString("type", edge.type); |
| 330 | value->EndDictionary(); |
| 331 | } |
| 332 | value->EndArray(); |
| 333 | } |
| 334 | |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 335 | void ProcessMemoryDump::AddOwnershipEdge(const MemoryAllocatorDumpGuid& source, |
| 336 | const MemoryAllocatorDumpGuid& target, |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 337 | int importance) { |
| 338 | allocator_dumps_edges_.push_back( |
| 339 | {source, target, importance, kEdgeTypeOwnership}); |
| 340 | } |
| 341 | |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 342 | void ProcessMemoryDump::AddOwnershipEdge( |
| 343 | const MemoryAllocatorDumpGuid& source, |
| 344 | const MemoryAllocatorDumpGuid& target) { |
primiano | 2d1b2f1b | 2015-05-28 12:34:49 | [diff] [blame] | 345 | AddOwnershipEdge(source, target, 0 /* importance */); |
primiano | f11ccf5 | 2015-02-17 23:21:19 | [diff] [blame] | 346 | } |
| 347 | |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 348 | void ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source, |
| 349 | const std::string& target_node_name) { |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 350 | // Do not create new dumps for suballocations in background mode. |
| 351 | if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) |
| 352 | return; |
| 353 | |
primiano | 3b4bd6b0 | 2015-06-03 09:52:52 | [diff] [blame] | 354 | std::string child_mad_name = target_node_name + "/__" + source.ToString(); |
| 355 | MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name); |
| 356 | AddOwnershipEdge(source, target_child_mad->guid()); |
| 357 | } |
| 358 | |
ssid | 448e5ed | 2016-06-04 12:40:51 | [diff] [blame] | 359 | MemoryAllocatorDump* ProcessMemoryDump::GetBlackHoleMad() { |
| 360 | DCHECK(is_black_hole_non_fatal_for_testing_); |
| 361 | if (!black_hole_mad_) |
| 362 | black_hole_mad_.reset(new MemoryAllocatorDump("discarded", this)); |
| 363 | return black_hole_mad_.get(); |
| 364 | } |
| 365 | |
primiano | f11ccf5 | 2015-02-17 23:21:19 | [diff] [blame] | 366 | } // namespace trace_event |
| 367 | } // namespace base |