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 <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/memory/aligned_memory.h" | 9 #include "base/memory/aligned_memory.h" |
10 #include "base/memory/ptr_util.h" | |
10 #include "base/process/process_metrics.h" | 11 #include "base/process/process_metrics.h" |
11 #include "base/trace_event/memory_allocator_dump_guid.h" | 12 #include "base/trace_event/memory_allocator_dump_guid.h" |
13 #include "base/trace_event/memory_infra_background_whitelist.h" | |
12 #include "base/trace_event/trace_event_argument.h" | 14 #include "base/trace_event/trace_event_argument.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
14 | 16 |
15 namespace base { | 17 namespace base { |
16 namespace trace_event { | 18 namespace trace_event { |
17 | 19 |
18 namespace { | 20 namespace { |
21 | |
22 const MemoryDumpArgs kDetailedDumpArgs = {MemoryDumpLevelOfDetail::DETAILED}; | |
23 const char* const kTestDumpNameWhitelist[] = {"WhitelistedTestName", nullptr}; | |
Primiano Tucci (use gerrit)
2016/06/02 20:24:04
I think you should move this below, because you re
ssid
2016/06/03 01:59:46
Hm it is bad i will be setting a global g_whitelis
| |
24 | |
19 TracedValue* GetHeapDump(const ProcessMemoryDump& pmd, const char* name) { | 25 TracedValue* GetHeapDump(const ProcessMemoryDump& pmd, const char* name) { |
20 auto it = pmd.heap_dumps().find(name); | 26 auto it = pmd.heap_dumps().find(name); |
21 return it == pmd.heap_dumps().end() ? nullptr : it->second.get(); | 27 return it == pmd.heap_dumps().end() ? nullptr : it->second.get(); |
22 } | 28 } |
29 | |
23 } // namespace | 30 } // namespace |
24 | 31 |
25 TEST(ProcessMemoryDumpTest, Clear) { | 32 class ProcessMemoryDumpTest : public testing::Test { |
26 std::unique_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr)); | 33 protected: |
34 MemoryAllocatorDump* CreateAllocatorDumpInPMD(ProcessMemoryDump* pmd, | |
35 const char* name) { | |
36 return pmd->AddAllocatorDumpInternal(WrapUnique( | |
37 new MemoryAllocatorDump(name, pmd, MemoryAllocatorDumpGuid()))); | |
38 } | |
39 }; | |
40 | |
41 TEST_F(ProcessMemoryDumpTest, Clear) { | |
42 std::unique_ptr<ProcessMemoryDump> pmd1( | |
43 new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); | |
27 pmd1->CreateAllocatorDump("mad1"); | 44 pmd1->CreateAllocatorDump("mad1"); |
28 pmd1->CreateAllocatorDump("mad2"); | 45 pmd1->CreateAllocatorDump("mad2"); |
29 ASSERT_FALSE(pmd1->allocator_dumps().empty()); | 46 ASSERT_FALSE(pmd1->allocator_dumps().empty()); |
30 | 47 |
31 pmd1->process_totals()->set_resident_set_bytes(42); | 48 pmd1->process_totals()->set_resident_set_bytes(42); |
32 pmd1->set_has_process_totals(); | 49 pmd1->set_has_process_totals(); |
33 | 50 |
34 pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion()); | 51 pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion()); |
35 pmd1->set_has_process_mmaps(); | 52 pmd1->set_has_process_mmaps(); |
36 | 53 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); | 88 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); |
72 ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2)); | 89 ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2)); |
73 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad2->flags()); | 90 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad2->flags()); |
74 | 91 |
75 traced_value.reset(new TracedValue); | 92 traced_value.reset(new TracedValue); |
76 pmd1->AsValueInto(traced_value.get()); | 93 pmd1->AsValueInto(traced_value.get()); |
77 | 94 |
78 pmd1.reset(); | 95 pmd1.reset(); |
79 } | 96 } |
80 | 97 |
81 TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) { | 98 TEST_F(ProcessMemoryDumpTest, TakeAllDumpsFrom) { |
82 std::unique_ptr<TracedValue> traced_value(new TracedValue); | 99 std::unique_ptr<TracedValue> traced_value(new TracedValue); |
83 hash_map<AllocationContext, AllocationMetrics> metrics_by_context; | 100 hash_map<AllocationContext, AllocationMetrics> metrics_by_context; |
84 metrics_by_context[AllocationContext()] = { 1, 1 }; | 101 metrics_by_context[AllocationContext()] = { 1, 1 }; |
85 TraceEventMemoryOverhead overhead; | 102 TraceEventMemoryOverhead overhead; |
86 | 103 |
87 std::unique_ptr<ProcessMemoryDump> pmd1( | 104 std::unique_ptr<ProcessMemoryDump> pmd1( |
88 new ProcessMemoryDump(new MemoryDumpSessionState())); | 105 new ProcessMemoryDump(new MemoryDumpSessionState(), kDetailedDumpArgs)); |
89 auto mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1"); | 106 auto mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1"); |
90 auto mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2"); | 107 auto mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2"); |
91 pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid()); | 108 pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid()); |
92 pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump1"); | 109 pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump1"); |
93 pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump2"); | 110 pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump2"); |
94 | 111 |
95 std::unique_ptr<ProcessMemoryDump> pmd2( | 112 std::unique_ptr<ProcessMemoryDump> pmd2( |
96 new ProcessMemoryDump(new MemoryDumpSessionState())); | 113 new ProcessMemoryDump(new MemoryDumpSessionState(), kDetailedDumpArgs)); |
97 auto mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1"); | 114 auto mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1"); |
98 auto mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2"); | 115 auto mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2"); |
99 pmd2->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid()); | 116 pmd2->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid()); |
100 pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump1"); | 117 pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump1"); |
101 pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump2"); | 118 pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump2"); |
102 | 119 |
103 MemoryAllocatorDumpGuid shared_mad_guid1(1); | 120 MemoryAllocatorDumpGuid shared_mad_guid1(1); |
104 MemoryAllocatorDumpGuid shared_mad_guid2(2); | 121 MemoryAllocatorDumpGuid shared_mad_guid2(2); |
105 auto shared_mad1 = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid1); | 122 auto shared_mad1 = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid1); |
106 auto shared_mad2 = | 123 auto shared_mad2 = |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
141 ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump1") != nullptr); | 158 ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump1") != nullptr); |
142 ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump2") != nullptr); | 159 ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump2") != nullptr); |
143 | 160 |
144 // Check that calling AsValueInto() doesn't cause a crash. | 161 // Check that calling AsValueInto() doesn't cause a crash. |
145 traced_value.reset(new TracedValue); | 162 traced_value.reset(new TracedValue); |
146 pmd1->AsValueInto(traced_value.get()); | 163 pmd1->AsValueInto(traced_value.get()); |
147 | 164 |
148 pmd1.reset(); | 165 pmd1.reset(); |
149 } | 166 } |
150 | 167 |
151 TEST(ProcessMemoryDumpTest, Suballocations) { | 168 TEST_F(ProcessMemoryDumpTest, Suballocations) { |
152 std::unique_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr)); | 169 std::unique_ptr<ProcessMemoryDump> pmd( |
170 new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); | |
153 const std::string allocator_dump_name = "fakealloc/allocated_objects"; | 171 const std::string allocator_dump_name = "fakealloc/allocated_objects"; |
154 pmd->CreateAllocatorDump(allocator_dump_name); | 172 pmd->CreateAllocatorDump(allocator_dump_name); |
155 | 173 |
156 // Create one allocation with an auto-assigned guid and mark it as a | 174 // Create one allocation with an auto-assigned guid and mark it as a |
157 // suballocation of "fakealloc/allocated_objects". | 175 // suballocation of "fakealloc/allocated_objects". |
158 auto pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1"); | 176 auto pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1"); |
159 pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name); | 177 pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name); |
160 | 178 |
161 // Same here, but this time create an allocation with an explicit guid. | 179 // Same here, but this time create an allocation with an explicit guid. |
162 auto pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2", | 180 auto pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2", |
(...skipping 22 matching lines...) Expand all Loading... | |
185 ASSERT_TRUE(found_edge[0]); | 203 ASSERT_TRUE(found_edge[0]); |
186 ASSERT_TRUE(found_edge[1]); | 204 ASSERT_TRUE(found_edge[1]); |
187 | 205 |
188 // Check that calling AsValueInto() doesn't cause a crash. | 206 // Check that calling AsValueInto() doesn't cause a crash. |
189 std::unique_ptr<TracedValue> traced_value(new TracedValue); | 207 std::unique_ptr<TracedValue> traced_value(new TracedValue); |
190 pmd->AsValueInto(traced_value.get()); | 208 pmd->AsValueInto(traced_value.get()); |
191 | 209 |
192 pmd.reset(); | 210 pmd.reset(); |
193 } | 211 } |
194 | 212 |
195 TEST(ProcessMemoryDumpTest, GlobalAllocatorDumpTest) { | 213 TEST_F(ProcessMemoryDumpTest, GlobalAllocatorDumpTest) { |
196 std::unique_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr)); | 214 std::unique_ptr<ProcessMemoryDump> pmd( |
215 new ProcessMemoryDump(nullptr, kDetailedDumpArgs)); | |
197 MemoryAllocatorDumpGuid shared_mad_guid(1); | 216 MemoryAllocatorDumpGuid shared_mad_guid(1); |
198 auto shared_mad1 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); | 217 auto shared_mad1 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); |
199 ASSERT_EQ(shared_mad_guid, shared_mad1->guid()); | 218 ASSERT_EQ(shared_mad_guid, shared_mad1->guid()); |
200 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); | 219 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); |
201 | 220 |
202 auto shared_mad2 = pmd->GetSharedGlobalAllocatorDump(shared_mad_guid); | 221 auto shared_mad2 = pmd->GetSharedGlobalAllocatorDump(shared_mad_guid); |
203 ASSERT_EQ(shared_mad1, shared_mad2); | 222 ASSERT_EQ(shared_mad1, shared_mad2); |
204 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); | 223 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); |
205 | 224 |
206 auto shared_mad3 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); | 225 auto shared_mad3 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); |
207 ASSERT_EQ(shared_mad1, shared_mad3); | 226 ASSERT_EQ(shared_mad1, shared_mad3); |
208 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); | 227 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); |
209 | 228 |
210 auto shared_mad4 = pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid); | 229 auto shared_mad4 = pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid); |
211 ASSERT_EQ(shared_mad1, shared_mad4); | 230 ASSERT_EQ(shared_mad1, shared_mad4); |
212 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); | 231 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); |
213 | 232 |
214 auto shared_mad5 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); | 233 auto shared_mad5 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); |
215 ASSERT_EQ(shared_mad1, shared_mad5); | 234 ASSERT_EQ(shared_mad1, shared_mad5); |
216 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); | 235 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); |
217 } | 236 } |
218 | 237 |
238 TEST_F(ProcessMemoryDumpTest, BackgroundModeTest) { | |
239 MemoryDumpArgs background_args = {MemoryDumpLevelOfDetail::BACKGROUND}; | |
240 std::unique_ptr<ProcessMemoryDump> pmd( | |
241 new ProcessMemoryDump(nullptr, background_args)); | |
242 SetAllocatorDumpNameWhitelistForTesting(kTestDumpNameWhitelist); | |
243 MemoryAllocatorDump* black_hole_mad = pmd->black_hole_mad_.get(); | |
244 | |
245 // Invalid dump names. | |
246 EXPECT_EQ(black_hole_mad, | |
247 CreateAllocatorDumpInPMD(pmd.get(), "NotWhitelistedTestName")); | |
Primiano Tucci (use gerrit)
2016/06/02 20:24:04
Isn't this going to hit all those DCHECKs? I guess
ssid
2016/06/03 01:59:46
No, I had to make the test class and call AddInter
| |
248 EXPECT_EQ(black_hole_mad, | |
249 CreateAllocatorDumpInPMD(pmd.get(), "NotWhitelistedTestName")); | |
Primiano Tucci (use gerrit)
2016/06/02 20:24:04
I think this is identical to the above?
ssid
2016/06/03 01:59:46
fixed.
| |
250 EXPECT_EQ(black_hole_mad, CreateAllocatorDumpInPMD(pmd.get(), "TestName")); | |
251 EXPECT_EQ(black_hole_mad, | |
252 CreateAllocatorDumpInPMD(pmd.get(), "Whitelisted/Test")); | |
253 EXPECT_EQ(black_hole_mad, | |
254 CreateAllocatorDumpInPMD(pmd.get(), "Not/Whitelisted/TestName")); | |
255 EXPECT_EQ(black_hole_mad, | |
256 CreateAllocatorDumpInPMD(pmd.get(), "Whitelisted/TestName/Google")); | |
257 EXPECT_EQ(black_hole_mad, CreateAllocatorDumpInPMD( | |
258 pmd.get(), "Whitelisted/TestName/0x1a2Google")); | |
259 EXPECT_EQ(black_hole_mad, CreateAllocatorDumpInPMD( | |
260 pmd.get(), "Whitelisted/TestName/__12/Google")); | |
261 | |
262 // Global dumps. | |
263 MemoryAllocatorDumpGuid guid(1); | |
264 EXPECT_EQ(black_hole_mad, pmd->CreateSharedGlobalAllocatorDump(guid)); | |
265 EXPECT_EQ(black_hole_mad, pmd->CreateWeakSharedGlobalAllocatorDump(guid)); | |
266 EXPECT_EQ(black_hole_mad, pmd->GetSharedGlobalAllocatorDump(guid)); | |
267 | |
268 // Suballocations. | |
269 pmd->AddSuballocation(guid, "malloc/allocated_objects"); | |
270 EXPECT_EQ(0u, pmd->allocator_dumps_edges_.size()); | |
271 EXPECT_EQ(0u, pmd->allocator_dumps_.size()); | |
272 | |
273 // Valid dump names. | |
274 EXPECT_NE(black_hole_mad, | |
275 CreateAllocatorDumpInPMD(pmd.get(), "WhitelistedTestName")); | |
276 EXPECT_NE(black_hole_mad, | |
277 CreateAllocatorDumpInPMD(pmd.get(), "Whitelisted/TestName/0xA1b2")); | |
278 EXPECT_NE(black_hole_mad, CreateAllocatorDumpInPMD( | |
279 pmd.get(), "Whitelisted/TestName_123/0xab")); | |
280 EXPECT_NE(black_hole_mad, CreateAllocatorDumpInPMD( | |
281 pmd.get(), "Whitelisted_12/0xaB/TestName")); | |
282 | |
283 // GetAllocatorDump is consistent. | |
284 EXPECT_EQ(black_hole_mad, pmd->GetAllocatorDump("NotWhitelistedTestName")); | |
285 auto mad = pmd->GetAllocatorDump("WhitelistedTestName"); | |
286 EXPECT_NE(black_hole_mad, mad); | |
287 } | |
288 | |
219 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 289 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
220 TEST(ProcessMemoryDumpTest, CountResidentBytes) { | 290 TEST_F(ProcessMemoryDumpTest, CountResidentBytes) { |
221 const size_t page_size = ProcessMemoryDump::GetSystemPageSize(); | 291 const size_t page_size = ProcessMemoryDump::GetSystemPageSize(); |
222 | 292 |
223 // Allocate few page of dirty memory and check if it is resident. | 293 // Allocate few page of dirty memory and check if it is resident. |
224 const size_t size1 = 5 * page_size; | 294 const size_t size1 = 5 * page_size; |
225 std::unique_ptr<char, base::AlignedFreeDeleter> memory1( | 295 std::unique_ptr<char, base::AlignedFreeDeleter> memory1( |
226 static_cast<char*>(base::AlignedAlloc(size1, page_size))); | 296 static_cast<char*>(base::AlignedAlloc(size1, page_size))); |
227 memset(memory1.get(), 0, size1); | 297 memset(memory1.get(), 0, size1); |
228 size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1); | 298 size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1); |
229 ASSERT_EQ(res1, size1); | 299 ASSERT_EQ(res1, size1); |
230 | 300 |
231 // Allocate a large memory segment (> 8Mib). | 301 // Allocate a large memory segment (> 8Mib). |
232 const size_t kVeryLargeMemorySize = 15 * 1024 * 1024; | 302 const size_t kVeryLargeMemorySize = 15 * 1024 * 1024; |
233 std::unique_ptr<char, base::AlignedFreeDeleter> memory2( | 303 std::unique_ptr<char, base::AlignedFreeDeleter> memory2( |
234 static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size))); | 304 static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size))); |
235 memset(memory2.get(), 0, kVeryLargeMemorySize); | 305 memset(memory2.get(), 0, kVeryLargeMemorySize); |
236 size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(), | 306 size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(), |
237 kVeryLargeMemorySize); | 307 kVeryLargeMemorySize); |
238 ASSERT_EQ(res2, kVeryLargeMemorySize); | 308 ASSERT_EQ(res2, kVeryLargeMemorySize); |
239 } | 309 } |
240 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 310 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
241 | 311 |
242 } // namespace trace_event | 312 } // namespace trace_event |
243 } // namespace base | 313 } // namespace base |
OLD | NEW |