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

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

Powered by Google App Engine
This is Rietveld 408576698