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