• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 #include <stddef.h>
8 
9 #include "base/memory/aligned_memory.h"
10 #include "base/process/process_metrics.h"
11 #include "base/trace_event/memory_allocator_dump_guid.h"
12 #include "base/trace_event/trace_event_argument.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace base {
16 namespace trace_event {
17 
TEST(ProcessMemoryDumpTest,Clear)18 TEST(ProcessMemoryDumpTest, Clear) {
19   scoped_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr));
20   pmd1->CreateAllocatorDump("mad1");
21   pmd1->CreateAllocatorDump("mad2");
22   ASSERT_FALSE(pmd1->allocator_dumps().empty());
23 
24   pmd1->process_totals()->set_resident_set_bytes(42);
25   pmd1->set_has_process_totals();
26 
27   pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion());
28   pmd1->set_has_process_mmaps();
29 
30   pmd1->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
31                          MemoryAllocatorDumpGuid(4242));
32 
33   MemoryAllocatorDumpGuid shared_mad_guid(1);
34   pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid);
35 
36   pmd1->Clear();
37   ASSERT_TRUE(pmd1->allocator_dumps().empty());
38   ASSERT_TRUE(pmd1->allocator_dumps_edges().empty());
39   ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad1"));
40   ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
41   ASSERT_FALSE(pmd1->has_process_totals());
42   ASSERT_FALSE(pmd1->has_process_mmaps());
43   ASSERT_TRUE(pmd1->process_mmaps()->vm_regions().empty());
44   ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
45 
46   // Check that calling AsValueInto() doesn't cause a crash.
47   scoped_refptr<TracedValue> traced_value(new TracedValue());
48   pmd1->AsValueInto(traced_value.get());
49 
50   // Check that the pmd can be reused and behaves as expected.
51   auto mad1 = pmd1->CreateAllocatorDump("mad1");
52   auto mad3 = pmd1->CreateAllocatorDump("mad3");
53   auto shared_mad = pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid);
54   ASSERT_EQ(3u, pmd1->allocator_dumps().size());
55   ASSERT_EQ(mad1, pmd1->GetAllocatorDump("mad1"));
56   ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
57   ASSERT_EQ(mad3, pmd1->GetAllocatorDump("mad3"));
58   ASSERT_EQ(shared_mad, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
59 
60   traced_value = new TracedValue();
61   pmd1->AsValueInto(traced_value.get());
62 
63   pmd1.reset();
64 }
65 
TEST(ProcessMemoryDumpTest,TakeAllDumpsFrom)66 TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) {
67   scoped_refptr<TracedValue> traced_value(new TracedValue());
68 
69   scoped_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr));
70   auto mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1");
71   auto mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2");
72   pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid());
73 
74   scoped_ptr<ProcessMemoryDump> pmd2(new ProcessMemoryDump(nullptr));
75   auto mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1");
76   auto mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2");
77   pmd1->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid());
78 
79   MemoryAllocatorDumpGuid shared_mad_guid(1);
80   auto shared_mad = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid);
81 
82   pmd1->TakeAllDumpsFrom(pmd2.get());
83 
84   // Make sure that pmd2 is empty but still usable after it has been emptied.
85   ASSERT_TRUE(pmd2->allocator_dumps().empty());
86   ASSERT_TRUE(pmd2->allocator_dumps_edges().empty());
87   pmd2->CreateAllocatorDump("pmd2/this_mad_stays_with_pmd2");
88   ASSERT_EQ(1u, pmd2->allocator_dumps().size());
89   ASSERT_EQ(1u, pmd2->allocator_dumps().count("pmd2/this_mad_stays_with_pmd2"));
90   pmd2->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
91                          MemoryAllocatorDumpGuid(4242));
92 
93   // Check that calling AsValueInto() doesn't cause a crash.
94   pmd2->AsValueInto(traced_value.get());
95 
96   // Free the |pmd2| to check that the memory ownership of the two MAD(s)
97   // has been transferred to |pmd1|.
98   pmd2.reset();
99 
100   // Now check that |pmd1| has been effectively merged.
101   ASSERT_EQ(5u, pmd1->allocator_dumps().size());
102   ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad1"));
103   ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
104   ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd2/mad1"));
105   ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
106   ASSERT_EQ(2u, pmd1->allocator_dumps_edges().size());
107   ASSERT_EQ(shared_mad, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
108 
109   // Check that calling AsValueInto() doesn't cause a crash.
110   traced_value = new TracedValue();
111   pmd1->AsValueInto(traced_value.get());
112 
113   pmd1.reset();
114 }
115 
TEST(ProcessMemoryDumpTest,Suballocations)116 TEST(ProcessMemoryDumpTest, Suballocations) {
117   scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
118   const std::string allocator_dump_name = "fakealloc/allocated_objects";
119   pmd->CreateAllocatorDump(allocator_dump_name);
120 
121   // Create one allocation with an auto-assigned guid and mark it as a
122   // suballocation of "fakealloc/allocated_objects".
123   auto pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1");
124   pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name);
125 
126   // Same here, but this time create an allocation with an explicit guid.
127   auto pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2",
128                                             MemoryAllocatorDumpGuid(0x42));
129   pmd->AddSuballocation(pic2_dump->guid(), allocator_dump_name);
130 
131   // Now check that AddSuballocation() has created anonymous child dumps under
132   // "fakealloc/allocated_objects".
133   auto anon_node_1_it = pmd->allocator_dumps().find(
134       allocator_dump_name + "/__" + pic1_dump->guid().ToString());
135   ASSERT_NE(pmd->allocator_dumps().end(), anon_node_1_it);
136 
137   auto anon_node_2_it =
138       pmd->allocator_dumps().find(allocator_dump_name + "/__42");
139   ASSERT_NE(pmd->allocator_dumps().end(), anon_node_2_it);
140 
141   // Finally check that AddSuballocation() has created also the
142   // edges between the pictures and the anonymous allocator child dumps.
143   bool found_edge[2]{false, false};
144   for (const auto& e : pmd->allocator_dumps_edges()) {
145     found_edge[0] |= (e.source == pic1_dump->guid() &&
146                       e.target == anon_node_1_it->second->guid());
147     found_edge[1] |= (e.source == pic2_dump->guid() &&
148                       e.target == anon_node_2_it->second->guid());
149   }
150   ASSERT_TRUE(found_edge[0]);
151   ASSERT_TRUE(found_edge[1]);
152 
153   // Check that calling AsValueInto() doesn't cause a crash.
154   scoped_refptr<TracedValue> traced_value(new TracedValue());
155   pmd->AsValueInto(traced_value.get());
156 
157   pmd.reset();
158 }
159 
160 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
TEST(ProcessMemoryDumpTest,CountResidentBytes)161 TEST(ProcessMemoryDumpTest, CountResidentBytes) {
162   const size_t page_size = base::GetPageSize();
163 
164   // Allocate few page of dirty memory and check if it is resident.
165   const size_t size1 = 5 * page_size;
166   scoped_ptr<char, base::AlignedFreeDeleter> memory1(
167       static_cast<char*>(base::AlignedAlloc(size1, page_size)));
168   memset(memory1.get(), 0, size1);
169   size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1);
170   ASSERT_EQ(res1, size1);
171 
172   // Allocate a large memory segment (>32Mib).
173   const size_t kVeryLargeMemorySize = 34 * 1024 * 1024;
174   scoped_ptr<char, base::AlignedFreeDeleter> memory2(
175       static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size)));
176   memset(memory2.get(), 0, kVeryLargeMemorySize);
177   size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(),
178                                                       kVeryLargeMemorySize);
179   ASSERT_EQ(res2, kVeryLargeMemorySize);
180 }
181 #endif  // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
182 
183 }  // namespace trace_event
184 }  // namespace base
185