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/process/process_metrics.h" | 10 #include "base/process/process_metrics.h" |
11 #include "base/trace_event/memory_allocator_dump_guid.h" | 11 #include "base/trace_event/memory_allocator_dump_guid.h" |
12 #include "base/trace_event/trace_event_argument.h" | 12 #include "base/trace_event/trace_event_argument.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
14 | 14 |
15 namespace base { | 15 namespace base { |
16 namespace trace_event { | 16 namespace trace_event { |
17 | 17 |
18 namespace { | 18 namespace { |
19 TracedValue* GetHeapDump(const ProcessMemoryDump& pmd, const char* name) { | 19 TracedValue* GetHeapDump(const ProcessMemoryDump& pmd, const char* name) { |
20 auto it = pmd.heap_dumps().find(name); | 20 auto it = pmd.heap_dumps().find(name); |
21 return it == pmd.heap_dumps().end() ? nullptr : it->second.get(); | 21 return it == pmd.heap_dumps().end() ? nullptr : it->second.get(); |
22 } | 22 } |
23 } // namespace | 23 } // namespace |
24 | 24 |
25 TEST(ProcessMemoryDumpTest, Clear) { | 25 TEST(ProcessMemoryDumpTest, Clear) { |
26 std::unique_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr)); | 26 std::unique_ptr<ProcessMemoryDump> pmd1( |
| 27 new ProcessMemoryDump(nullptr, MemoryDumpLevelOfDetail::DETAILED)); |
27 pmd1->CreateAllocatorDump("mad1"); | 28 pmd1->CreateAllocatorDump("mad1"); |
28 pmd1->CreateAllocatorDump("mad2"); | 29 pmd1->CreateAllocatorDump("mad2"); |
29 ASSERT_FALSE(pmd1->allocator_dumps().empty()); | 30 ASSERT_FALSE(pmd1->allocator_dumps().empty()); |
30 | 31 |
31 pmd1->process_totals()->set_resident_set_bytes(42); | 32 pmd1->process_totals()->set_resident_set_bytes(42); |
32 pmd1->set_has_process_totals(); | 33 pmd1->set_has_process_totals(); |
33 | 34 |
34 pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion()); | 35 pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion()); |
35 pmd1->set_has_process_mmaps(); | 36 pmd1->set_has_process_mmaps(); |
36 | 37 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 pmd1->AsValueInto(traced_value.get()); | 77 pmd1->AsValueInto(traced_value.get()); |
77 | 78 |
78 pmd1.reset(); | 79 pmd1.reset(); |
79 } | 80 } |
80 | 81 |
81 TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) { | 82 TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) { |
82 std::unique_ptr<TracedValue> traced_value(new TracedValue); | 83 std::unique_ptr<TracedValue> traced_value(new TracedValue); |
83 TracedValue* heap_dumps_ptr[4]; | 84 TracedValue* heap_dumps_ptr[4]; |
84 std::unique_ptr<TracedValue> heap_dump; | 85 std::unique_ptr<TracedValue> heap_dump; |
85 | 86 |
86 std::unique_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr)); | 87 std::unique_ptr<ProcessMemoryDump> pmd1( |
| 88 new ProcessMemoryDump(nullptr, MemoryDumpLevelOfDetail::DETAILED)); |
87 auto mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1"); | 89 auto mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1"); |
88 auto mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2"); | 90 auto mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2"); |
89 pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid()); | 91 pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid()); |
90 heap_dump.reset(new TracedValue); | 92 heap_dump.reset(new TracedValue); |
91 heap_dumps_ptr[0] = heap_dump.get(); | 93 heap_dumps_ptr[0] = heap_dump.get(); |
92 pmd1->AddHeapDump("pmd1/heap_dump1", std::move(heap_dump)); | 94 pmd1->AddHeapDump("pmd1/heap_dump1", std::move(heap_dump)); |
93 heap_dump.reset(new TracedValue); | 95 heap_dump.reset(new TracedValue); |
94 heap_dumps_ptr[1] = heap_dump.get(); | 96 heap_dumps_ptr[1] = heap_dump.get(); |
95 pmd1->AddHeapDump("pmd1/heap_dump2", std::move(heap_dump)); | 97 pmd1->AddHeapDump("pmd1/heap_dump2", std::move(heap_dump)); |
96 | 98 |
97 std::unique_ptr<ProcessMemoryDump> pmd2(new ProcessMemoryDump(nullptr)); | 99 std::unique_ptr<ProcessMemoryDump> pmd2( |
| 100 new ProcessMemoryDump(nullptr, MemoryDumpLevelOfDetail::DETAILED)); |
98 auto mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1"); | 101 auto mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1"); |
99 auto mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2"); | 102 auto mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2"); |
100 pmd2->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid()); | 103 pmd2->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid()); |
101 heap_dump.reset(new TracedValue); | 104 heap_dump.reset(new TracedValue); |
102 heap_dumps_ptr[2] = heap_dump.get(); | 105 heap_dumps_ptr[2] = heap_dump.get(); |
103 pmd2->AddHeapDump("pmd2/heap_dump1", std::move(heap_dump)); | 106 pmd2->AddHeapDump("pmd2/heap_dump1", std::move(heap_dump)); |
104 heap_dump.reset(new TracedValue); | 107 heap_dump.reset(new TracedValue); |
105 heap_dumps_ptr[3] = heap_dump.get(); | 108 heap_dumps_ptr[3] = heap_dump.get(); |
106 pmd2->AddHeapDump("pmd2/heap_dump2", std::move(heap_dump)); | 109 pmd2->AddHeapDump("pmd2/heap_dump2", std::move(heap_dump)); |
107 | 110 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 ASSERT_EQ(heap_dumps_ptr[3], GetHeapDump(*pmd1, "pmd2/heap_dump2")); | 150 ASSERT_EQ(heap_dumps_ptr[3], GetHeapDump(*pmd1, "pmd2/heap_dump2")); |
148 | 151 |
149 // Check that calling AsValueInto() doesn't cause a crash. | 152 // Check that calling AsValueInto() doesn't cause a crash. |
150 traced_value.reset(new TracedValue); | 153 traced_value.reset(new TracedValue); |
151 pmd1->AsValueInto(traced_value.get()); | 154 pmd1->AsValueInto(traced_value.get()); |
152 | 155 |
153 pmd1.reset(); | 156 pmd1.reset(); |
154 } | 157 } |
155 | 158 |
156 TEST(ProcessMemoryDumpTest, Suballocations) { | 159 TEST(ProcessMemoryDumpTest, Suballocations) { |
157 std::unique_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr)); | 160 std::unique_ptr<ProcessMemoryDump> pmd( |
| 161 new ProcessMemoryDump(nullptr, MemoryDumpLevelOfDetail::DETAILED)); |
158 const std::string allocator_dump_name = "fakealloc/allocated_objects"; | 162 const std::string allocator_dump_name = "fakealloc/allocated_objects"; |
159 pmd->CreateAllocatorDump(allocator_dump_name); | 163 pmd->CreateAllocatorDump(allocator_dump_name); |
160 | 164 |
161 // Create one allocation with an auto-assigned guid and mark it as a | 165 // Create one allocation with an auto-assigned guid and mark it as a |
162 // suballocation of "fakealloc/allocated_objects". | 166 // suballocation of "fakealloc/allocated_objects". |
163 auto pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1"); | 167 auto pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1"); |
164 pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name); | 168 pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name); |
165 | 169 |
166 // Same here, but this time create an allocation with an explicit guid. | 170 // Same here, but this time create an allocation with an explicit guid. |
167 auto pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2", | 171 auto pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2", |
(...skipping 23 matching lines...) Expand all Loading... |
191 ASSERT_TRUE(found_edge[1]); | 195 ASSERT_TRUE(found_edge[1]); |
192 | 196 |
193 // Check that calling AsValueInto() doesn't cause a crash. | 197 // Check that calling AsValueInto() doesn't cause a crash. |
194 std::unique_ptr<TracedValue> traced_value(new TracedValue); | 198 std::unique_ptr<TracedValue> traced_value(new TracedValue); |
195 pmd->AsValueInto(traced_value.get()); | 199 pmd->AsValueInto(traced_value.get()); |
196 | 200 |
197 pmd.reset(); | 201 pmd.reset(); |
198 } | 202 } |
199 | 203 |
200 TEST(ProcessMemoryDumpTest, GlobalAllocatorDumpTest) { | 204 TEST(ProcessMemoryDumpTest, GlobalAllocatorDumpTest) { |
201 std::unique_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr)); | 205 std::unique_ptr<ProcessMemoryDump> pmd( |
| 206 new ProcessMemoryDump(nullptr, MemoryDumpLevelOfDetail::DETAILED)); |
202 MemoryAllocatorDumpGuid shared_mad_guid(1); | 207 MemoryAllocatorDumpGuid shared_mad_guid(1); |
203 auto shared_mad1 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); | 208 auto shared_mad1 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); |
204 ASSERT_EQ(shared_mad_guid, shared_mad1->guid()); | 209 ASSERT_EQ(shared_mad_guid, shared_mad1->guid()); |
205 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); | 210 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); |
206 | 211 |
207 auto shared_mad2 = pmd->GetSharedGlobalAllocatorDump(shared_mad_guid); | 212 auto shared_mad2 = pmd->GetSharedGlobalAllocatorDump(shared_mad_guid); |
208 ASSERT_EQ(shared_mad1, shared_mad2); | 213 ASSERT_EQ(shared_mad1, shared_mad2); |
209 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); | 214 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); |
210 | 215 |
211 auto shared_mad3 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); | 216 auto shared_mad3 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); |
212 ASSERT_EQ(shared_mad1, shared_mad3); | 217 ASSERT_EQ(shared_mad1, shared_mad3); |
213 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); | 218 ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags()); |
214 | 219 |
215 auto shared_mad4 = pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid); | 220 auto shared_mad4 = pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid); |
216 ASSERT_EQ(shared_mad1, shared_mad4); | 221 ASSERT_EQ(shared_mad1, shared_mad4); |
217 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); | 222 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); |
218 | 223 |
219 auto shared_mad5 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); | 224 auto shared_mad5 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid); |
220 ASSERT_EQ(shared_mad1, shared_mad5); | 225 ASSERT_EQ(shared_mad1, shared_mad5); |
221 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); | 226 ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags()); |
222 } | 227 } |
223 | 228 |
| 229 TEST(ProcessMemoryDumpTest, BackgroundModeTest) { |
| 230 std::unique_ptr<ProcessMemoryDump> pmd( |
| 231 new ProcessMemoryDump(nullptr, MemoryDumpLevelOfDetail::BACKGROUND)); |
| 232 pmd->whitelisted_name_for_testing_ = "WhitelistedTestName"; |
| 233 MemoryAllocatorDump* dummy_mad = pmd->dummy_mad_.get(); |
| 234 |
| 235 // Invalid dump names. |
| 236 EXPECT_EQ(dummy_mad, pmd->CreateAllocatorDump("NotWhitelistedTestName")); |
| 237 EXPECT_EQ(dummy_mad, pmd->CreateAllocatorDump("TestName")); |
| 238 EXPECT_EQ(dummy_mad, pmd->CreateAllocatorDump("Whitelisted/Test")); |
| 239 EXPECT_EQ(dummy_mad, pmd->CreateAllocatorDump("Not/Whitelisted/TestName")); |
| 240 EXPECT_EQ(dummy_mad, pmd->CreateAllocatorDump("Whitelisted/TestName/Google")); |
| 241 EXPECT_EQ(dummy_mad, |
| 242 pmd->CreateAllocatorDump("Whitelisted/TestName/0x1a2Google")); |
| 243 EXPECT_EQ(dummy_mad, |
| 244 pmd->CreateAllocatorDump("Whitelisted/TestName/__12/Google")); |
| 245 |
| 246 // Global dumps. |
| 247 MemoryAllocatorDumpGuid guid(1); |
| 248 EXPECT_EQ(dummy_mad, pmd->CreateSharedGlobalAllocatorDump(guid)); |
| 249 EXPECT_EQ(dummy_mad, pmd->CreateWeakSharedGlobalAllocatorDump(guid)); |
| 250 EXPECT_EQ(dummy_mad, pmd->GetSharedGlobalAllocatorDump(guid)); |
| 251 |
| 252 // Suballocations. |
| 253 pmd->AddSuballocation(guid, "malloc/allocated_objects"); |
| 254 EXPECT_EQ(0u, pmd->allocator_dumps_edges_.size()); |
| 255 EXPECT_EQ(0u, pmd->allocator_dumps_.size()); |
| 256 |
| 257 // Valid dump names. |
| 258 EXPECT_NE(dummy_mad, pmd->CreateAllocatorDump("WhitelistedTestName")); |
| 259 EXPECT_NE(dummy_mad, pmd->CreateAllocatorDump("Whitelisted/TestName/0xA1b2")); |
| 260 EXPECT_NE(dummy_mad, |
| 261 pmd->CreateAllocatorDump("Whitelisted/TestName_123/0xab")); |
| 262 EXPECT_NE(dummy_mad, |
| 263 pmd->CreateAllocatorDump("Whitelisted_12/0xaB/TestName")); |
| 264 |
| 265 // GetAllocatorDump is consistent. |
| 266 EXPECT_EQ(dummy_mad, pmd->GetAllocatorDump("NotWhitelistedTestName")); |
| 267 auto mad = pmd->GetAllocatorDump("WhitelistedTestName"); |
| 268 EXPECT_NE(dummy_mad, mad); |
| 269 |
| 270 // String attributes are disabled in MAD. |
| 271 mad->AddString("url", "text", "google"); |
| 272 std::string out; |
| 273 mad->attributes_for_testing()->AppendAsTraceFormat(&out); |
| 274 EXPECT_EQ("{}", out); |
| 275 |
| 276 pmd->whitelisted_name_for_testing_ = nullptr; |
| 277 } |
| 278 |
224 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 279 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
225 TEST(ProcessMemoryDumpTest, CountResidentBytes) { | 280 TEST(ProcessMemoryDumpTest, CountResidentBytes) { |
226 const size_t page_size = ProcessMemoryDump::GetSystemPageSize(); | 281 const size_t page_size = ProcessMemoryDump::GetSystemPageSize(); |
227 | 282 |
228 // Allocate few page of dirty memory and check if it is resident. | 283 // Allocate few page of dirty memory and check if it is resident. |
229 const size_t size1 = 5 * page_size; | 284 const size_t size1 = 5 * page_size; |
230 std::unique_ptr<char, base::AlignedFreeDeleter> memory1( | 285 std::unique_ptr<char, base::AlignedFreeDeleter> memory1( |
231 static_cast<char*>(base::AlignedAlloc(size1, page_size))); | 286 static_cast<char*>(base::AlignedAlloc(size1, page_size))); |
232 memset(memory1.get(), 0, size1); | 287 memset(memory1.get(), 0, size1); |
233 size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1); | 288 size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1); |
234 ASSERT_EQ(res1, size1); | 289 ASSERT_EQ(res1, size1); |
235 | 290 |
236 // Allocate a large memory segment (> 8Mib). | 291 // Allocate a large memory segment (> 8Mib). |
237 const size_t kVeryLargeMemorySize = 15 * 1024 * 1024; | 292 const size_t kVeryLargeMemorySize = 15 * 1024 * 1024; |
238 std::unique_ptr<char, base::AlignedFreeDeleter> memory2( | 293 std::unique_ptr<char, base::AlignedFreeDeleter> memory2( |
239 static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size))); | 294 static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size))); |
240 memset(memory2.get(), 0, kVeryLargeMemorySize); | 295 memset(memory2.get(), 0, kVeryLargeMemorySize); |
241 size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(), | 296 size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(), |
242 kVeryLargeMemorySize); | 297 kVeryLargeMemorySize); |
243 ASSERT_EQ(res2, kVeryLargeMemorySize); | 298 ASSERT_EQ(res2, kVeryLargeMemorySize); |
244 } | 299 } |
245 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 300 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
246 | 301 |
247 } // namespace trace_event | 302 } // namespace trace_event |
248 } // namespace base | 303 } // namespace base |
OLD | NEW |