OLD | NEW |
| (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 | |
OLD | NEW |