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