| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 static NEVER_INLINE void partitionExcessiveAllocationSize() | 314 static NEVER_INLINE void partitionExcessiveAllocationSize() |
| 315 { | 315 { |
| 316 IMMEDIATE_CRASH(); | 316 IMMEDIATE_CRASH(); |
| 317 } | 317 } |
| 318 | 318 |
| 319 static NEVER_INLINE void partitionBucketFull() | 319 static NEVER_INLINE void partitionBucketFull() |
| 320 { | 320 { |
| 321 IMMEDIATE_CRASH(); | 321 IMMEDIATE_CRASH(); |
| 322 } | 322 } |
| 323 | 323 |
| 324 static bool partitionPageStateIsEmpty(const PartitionPage* page) | 324 // partitionPageStateIs* |
| 325 // Note that it's only valid to call these functions on pages found on one of |
| 326 // the page lists. Specifically, you can't call these functions on full pages |
| 327 // that were detached from the active list. |
| 328 static bool ALWAYS_INLINE partitionPageStateIsActive(const PartitionPage* page) |
| 325 { | 329 { |
| 326 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 330 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 327 return !page->numAllocatedSlots; | 331 ASSERT(!page->pageOffset); |
| 332 return (page->numAllocatedSlots > 0 && (page->freelistHead || page->numUnpro
visionedSlots)); |
| 328 } | 333 } |
| 329 | 334 |
| 330 static bool partitionPageStateIsDecommitted(const PartitionPage* page) | 335 static bool ALWAYS_INLINE partitionPageStateIsFull(const PartitionPage* page) |
| 331 { | 336 { |
| 332 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 337 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 333 bool ret = !page->numAllocatedSlots && !page->freelistHead; | 338 ASSERT(!page->pageOffset); |
| 339 bool ret = (page->numAllocatedSlots == partitionBucketSlots(page->bucket)); |
| 340 if (ret) { |
| 341 ASSERT(!page->freelistHead); |
| 342 ASSERT(!page->numUnprovisionedSlots); |
| 343 } |
| 344 return ret; |
| 345 } |
| 346 |
| 347 static bool ALWAYS_INLINE partitionPageStateIsEmpty(const PartitionPage* page) |
| 348 { |
| 349 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 350 ASSERT(!page->pageOffset); |
| 351 return (!page->numAllocatedSlots && page->freelistHead); |
| 352 } |
| 353 |
| 354 static bool ALWAYS_INLINE partitionPageStateIsDecommitted(const PartitionPage* p
age) |
| 355 { |
| 356 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| 357 ASSERT(!page->pageOffset); |
| 358 bool ret = (!page->numAllocatedSlots && !page->freelistHead); |
| 334 if (ret) { | 359 if (ret) { |
| 335 ASSERT(!page->numUnprovisionedSlots); | 360 ASSERT(!page->numUnprovisionedSlots); |
| 336 ASSERT(page->emptyCacheIndex == -1); | 361 ASSERT(page->emptyCacheIndex == -1); |
| 337 ASSERT(!page->pageOffset); | |
| 338 } | 362 } |
| 339 return ret; | 363 return ret; |
| 340 } | 364 } |
| 341 | 365 |
| 342 static void partitionIncreaseCommittedPages(PartitionRootBase* root, size_t len) | 366 static void partitionIncreaseCommittedPages(PartitionRootBase* root, size_t len) |
| 343 { | 367 { |
| 344 root->totalSizeOfCommittedPages += len; | 368 root->totalSizeOfCommittedPages += len; |
| 345 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root
->totalSizeOfDirectMappedPages); | 369 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root
->totalSizeOfDirectMappedPages); |
| 346 } | 370 } |
| 347 | 371 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 ASSERT(ret >= currentExtent->superPageBase && ret < currentExtent->super
PagesEnd); | 469 ASSERT(ret >= currentExtent->superPageBase && ret < currentExtent->super
PagesEnd); |
| 446 } | 470 } |
| 447 return ret; | 471 return ret; |
| 448 } | 472 } |
| 449 | 473 |
| 450 static ALWAYS_INLINE uint16_t partitionBucketPartitionPages(const PartitionBucke
t* bucket) | 474 static ALWAYS_INLINE uint16_t partitionBucketPartitionPages(const PartitionBucke
t* bucket) |
| 451 { | 475 { |
| 452 return (bucket->numSystemPagesPerSlotSpan + (kNumSystemPagesPerPartitionPage
- 1)) / kNumSystemPagesPerPartitionPage; | 476 return (bucket->numSystemPagesPerSlotSpan + (kNumSystemPagesPerPartitionPage
- 1)) / kNumSystemPagesPerPartitionPage; |
| 453 } | 477 } |
| 454 | 478 |
| 455 static ALWAYS_INLINE void partitionPageReset(PartitionPage* page, PartitionBucke
t* bucket) | 479 static ALWAYS_INLINE void partitionPageReset(PartitionPage* page) |
| 456 { | 480 { |
| 457 ASSERT(page->bucket == bucket); | |
| 458 ASSERT(partitionPageStateIsDecommitted(page)); | 481 ASSERT(partitionPageStateIsDecommitted(page)); |
| 459 | 482 |
| 460 page->numUnprovisionedSlots = partitionBucketSlots(bucket); | 483 page->numUnprovisionedSlots = partitionBucketSlots(page->bucket); |
| 461 ASSERT(page->numUnprovisionedSlots); | 484 ASSERT(page->numUnprovisionedSlots); |
| 462 | 485 |
| 463 page->nextPage = nullptr; | 486 page->nextPage = nullptr; |
| 464 } | 487 } |
| 465 | 488 |
| 466 static ALWAYS_INLINE void partitionPageSetup(PartitionPage* page, PartitionBucke
t* bucket) | 489 static ALWAYS_INLINE void partitionPageSetup(PartitionPage* page, PartitionBucke
t* bucket) |
| 467 { | 490 { |
| 468 // The bucket never changes. We set it up once. | 491 // The bucket never changes. We set it up once. |
| 469 page->bucket = bucket; | 492 page->bucket = bucket; |
| 470 page->emptyCacheIndex = -1; | 493 page->emptyCacheIndex = -1; |
| 471 | 494 |
| 472 partitionPageReset(page, bucket); | 495 partitionPageReset(page); |
| 473 | 496 |
| 474 // If this page has just a single slot, do not set up page offsets for any | 497 // If this page has just a single slot, do not set up page offsets for any |
| 475 // page metadata other than the first one. This ensures that attempts to | 498 // page metadata other than the first one. This ensures that attempts to |
| 476 // touch invalid page metadata fail. | 499 // touch invalid page metadata fail. |
| 477 if (page->numUnprovisionedSlots == 1) | 500 if (page->numUnprovisionedSlots == 1) |
| 478 return; | 501 return; |
| 479 | 502 |
| 480 uint16_t numPartitionPages = partitionBucketPartitionPages(bucket); | 503 uint16_t numPartitionPages = partitionBucketPartitionPages(bucket); |
| 481 char* pageCharPtr = reinterpret_cast<char*>(page); | 504 char* pageCharPtr = reinterpret_cast<char*>(page); |
| 482 for (uint16_t i = 1; i < numPartitionPages; ++i) { | 505 for (uint16_t i = 1; i < numPartitionPages; ++i) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 | 597 |
| 575 PartitionPage* nextPage; | 598 PartitionPage* nextPage; |
| 576 | 599 |
| 577 for (; page; page = nextPage) { | 600 for (; page; page = nextPage) { |
| 578 nextPage = page->nextPage; | 601 nextPage = page->nextPage; |
| 579 ASSERT(page->bucket == bucket); | 602 ASSERT(page->bucket == bucket); |
| 580 ASSERT(page != bucket->emptyPagesHead); | 603 ASSERT(page != bucket->emptyPagesHead); |
| 581 ASSERT(page != bucket->decommittedPagesHead); | 604 ASSERT(page != bucket->decommittedPagesHead); |
| 582 | 605 |
| 583 // Deal with empty and decommitted pages. | 606 // Deal with empty and decommitted pages. |
| 584 if (UNLIKELY(!page->numAllocatedSlots)) { | 607 if (LIKELY(partitionPageStateIsActive(page))) { |
| 585 ASSERT(partitionPageStateIsEmpty(page)); | |
| 586 if (UNLIKELY(!page->freelistHead)) { | |
| 587 ASSERT(partitionPageStateIsDecommitted(page)); | |
| 588 page->nextPage = bucket->decommittedPagesHead; | |
| 589 bucket->decommittedPagesHead = page; | |
| 590 } else { | |
| 591 page->nextPage = bucket->emptyPagesHead; | |
| 592 bucket->emptyPagesHead = page; | |
| 593 } | |
| 594 } else if (LIKELY(page->freelistHead != 0) || LIKELY(page->numUnprovisio
nedSlots)) { | |
| 595 // This page is usable because it has freelist entries, or has | 608 // This page is usable because it has freelist entries, or has |
| 596 // unprovisioned slots we can create freelist entries from. | 609 // unprovisioned slots we can create freelist entries from. |
| 597 bucket->activePagesHead = page; | 610 bucket->activePagesHead = page; |
| 598 return true; | 611 return true; |
| 612 } |
| 613 if (LIKELY(partitionPageStateIsEmpty(page))) { |
| 614 page->nextPage = bucket->emptyPagesHead; |
| 615 bucket->emptyPagesHead = page; |
| 616 } else if (LIKELY(partitionPageStateIsDecommitted(page))) { |
| 617 page->nextPage = bucket->decommittedPagesHead; |
| 618 bucket->decommittedPagesHead = page; |
| 599 } else { | 619 } else { |
| 620 ASSERT(partitionPageStateIsFull(page)); |
| 600 // If we get here, we found a full page. Skip over it too, and also | 621 // If we get here, we found a full page. Skip over it too, and also |
| 601 // tag it as full (via a negative value). We need it tagged so that | 622 // tag it as full (via a negative value). We need it tagged so that |
| 602 // free'ing can tell, and move it back into the active page list. | 623 // free'ing can tell, and move it back into the active page list. |
| 603 ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket)); | |
| 604 page->numAllocatedSlots = -page->numAllocatedSlots; | 624 page->numAllocatedSlots = -page->numAllocatedSlots; |
| 605 ++bucket->numFullPages; | 625 ++bucket->numFullPages; |
| 606 // numFullPages is a uint16_t for efficient packing so guard against | 626 // numFullPages is a uint16_t for efficient packing so guard against |
| 607 // overflow to be safe. | 627 // overflow to be safe. |
| 608 if (UNLIKELY(!bucket->numFullPages)) | 628 if (UNLIKELY(!bucket->numFullPages)) |
| 609 partitionBucketFull(); | 629 partitionBucketFull(); |
| 610 // Not necessary but might help stop accidents. | 630 // Not necessary but might help stop accidents. |
| 611 page->nextPage = 0; | 631 page->nextPage = 0; |
| 612 } | 632 } |
| 613 } | 633 } |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 760 ASSERT(bucket->activePagesHead == &PartitionRootGeneric::gSeedPage); | 780 ASSERT(bucket->activePagesHead == &PartitionRootGeneric::gSeedPage); |
| 761 if (size > kGenericMaxDirectMapped) { | 781 if (size > kGenericMaxDirectMapped) { |
| 762 if (returnNull) | 782 if (returnNull) |
| 763 return nullptr; | 783 return nullptr; |
| 764 partitionExcessiveAllocationSize(); | 784 partitionExcessiveAllocationSize(); |
| 765 } | 785 } |
| 766 newPage = partitionDirectMap(root, flags, size); | 786 newPage = partitionDirectMap(root, flags, size); |
| 767 } else if (LIKELY(partitionSetNewActivePage(bucket))) { | 787 } else if (LIKELY(partitionSetNewActivePage(bucket))) { |
| 768 // First, did we find an active page in the active pages list? | 788 // First, did we find an active page in the active pages list? |
| 769 newPage = bucket->activePagesHead; | 789 newPage = bucket->activePagesHead; |
| 770 ASSERT(newPage != &PartitionRootGeneric::gSeedPage); | 790 ASSERT(partitionPageStateIsActive(newPage)); |
| 771 } else if (LIKELY(bucket->emptyPagesHead != nullptr) || LIKELY(bucket->decom
mittedPagesHead != nullptr)) { | 791 } else if (LIKELY(bucket->emptyPagesHead != nullptr) || LIKELY(bucket->decom
mittedPagesHead != nullptr)) { |
| 772 // Second, look in our lists of empty and decommitted pages. | 792 // Second, look in our lists of empty and decommitted pages. |
| 773 // Check empty pages first, which are preferred, but beware that an | 793 // Check empty pages first, which are preferred, but beware that an |
| 774 // empty page might have been decommitted. | 794 // empty page might have been decommitted. |
| 775 while (LIKELY((newPage = bucket->emptyPagesHead) != nullptr)) { | 795 while (LIKELY((newPage = bucket->emptyPagesHead) != nullptr)) { |
| 776 ASSERT(partitionPageStateIsEmpty(newPage)); | 796 ASSERT(newPage->bucket == bucket); |
| 797 ASSERT(partitionPageStateIsEmpty(newPage) || partitionPageStateIsDec
ommitted(newPage)); |
| 777 bucket->emptyPagesHead = newPage->nextPage; | 798 bucket->emptyPagesHead = newPage->nextPage; |
| 778 // Accept the empty page unless it got decommitted. | 799 // Accept the empty page unless it got decommitted. |
| 779 if (newPage->freelistHead) { | 800 if (newPage->freelistHead) { |
| 780 newPage->nextPage = nullptr; | 801 newPage->nextPage = nullptr; |
| 781 break; | 802 break; |
| 782 } | 803 } |
| 783 ASSERT(partitionPageStateIsDecommitted(newPage)); | 804 ASSERT(partitionPageStateIsDecommitted(newPage)); |
| 784 newPage->nextPage = bucket->decommittedPagesHead; | 805 newPage->nextPage = bucket->decommittedPagesHead; |
| 785 bucket->decommittedPagesHead = newPage; | 806 bucket->decommittedPagesHead = newPage; |
| 786 } | 807 } |
| 787 if (UNLIKELY(!newPage) && LIKELY(bucket->decommittedPagesHead != nullptr
)) { | 808 if (UNLIKELY(!newPage) && LIKELY(bucket->decommittedPagesHead != nullptr
)) { |
| 788 newPage = bucket->decommittedPagesHead; | 809 newPage = bucket->decommittedPagesHead; |
| 810 ASSERT(newPage->bucket == bucket); |
| 811 ASSERT(partitionPageStateIsDecommitted(newPage)); |
| 789 bucket->decommittedPagesHead = newPage->nextPage; | 812 bucket->decommittedPagesHead = newPage->nextPage; |
| 790 ASSERT(partitionPageStateIsDecommitted(newPage)); | |
| 791 void* addr = partitionPageToPointer(newPage); | 813 void* addr = partitionPageToPointer(newPage); |
| 792 partitionRecommitSystemPages(root, addr, partitionBucketBytes(newPag
e->bucket)); | 814 partitionRecommitSystemPages(root, addr, partitionBucketBytes(newPag
e->bucket)); |
| 793 partitionPageReset(newPage, bucket); | 815 partitionPageReset(newPage); |
| 794 } | 816 } |
| 795 ASSERT(newPage); | 817 ASSERT(newPage); |
| 796 } else { | 818 } else { |
| 797 // Third. If we get here, we need a brand new page. | 819 // Third. If we get here, we need a brand new page. |
| 798 uint16_t numPartitionPages = partitionBucketPartitionPages(bucket); | 820 uint16_t numPartitionPages = partitionBucketPartitionPages(bucket); |
| 799 void* rawPages = partitionAllocPartitionPages(root, flags, numPartitionP
ages); | 821 void* rawPages = partitionAllocPartitionPages(root, flags, numPartitionP
ages); |
| 800 if (LIKELY(rawPages != nullptr)) { | 822 if (LIKELY(rawPages != nullptr)) { |
| 801 newPage = partitionPointerToPageNoAlignmentCheck(rawPages); | 823 newPage = partitionPointerToPageNoAlignmentCheck(rawPages); |
| 802 partitionPageSetup(newPage, bucket); | 824 partitionPageSetup(newPage, bucket); |
| 803 } | 825 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 826 return entry; | 848 return entry; |
| 827 } | 849 } |
| 828 // Otherwise, we need to build the freelist. | 850 // Otherwise, we need to build the freelist. |
| 829 ASSERT(newPage->numUnprovisionedSlots); | 851 ASSERT(newPage->numUnprovisionedSlots); |
| 830 return partitionPageAllocAndFillFreelist(newPage); | 852 return partitionPageAllocAndFillFreelist(newPage); |
| 831 } | 853 } |
| 832 | 854 |
| 833 static ALWAYS_INLINE void partitionDecommitPage(PartitionRootBase* root, Partiti
onPage* page) | 855 static ALWAYS_INLINE void partitionDecommitPage(PartitionRootBase* root, Partiti
onPage* page) |
| 834 { | 856 { |
| 835 ASSERT(partitionPageStateIsEmpty(page)); | 857 ASSERT(partitionPageStateIsEmpty(page)); |
| 836 ASSERT(page->freelistHead); | |
| 837 ASSERT(!partitionBucketIsDirectMapped(page->bucket)); | 858 ASSERT(!partitionBucketIsDirectMapped(page->bucket)); |
| 838 void* addr = partitionPageToPointer(page); | 859 void* addr = partitionPageToPointer(page); |
| 839 partitionDecommitSystemPages(root, addr, partitionBucketBytes(page->bucket))
; | 860 partitionDecommitSystemPages(root, addr, partitionBucketBytes(page->bucket))
; |
| 840 | 861 |
| 841 // We actually leave the decommitted page in the active list. We'll sweep | 862 // We actually leave the decommitted page in the active list. We'll sweep |
| 842 // it on to the decommitted page list when we next walk the active page | 863 // it on to the decommitted page list when we next walk the active page |
| 843 // list. | 864 // list. |
| 844 // Pulling this trick enables us to use a singly-linked page list for all | 865 // Pulling this trick enables us to use a singly-linked page list for all |
| 845 // cases, which is critical in keeping the page metadata structure down to | 866 // cases, which is critical in keeping the page metadata structure down to |
| 846 // 32 bytes in size. | 867 // 32 bytes in size. |
| 847 page->freelistHead = 0; | 868 page->freelistHead = 0; |
| 848 page->numUnprovisionedSlots = 0; | 869 page->numUnprovisionedSlots = 0; |
| 870 ASSERT(partitionPageStateIsDecommitted(page)); |
| 849 } | 871 } |
| 850 | 872 |
| 851 static void partitionDecommitPageIfPossible(PartitionRootBase* root, PartitionPa
ge* page) | 873 static void partitionDecommitPageIfPossible(PartitionRootBase* root, PartitionPa
ge* page) |
| 852 { | 874 { |
| 853 ASSERT(page->emptyCacheIndex >= 0); | 875 ASSERT(page->emptyCacheIndex >= 0); |
| 854 ASSERT(static_cast<unsigned>(page->emptyCacheIndex) < kMaxFreeableSpans); | 876 ASSERT(static_cast<unsigned>(page->emptyCacheIndex) < kMaxFreeableSpans); |
| 855 ASSERT(page == root->globalEmptyPageRing[page->emptyCacheIndex]); | 877 ASSERT(page == root->globalEmptyPageRing[page->emptyCacheIndex]); |
| 856 if (!page->numAllocatedSlots && page->freelistHead) { | 878 page->emptyCacheIndex = -1; |
| 857 // The page is still empty, and not decommitted, so _really_ decommit | 879 if (partitionPageStateIsEmpty(page)) |
| 858 // it. | |
| 859 partitionDecommitPage(root, page); | 880 partitionDecommitPage(root, page); |
| 860 } | |
| 861 page->emptyCacheIndex = -1; | |
| 862 } | 881 } |
| 863 | 882 |
| 864 static ALWAYS_INLINE void partitionRegisterEmptyPage(PartitionPage* page) | 883 static ALWAYS_INLINE void partitionRegisterEmptyPage(PartitionPage* page) |
| 865 { | 884 { |
| 866 ASSERT(partitionPageStateIsEmpty(page)); | 885 ASSERT(partitionPageStateIsEmpty(page)); |
| 867 PartitionRootBase* root = partitionPageToRoot(page); | 886 PartitionRootBase* root = partitionPageToRoot(page); |
| 868 | 887 |
| 869 // If the page is already registered as empty, give it another life. | 888 // If the page is already registered as empty, give it another life. |
| 870 if (page->emptyCacheIndex != -1) { | 889 if (page->emptyCacheIndex != -1) { |
| 871 ASSERT(page->emptyCacheIndex >= 0); | 890 ASSERT(page->emptyCacheIndex >= 0); |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1183 if (rawSize) | 1202 if (rawSize) |
| 1184 statsOut->activeBytes += static_cast<uint32_t>(rawSize); | 1203 statsOut->activeBytes += static_cast<uint32_t>(rawSize); |
| 1185 else | 1204 else |
| 1186 statsOut->activeBytes += (page->numAllocatedSlots * statsOut->bucketSlot
Size); | 1205 statsOut->activeBytes += (page->numAllocatedSlots * statsOut->bucketSlot
Size); |
| 1187 | 1206 |
| 1188 size_t pageBytesResident = partitionRoundUpToSystemPage((bucketNumSlots - pa
ge->numUnprovisionedSlots) * statsOut->bucketSlotSize); | 1207 size_t pageBytesResident = partitionRoundUpToSystemPage((bucketNumSlots - pa
ge->numUnprovisionedSlots) * statsOut->bucketSlotSize); |
| 1189 statsOut->residentBytes += pageBytesResident; | 1208 statsOut->residentBytes += pageBytesResident; |
| 1190 if (partitionPageStateIsEmpty(page)) { | 1209 if (partitionPageStateIsEmpty(page)) { |
| 1191 statsOut->decommittableBytes += pageBytesResident; | 1210 statsOut->decommittableBytes += pageBytesResident; |
| 1192 ++statsOut->numEmptyPages; | 1211 ++statsOut->numEmptyPages; |
| 1193 } else if (page->numAllocatedSlots == bucketNumSlots) { | 1212 } else if (partitionPageStateIsFull(page)) { |
| 1194 ++statsOut->numFullPages; | 1213 ++statsOut->numFullPages; |
| 1195 } else { | 1214 } else { |
| 1196 ASSERT(page->numAllocatedSlots > 0); | 1215 ASSERT(partitionPageStateIsActive(page)); |
| 1197 ++statsOut->numActivePages; | 1216 ++statsOut->numActivePages; |
| 1198 } | 1217 } |
| 1199 } | 1218 } |
| 1200 | 1219 |
| 1201 static void partitionDumpBucketStats(PartitionBucketMemoryStats* statsOut, const
PartitionBucket* bucket) | 1220 static void partitionDumpBucketStats(PartitionBucketMemoryStats* statsOut, const
PartitionBucket* bucket) |
| 1202 { | 1221 { |
| 1203 ASSERT(!partitionBucketIsDirectMapped(bucket)); | 1222 ASSERT(!partitionBucketIsDirectMapped(bucket)); |
| 1204 statsOut->isValid = false; | 1223 statsOut->isValid = false; |
| 1205 // If the active page list is empty (== &PartitionRootGeneric::gSeedPage), | 1224 // If the active page list is empty (== &PartitionRootGeneric::gSeedPage), |
| 1206 // the bucket might still need to be reported if it has a list of empty, | 1225 // the bucket might still need to be reported if it has a list of empty, |
| 1207 // decommitted or full pages. | 1226 // decommitted or full pages. |
| 1208 if (bucket->activePagesHead == &PartitionRootGeneric::gSeedPage && !bucket->
emptyPagesHead && !bucket->decommittedPagesHead && !bucket->numFullPages) | 1227 if (bucket->activePagesHead == &PartitionRootGeneric::gSeedPage && !bucket->
emptyPagesHead && !bucket->decommittedPagesHead && !bucket->numFullPages) |
| 1209 return; | 1228 return; |
| 1210 | 1229 |
| 1211 memset(statsOut, '\0', sizeof(*statsOut)); | 1230 memset(statsOut, '\0', sizeof(*statsOut)); |
| 1212 statsOut->isValid = true; | 1231 statsOut->isValid = true; |
| 1213 statsOut->isDirectMap = false; | 1232 statsOut->isDirectMap = false; |
| 1214 statsOut->numFullPages = static_cast<size_t>(bucket->numFullPages); | 1233 statsOut->numFullPages = static_cast<size_t>(bucket->numFullPages); |
| 1215 statsOut->bucketSlotSize = bucket->slotSize; | 1234 statsOut->bucketSlotSize = bucket->slotSize; |
| 1216 uint16_t bucketNumSlots = partitionBucketSlots(bucket); | 1235 uint16_t bucketNumSlots = partitionBucketSlots(bucket); |
| 1217 size_t bucketUsefulStorage = statsOut->bucketSlotSize * bucketNumSlots; | 1236 size_t bucketUsefulStorage = statsOut->bucketSlotSize * bucketNumSlots; |
| 1218 statsOut->allocatedPageSize = partitionBucketBytes(bucket); | 1237 statsOut->allocatedPageSize = partitionBucketBytes(bucket); |
| 1219 statsOut->activeBytes = bucket->numFullPages * bucketUsefulStorage; | 1238 statsOut->activeBytes = bucket->numFullPages * bucketUsefulStorage; |
| 1220 statsOut->residentBytes = bucket->numFullPages * statsOut->allocatedPageSize
; | 1239 statsOut->residentBytes = bucket->numFullPages * statsOut->allocatedPageSize
; |
| 1221 | 1240 |
| 1222 for (const PartitionPage* page = bucket->emptyPagesHead; page; page = page->
nextPage) { | 1241 for (const PartitionPage* page = bucket->emptyPagesHead; page; page = page->
nextPage) { |
| 1223 ASSERT(partitionPageStateIsEmpty(page)); | 1242 ASSERT(partitionPageStateIsEmpty(page) || partitionPageStateIsDecommitte
d(page)); |
| 1224 partitionDumpPageStats(statsOut, page); | 1243 partitionDumpPageStats(statsOut, page); |
| 1225 } | 1244 } |
| 1226 for (const PartitionPage* page = bucket->decommittedPagesHead; page; page =
page->nextPage) { | 1245 for (const PartitionPage* page = bucket->decommittedPagesHead; page; page =
page->nextPage) { |
| 1227 ASSERT(partitionPageStateIsDecommitted(page)); | 1246 ASSERT(partitionPageStateIsDecommitted(page)); |
| 1228 partitionDumpPageStats(statsOut, page); | 1247 partitionDumpPageStats(statsOut, page); |
| 1229 } | 1248 } |
| 1230 | 1249 |
| 1231 if (bucket->activePagesHead != &PartitionRootGeneric::gSeedPage) { | 1250 if (bucket->activePagesHead != &PartitionRootGeneric::gSeedPage) { |
| 1232 for (const PartitionPage* page = bucket->activePagesHead; page; page = p
age->nextPage) { | 1251 for (const PartitionPage* page = bucket->activePagesHead; page; page = p
age->nextPage) { |
| 1233 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 1252 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1301 // partitionsDumpBucketStats is called after collecting stats because it | 1320 // partitionsDumpBucketStats is called after collecting stats because it |
| 1302 // can use PartitionAlloc to allocate and this can affect the statistics. | 1321 // can use PartitionAlloc to allocate and this can affect the statistics. |
| 1303 for (size_t i = 0; i < partitionNumBuckets; ++i) { | 1322 for (size_t i = 0; i < partitionNumBuckets; ++i) { |
| 1304 if (memoryStats[i].isValid) | 1323 if (memoryStats[i].isValid) |
| 1305 partitionStatsDumper->partitionsDumpBucketStats(partitionName, &memo
ryStats[i]); | 1324 partitionStatsDumper->partitionsDumpBucketStats(partitionName, &memo
ryStats[i]); |
| 1306 } | 1325 } |
| 1307 } | 1326 } |
| 1308 | 1327 |
| 1309 } // namespace WTF | 1328 } // namespace WTF |
| 1310 | 1329 |
| OLD | NEW |