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

Side by Side Diff: components/metrics/leak_detector/leak_analyzer_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/leak_analyzer.h"
6
7 #include "base/macros.h"
8 #include "components/metrics/leak_detector/custom_allocator.h"
9 #include "components/metrics/leak_detector/ranked_list.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace leak_detector {
13
14 namespace {
15
16 // Default ranking size and threshold used for leak analysis.
17 const int kDefaultRankedListSize = 10;
18 const int kDefaultLeakThreshold = 5;
19
20 // Makes it easier to instantiate LeakDetectorValueTypes. Instantiates with an
21 // integer value that indicates an allocation size. Storing the size allows us
22 // to track the storage of the LeakDetectorValueType object within LeakAnalyzer.
23 //
24 // There is no need to test this with call stacks in addition to sizes because
25 // call stacks will be contained in a LeakDetectorValueType object as well.
26 LeakDetectorValueType Size(uint32_t value) {
27 return LeakDetectorValueType(value);
28 }
29
30 } // namespace
31
32 class LeakAnalyzerTest : public ::testing::Test {
33 public:
34 LeakAnalyzerTest() {}
35
36 void SetUp() override {
37 CustomAllocator::Initialize();
38 }
39 void TearDown() override {
40 EXPECT_TRUE(CustomAllocator::Shutdown());
41 }
42
43 private:
44 DISALLOW_COPY_AND_ASSIGN(LeakAnalyzerTest);
45 };
46
47 TEST_F(LeakAnalyzerTest, Empty) {
48 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
49 EXPECT_TRUE(analyzer.suspected_leaks().empty());
50 }
51
52 TEST_F(LeakAnalyzerTest, SingleSize) {
53 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
54
55 for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
56 RankedList list(kDefaultRankedListSize);
57 list.Add(Size(24), 10);
58 analyzer.AddSample(std::move(list));
59
60 // No leaks should have been detected.
61 EXPECT_TRUE(analyzer.suspected_leaks().empty());
62 }
63 }
64
65 TEST_F(LeakAnalyzerTest, VariousSizesWithoutIncrease) {
66 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
67
68 for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
69 RankedList list(kDefaultRankedListSize);
70 list.Add(Size(24), 30);
71 list.Add(Size(32), 10);
72 list.Add(Size(56), 90);
73 list.Add(Size(64), 40);
74 analyzer.AddSample(std::move(list));
75
76 // No leaks should have been detected.
77 EXPECT_TRUE(analyzer.suspected_leaks().empty());
78 }
79 }
80
81 TEST_F(LeakAnalyzerTest, VariousSizesWithEqualIncrease) {
82 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
83
84 for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
85 RankedList list(kDefaultRankedListSize);
86 list.Add(Size(24), 30 + i * 10);
87 list.Add(Size(32), 10 + i * 10);
88 list.Add(Size(56), 90 + i * 10);
89 list.Add(Size(64), 40 + i * 10);
90 analyzer.AddSample(std::move(list));
91
92 // No leaks should have been detected.
93 EXPECT_TRUE(analyzer.suspected_leaks().empty());
94 }
95 }
96
97 TEST_F(LeakAnalyzerTest, NotEnoughRunsToTriggerLeak) {
98 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
99
100 // Run this one iteration short of the number of cycles needed to trigger a
101 // leak. Note that because LeakAnalyzer requires |kDefaultLeakThreshold|
102 // suspicions based on deltas between AddSample() calls, the below loop needs
103 // to run |kDefaultLeakThreshold + 1| times to trigger a leak.
104 for (int i = 0; i <= kDefaultLeakThreshold - 1; ++i) {
105 RankedList list(kDefaultRankedListSize);
106 list.Add(Size(24), 30 + i * 10); // This one has a potential leak.
107 list.Add(Size(32), 10 + i * 2);
108 list.Add(Size(56), 90 + i);
109 list.Add(Size(64), 40 + i / 2);
110 analyzer.AddSample(std::move(list));
111
112 // No leaks should have been detected.
113 EXPECT_TRUE(analyzer.suspected_leaks().empty());
114 }
115 }
116
117 TEST_F(LeakAnalyzerTest, LeakSingleSize) {
118 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
119
120 // Run this past the number of iterations required to trigger a leak.
121 for (int i = 0; i < kDefaultLeakThreshold + 10; ++i) {
122 RankedList list(kDefaultRankedListSize);
123 list.Add(Size(32), 10);
124 list.Add(Size(56), 90);
125 list.Add(Size(24), 30 + i * 10); // This one has a potential leak.
126 list.Add(Size(64), 40);
127 analyzer.AddSample(std::move(list));
128
129 // No leaks should have been detected initially...
130 if (i < kDefaultLeakThreshold) {
131 EXPECT_TRUE(analyzer.suspected_leaks().empty());
132 } else {
133 // ... but there should be reported leaks once the threshold is reached.
134 const auto& leaks = analyzer.suspected_leaks();
135 ASSERT_EQ(1U, leaks.size());
136 EXPECT_EQ(24U, leaks[0].size());
137 }
138 }
139 }
140
141 TEST_F(LeakAnalyzerTest, LeakSingleSizeOthersAlsoIncreasing) {
142 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
143
144 for (int i = 0; i < kDefaultLeakThreshold + 10; ++i) {
145 RankedList list(kDefaultRankedListSize);
146 list.Add(Size(24), 30 + i * 10); // This one has a potential leak.
147 list.Add(Size(32), 10 + i * 2);
148 list.Add(Size(56), 90 + i);
149 list.Add(Size(64), 40 + i / 2);
150 analyzer.AddSample(std::move(list));
151
152 // No leaks should have been detected initially...
153 if (i < kDefaultLeakThreshold) {
154 EXPECT_TRUE(analyzer.suspected_leaks().empty());
155 } else {
156 // ... but there should be reported leaks once the threshold is reached.
157 const auto& leaks = analyzer.suspected_leaks();
158 ASSERT_EQ(1U, leaks.size());
159 EXPECT_EQ(24U, leaks[0].size());
160 }
161 }
162 }
163
164 TEST_F(LeakAnalyzerTest, LeakMultipleSizes) {
165 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
166
167 for (int i = 0; i < kDefaultLeakThreshold + 10; ++i) {
168 RankedList list(kDefaultRankedListSize);
169 list.Add(Size(24), 30 + i * 5);
170 list.Add(Size(32), 10 + i * 40);
171 list.Add(Size(56), 90 + i * 30);
172 list.Add(Size(64), 40 + i * 20);
173 list.Add(Size(80), 20 + i * 3);
174 analyzer.AddSample(std::move(list));
175
176 // No leaks should have been detected initially...
177 if (i < kDefaultLeakThreshold) {
178 EXPECT_TRUE(analyzer.suspected_leaks().empty());
179 } else {
180 // ... but there should be reported leaks once the threshold is reached.
181 const auto& leaks = analyzer.suspected_leaks();
182 ASSERT_EQ(3U, leaks.size());
183 // These should be in order of increasing allocation size.
184 EXPECT_EQ(32U, leaks[0].size());
185 EXPECT_EQ(56U, leaks[1].size());
186 EXPECT_EQ(64U, leaks[2].size());
187 }
188 }
189 }
190
191 TEST_F(LeakAnalyzerTest, LeakMultipleSizesValueOrder) {
192 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
193
194 for (int i = 0; i <= kDefaultLeakThreshold; ++i) {
195 RankedList list(kDefaultRankedListSize);
196 // These are similar to LeakMultipleSizes, but the relative order of
197 // allocation increases is different from the relative order of sizes.
198 list.Add(Size(24), 30 + i * 5);
199 list.Add(Size(32), 10 + i * 20);
200 list.Add(Size(56), 90 + i * 40);
201 list.Add(Size(64), 40 + i * 30);
202 list.Add(Size(80), 20 + i * 3);
203 analyzer.AddSample(std::move(list));
204 }
205
206 const auto& leaks = analyzer.suspected_leaks();
207 ASSERT_EQ(3U, leaks.size());
208 // These should be in order of increasing allocation size, NOT in order of
209 // allocation count or deltas.
210 EXPECT_EQ(32U, leaks[0].size());
211 EXPECT_EQ(56U, leaks[1].size());
212 EXPECT_EQ(64U, leaks[2].size());
213 }
214
215 TEST_F(LeakAnalyzerTest, EqualIncreasesNoLeak) {
216 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
217
218 for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
219 RankedList list(kDefaultRankedListSize);
220 list.Add(Size(24), 30 + i * 10);
221 list.Add(Size(32), 10 + i * 10);
222 list.Add(Size(56), 90 + i * 10);
223 list.Add(Size(64), 40 + i * 10);
224 list.Add(Size(80), 20 + i * 10);
225 analyzer.AddSample(std::move(list));
226
227 EXPECT_TRUE(analyzer.suspected_leaks().empty());
228 }
229 }
230
231 TEST_F(LeakAnalyzerTest, NotBigEnoughDeltaGap) {
232 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
233
234 for (int i = 0; i < kDefaultLeakThreshold + 20; ++i) {
235 RankedList list(kDefaultRankedListSize);
236 // These all have different increments but there is no clear group of
237 // increases that are larger than the rest.
238 list.Add(Size(24), 30 + i * 80);
239 list.Add(Size(32), 10 + i * 45);
240 list.Add(Size(56), 90 + i * 25);
241 list.Add(Size(64), 40 + i * 15);
242 list.Add(Size(80), 20 + i * 10);
243 analyzer.AddSample(std::move(list));
244
245 EXPECT_TRUE(analyzer.suspected_leaks().empty());
246 }
247 }
248
249 TEST_F(LeakAnalyzerTest, RepeatedRisesUntilLeakFound) {
250 LeakAnalyzer analyzer(kDefaultRankedListSize, kDefaultLeakThreshold);
251
252 // Remember, there is an extra iteration beyond |kDefaultLeakThreshold| needed
253 // to actually trigger the leak detection.
254 for (int i = 0; i <= kDefaultLeakThreshold - 2; ++i) {
255 RankedList list(kDefaultRankedListSize);
256 list.Add(Size(24), 30 + i * 10);
257 list.Add(Size(32), 10);
258 list.Add(Size(56), 90);
259 list.Add(Size(64), 40);
260 list.Add(Size(80), 20);
261 analyzer.AddSample(std::move(list));
262
263 EXPECT_TRUE(analyzer.suspected_leaks().empty());
264 }
265
266 // Drop back down to 30.
267 for (int i = 0; i <= kDefaultLeakThreshold - 1; ++i) {
268 RankedList list(kDefaultRankedListSize);
269 list.Add(Size(24), 30 + i * 10);
270 list.Add(Size(32), 10);
271 list.Add(Size(56), 90);
272 list.Add(Size(64), 40);
273 list.Add(Size(80), 20);
274 analyzer.AddSample(std::move(list));
275
276 EXPECT_TRUE(analyzer.suspected_leaks().empty());
277 }
278
279 // Drop back down to 30.
280 for (int i = 0; i <= kDefaultLeakThreshold; ++i) {
281 // Initially there should not be any leak detected.
282 EXPECT_TRUE(analyzer.suspected_leaks().empty());
283
284 RankedList list(kDefaultRankedListSize);
285 list.Add(Size(24), 30 + i * 10);
286 list.Add(Size(32), 10);
287 list.Add(Size(56), 90);
288 list.Add(Size(64), 40);
289 list.Add(Size(80), 20);
290 analyzer.AddSample(std::move(list));
291 }
292 const auto& leaks = analyzer.suspected_leaks();
293 ASSERT_EQ(1U, leaks.size());
294 EXPECT_EQ(24U, leaks[0].size());
295 }
296
297 TEST_F(LeakAnalyzerTest, LeakWithMultipleGroupsOfDeltas) {
298 const int kRankedListSize = 20;
299 LeakAnalyzer analyzer(kRankedListSize, kDefaultLeakThreshold);
300
301 for (int i = 0; i <= kDefaultLeakThreshold; ++i) {
302 RankedList list(kRankedListSize);
303 list.Add(Size(24), 30 + i * 10); // A group of smaller deltas.
304 list.Add(Size(32), 10 + i * 3);
305 list.Add(Size(80), 20 + i * 5);
306 list.Add(Size(40), 30 + i * 7);
307 list.Add(Size(56), 90);
308 list.Add(Size(64), 40);
309 list.Add(Size(128), 100);
310 list.Add(Size(44), 100 + i * 10); // A group of medium deltas.
311 list.Add(Size(16), 60 + i * 50);
312 list.Add(Size(4), 20 + i * 40);
313 list.Add(Size(8), 100 + i * 60);
314 list.Add(Size(48), 100);
315 list.Add(Size(72), 60 + i * 240); // A group of largest deltas.
316 list.Add(Size(28), 100);
317 list.Add(Size(100), 100 + i * 200);
318 list.Add(Size(104), 60 + i * 128);
319 analyzer.AddSample(std::move(list));
320 }
321 // Only the group of largest deltas should be caught.
322 const auto& leaks = analyzer.suspected_leaks();
323 ASSERT_EQ(3U, leaks.size());
324 // These should be in order of increasing allocation size.
325 EXPECT_EQ(72U, leaks[0].size());
326 EXPECT_EQ(100U, leaks[1].size());
327 EXPECT_EQ(104U, leaks[2].size());
328 }
329
330 TEST_F(LeakAnalyzerTest, LeakMultipleSizesWithLargeThreshold) {
331 const int kLeakThreshold = 50;
332 LeakAnalyzer analyzer(kDefaultRankedListSize, kLeakThreshold);
333
334 for (int i = 0; i <= kLeakThreshold + 10; ++i) {
335 RankedList list(kDefaultRankedListSize);
336 // * - Cluster of larger deltas
337 list.Add(Size(24), 30 + i * 5);
338 list.Add(Size(32), 10 + i * 40); // *
339 list.Add(Size(56), 90 + i * 30); // *
340 list.Add(Size(40), 30 + i * 7);
341 list.Add(Size(64), 40 + i * 25); // *
342 list.Add(Size(80), 20 + i * 3);
343 list.Add(Size(128), 100);
344 list.Add(Size(44), 100 + i * 10);
345 list.Add(Size(16), 60 + i * 50); // *
346 analyzer.AddSample(std::move(list));
347
348 // No leaks should have been detected initially...
349 if (i < kLeakThreshold) {
350 EXPECT_TRUE(analyzer.suspected_leaks().empty());
351 } else {
352 // ... but there should be reported leaks once the threshold is reached.
353 const auto& leaks = analyzer.suspected_leaks();
354 ASSERT_EQ(4U, leaks.size());
355 // These should be in order of increasing allocation size.
356 EXPECT_EQ(16U, leaks[0].size());
357 EXPECT_EQ(32U, leaks[1].size());
358 EXPECT_EQ(56U, leaks[2].size());
359 EXPECT_EQ(64U, leaks[3].size());
360 }
361 }
362 }
363
364 } // namespace leak_detector
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698