OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/trace_event/process_memory_dump.h" | 5 #include "base/trace_event/process_memory_dump.h" |
6 | 6 |
7 #include <ctype.h> | |
7 #include <errno.h> | 8 #include <errno.h> |
8 | 9 |
9 #include <vector> | 10 #include <vector> |
10 | 11 |
11 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
12 #include "base/process/process_metrics.h" | 13 #include "base/process/process_metrics.h" |
13 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
14 #include "base/trace_event/heap_profiler_heap_dump_writer.h" | 15 #include "base/trace_event/heap_profiler_heap_dump_writer.h" |
16 #include "base/trace_event/memory_dump_request_args.h" | |
15 #include "base/trace_event/process_memory_totals.h" | 17 #include "base/trace_event/process_memory_totals.h" |
16 #include "base/trace_event/trace_event_argument.h" | 18 #include "base/trace_event/trace_event_argument.h" |
17 #include "build/build_config.h" | 19 #include "build/build_config.h" |
18 | 20 |
19 #if defined(OS_IOS) | 21 #if defined(OS_IOS) |
20 #include <sys/sysctl.h> | 22 #include <sys/sysctl.h> |
21 #endif | 23 #endif |
22 | 24 |
23 #if defined(OS_POSIX) | 25 #if defined(OS_POSIX) |
24 #include <sys/mman.h> | 26 #include <sys/mman.h> |
(...skipping 14 matching lines...) Expand all Loading... | |
39 const MemoryAllocatorDumpGuid& guid) { | 41 const MemoryAllocatorDumpGuid& guid) { |
40 return "global/" + guid.ToString(); | 42 return "global/" + guid.ToString(); |
41 } | 43 } |
42 | 44 |
43 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 45 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
44 size_t GetSystemPageCount(size_t mapped_size, size_t page_size) { | 46 size_t GetSystemPageCount(size_t mapped_size, size_t page_size) { |
45 return (mapped_size + page_size - 1) / page_size; | 47 return (mapped_size + page_size - 1) / page_size; |
46 } | 48 } |
47 #endif | 49 #endif |
48 | 50 |
51 // A list of string names that are allowed for the allocator dumps in background | |
52 // mode. | |
53 const char* const kDumpNameWhitelist[] = { | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
Ok I think at this point we want a memory_infra_ba
ssid
2016/05/31 22:33:20
Done.
| |
54 // TODO(ssid): Fill this list with dump names, crbug.com/613198. | |
55 "", | |
56 }; | |
57 | |
58 // Check if the string is in the whitelist. | |
59 bool IsNameValidForBackgroundMode(const std::string& name, | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
s/Valid/Whitelisted/ ... which makes then the comm
ssid
2016/05/31 22:33:20
Acknowledged.
| |
60 const char* whitelisted_name_for_testing) { | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
see my comment in the other cl, having to pass thi
ssid
2016/05/31 22:33:20
Done.
| |
61 static size_t kListSize = arraysize(kDumpNameWhitelist); | |
62 | |
63 // Remove special characters, numbers (including hexadecimal which are makred | |
Dmitry Skiba
2016/05/31 06:48:46
*marked
ssid
2016/05/31 22:33:20
Done.
| |
64 // by '0x') from the given string. | |
65 const size_t length = name.size(); | |
66 std::unique_ptr<char[]> stripped_str(new char[length]); | |
Dmitry Skiba
2016/05/31 06:48:46
Uhm, why not std::string? And push_back() instead
ssid
2016/05/31 22:33:20
Done.
| |
67 size_t str_index = 0; | |
68 bool parsing_hex = false; | |
69 for (size_t i = 0; i < length; ++i) { | |
70 if (parsing_hex) { | |
71 if (isxdigit(name[i])) { | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
instead of having this state machine here, can you
ssid
2016/05/27 17:42:48
Sorry, I don't get it.
Yeah I would still need thi
Primiano Tucci (use gerrit)
2016/05/27 17:51:19
Ok sorry this was a stupid comment from my side. I
ssid
2016/05/31 22:33:20
isalpha is there because there could be cases wher
Primiano Tucci (use gerrit)
2016/06/02 20:24:04
Ah right, I think it's ok.
| |
72 continue; | |
73 } else { | |
74 parsing_hex = false; | |
75 } | |
76 } | |
77 if (i + 1 < length && name[i] == '0' && name[i + 1] == 'x') { | |
78 parsing_hex = true; | |
79 ++i; | |
80 } else if (isalpha(name[i])) { | |
81 stripped_str[str_index++] = name[i]; | |
82 } | |
83 } | |
84 stripped_str[str_index] = '\0'; | |
85 | |
86 if (whitelisted_name_for_testing) | |
87 return strcmp(stripped_str.get(), whitelisted_name_for_testing) == 0; | |
88 | |
89 for (size_t i = 0; i < kListSize; ++i) { | |
90 if (strcmp(stripped_str.get(), kDumpNameWhitelist[i]) == 0) | |
91 return true; | |
92 } | |
93 return false; | |
94 } | |
95 | |
49 } // namespace | 96 } // namespace |
50 | 97 |
51 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 98 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
52 // static | 99 // static |
53 size_t ProcessMemoryDump::GetSystemPageSize() { | 100 size_t ProcessMemoryDump::GetSystemPageSize() { |
54 #if defined(OS_IOS) | 101 #if defined(OS_IOS) |
55 // On iOS, getpagesize() returns the user page sizes, but for allocating | 102 // On iOS, getpagesize() returns the user page sizes, but for allocating |
56 // arrays for mincore(), kernel page sizes is needed. sysctlbyname() should | 103 // arrays for mincore(), kernel page sizes is needed. sysctlbyname() should |
57 // be used for this. Refer to crbug.com/542671 and Apple rdar://23651782 | 104 // be used for this. Refer to crbug.com/542671 and Apple rdar://23651782 |
58 int pagesize; | 105 int pagesize; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
141 DCHECK(!failure); | 188 DCHECK(!failure); |
142 if (failure) { | 189 if (failure) { |
143 total_resident_size = 0; | 190 total_resident_size = 0; |
144 LOG(ERROR) << "CountResidentBytes failed. The resident size is invalid"; | 191 LOG(ERROR) << "CountResidentBytes failed. The resident size is invalid"; |
145 } | 192 } |
146 return total_resident_size; | 193 return total_resident_size; |
147 } | 194 } |
148 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 195 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
149 | 196 |
150 ProcessMemoryDump::ProcessMemoryDump( | 197 ProcessMemoryDump::ProcessMemoryDump( |
151 scoped_refptr<MemoryDumpSessionState> session_state) | 198 scoped_refptr<MemoryDumpSessionState> session_state, |
199 MemoryDumpLevelOfDetail level_of_detail) | |
152 : has_process_totals_(false), | 200 : has_process_totals_(false), |
153 has_process_mmaps_(false), | 201 has_process_mmaps_(false), |
154 session_state_(std::move(session_state)) {} | 202 session_state_(std::move(session_state)), |
203 level_of_detail_(level_of_detail), | |
204 whitelisted_name_for_testing_(nullptr) { | |
205 if (level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND) { | |
206 dummy_mad_.reset(new MemoryAllocatorDump("dummy", this)); | |
207 } | |
208 } | |
155 | 209 |
156 ProcessMemoryDump::~ProcessMemoryDump() {} | 210 ProcessMemoryDump::~ProcessMemoryDump() {} |
157 | 211 |
158 MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( | 212 MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( |
159 const std::string& absolute_name) { | 213 const std::string& absolute_name) { |
160 return AddAllocatorDumpInternal( | 214 return AddAllocatorDumpInternal( |
161 WrapUnique(new MemoryAllocatorDump(absolute_name, this))); | 215 WrapUnique(new MemoryAllocatorDump(absolute_name, this))); |
162 } | 216 } |
163 | 217 |
164 MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( | 218 MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump( |
165 const std::string& absolute_name, | 219 const std::string& absolute_name, |
166 const MemoryAllocatorDumpGuid& guid) { | 220 const MemoryAllocatorDumpGuid& guid) { |
167 return AddAllocatorDumpInternal( | 221 return AddAllocatorDumpInternal( |
168 WrapUnique(new MemoryAllocatorDump(absolute_name, this, guid))); | 222 WrapUnique(new MemoryAllocatorDump(absolute_name, this, guid))); |
169 } | 223 } |
170 | 224 |
171 MemoryAllocatorDump* ProcessMemoryDump::AddAllocatorDumpInternal( | 225 MemoryAllocatorDump* ProcessMemoryDump::AddAllocatorDumpInternal( |
172 std::unique_ptr<MemoryAllocatorDump> mad) { | 226 std::unique_ptr<MemoryAllocatorDump> mad) { |
227 // In background mode return dummy dump if invalid dump name is given. | |
228 if (level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND && | |
229 !IsNameValidForBackgroundMode(mad->absolute_name(), | |
230 whitelisted_name_for_testing_)) { | |
231 return dummy_mad_.get(); | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
maybe NOTREACHED also here to help debugging?
ssid
2016/05/31 22:33:20
I have changed the tests to use AddAllocatorDumpIn
Primiano Tucci (use gerrit)
2016/06/02 20:24:03
You can just check the allocator_dumps().count("na
| |
232 } | |
233 | |
173 auto insertion_result = allocator_dumps_.insert( | 234 auto insertion_result = allocator_dumps_.insert( |
174 std::make_pair(mad->absolute_name(), std::move(mad))); | 235 std::make_pair(mad->absolute_name(), std::move(mad))); |
175 MemoryAllocatorDump* inserted_mad = insertion_result.first->second.get(); | 236 MemoryAllocatorDump* inserted_mad = insertion_result.first->second.get(); |
176 DCHECK(insertion_result.second) << "Duplicate name: " | 237 DCHECK(insertion_result.second) << "Duplicate name: " |
177 << inserted_mad->absolute_name(); | 238 << inserted_mad->absolute_name(); |
178 return inserted_mad; | 239 return inserted_mad; |
179 } | 240 } |
180 | 241 |
181 MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump( | 242 MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump( |
182 const std::string& absolute_name) const { | 243 const std::string& absolute_name) const { |
183 auto it = allocator_dumps_.find(absolute_name); | 244 auto it = allocator_dumps_.find(absolute_name); |
184 return it == allocator_dumps_.end() ? nullptr : it->second.get(); | 245 if (it != allocator_dumps_.end()) |
246 return it->second.get(); | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
should you just leave this as it is and return nul
ssid
2016/05/27 17:42:48
I can't do that. Some dump providers assume that t
Primiano Tucci (use gerrit)
2016/06/02 20:24:03
Acknowledged.
| |
247 return level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND | |
248 ? dummy_mad_.get() | |
249 : nullptr; | |
185 } | 250 } |
186 | 251 |
187 MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump( | 252 MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump( |
188 const std::string& absolute_name) { | 253 const std::string& absolute_name) { |
189 MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name); | 254 MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name); |
190 return mad ? mad : CreateAllocatorDump(absolute_name); | 255 return mad ? mad : CreateAllocatorDump(absolute_name); |
191 } | 256 } |
192 | 257 |
193 MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump( | 258 MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump( |
194 const MemoryAllocatorDumpGuid& guid) { | 259 const MemoryAllocatorDumpGuid& guid) { |
260 // Global dumps are disabled in background mode. | |
261 if (level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND) | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
I don't think global dumps are a problem right? th
ssid
2016/05/27 17:42:48
Global dumps are not required. Anyway we report ju
| |
262 return dummy_mad_.get(); | |
263 | |
195 // A shared allocator dump can be shared within a process and the guid could | 264 // A shared allocator dump can be shared within a process and the guid could |
196 // have been created already. | 265 // have been created already. |
197 MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); | 266 MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); |
198 if (mad) { | 267 if (mad) { |
199 // The weak flag is cleared because this method should create a non-weak | 268 // The weak flag is cleared because this method should create a non-weak |
200 // dump. | 269 // dump. |
201 mad->clear_flags(MemoryAllocatorDump::Flags::WEAK); | 270 mad->clear_flags(MemoryAllocatorDump::Flags::WEAK); |
202 return mad; | 271 return mad; |
203 } | 272 } |
204 return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); | 273 return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); |
205 } | 274 } |
206 | 275 |
207 MemoryAllocatorDump* ProcessMemoryDump::CreateWeakSharedGlobalAllocatorDump( | 276 MemoryAllocatorDump* ProcessMemoryDump::CreateWeakSharedGlobalAllocatorDump( |
208 const MemoryAllocatorDumpGuid& guid) { | 277 const MemoryAllocatorDumpGuid& guid) { |
278 // Global dumps are disabled in background mode. | |
279 if (level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND) | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
ditto don't think you need this
| |
280 return dummy_mad_.get(); | |
281 | |
209 MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); | 282 MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid); |
210 if (mad) | 283 if (mad) |
211 return mad; | 284 return mad; |
212 mad = CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); | 285 mad = CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid); |
213 mad->set_flags(MemoryAllocatorDump::Flags::WEAK); | 286 mad->set_flags(MemoryAllocatorDump::Flags::WEAK); |
214 return mad; | 287 return mad; |
215 } | 288 } |
216 | 289 |
217 MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump( | 290 MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump( |
218 const MemoryAllocatorDumpGuid& guid) const { | 291 const MemoryAllocatorDumpGuid& guid) const { |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
326 } | 399 } |
327 | 400 |
328 void ProcessMemoryDump::AddOwnershipEdge( | 401 void ProcessMemoryDump::AddOwnershipEdge( |
329 const MemoryAllocatorDumpGuid& source, | 402 const MemoryAllocatorDumpGuid& source, |
330 const MemoryAllocatorDumpGuid& target) { | 403 const MemoryAllocatorDumpGuid& target) { |
331 AddOwnershipEdge(source, target, 0 /* importance */); | 404 AddOwnershipEdge(source, target, 0 /* importance */); |
332 } | 405 } |
333 | 406 |
334 void ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source, | 407 void ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source, |
335 const std::string& target_node_name) { | 408 const std::string& target_node_name) { |
409 // Do not create new dumps for suballocations in background mode. | |
410 if (level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND) | |
Primiano Tucci (use gerrit)
2016/05/27 17:23:35
ditto
ssid
2016/05/27 17:42:48
Why create unnecessary dumps when we are not inter
| |
411 return; | |
412 | |
336 std::string child_mad_name = target_node_name + "/__" + source.ToString(); | 413 std::string child_mad_name = target_node_name + "/__" + source.ToString(); |
337 MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name); | 414 MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name); |
338 AddOwnershipEdge(source, target_child_mad->guid()); | 415 AddOwnershipEdge(source, target_child_mad->guid()); |
339 } | 416 } |
340 | 417 |
341 } // namespace trace_event | 418 } // namespace trace_event |
342 } // namespace base | 419 } // namespace base |
OLD | NEW |