Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: components/metrics/leak_detector/call_stack_table_unittest.cc

Issue 986503002: components/metrics: Add runtime memory leak detector (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Mac build fixes: const arg in comparator, rm const in func return type Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "components/metrics/leak_detector/call_stack_table.h"
6
7 #include <set>
8
9 #include "base/macros.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "components/metrics/leak_detector/call_stack_manager.h"
12 #include "components/metrics/leak_detector/custom_allocator.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace metrics {
16 namespace leak_detector {
17
18 namespace {
19
20 // Default threshold used for leak analysis.
21 const int kDefaultLeakThreshold = 5;
22
23 // Some test call stacks.
24 const void* kRawStack0[] = {
25 reinterpret_cast<const void*>(0xaabbccdd),
26 reinterpret_cast<const void*>(0x11223344),
27 reinterpret_cast<const void*>(0x55667788),
28 reinterpret_cast<const void*>(0x99887766),
29 };
30 const void* kRawStack1[] = {
31 reinterpret_cast<const void*>(0xdeadbeef),
32 reinterpret_cast<const void*>(0x900df00d),
33 reinterpret_cast<const void*>(0xcafedeed),
34 reinterpret_cast<const void*>(0xdeafbabe),
35 };
36 const void* kRawStack2[] = {
37 reinterpret_cast<const void*>(0x12345678),
38 reinterpret_cast<const void*>(0xabcdef01),
39 reinterpret_cast<const void*>(0xfdecab98),
40 };
41 const void* kRawStack3[] = {
42 reinterpret_cast<const void*>(0xdead0001),
43 reinterpret_cast<const void*>(0xbeef0002),
44 reinterpret_cast<const void*>(0x900d0003),
45 reinterpret_cast<const void*>(0xf00d0004),
46 reinterpret_cast<const void*>(0xcafe0005),
47 reinterpret_cast<const void*>(0xdeed0006),
48 reinterpret_cast<const void*>(0xdeaf0007),
49 reinterpret_cast<const void*>(0xbabe0008),
50 };
51
52 } // namespace
53
54 class CallStackTableTest : public ::testing::Test {
55 public:
56 CallStackTableTest()
57 : stack0_(nullptr),
58 stack1_(nullptr),
59 stack2_(nullptr),
60 stack3_(nullptr) {}
61
62 void SetUp() override {
63 CustomAllocator::Initialize();
64
65 manager_.reset(new CallStackManager);
66
67 // The unit tests expect a certain order to the call stack pointers. It is
68 // an important detail when checking the output of LeakAnalyzer's suspected
69 // leaks, which are ordered by the leak value (call stack pointer). Use a
70 // set to sort the pointers as they are created.
71 std::set<const CallStack*> stacks;
72 stacks.insert(manager_->GetCallStack(arraysize(kRawStack0), kRawStack0));
73 stacks.insert(manager_->GetCallStack(arraysize(kRawStack1), kRawStack1));
74 stacks.insert(manager_->GetCallStack(arraysize(kRawStack2), kRawStack2));
75 stacks.insert(manager_->GetCallStack(arraysize(kRawStack3), kRawStack3));
76 ASSERT_EQ(4U, stacks.size());
77
78 std::set<const CallStack*>::const_iterator iter = stacks.begin();
79 stack0_ = *iter++;
80 stack1_ = *iter++;
81 stack2_ = *iter++;
82 stack3_ = *iter++;
83 }
84
85 void TearDown() override {
86 // All call stacks generated by |manager_| will be invalidated when it is
87 // destroyed.
88 stack0_ = nullptr;
89 stack1_ = nullptr;
90 stack2_ = nullptr;
91 stack3_ = nullptr;
92
93 // Destroy the call stack manager before shutting down the allocator.
94 manager_.reset();
95
96 EXPECT_TRUE(CustomAllocator::Shutdown());
97 }
98
99 protected:
100 // Unit tests should directly reference these pointers to CallStack objects.
101 const CallStack* stack0_;
102 const CallStack* stack1_;
103 const CallStack* stack2_;
104 const CallStack* stack3_;
105
106 private:
107 scoped_ptr<CallStackManager> manager_;
108
109 DISALLOW_COPY_AND_ASSIGN(CallStackTableTest);
110 };
111
112 TEST_F(CallStackTableTest, PointerOrder) {
113 EXPECT_LT(stack0_, stack1_);
114 EXPECT_LT(stack1_, stack2_);
115 EXPECT_LT(stack2_, stack3_);
116 }
117
118 TEST_F(CallStackTableTest, EmptyTable) {
119 CallStackTable table(kDefaultLeakThreshold);
120 EXPECT_TRUE(table.empty());
121
122 EXPECT_EQ(0U, table.num_allocs());
123 EXPECT_EQ(0U, table.num_frees());
124
125 // The table should be able to gracefully handle an attempt to remove a call
126 // stack entry when none exists.
127 table.Remove(stack0_);
128 table.Remove(stack1_);
129 table.Remove(stack2_);
130 table.Remove(stack3_);
131
132 EXPECT_EQ(0U, table.num_allocs());
133 EXPECT_EQ(0U, table.num_frees());
134 }
135
136 TEST_F(CallStackTableTest, InsertionAndRemoval) {
137 CallStackTable table(kDefaultLeakThreshold);
138
139 table.Add(stack0_);
140 EXPECT_EQ(1U, table.size());
141 EXPECT_EQ(1U, table.num_allocs());
142 table.Add(stack1_);
143 EXPECT_EQ(2U, table.size());
144 EXPECT_EQ(2U, table.num_allocs());
145 table.Add(stack2_);
146 EXPECT_EQ(3U, table.size());
147 EXPECT_EQ(3U, table.num_allocs());
148 table.Add(stack3_);
149 EXPECT_EQ(4U, table.size());
150 EXPECT_EQ(4U, table.num_allocs());
151
152 // Add some call stacks that have already been added. There should be no
153 // change in the number of entries, as they are aggregated by call stack.
154 table.Add(stack2_);
155 EXPECT_EQ(4U, table.size());
156 EXPECT_EQ(5U, table.num_allocs());
157 table.Add(stack3_);
158 EXPECT_EQ(4U, table.size());
159 EXPECT_EQ(6U, table.num_allocs());
160
161 // Start removing entries.
162 EXPECT_EQ(0U, table.num_frees());
163
164 table.Remove(stack0_);
165 EXPECT_EQ(3U, table.size());
166 EXPECT_EQ(1U, table.num_frees());
167 table.Remove(stack1_);
168 EXPECT_EQ(2U, table.size());
169 EXPECT_EQ(2U, table.num_frees());
170
171 // Removing call stacks with multiple counts will not reduce the overall
172 // number of table entries, until the count reaches 0.
173 table.Remove(stack2_);
174 EXPECT_EQ(2U, table.size());
175 EXPECT_EQ(3U, table.num_frees());
176 table.Remove(stack3_);
177 EXPECT_EQ(2U, table.size());
178 EXPECT_EQ(4U, table.num_frees());
179
180 table.Remove(stack2_);
181 EXPECT_EQ(1U, table.size());
182 EXPECT_EQ(5U, table.num_frees());
183 table.Remove(stack3_);
184 EXPECT_EQ(0U, table.size());
185 EXPECT_EQ(6U, table.num_frees());
186
187 // Now the table should be empty, but attempt to remove some more and make
188 // sure nothing breaks.
189 table.Remove(stack0_);
190 table.Remove(stack1_);
191 table.Remove(stack2_);
192 table.Remove(stack3_);
193
194 EXPECT_TRUE(table.empty());
195 EXPECT_EQ(6U, table.num_allocs());
196 EXPECT_EQ(6U, table.num_frees());
197 }
198
199 TEST_F(CallStackTableTest, MassiveInsertionAndRemoval) {
200 CallStackTable table(kDefaultLeakThreshold);
201
202 for (int i = 0; i < 100; ++i)
203 table.Add(stack3_);
204 EXPECT_EQ(1U, table.size());
205 EXPECT_EQ(100U, table.num_allocs());
206
207 for (int i = 0; i < 100; ++i)
208 table.Add(stack2_);
209 EXPECT_EQ(2U, table.size());
210 EXPECT_EQ(200U, table.num_allocs());
211
212 for (int i = 0; i < 100; ++i)
213 table.Add(stack1_);
214 EXPECT_EQ(3U, table.size());
215 EXPECT_EQ(300U, table.num_allocs());
216
217 for (int i = 0; i < 100; ++i)
218 table.Add(stack0_);
219 EXPECT_EQ(4U, table.size());
220 EXPECT_EQ(400U, table.num_allocs());
221
222 // Remove them in a different order, by removing one of each stack during one
223 // iteration. The size should not decrease until the last iteration.
224 EXPECT_EQ(0U, table.num_frees());
225
226 for (int i = 0; i < 100; ++i) {
227 table.Remove(stack0_);
228 EXPECT_EQ(4U * i + 1, table.num_frees());
229
230 table.Remove(stack1_);
231 EXPECT_EQ(4U * i + 2, table.num_frees());
232
233 table.Remove(stack2_);
234 EXPECT_EQ(4U * i + 3, table.num_frees());
235
236 table.Remove(stack3_);
237 EXPECT_EQ(4U * i + 4, table.num_frees());
238 }
239 EXPECT_EQ(400U, table.num_frees());
240 EXPECT_TRUE(table.empty());
241
242 // Try to remove some more from an empty table and make sure nothing breaks.
243 table.Remove(stack0_);
244 table.Remove(stack1_);
245 table.Remove(stack2_);
246 table.Remove(stack3_);
247
248 EXPECT_TRUE(table.empty());
249 EXPECT_EQ(400U, table.num_allocs());
250 EXPECT_EQ(400U, table.num_frees());
251 }
252
253 TEST_F(CallStackTableTest, DetectLeak) {
254 CallStackTable table(kDefaultLeakThreshold);
255
256 // Add some base number of entries.
257 for (int i = 0; i < 60; ++i)
258 table.Add(stack0_);
259 for (int i = 0; i < 50; ++i)
260 table.Add(stack1_);
261 for (int i = 0; i < 64; ++i)
262 table.Add(stack2_);
263 for (int i = 0; i < 72; ++i)
264 table.Add(stack3_);
265
266 table.TestForLeaks();
267 EXPECT_TRUE(table.leak_analyzer().suspected_leaks().empty());
268
269 // Use the following scheme:
270 // - stack0_: increase by 4 each time -- leak suspect
271 // - stack1_: increase by 3 each time -- leak suspect
272 // - stack2_: increase by 1 each time -- not a suspect
273 // - stack3_: alternate between increasing and decreasing - not a suspect
274 bool increase_kstack3 = true;
275 for (int i = 0; i < kDefaultLeakThreshold; ++i) {
276 EXPECT_TRUE(table.leak_analyzer().suspected_leaks().empty());
277
278 for (int j = 0; j < 4; ++j)
279 table.Add(stack0_);
280
281 for (int j = 0; j < 3; ++j)
282 table.Add(stack1_);
283
284 table.Add(stack2_);
285
286 // Alternate between adding and removing.
287 if (increase_kstack3)
288 table.Add(stack3_);
289 else
290 table.Remove(stack3_);
291 increase_kstack3 = !increase_kstack3;
292
293 table.TestForLeaks();
294 }
295
296 // Check that the correct leak values have been detected.
297 const auto& leaks = table.leak_analyzer().suspected_leaks();
298 ASSERT_EQ(2U, leaks.size());
299 // Suspected leaks are reported in increasing leak value -- in this case, the
300 // CallStack object's address.
301 EXPECT_EQ(stack0_, leaks[0].call_stack());
302 EXPECT_EQ(stack1_, leaks[1].call_stack());
303 }
304
305 } // namespace leak_detector
306 } // namespace metrics
OLDNEW
« no previous file with comments | « components/metrics/leak_detector/call_stack_table.cc ('k') | components/metrics/leak_detector/custom_allocator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698