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

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

Powered by Google App Engine
This is Rietveld 408576698