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

Side by Side Diff: components/metrics/leak_detector/leak_analyzer_unittest.cc

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