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

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

Powered by Google App Engine
This is Rietveld 408576698