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

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: Addressed Alexei's comments 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() : stack0_(nullptr),
57 stack1_(nullptr),
58 stack2_(nullptr),
59 stack3_(nullptr) {}
60
61 void SetUp() override {
62 CustomAllocator::Initialize();
63
64 manager_.reset(new CallStackManager);
65
66 // The unit tests expect a certain order to the call stack pointers. It is
67 // an important detail when checking the output of LeakAnalyzer's suspected
68 // leaks, which are ordered by the leak value (call stack pointer). Use a
69 // set to sort the pointers as they are created.
70 std::set<const CallStack*> stacks;
71 stacks.insert(manager_->GetCallStack(arraysize(kRawStack0), kRawStack0));
72 stacks.insert(manager_->GetCallStack(arraysize(kRawStack1), kRawStack1));
73 stacks.insert(manager_->GetCallStack(arraysize(kRawStack2), kRawStack2));
74 stacks.insert(manager_->GetCallStack(arraysize(kRawStack3), kRawStack3));
75 ASSERT_EQ(4U, stacks.size());
76
77 std::set<const CallStack*>::const_iterator iter = stacks.begin();
78 stack0_ = *iter++;
79 stack1_ = *iter++;
80 stack2_ = *iter++;
81 stack3_ = *iter++;
82 }
83
84 void TearDown() override {
85 // All call stacks generated by |manager_| will be invalidated when it is
86 // destroyed.
87 stack0_ = nullptr;
88 stack1_ = nullptr;
89 stack2_ = nullptr;
90 stack3_ = nullptr;
91
92 // Destroy the call stack manager before shutting down the allocator.
93 manager_.reset();
94
95 EXPECT_TRUE(CustomAllocator::Shutdown());
96 }
97
98 protected:
99 // Unit tests should directly reference these pointers to CallStack objects.
100 const CallStack* stack0_;
101 const CallStack* stack1_;
102 const CallStack* stack2_;
103 const CallStack* stack3_;
104
105 private:
106 scoped_ptr<CallStackManager> manager_;
107
108 DISALLOW_COPY_AND_ASSIGN(CallStackTableTest);
109 };
110
111 TEST_F(CallStackTableTest, PointerOrder) {
112 EXPECT_LT(stack0_, stack1_);
113 EXPECT_LT(stack1_, stack2_);
114 EXPECT_LT(stack2_, stack3_);
115 }
116
117 TEST_F(CallStackTableTest, EmptyTable) {
118 CallStackTable table(kDefaultLeakThreshold);
119 EXPECT_TRUE(table.empty());
120
121 EXPECT_EQ(0U, table.num_allocs());
122 EXPECT_EQ(0U, table.num_frees());
123
124 // The table should be able to gracefully handle an attempt to remove a call
125 // stack entry when none exists.
126 table.Remove(stack0_);
127 table.Remove(stack1_);
128 table.Remove(stack2_);
129 table.Remove(stack3_);
130
131 EXPECT_EQ(0U, table.num_allocs());
132 EXPECT_EQ(0U, table.num_frees());
133 }
134
135 TEST_F(CallStackTableTest, InsertionAndRemoval) {
136 CallStackTable table(kDefaultLeakThreshold);
137
138 table.Add(stack0_);
139 EXPECT_EQ(1U, table.size());
140 EXPECT_EQ(1U, table.num_allocs());
141 table.Add(stack1_);
142 EXPECT_EQ(2U, table.size());
143 EXPECT_EQ(2U, table.num_allocs());
144 table.Add(stack2_);
145 EXPECT_EQ(3U, table.size());
146 EXPECT_EQ(3U, table.num_allocs());
147 table.Add(stack3_);
148 EXPECT_EQ(4U, table.size());
149 EXPECT_EQ(4U, table.num_allocs());
150
151 // Add some call stacks that have already been added. There should be no
152 // change in the number of entries, as they are aggregated by call stack.
153 table.Add(stack2_);
154 EXPECT_EQ(4U, table.size());
155 EXPECT_EQ(5U, table.num_allocs());
156 table.Add(stack3_);
157 EXPECT_EQ(4U, table.size());
158 EXPECT_EQ(6U, table.num_allocs());
159
160 // Start removing entries.
161 EXPECT_EQ(0U, table.num_frees());
162
163 table.Remove(stack0_);
164 EXPECT_EQ(3U, table.size());
165 EXPECT_EQ(1U, table.num_frees());
166 table.Remove(stack1_);
167 EXPECT_EQ(2U, table.size());
168 EXPECT_EQ(2U, table.num_frees());
169
170 // Removing call stacks with multiple counts will not reduce the overall
171 // number of table entries, until the count reaches 0.
172 table.Remove(stack2_);
173 EXPECT_EQ(2U, table.size());
174 EXPECT_EQ(3U, table.num_frees());
175 table.Remove(stack3_);
176 EXPECT_EQ(2U, table.size());
177 EXPECT_EQ(4U, table.num_frees());
178
179 table.Remove(stack2_);
180 EXPECT_EQ(1U, table.size());
181 EXPECT_EQ(5U, table.num_frees());
182 table.Remove(stack3_);
183 EXPECT_EQ(0U, table.size());
184 EXPECT_EQ(6U, table.num_frees());
185
186 // Now the table should be empty, but attempt to remove some more and make
187 // sure nothing breaks.
188 table.Remove(stack0_);
189 table.Remove(stack1_);
190 table.Remove(stack2_);
191 table.Remove(stack3_);
192
193 EXPECT_TRUE(table.empty());
194 EXPECT_EQ(6U, table.num_allocs());
195 EXPECT_EQ(6U, table.num_frees());
196 }
197
198 TEST_F(CallStackTableTest, MassiveInsertionAndRemoval) {
199 CallStackTable table(kDefaultLeakThreshold);
200
201 for (int i = 0; i < 100; ++i)
202 table.Add(stack3_);
203 EXPECT_EQ(1U, table.size());
204 EXPECT_EQ(100U, table.num_allocs());
205
206 for (int i = 0; i < 100; ++i)
207 table.Add(stack2_);
208 EXPECT_EQ(2U, table.size());
209 EXPECT_EQ(200U, table.num_allocs());
210
211 for (int i = 0; i < 100; ++i)
212 table.Add(stack1_);
213 EXPECT_EQ(3U, table.size());
214 EXPECT_EQ(300U, table.num_allocs());
215
216 for (int i = 0; i < 100; ++i)
217 table.Add(stack0_);
218 EXPECT_EQ(4U, table.size());
219 EXPECT_EQ(400U, table.num_allocs());
220
221 // Remove them in a different order, by removing one of each stack during one
222 // iteration. The size should not decrease until the last iteration.
223 EXPECT_EQ(0U, table.num_frees());
224
225 for (int i = 0; i < 100; ++i) {
226 table.Remove(stack0_);
227 EXPECT_EQ(4U * i + 1, table.num_frees());
228
229 table.Remove(stack1_);
230 EXPECT_EQ(4U * i + 2, table.num_frees());
231
232 table.Remove(stack2_);
233 EXPECT_EQ(4U * i + 3, table.num_frees());
234
235 table.Remove(stack3_);
236 EXPECT_EQ(4U * i + 4, table.num_frees());
237 }
238 EXPECT_EQ(400U, table.num_frees());
239 EXPECT_TRUE(table.empty());
240
241 // Try to remove some more from an empty table and make sure nothing breaks.
242 table.Remove(stack0_);
243 table.Remove(stack1_);
244 table.Remove(stack2_);
245 table.Remove(stack3_);
246
247 EXPECT_TRUE(table.empty());
248 EXPECT_EQ(400U, table.num_allocs());
249 EXPECT_EQ(400U, table.num_frees());
250 }
251
252 TEST_F(CallStackTableTest, DetectLeak) {
253 CallStackTable table(kDefaultLeakThreshold);
254
255 // Add some base number of entries.
256 for (int i = 0; i < 60; ++i)
257 table.Add(stack0_);
258 for (int i = 0; i < 50; ++i)
259 table.Add(stack1_);
260 for (int i = 0; i < 64; ++i)
261 table.Add(stack2_);
262 for (int i = 0; i < 72; ++i)
263 table.Add(stack3_);
264
265 table.TestForLeaks();
266 EXPECT_TRUE(table.leak_analyzer().suspected_leaks().empty());
267
268 // Use the following scheme:
269 // - stack0_: increase by 4 each time -- leak suspect
270 // - stack1_: increase by 3 each time -- leak suspect
271 // - stack2_: increase by 1 each time -- not a suspect
272 // - stack3_: alternate between increasing and decreasing - not a suspect
273 bool increase_kstack3 = true;
274 for (int i = 0; i < kDefaultLeakThreshold; ++i) {
275 EXPECT_TRUE(table.leak_analyzer().suspected_leaks().empty());
276
277 for (int j = 0; j < 4; ++j)
278 table.Add(stack0_);
279
280 for (int j = 0; j < 3; ++j)
281 table.Add(stack1_);
282
283 table.Add(stack2_);
284
285 // Alternate between adding and removing.
286 if (increase_kstack3)
287 table.Add(stack3_);
288 else
289 table.Remove(stack3_);
290 increase_kstack3 = !increase_kstack3;
291
292 table.TestForLeaks();
293 }
294
295 // Check that the correct leak values have been detected.
296 const auto& leaks = table.leak_analyzer().suspected_leaks();
297 ASSERT_EQ(2U, leaks.size());
298 // Suspected leaks are reported in increasing leak value -- in this case, the
299 // CallStack object's address.
300 EXPECT_EQ(stack0_, leaks[0].call_stack());
301 EXPECT_EQ(stack1_, leaks[1].call_stack());
302 }
303
304 } // namespace leak_detector
305 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698