OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/scoped_thread_heap_usage.h" | 5 #include "base/debug/thread_heap_usage_tracker.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/allocator/allocator_shim.h" | 9 #include "base/allocator/allocator_shim.h" |
10 #include "base/allocator/features.h" | 10 #include "base/allocator/features.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
12 | 12 |
13 namespace base { | 13 namespace base { |
14 namespace debug { | 14 namespace debug { |
15 | 15 |
16 namespace { | 16 namespace { |
17 | 17 |
18 class TestingScopedThreadHeapUsage : public ScopedThreadHeapUsage { | 18 class TestingThreadHeapUsageTracker : public ThreadHeapUsageTracker { |
19 public: | 19 public: |
20 using ScopedThreadHeapUsage::DisableHeapTrackingForTesting; | 20 using ThreadHeapUsageTracker::DisableHeapTrackingForTesting; |
21 using ScopedThreadHeapUsage::GetDispatchForTesting; | 21 using ThreadHeapUsageTracker::EnsureTLSInitializedForTesting; |
| 22 using ThreadHeapUsageTracker::GetDispatchForTesting; |
22 }; | 23 }; |
23 | 24 |
24 // A fixture class that allows testing the AllocatorDispatch associated with | 25 // A fixture class that allows testing the AllocatorDispatch associated with |
25 // the ScopedThreadHeapUsage class in isolation against a mocked underlying | 26 // the ThreadHeapUsageTracker class in isolation against a mocked |
| 27 // underlying |
26 // heap implementation. | 28 // heap implementation. |
27 class ScopedThreadHeapUsageTest : public testing::Test { | 29 class ThreadHeapUsageTrackerTest : public testing::Test { |
28 public: | 30 public: |
29 using AllocatorDispatch = base::allocator::AllocatorDispatch; | 31 using AllocatorDispatch = base::allocator::AllocatorDispatch; |
30 | 32 |
31 static const size_t kAllocationPadding; | 33 static const size_t kAllocationPadding; |
32 enum SizeFunctionKind { | 34 enum SizeFunctionKind { |
33 EXACT_SIZE_FUNCTION, | 35 EXACT_SIZE_FUNCTION, |
34 PADDING_SIZE_FUNCTION, | 36 PADDING_SIZE_FUNCTION, |
35 ZERO_SIZE_FUNCTION, | 37 ZERO_SIZE_FUNCTION, |
36 }; | 38 }; |
37 | 39 |
38 ScopedThreadHeapUsageTest() : size_function_kind_(EXACT_SIZE_FUNCTION) { | 40 ThreadHeapUsageTrackerTest() : size_function_kind_(EXACT_SIZE_FUNCTION) { |
39 EXPECT_EQ(nullptr, g_self); | 41 EXPECT_EQ(nullptr, g_self); |
40 g_self = this; | 42 g_self = this; |
41 } | 43 } |
42 | 44 |
43 ~ScopedThreadHeapUsageTest() override { | 45 ~ThreadHeapUsageTrackerTest() override { |
44 EXPECT_EQ(this, g_self); | 46 EXPECT_EQ(this, g_self); |
45 g_self = nullptr; | 47 g_self = nullptr; |
46 } | 48 } |
47 | 49 |
48 void set_size_function_kind(SizeFunctionKind kind) { | 50 void set_size_function_kind(SizeFunctionKind kind) { |
49 size_function_kind_ = kind; | 51 size_function_kind_ = kind; |
50 } | 52 } |
51 | 53 |
52 void SetUp() override { | 54 void SetUp() override { |
53 ScopedThreadHeapUsage::Initialize(); | 55 TestingThreadHeapUsageTracker::EnsureTLSInitializedForTesting(); |
54 | 56 |
55 dispatch_under_test_ = | 57 dispatch_under_test_ = |
56 TestingScopedThreadHeapUsage::GetDispatchForTesting(); | 58 TestingThreadHeapUsageTracker::GetDispatchForTesting(); |
57 ASSERT_EQ(nullptr, dispatch_under_test_->next); | 59 ASSERT_EQ(nullptr, dispatch_under_test_->next); |
58 | 60 |
59 dispatch_under_test_->next = &g_mock_dispatch; | 61 dispatch_under_test_->next = &g_mock_dispatch; |
60 } | 62 } |
61 | 63 |
62 void TearDown() override { | 64 void TearDown() override { |
63 ASSERT_EQ(&g_mock_dispatch, dispatch_under_test_->next); | 65 ASSERT_EQ(&g_mock_dispatch, dispatch_under_test_->next); |
64 | 66 |
65 dispatch_under_test_->next = nullptr; | 67 dispatch_under_test_->next = nullptr; |
66 } | 68 } |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 return g_self->GetSizeEstimate(address); | 181 return g_self->GetSizeEstimate(address); |
180 } | 182 } |
181 | 183 |
182 using AllocationSizeMap = std::map<void*, size_t>; | 184 using AllocationSizeMap = std::map<void*, size_t>; |
183 | 185 |
184 SizeFunctionKind size_function_kind_; | 186 SizeFunctionKind size_function_kind_; |
185 AllocationSizeMap allocation_size_map_; | 187 AllocationSizeMap allocation_size_map_; |
186 AllocatorDispatch* dispatch_under_test_; | 188 AllocatorDispatch* dispatch_under_test_; |
187 | 189 |
188 static base::allocator::AllocatorDispatch g_mock_dispatch; | 190 static base::allocator::AllocatorDispatch g_mock_dispatch; |
189 static ScopedThreadHeapUsageTest* g_self; | 191 static ThreadHeapUsageTrackerTest* g_self; |
190 }; | 192 }; |
191 | 193 |
192 const size_t ScopedThreadHeapUsageTest::kAllocationPadding = 23; | 194 const size_t ThreadHeapUsageTrackerTest::kAllocationPadding = 23; |
193 | 195 |
194 ScopedThreadHeapUsageTest* ScopedThreadHeapUsageTest::g_self = nullptr; | 196 ThreadHeapUsageTrackerTest* ThreadHeapUsageTrackerTest::g_self = nullptr; |
195 | 197 |
196 base::allocator::AllocatorDispatch ScopedThreadHeapUsageTest::g_mock_dispatch = | 198 base::allocator::AllocatorDispatch ThreadHeapUsageTrackerTest::g_mock_dispatch = |
197 { | 199 { |
198 &ScopedThreadHeapUsageTest::OnAllocFn, // alloc_function | 200 &ThreadHeapUsageTrackerTest::OnAllocFn, // alloc_function |
199 &ScopedThreadHeapUsageTest:: | 201 &ThreadHeapUsageTrackerTest:: |
200 OnAllocZeroInitializedFn, // alloc_zero_initialized_function | 202 OnAllocZeroInitializedFn, // alloc_zero_initialized_function |
201 &ScopedThreadHeapUsageTest::OnAllocAlignedFn, // alloc_aligned_function | 203 &ThreadHeapUsageTrackerTest:: |
202 &ScopedThreadHeapUsageTest::OnReallocFn, // realloc_function | 204 OnAllocAlignedFn, // alloc_aligned_function |
203 &ScopedThreadHeapUsageTest::OnFreeFn, // free_function | 205 &ThreadHeapUsageTrackerTest::OnReallocFn, // realloc_function |
204 &ScopedThreadHeapUsageTest:: | 206 &ThreadHeapUsageTrackerTest::OnFreeFn, // free_function |
| 207 &ThreadHeapUsageTrackerTest:: |
205 OnGetSizeEstimateFn, // get_size_estimate_function | 208 OnGetSizeEstimateFn, // get_size_estimate_function |
206 nullptr, // next | 209 nullptr, // next |
207 }; | 210 }; |
208 | 211 |
209 } // namespace | 212 } // namespace |
210 | 213 |
211 TEST_F(ScopedThreadHeapUsageTest, SimpleUsageWithExactSizeFunction) { | 214 TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithExactSizeFunction) { |
212 set_size_function_kind(EXACT_SIZE_FUNCTION); | 215 set_size_function_kind(EXACT_SIZE_FUNCTION); |
213 | 216 |
214 ScopedThreadHeapUsage scoped_usage; | 217 ThreadHeapUsageTracker usage_tracker; |
| 218 usage_tracker.Start(); |
215 | 219 |
216 ScopedThreadHeapUsage::ThreadAllocatorUsage u1 = | 220 ThreadHeapUsage u1 = ThreadHeapUsageTracker::CurrentUsage(); |
217 ScopedThreadHeapUsage::CurrentUsage(); | |
218 | 221 |
219 EXPECT_EQ(0U, u1.alloc_ops); | 222 EXPECT_EQ(0U, u1.alloc_ops); |
220 EXPECT_EQ(0U, u1.alloc_bytes); | 223 EXPECT_EQ(0U, u1.alloc_bytes); |
221 EXPECT_EQ(0U, u1.alloc_overhead_bytes); | 224 EXPECT_EQ(0U, u1.alloc_overhead_bytes); |
222 EXPECT_EQ(0U, u1.free_ops); | 225 EXPECT_EQ(0U, u1.free_ops); |
223 EXPECT_EQ(0U, u1.free_bytes); | 226 EXPECT_EQ(0U, u1.free_bytes); |
224 EXPECT_EQ(0U, u1.max_allocated_bytes); | 227 EXPECT_EQ(0U, u1.max_allocated_bytes); |
225 | 228 |
226 const size_t kAllocSize = 1029U; | 229 const size_t kAllocSize = 1029U; |
227 void* ptr = MockMalloc(kAllocSize); | 230 void* ptr = MockMalloc(kAllocSize); |
228 MockFree(ptr); | 231 MockFree(ptr); |
229 | 232 |
230 ScopedThreadHeapUsage::ThreadAllocatorUsage u2 = | 233 usage_tracker.Stop(false); |
231 ScopedThreadHeapUsage::CurrentUsage(); | 234 ThreadHeapUsage u2 = usage_tracker.usage(); |
232 | 235 |
233 EXPECT_EQ(1U, u2.alloc_ops); | 236 EXPECT_EQ(1U, u2.alloc_ops); |
234 EXPECT_EQ(kAllocSize, u2.alloc_bytes); | 237 EXPECT_EQ(kAllocSize, u2.alloc_bytes); |
235 EXPECT_EQ(0U, u2.alloc_overhead_bytes); | 238 EXPECT_EQ(0U, u2.alloc_overhead_bytes); |
236 EXPECT_EQ(1U, u2.free_ops); | 239 EXPECT_EQ(1U, u2.free_ops); |
237 EXPECT_EQ(kAllocSize, u2.free_bytes); | 240 EXPECT_EQ(kAllocSize, u2.free_bytes); |
238 EXPECT_EQ(kAllocSize, u2.max_allocated_bytes); | 241 EXPECT_EQ(kAllocSize, u2.max_allocated_bytes); |
239 } | 242 } |
240 | 243 |
241 TEST_F(ScopedThreadHeapUsageTest, SimpleUsageWithPaddingSizeFunction) { | 244 TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithPaddingSizeFunction) { |
242 set_size_function_kind(PADDING_SIZE_FUNCTION); | 245 set_size_function_kind(PADDING_SIZE_FUNCTION); |
243 | 246 |
244 ScopedThreadHeapUsage scoped_usage; | 247 ThreadHeapUsageTracker usage_tracker; |
| 248 usage_tracker.Start(); |
245 | 249 |
246 ScopedThreadHeapUsage::ThreadAllocatorUsage u1 = | 250 ThreadHeapUsage u1 = ThreadHeapUsageTracker::CurrentUsage(); |
247 ScopedThreadHeapUsage::CurrentUsage(); | |
248 | 251 |
249 EXPECT_EQ(0U, u1.alloc_ops); | 252 EXPECT_EQ(0U, u1.alloc_ops); |
250 EXPECT_EQ(0U, u1.alloc_bytes); | 253 EXPECT_EQ(0U, u1.alloc_bytes); |
251 EXPECT_EQ(0U, u1.alloc_overhead_bytes); | 254 EXPECT_EQ(0U, u1.alloc_overhead_bytes); |
252 EXPECT_EQ(0U, u1.free_ops); | 255 EXPECT_EQ(0U, u1.free_ops); |
253 EXPECT_EQ(0U, u1.free_bytes); | 256 EXPECT_EQ(0U, u1.free_bytes); |
254 EXPECT_EQ(0U, u1.max_allocated_bytes); | 257 EXPECT_EQ(0U, u1.max_allocated_bytes); |
255 | 258 |
256 const size_t kAllocSize = 1029U; | 259 const size_t kAllocSize = 1029U; |
257 void* ptr = MockMalloc(kAllocSize); | 260 void* ptr = MockMalloc(kAllocSize); |
258 MockFree(ptr); | 261 MockFree(ptr); |
259 | 262 |
260 ScopedThreadHeapUsage::ThreadAllocatorUsage u2 = | 263 usage_tracker.Stop(false); |
261 ScopedThreadHeapUsage::CurrentUsage(); | 264 ThreadHeapUsage u2 = usage_tracker.usage(); |
262 | 265 |
263 EXPECT_EQ(1U, u2.alloc_ops); | 266 EXPECT_EQ(1U, u2.alloc_ops); |
264 EXPECT_EQ(kAllocSize + kAllocationPadding, u2.alloc_bytes); | 267 EXPECT_EQ(kAllocSize + kAllocationPadding, u2.alloc_bytes); |
265 EXPECT_EQ(kAllocationPadding, u2.alloc_overhead_bytes); | 268 EXPECT_EQ(kAllocationPadding, u2.alloc_overhead_bytes); |
266 EXPECT_EQ(1U, u2.free_ops); | 269 EXPECT_EQ(1U, u2.free_ops); |
267 EXPECT_EQ(kAllocSize + kAllocationPadding, u2.free_bytes); | 270 EXPECT_EQ(kAllocSize + kAllocationPadding, u2.free_bytes); |
268 EXPECT_EQ(kAllocSize + kAllocationPadding, u2.max_allocated_bytes); | 271 EXPECT_EQ(kAllocSize + kAllocationPadding, u2.max_allocated_bytes); |
269 } | 272 } |
270 | 273 |
271 TEST_F(ScopedThreadHeapUsageTest, SimpleUsageWithZeroSizeFunction) { | 274 TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithZeroSizeFunction) { |
272 set_size_function_kind(ZERO_SIZE_FUNCTION); | 275 set_size_function_kind(ZERO_SIZE_FUNCTION); |
273 | 276 |
274 ScopedThreadHeapUsage scoped_usage; | 277 ThreadHeapUsageTracker usage_tracker; |
| 278 usage_tracker.Start(); |
275 | 279 |
276 ScopedThreadHeapUsage::ThreadAllocatorUsage u1 = | 280 ThreadHeapUsage u1 = ThreadHeapUsageTracker::CurrentUsage(); |
277 ScopedThreadHeapUsage::CurrentUsage(); | |
278 EXPECT_EQ(0U, u1.alloc_ops); | 281 EXPECT_EQ(0U, u1.alloc_ops); |
279 EXPECT_EQ(0U, u1.alloc_bytes); | 282 EXPECT_EQ(0U, u1.alloc_bytes); |
280 EXPECT_EQ(0U, u1.alloc_overhead_bytes); | 283 EXPECT_EQ(0U, u1.alloc_overhead_bytes); |
281 EXPECT_EQ(0U, u1.free_ops); | 284 EXPECT_EQ(0U, u1.free_ops); |
282 EXPECT_EQ(0U, u1.free_bytes); | 285 EXPECT_EQ(0U, u1.free_bytes); |
283 EXPECT_EQ(0U, u1.max_allocated_bytes); | 286 EXPECT_EQ(0U, u1.max_allocated_bytes); |
284 | 287 |
285 const size_t kAllocSize = 1029U; | 288 const size_t kAllocSize = 1029U; |
286 void* ptr = MockMalloc(kAllocSize); | 289 void* ptr = MockMalloc(kAllocSize); |
287 MockFree(ptr); | 290 MockFree(ptr); |
288 | 291 |
289 ScopedThreadHeapUsage::ThreadAllocatorUsage u2 = | 292 usage_tracker.Stop(false); |
290 ScopedThreadHeapUsage::CurrentUsage(); | 293 ThreadHeapUsage u2 = usage_tracker.usage(); |
291 | 294 |
292 // With a get-size function that returns zero, there's no way to get the size | 295 // With a get-size function that returns zero, there's no way to get the size |
293 // of an allocation that's being freed, hence the shim can't tally freed bytes | 296 // of an allocation that's being freed, hence the shim can't tally freed bytes |
294 // nor the high-watermark allocated bytes. | 297 // nor the high-watermark allocated bytes. |
295 EXPECT_EQ(1U, u2.alloc_ops); | 298 EXPECT_EQ(1U, u2.alloc_ops); |
296 EXPECT_EQ(kAllocSize, u2.alloc_bytes); | 299 EXPECT_EQ(kAllocSize, u2.alloc_bytes); |
297 EXPECT_EQ(0U, u2.alloc_overhead_bytes); | 300 EXPECT_EQ(0U, u2.alloc_overhead_bytes); |
298 EXPECT_EQ(1U, u2.free_ops); | 301 EXPECT_EQ(1U, u2.free_ops); |
299 EXPECT_EQ(0U, u2.free_bytes); | 302 EXPECT_EQ(0U, u2.free_bytes); |
300 EXPECT_EQ(0U, u2.max_allocated_bytes); | 303 EXPECT_EQ(0U, u2.max_allocated_bytes); |
301 } | 304 } |
302 | 305 |
303 TEST_F(ScopedThreadHeapUsageTest, ReallocCorrectlyTallied) { | 306 TEST_F(ThreadHeapUsageTrackerTest, ReallocCorrectlyTallied) { |
304 const size_t kAllocSize = 237U; | 307 const size_t kAllocSize = 237U; |
305 | 308 |
306 { | 309 { |
307 ScopedThreadHeapUsage scoped_usage; | 310 ThreadHeapUsageTracker usage_tracker; |
| 311 usage_tracker.Start(); |
308 | 312 |
309 // Reallocating nullptr should count as a single alloc. | 313 // Reallocating nullptr should count as a single alloc. |
310 void* ptr = MockRealloc(nullptr, kAllocSize); | 314 void* ptr = MockRealloc(nullptr, kAllocSize); |
311 ScopedThreadHeapUsage::ThreadAllocatorUsage usage = | 315 ThreadHeapUsage usage = ThreadHeapUsageTracker::CurrentUsage(); |
312 ScopedThreadHeapUsage::CurrentUsage(); | |
313 EXPECT_EQ(1U, usage.alloc_ops); | 316 EXPECT_EQ(1U, usage.alloc_ops); |
314 EXPECT_EQ(kAllocSize, usage.alloc_bytes); | 317 EXPECT_EQ(kAllocSize, usage.alloc_bytes); |
315 EXPECT_EQ(0U, usage.alloc_overhead_bytes); | 318 EXPECT_EQ(0U, usage.alloc_overhead_bytes); |
316 EXPECT_EQ(0U, usage.free_ops); | 319 EXPECT_EQ(0U, usage.free_ops); |
317 EXPECT_EQ(0U, usage.free_bytes); | 320 EXPECT_EQ(0U, usage.free_bytes); |
318 EXPECT_EQ(kAllocSize, usage.max_allocated_bytes); | 321 EXPECT_EQ(kAllocSize, usage.max_allocated_bytes); |
319 | 322 |
320 // Reallocating a valid pointer to a zero size should count as a single | 323 // Reallocating a valid pointer to a zero size should count as a single |
321 // free. | 324 // free. |
322 ptr = MockRealloc(ptr, 0U); | 325 ptr = MockRealloc(ptr, 0U); |
323 | 326 |
324 usage = ScopedThreadHeapUsage::CurrentUsage(); | 327 usage_tracker.Stop(false); |
325 EXPECT_EQ(1U, usage.alloc_ops); | 328 EXPECT_EQ(1U, usage_tracker.usage().alloc_ops); |
326 EXPECT_EQ(kAllocSize, usage.alloc_bytes); | 329 EXPECT_EQ(kAllocSize, usage_tracker.usage().alloc_bytes); |
327 EXPECT_EQ(0U, usage.alloc_overhead_bytes); | 330 EXPECT_EQ(0U, usage_tracker.usage().alloc_overhead_bytes); |
328 EXPECT_EQ(1U, usage.free_ops); | 331 EXPECT_EQ(1U, usage_tracker.usage().free_ops); |
329 EXPECT_EQ(kAllocSize, usage.free_bytes); | 332 EXPECT_EQ(kAllocSize, usage_tracker.usage().free_bytes); |
330 EXPECT_EQ(kAllocSize, usage.max_allocated_bytes); | 333 EXPECT_EQ(kAllocSize, usage_tracker.usage().max_allocated_bytes); |
331 | 334 |
332 // Realloc to zero size may or may not return a nullptr - make sure to | 335 // Realloc to zero size may or may not return a nullptr - make sure to |
333 // free the zero-size alloc in the latter case. | 336 // free the zero-size alloc in the latter case. |
334 if (ptr != nullptr) | 337 if (ptr != nullptr) |
335 MockFree(ptr); | 338 MockFree(ptr); |
336 } | 339 } |
337 | 340 |
338 { | 341 { |
339 ScopedThreadHeapUsage scoped_usage; | 342 ThreadHeapUsageTracker usage_tracker; |
| 343 usage_tracker.Start(); |
340 | 344 |
341 void* ptr = MockMalloc(kAllocSize); | 345 void* ptr = MockMalloc(kAllocSize); |
342 ScopedThreadHeapUsage::ThreadAllocatorUsage usage = | 346 ThreadHeapUsage usage = ThreadHeapUsageTracker::CurrentUsage(); |
343 ScopedThreadHeapUsage::CurrentUsage(); | |
344 EXPECT_EQ(1U, usage.alloc_ops); | 347 EXPECT_EQ(1U, usage.alloc_ops); |
345 | 348 |
346 // Now try reallocating a valid pointer to a larger size, this should count | 349 // Now try reallocating a valid pointer to a larger size, this should count |
347 // as one free and one alloc. | 350 // as one free and one alloc. |
348 const size_t kLargerAllocSize = kAllocSize + 928U; | 351 const size_t kLargerAllocSize = kAllocSize + 928U; |
349 ptr = MockRealloc(ptr, kLargerAllocSize); | 352 ptr = MockRealloc(ptr, kLargerAllocSize); |
350 | 353 |
351 usage = ScopedThreadHeapUsage::CurrentUsage(); | 354 usage_tracker.Stop(false); |
352 EXPECT_EQ(2U, usage.alloc_ops); | 355 EXPECT_EQ(2U, usage_tracker.usage().alloc_ops); |
353 EXPECT_EQ(kAllocSize + kLargerAllocSize, usage.alloc_bytes); | 356 EXPECT_EQ(kAllocSize + kLargerAllocSize, usage_tracker.usage().alloc_bytes); |
354 EXPECT_EQ(0U, usage.alloc_overhead_bytes); | 357 EXPECT_EQ(0U, usage_tracker.usage().alloc_overhead_bytes); |
355 EXPECT_EQ(1U, usage.free_ops); | 358 EXPECT_EQ(1U, usage_tracker.usage().free_ops); |
356 EXPECT_EQ(kAllocSize, usage.free_bytes); | 359 EXPECT_EQ(kAllocSize, usage_tracker.usage().free_bytes); |
357 EXPECT_EQ(kLargerAllocSize, usage.max_allocated_bytes); | 360 EXPECT_EQ(kLargerAllocSize, usage_tracker.usage().max_allocated_bytes); |
358 | 361 |
359 MockFree(ptr); | 362 MockFree(ptr); |
360 } | 363 } |
361 } | 364 } |
362 | 365 |
363 TEST_F(ScopedThreadHeapUsageTest, NestedMaxWorks) { | 366 TEST_F(ThreadHeapUsageTrackerTest, NestedMaxWorks) { |
364 ScopedThreadHeapUsage outer_scoped_usage; | 367 ThreadHeapUsageTracker usage_tracker; |
| 368 usage_tracker.Start(); |
365 | 369 |
366 const size_t kOuterAllocSize = 1029U; | 370 const size_t kOuterAllocSize = 1029U; |
367 void* ptr = MockMalloc(kOuterAllocSize); | 371 void* ptr = MockMalloc(kOuterAllocSize); |
368 MockFree(ptr); | 372 MockFree(ptr); |
369 | 373 |
370 EXPECT_EQ(kOuterAllocSize, | 374 EXPECT_EQ(kOuterAllocSize, |
371 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 375 ThreadHeapUsageTracker::CurrentUsage().max_allocated_bytes); |
372 | 376 |
373 { | 377 { |
374 ScopedThreadHeapUsage inner_scoped_usage; | 378 ThreadHeapUsageTracker inner_usage_tracker; |
| 379 inner_usage_tracker.Start(); |
375 | 380 |
376 const size_t kInnerAllocSize = 673U; | 381 const size_t kInnerAllocSize = 673U; |
377 ptr = MockMalloc(kInnerAllocSize); | 382 ptr = MockMalloc(kInnerAllocSize); |
378 MockFree(ptr); | 383 MockFree(ptr); |
379 | 384 |
380 EXPECT_EQ(kInnerAllocSize, | 385 inner_usage_tracker.Stop(false); |
381 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 386 |
| 387 EXPECT_EQ(kInnerAllocSize, inner_usage_tracker.usage().max_allocated_bytes); |
382 } | 388 } |
383 | 389 |
384 // The greater, outer allocation size should have been restored. | 390 // The greater, outer allocation size should have been restored. |
385 EXPECT_EQ(kOuterAllocSize, | 391 EXPECT_EQ(kOuterAllocSize, |
386 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 392 ThreadHeapUsageTracker::CurrentUsage().max_allocated_bytes); |
387 | 393 |
388 const size_t kLargerInnerAllocSize = kOuterAllocSize + 673U; | 394 const size_t kLargerInnerAllocSize = kOuterAllocSize + 673U; |
389 { | 395 { |
390 ScopedThreadHeapUsage inner_scoped_usage; | 396 ThreadHeapUsageTracker inner_usage_tracker; |
| 397 inner_usage_tracker.Start(); |
391 | 398 |
392 ptr = MockMalloc(kLargerInnerAllocSize); | 399 ptr = MockMalloc(kLargerInnerAllocSize); |
393 MockFree(ptr); | 400 MockFree(ptr); |
394 | 401 |
| 402 inner_usage_tracker.Stop(false); |
395 EXPECT_EQ(kLargerInnerAllocSize, | 403 EXPECT_EQ(kLargerInnerAllocSize, |
396 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 404 inner_usage_tracker.usage().max_allocated_bytes); |
397 } | 405 } |
398 | 406 |
399 // The greater, inner allocation size should have been preserved. | 407 // The greater, inner allocation size should have been preserved. |
400 EXPECT_EQ(kLargerInnerAllocSize, | 408 EXPECT_EQ(kLargerInnerAllocSize, |
401 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 409 ThreadHeapUsageTracker::CurrentUsage().max_allocated_bytes); |
402 | 410 |
403 // Now try the case with an outstanding net alloc size when entering the | 411 // Now try the case with an outstanding net alloc size when entering the |
404 // inner scope. | 412 // inner scope. |
405 void* outer_ptr = MockMalloc(kOuterAllocSize); | 413 void* outer_ptr = MockMalloc(kOuterAllocSize); |
406 EXPECT_EQ(kLargerInnerAllocSize, | 414 EXPECT_EQ(kLargerInnerAllocSize, |
407 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 415 ThreadHeapUsageTracker::CurrentUsage().max_allocated_bytes); |
408 { | 416 { |
409 ScopedThreadHeapUsage inner_scoped_usage; | 417 ThreadHeapUsageTracker inner_usage_tracker; |
| 418 inner_usage_tracker.Start(); |
410 | 419 |
411 ptr = MockMalloc(kLargerInnerAllocSize); | 420 ptr = MockMalloc(kLargerInnerAllocSize); |
412 MockFree(ptr); | 421 MockFree(ptr); |
413 | 422 |
| 423 inner_usage_tracker.Stop(false); |
414 EXPECT_EQ(kLargerInnerAllocSize, | 424 EXPECT_EQ(kLargerInnerAllocSize, |
415 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 425 inner_usage_tracker.usage().max_allocated_bytes); |
416 } | 426 } |
417 | 427 |
418 // While the inner scope saw only the inner net outstanding allocation size, | 428 // While the inner scope saw only the inner net outstanding allocation size, |
419 // the outer scope saw both outstanding at the same time. | 429 // the outer scope saw both outstanding at the same time. |
420 EXPECT_EQ(kOuterAllocSize + kLargerInnerAllocSize, | 430 EXPECT_EQ(kOuterAllocSize + kLargerInnerAllocSize, |
421 ScopedThreadHeapUsage::CurrentUsage().max_allocated_bytes); | 431 ThreadHeapUsageTracker::CurrentUsage().max_allocated_bytes); |
422 | 432 |
423 MockFree(outer_ptr); | 433 MockFree(outer_ptr); |
| 434 |
| 435 // Test a net-negative scope. |
| 436 ptr = MockMalloc(kLargerInnerAllocSize); |
| 437 { |
| 438 ThreadHeapUsageTracker inner_usage_tracker; |
| 439 inner_usage_tracker.Start(); |
| 440 |
| 441 MockFree(ptr); |
| 442 |
| 443 const size_t kInnerAllocSize = 1; |
| 444 ptr = MockMalloc(kInnerAllocSize); |
| 445 |
| 446 inner_usage_tracker.Stop(false); |
| 447 // Since the scope is still net-negative, the max is clamped at zero. |
| 448 EXPECT_EQ(0U, inner_usage_tracker.usage().max_allocated_bytes); |
| 449 } |
| 450 |
| 451 MockFree(ptr); |
424 } | 452 } |
425 | 453 |
426 TEST_F(ScopedThreadHeapUsageTest, AllShimFunctionsAreProvided) { | 454 TEST_F(ThreadHeapUsageTrackerTest, NoStopImpliesInclusive) { |
| 455 ThreadHeapUsageTracker usage_tracker; |
| 456 usage_tracker.Start(); |
| 457 |
| 458 const size_t kOuterAllocSize = 1029U; |
| 459 void* ptr = MockMalloc(kOuterAllocSize); |
| 460 MockFree(ptr); |
| 461 |
| 462 ThreadHeapUsage usage = ThreadHeapUsageTracker::CurrentUsage(); |
| 463 EXPECT_EQ(kOuterAllocSize, usage.max_allocated_bytes); |
| 464 |
| 465 const size_t kInnerLargerAllocSize = kOuterAllocSize + 673U; |
| 466 |
| 467 { |
| 468 ThreadHeapUsageTracker inner_usage_tracker; |
| 469 inner_usage_tracker.Start(); |
| 470 |
| 471 // Make a larger allocation than the outer scope. |
| 472 ptr = MockMalloc(kInnerLargerAllocSize); |
| 473 MockFree(ptr); |
| 474 |
| 475 // inner_usage_tracker goes out of scope without a Stop(). |
| 476 } |
| 477 |
| 478 ThreadHeapUsage current = ThreadHeapUsageTracker::CurrentUsage(); |
| 479 EXPECT_EQ(usage.alloc_ops + 1, current.alloc_ops); |
| 480 EXPECT_EQ(usage.alloc_bytes + kInnerLargerAllocSize, current.alloc_bytes); |
| 481 EXPECT_EQ(usage.free_ops + 1, current.free_ops); |
| 482 EXPECT_EQ(usage.free_bytes + kInnerLargerAllocSize, current.free_bytes); |
| 483 EXPECT_EQ(kInnerLargerAllocSize, current.max_allocated_bytes); |
| 484 } |
| 485 |
| 486 TEST_F(ThreadHeapUsageTrackerTest, ExclusiveScopesWork) { |
| 487 ThreadHeapUsageTracker usage_tracker; |
| 488 usage_tracker.Start(); |
| 489 |
| 490 const size_t kOuterAllocSize = 1029U; |
| 491 void* ptr = MockMalloc(kOuterAllocSize); |
| 492 MockFree(ptr); |
| 493 |
| 494 ThreadHeapUsage usage = ThreadHeapUsageTracker::CurrentUsage(); |
| 495 EXPECT_EQ(kOuterAllocSize, usage.max_allocated_bytes); |
| 496 |
| 497 { |
| 498 ThreadHeapUsageTracker inner_usage_tracker; |
| 499 inner_usage_tracker.Start(); |
| 500 |
| 501 // Make a larger allocation than the outer scope. |
| 502 ptr = MockMalloc(kOuterAllocSize + 673U); |
| 503 MockFree(ptr); |
| 504 |
| 505 // This tracker is exlusive, all activity should be private to this scope. |
| 506 inner_usage_tracker.Stop(true); |
| 507 } |
| 508 |
| 509 ThreadHeapUsage current = ThreadHeapUsageTracker::CurrentUsage(); |
| 510 EXPECT_EQ(usage.alloc_ops, current.alloc_ops); |
| 511 EXPECT_EQ(usage.alloc_bytes, current.alloc_bytes); |
| 512 EXPECT_EQ(usage.alloc_overhead_bytes, current.alloc_overhead_bytes); |
| 513 EXPECT_EQ(usage.free_ops, current.free_ops); |
| 514 EXPECT_EQ(usage.free_bytes, current.free_bytes); |
| 515 EXPECT_EQ(usage.max_allocated_bytes, current.max_allocated_bytes); |
| 516 } |
| 517 |
| 518 TEST_F(ThreadHeapUsageTrackerTest, AllShimFunctionsAreProvided) { |
427 const size_t kAllocSize = 100; | 519 const size_t kAllocSize = 100; |
428 void* alloc = MockMalloc(kAllocSize); | 520 void* alloc = MockMalloc(kAllocSize); |
429 size_t estimate = MockGetSizeEstimate(alloc); | 521 size_t estimate = MockGetSizeEstimate(alloc); |
430 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); | 522 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); |
431 MockFree(alloc); | 523 MockFree(alloc); |
432 | 524 |
433 alloc = MockCalloc(kAllocSize, 1); | 525 alloc = MockCalloc(kAllocSize, 1); |
434 estimate = MockGetSizeEstimate(alloc); | 526 estimate = MockGetSizeEstimate(alloc); |
435 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); | 527 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); |
436 MockFree(alloc); | 528 MockFree(alloc); |
437 | 529 |
438 alloc = MockAllocAligned(1, kAllocSize); | 530 alloc = MockAllocAligned(1, kAllocSize); |
439 estimate = MockGetSizeEstimate(alloc); | 531 estimate = MockGetSizeEstimate(alloc); |
440 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); | 532 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); |
441 | 533 |
442 alloc = MockRealloc(alloc, kAllocSize); | 534 alloc = MockRealloc(alloc, kAllocSize); |
443 estimate = MockGetSizeEstimate(alloc); | 535 estimate = MockGetSizeEstimate(alloc); |
444 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); | 536 ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize); |
445 MockFree(alloc); | 537 MockFree(alloc); |
446 } | 538 } |
447 | 539 |
448 #if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) | 540 #if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) |
449 TEST(ScopedThreadHeapShimTest, HooksIntoMallocWhenShimAvailable) { | 541 TEST(ThreadHeapUsageShimTest, HooksIntoMallocWhenShimAvailable) { |
450 ScopedThreadHeapUsage::Initialize(); | 542 ASSERT_FALSE(ThreadHeapUsageTracker::IsHeapTrackingEnabled()); |
451 ScopedThreadHeapUsage::EnableHeapTracking(); | 543 |
| 544 ThreadHeapUsageTracker::EnableHeapTracking(); |
| 545 |
| 546 ASSERT_TRUE(ThreadHeapUsageTracker::IsHeapTrackingEnabled()); |
452 | 547 |
453 const size_t kAllocSize = 9993; | 548 const size_t kAllocSize = 9993; |
454 // This test verifies that the scoped heap data is affected by malloc & | 549 // This test verifies that the scoped heap data is affected by malloc & |
455 // free only when the shim is available. | 550 // free only when the shim is available. |
456 ScopedThreadHeapUsage scoped_usage; | 551 ThreadHeapUsageTracker usage_tracker; |
| 552 usage_tracker.Start(); |
457 | 553 |
458 ScopedThreadHeapUsage::ThreadAllocatorUsage u1 = | 554 ThreadHeapUsage u1 = ThreadHeapUsageTracker::CurrentUsage(); |
459 ScopedThreadHeapUsage::CurrentUsage(); | |
460 void* ptr = malloc(kAllocSize); | 555 void* ptr = malloc(kAllocSize); |
461 // Prevent the compiler from optimizing out the malloc/free pair. | 556 // Prevent the compiler from optimizing out the malloc/free pair. |
462 ASSERT_NE(nullptr, ptr); | 557 ASSERT_NE(nullptr, ptr); |
463 | 558 |
464 ScopedThreadHeapUsage::ThreadAllocatorUsage u2 = | 559 ThreadHeapUsage u2 = ThreadHeapUsageTracker::CurrentUsage(); |
465 ScopedThreadHeapUsage::CurrentUsage(); | |
466 free(ptr); | 560 free(ptr); |
467 ScopedThreadHeapUsage::ThreadAllocatorUsage u3 = | 561 |
468 ScopedThreadHeapUsage::CurrentUsage(); | 562 usage_tracker.Stop(false); |
| 563 ThreadHeapUsage u3 = usage_tracker.usage(); |
469 | 564 |
470 // Verify that at least one allocation operation was recorded, and that free | 565 // Verify that at least one allocation operation was recorded, and that free |
471 // operations are at least monotonically growing. | 566 // operations are at least monotonically growing. |
472 EXPECT_LE(0U, u1.alloc_ops); | 567 EXPECT_LE(0U, u1.alloc_ops); |
473 EXPECT_LE(u1.alloc_ops + 1, u2.alloc_ops); | 568 EXPECT_LE(u1.alloc_ops + 1, u2.alloc_ops); |
474 EXPECT_LE(u1.alloc_ops + 1, u3.alloc_ops); | 569 EXPECT_LE(u1.alloc_ops + 1, u3.alloc_ops); |
475 | 570 |
476 // Verify that at least the bytes above were recorded. | 571 // Verify that at least the bytes above were recorded. |
477 EXPECT_LE(u1.alloc_bytes + kAllocSize, u2.alloc_bytes); | 572 EXPECT_LE(u1.alloc_bytes + kAllocSize, u2.alloc_bytes); |
478 | 573 |
479 // Verify that at least the one free operation above was recorded. | 574 // Verify that at least the one free operation above was recorded. |
480 EXPECT_LE(u2.free_ops + 1, u3.free_ops); | 575 EXPECT_LE(u2.free_ops + 1, u3.free_ops); |
481 | 576 |
482 TestingScopedThreadHeapUsage::DisableHeapTrackingForTesting(); | 577 TestingThreadHeapUsageTracker::DisableHeapTrackingForTesting(); |
| 578 |
| 579 ASSERT_FALSE(ThreadHeapUsageTracker::IsHeapTrackingEnabled()); |
483 } | 580 } |
484 #endif // BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) | 581 #endif // BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) |
485 | 582 |
486 } // namespace debug | 583 } // namespace debug |
487 } // namespace base | 584 } // namespace base |
OLD | NEW |