Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: Source/wtf/PartitionAlloc.cpp

Issue 301743006: Report DOM partitionAlloc size to V8 GC. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: add unittest / fix windows Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/wtf/PartitionAlloc.h ('k') | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 spinLockLock(&PartitionRootBase::gInitializedLock); 105 spinLockLock(&PartitionRootBase::gInitializedLock);
106 if (!PartitionRootBase::gInitialized) { 106 if (!PartitionRootBase::gInitialized) {
107 PartitionRootBase::gInitialized = true; 107 PartitionRootBase::gInitialized = true;
108 // We mark the seed page as free to make sure it is skipped by our 108 // We mark the seed page as free to make sure it is skipped by our
109 // logic to find a new active page. 109 // logic to find a new active page.
110 PartitionRootBase::gPagedBucket.activePagesHead = &PartitionRootGeneric: :gSeedPage; 110 PartitionRootBase::gPagedBucket.activePagesHead = &PartitionRootGeneric: :gSeedPage;
111 } 111 }
112 spinLockUnlock(&PartitionRootBase::gInitializedLock); 112 spinLockUnlock(&PartitionRootBase::gInitializedLock);
113 113
114 root->initialized = true; 114 root->initialized = true;
115 root->totalSizeOfCommittedPages = 0;
115 root->totalSizeOfSuperPages = 0; 116 root->totalSizeOfSuperPages = 0;
116 root->nextSuperPage = 0; 117 root->nextSuperPage = 0;
117 root->nextPartitionPage = 0; 118 root->nextPartitionPage = 0;
118 root->nextPartitionPageEnd = 0; 119 root->nextPartitionPageEnd = 0;
119 root->firstExtent = 0; 120 root->firstExtent = 0;
120 root->currentExtent = 0; 121 root->currentExtent = 0;
121 122
122 memset(&root->globalEmptyPageRing, '\0', sizeof(root->globalEmptyPageRing)); 123 memset(&root->globalEmptyPageRing, '\0', sizeof(root->globalEmptyPageRing));
123 root->globalEmptyPageRingIndex = 0; 124 root->globalEmptyPageRingIndex = 0;
124 125
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 static NEVER_INLINE void partitionOutOfMemory() 302 static NEVER_INLINE void partitionOutOfMemory()
302 { 303 {
303 IMMEDIATE_CRASH(); 304 IMMEDIATE_CRASH();
304 } 305 }
305 306
306 static NEVER_INLINE void partitionFull() 307 static NEVER_INLINE void partitionFull()
307 { 308 {
308 IMMEDIATE_CRASH(); 309 IMMEDIATE_CRASH();
309 } 310 }
310 311
312 static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len)
313 {
314 decommitSystemPages(addr, len);
315 ASSERT(root->totalSizeOfCommittedPages > len);
316 root->totalSizeOfCommittedPages -= len;
317 }
318
319 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, void* addr, size_t len)
320 {
321 recommitSystemPages(addr, len);
322 root->totalSizeOfCommittedPages += len;
323 }
324
311 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, size_t numPartitionPages) 325 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, size_t numPartitionPages)
312 { 326 {
313 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize)); 327 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize));
314 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize)); 328 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize));
315 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); 329 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage);
316 size_t totalSize = kPartitionPageSize * numPartitionPages; 330 size_t totalSize = kPartitionPageSize * numPartitionPages;
331 root->totalSizeOfCommittedPages += totalSize;
317 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift; 332 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift;
318 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { 333 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) {
319 // In this case, we can still hand out pages from the current super page 334 // In this case, we can still hand out pages from the current super page
320 // allocation. 335 // allocation.
321 char* ret = root->nextPartitionPage; 336 char* ret = root->nextPartitionPage;
322 root->nextPartitionPage += totalSize; 337 root->nextPartitionPage += totalSize;
323 return ret; 338 return ret;
324 } 339 }
325 340
326 // Need a new super page. 341 // Need a new super page.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 currentExtent->superPagesEnd += kSuperPageSize; 390 currentExtent->superPagesEnd += kSuperPageSize;
376 ASSERT(ret >= currentExtent->superPageBase && ret < currentExtent->super PagesEnd); 391 ASSERT(ret >= currentExtent->superPageBase && ret < currentExtent->super PagesEnd);
377 } 392 }
378 // By storing the root in every extent metadata object, we have a fast way 393 // By storing the root in every extent metadata object, we have a fast way
379 // to go from a pointer within the partition to the root object. 394 // to go from a pointer within the partition to the root object.
380 latestExtent->root = root; 395 latestExtent->root = root;
381 396
382 return ret; 397 return ret;
383 } 398 }
384 399
385 static ALWAYS_INLINE void partitionUnusePage(PartitionPage* page) 400 static ALWAYS_INLINE void partitionUnusePage(PartitionRootBase* root, PartitionP age* page)
386 { 401 {
387 ASSERT(page->bucket->numSystemPagesPerSlotSpan); 402 ASSERT(page->bucket->numSystemPagesPerSlotSpan);
388 void* addr = partitionPageToPointer(page); 403 void* addr = partitionPageToPointer(page);
389 decommitSystemPages(addr, page->bucket->numSystemPagesPerSlotSpan * kSystemP ageSize); 404 partitionDecommitSystemPages(root, addr, page->bucket->numSystemPagesPerSlot Span * kSystemPageSize);
390 } 405 }
391 406
392 static ALWAYS_INLINE size_t partitionBucketSlots(const PartitionBucket* bucket) 407 static ALWAYS_INLINE size_t partitionBucketSlots(const PartitionBucket* bucket)
393 { 408 {
394 return (bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / bucket->slotS ize; 409 return (bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / bucket->slotS ize;
395 } 410 }
396 411
397 static ALWAYS_INLINE size_t partitionBucketPartitionPages(const PartitionBucket* bucket) 412 static ALWAYS_INLINE size_t partitionBucketPartitionPages(const PartitionBucket* bucket)
398 { 413 {
399 return (bucket->numSystemPagesPerSlotSpan + (kNumSystemPagesPerPartitionPage - 1)) / kNumSystemPagesPerPartitionPage; 414 return (bucket->numSystemPagesPerSlotSpan + (kNumSystemPagesPerPartitionPage - 1)) / kNumSystemPagesPerPartitionPage;
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 // Second, look in our list of freed but reserved pages. 683 // Second, look in our list of freed but reserved pages.
669 PartitionPage* newPage = bucket->freePagesHead; 684 PartitionPage* newPage = bucket->freePagesHead;
670 if (LIKELY(newPage != 0)) { 685 if (LIKELY(newPage != 0)) {
671 ASSERT(newPage != &PartitionRootGeneric::gSeedPage); 686 ASSERT(newPage != &PartitionRootGeneric::gSeedPage);
672 ASSERT(!newPage->freelistHead); 687 ASSERT(!newPage->freelistHead);
673 ASSERT(!newPage->numAllocatedSlots); 688 ASSERT(!newPage->numAllocatedSlots);
674 ASSERT(!newPage->numUnprovisionedSlots); 689 ASSERT(!newPage->numUnprovisionedSlots);
675 ASSERT(newPage->freeCacheIndex == -1); 690 ASSERT(newPage->freeCacheIndex == -1);
676 bucket->freePagesHead = newPage->nextPage; 691 bucket->freePagesHead = newPage->nextPage;
677 void* addr = partitionPageToPointer(newPage); 692 void* addr = partitionPageToPointer(newPage);
678 recommitSystemPages(addr, newPage->bucket->numSystemPagesPerSlotSpan * k SystemPageSize); 693 partitionRecommitSystemPages(root, addr, newPage->bucket->numSystemPages PerSlotSpan * kSystemPageSize);
679 } else { 694 } else {
680 // Third. If we get here, we need a brand new page. 695 // Third. If we get here, we need a brand new page.
681 size_t numPartitionPages = partitionBucketPartitionPages(bucket); 696 size_t numPartitionPages = partitionBucketPartitionPages(bucket);
682 void* rawNewPage = partitionAllocPartitionPages(root, flags, numPartitio nPages); 697 void* rawNewPage = partitionAllocPartitionPages(root, flags, numPartitio nPages);
683 if (UNLIKELY(!rawNewPage)) { 698 if (UNLIKELY(!rawNewPage)) {
684 ASSERT(returnNull); 699 ASSERT(returnNull);
685 return 0; 700 return 0;
686 } 701 }
687 // Skip the alignment check because it depends on page->bucket, which is not yet set. 702 // Skip the alignment check because it depends on page->bucket, which is not yet set.
688 newPage = partitionPointerToPageNoAlignmentCheck(rawNewPage); 703 newPage = partitionPointerToPageNoAlignmentCheck(rawNewPage);
689 } 704 }
690 705
691 partitionPageReset(newPage, bucket); 706 partitionPageReset(newPage, bucket);
692 bucket->activePagesHead = newPage; 707 bucket->activePagesHead = newPage;
693 return partitionPageAllocAndFillFreelist(newPage); 708 return partitionPageAllocAndFillFreelist(newPage);
694 } 709 }
695 710
696 static ALWAYS_INLINE void partitionFreePage(PartitionPage* page) 711 static ALWAYS_INLINE void partitionFreePage(PartitionRootBase* root, PartitionPa ge* page)
697 { 712 {
698 ASSERT(page->freelistHead); 713 ASSERT(page->freelistHead);
699 ASSERT(!page->numAllocatedSlots); 714 ASSERT(!page->numAllocatedSlots);
700 partitionUnusePage(page); 715 partitionUnusePage(root, page);
701 // We actually leave the freed page in the active list. We'll sweep it on 716 // We actually leave the freed page in the active list. We'll sweep it on
702 // to the free page list when we next walk the active page list. Pulling 717 // to the free page list when we next walk the active page list. Pulling
703 // this trick enables us to use a singly-linked page list for all cases, 718 // this trick enables us to use a singly-linked page list for all cases,
704 // which is critical in keeping the page metadata structure down to 32 719 // which is critical in keeping the page metadata structure down to 32
705 // bytes in size. 720 // bytes in size.
706 page->freelistHead = 0; 721 page->freelistHead = 0;
707 page->numUnprovisionedSlots = 0; 722 page->numUnprovisionedSlots = 0;
708 } 723 }
709 724
710 static ALWAYS_INLINE void partitionRegisterEmptyPage(PartitionPage* page) 725 static ALWAYS_INLINE void partitionRegisterEmptyPage(PartitionPage* page)
711 { 726 {
712 PartitionRootBase* root = partitionPageToRoot(page); 727 PartitionRootBase* root = partitionPageToRoot(page);
728
713 // If the page is already registered as empty, give it another life. 729 // If the page is already registered as empty, give it another life.
714 if (page->freeCacheIndex != -1) { 730 if (page->freeCacheIndex != -1) {
715 ASSERT(page->freeCacheIndex >= 0); 731 ASSERT(page->freeCacheIndex >= 0);
716 ASSERT(static_cast<unsigned>(page->freeCacheIndex) < kMaxFreeableSpans); 732 ASSERT(static_cast<unsigned>(page->freeCacheIndex) < kMaxFreeableSpans);
717 ASSERT(root->globalEmptyPageRing[page->freeCacheIndex] == page); 733 ASSERT(root->globalEmptyPageRing[page->freeCacheIndex] == page);
718 root->globalEmptyPageRing[page->freeCacheIndex] = 0; 734 root->globalEmptyPageRing[page->freeCacheIndex] = 0;
719 } 735 }
720 736
721 size_t currentIndex = root->globalEmptyPageRingIndex; 737 size_t currentIndex = root->globalEmptyPageRingIndex;
722 PartitionPage* pageToFree = root->globalEmptyPageRing[currentIndex]; 738 PartitionPage* pageToFree = root->globalEmptyPageRing[currentIndex];
723 // The page might well have been re-activated, filled up, etc. before we get 739 // The page might well have been re-activated, filled up, etc. before we get
724 // around to looking at it here. 740 // around to looking at it here.
725 if (pageToFree) { 741 if (pageToFree) {
726 ASSERT(pageToFree != &PartitionRootBase::gSeedPage); 742 ASSERT(pageToFree != &PartitionRootBase::gSeedPage);
727 ASSERT(pageToFree->freeCacheIndex >= 0); 743 ASSERT(pageToFree->freeCacheIndex >= 0);
728 ASSERT(static_cast<unsigned>(pageToFree->freeCacheIndex) < kMaxFreeableS pans); 744 ASSERT(static_cast<unsigned>(pageToFree->freeCacheIndex) < kMaxFreeableS pans);
729 ASSERT(pageToFree == root->globalEmptyPageRing[pageToFree->freeCacheInde x]); 745 ASSERT(pageToFree == root->globalEmptyPageRing[pageToFree->freeCacheInde x]);
730 if (!pageToFree->numAllocatedSlots && pageToFree->freelistHead) { 746 if (!pageToFree->numAllocatedSlots && pageToFree->freelistHead) {
731 // The page is still empty, and not freed, so _really_ free it. 747 // The page is still empty, and not freed, so _really_ free it.
732 partitionFreePage(pageToFree); 748 partitionFreePage(root, pageToFree);
733 } 749 }
734 pageToFree->freeCacheIndex = -1; 750 pageToFree->freeCacheIndex = -1;
735 } 751 }
736 752
737 // We put the empty slot span on our global list of "pages that were once 753 // We put the empty slot span on our global list of "pages that were once
738 // empty". thus providing it a bit of breathing room to get re-used before 754 // empty". thus providing it a bit of breathing room to get re-used before
739 // we really free it. This improves performance, particularly on Mac OS X 755 // we really free it. This improves performance, particularly on Mac OS X
740 // which has subpar memory management performance. 756 // which has subpar memory management performance.
741 root->globalEmptyPageRing[currentIndex] = page; 757 root->globalEmptyPageRing[currentIndex] = page;
742 page->freeCacheIndex = currentIndex; 758 page->freeCacheIndex = currentIndex;
743 ++currentIndex; 759 ++currentIndex;
744 if (currentIndex == kMaxFreeableSpans) 760 if (currentIndex == kMaxFreeableSpans)
745 currentIndex = 0; 761 currentIndex = 0;
746 root->globalEmptyPageRingIndex = currentIndex; 762 root->globalEmptyPageRingIndex = currentIndex;
747 } 763 }
748 764
749 void partitionFreeSlowPath(PartitionPage* page) 765 void partitionFreeSlowPath(PartitionPage* page)
750 { 766 {
751 PartitionBucket* bucket = page->bucket; 767 PartitionBucket* bucket = page->bucket;
752 ASSERT(page != &PartitionRootGeneric::gSeedPage); 768 ASSERT(page != &PartitionRootGeneric::gSeedPage);
753 ASSERT(bucket->activePagesHead != &PartitionRootGeneric::gSeedPage); 769 ASSERT(bucket->activePagesHead != &PartitionRootGeneric::gSeedPage);
754 if (LIKELY(page->numAllocatedSlots == 0)) { 770 if (LIKELY(page->numAllocatedSlots == 0)) {
755 // Page became fully unused. 771 // Page became fully unused.
756 if (UNLIKELY(partitionBucketIsDirectMapped(bucket))) { 772 if (UNLIKELY(partitionBucketIsDirectMapped(bucket))) {
757 partitionDirectUnmap(page); 773 partitionDirectUnmap(page);
758 return; 774 return;
759 } 775 }
760 // If it's the current page, attempt to change it. We'd prefer to leave 776 // If it's the current active page, attempt to change it. We'd prefer to leave
761 // the page empty as a gentle force towards defragmentation. 777 // the page empty as a gentle force towards defragmentation.
762 if (LIKELY(page == bucket->activePagesHead) && page->nextPage) { 778 if (LIKELY(page == bucket->activePagesHead) && page->nextPage) {
763 if (partitionSetNewActivePage(page->nextPage)) { 779 if (partitionSetNewActivePage(page->nextPage)) {
764 ASSERT(bucket->activePagesHead != page); 780 ASSERT(bucket->activePagesHead != page);
765 // Link the empty page back in after the new current page, to 781 // Link the empty page back in after the new current page, to
766 // avoid losing a reference to it. 782 // avoid losing a reference to it.
767 // TODO: consider walking the list to link the empty page after 783 // TODO: consider walking the list to link the empty page after
768 // all non-empty pages? 784 // all non-empty pages?
769 PartitionPage* currentPage = bucket->activePagesHead; 785 PartitionPage* currentPage = bucket->activePagesHead;
770 page->nextPage = currentPage->nextPage; 786 page->nextPage = currentPage->nextPage;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
820 if (newSize < currentSize) { 836 if (newSize < currentSize) {
821 size_t mapSize = partitionPageToDirectMapExtent(page)->mapSize; 837 size_t mapSize = partitionPageToDirectMapExtent(page)->mapSize;
822 838
823 // Don't reallocate in-place if new size is less than 80 % of the full 839 // Don't reallocate in-place if new size is less than 80 % of the full
824 // map size, to avoid holding on to too much unused address space. 840 // map size, to avoid holding on to too much unused address space.
825 if ((newSize / kSystemPageSize) * 5 < (mapSize / kSystemPageSize) * 4) 841 if ((newSize / kSystemPageSize) * 5 < (mapSize / kSystemPageSize) * 4)
826 return false; 842 return false;
827 843
828 // Shrink by decommitting unneeded pages and making them inaccessible. 844 // Shrink by decommitting unneeded pages and making them inaccessible.
829 size_t decommitSize = currentSize - newSize; 845 size_t decommitSize = currentSize - newSize;
830 decommitSystemPages(charPtr + newSize, decommitSize); 846 partitionDecommitSystemPages(root, charPtr + newSize, decommitSize);
831 setSystemPagesInaccessible(charPtr + newSize, decommitSize); 847 setSystemPagesInaccessible(charPtr + newSize, decommitSize);
832 } else if (newSize <= partitionPageToDirectMapExtent(page)->mapSize) { 848 } else if (newSize <= partitionPageToDirectMapExtent(page)->mapSize) {
833 // Grow within the actually allocated memory. Just need to make the 849 // Grow within the actually allocated memory. Just need to make the
834 // pages accessible again. 850 // pages accessible again.
835 size_t recommitSize = newSize - currentSize; 851 size_t recommitSize = newSize - currentSize;
836 setSystemPagesAccessible(charPtr + currentSize, recommitSize); 852 setSystemPagesAccessible(charPtr + currentSize, recommitSize);
837 recommitSystemPages(charPtr + currentSize, recommitSize); 853 partitionRecommitSystemPages(root, charPtr + currentSize, recommitSize);
838 854
839 #ifndef NDEBUG 855 #ifndef NDEBUG
840 memset(charPtr + currentSize, kUninitializedByte, recommitSize); 856 memset(charPtr + currentSize, kUninitializedByte, recommitSize);
841 #endif 857 #endif
842 } else { 858 } else {
843 // We can't perform the realloc in-place. 859 // We can't perform the realloc in-place.
844 // TODO: support this too when possible. 860 // TODO: support this too when possible.
845 return false; 861 return false;
846 } 862 }
847 863
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 printf("total live: %zu bytes\n", totalLive); 976 printf("total live: %zu bytes\n", totalLive);
961 printf("total resident: %zu bytes\n", totalResident); 977 printf("total resident: %zu bytes\n", totalResident);
962 printf("total freeable: %zu bytes\n", totalFreeable); 978 printf("total freeable: %zu bytes\n", totalFreeable);
963 fflush(stdout); 979 fflush(stdout);
964 } 980 }
965 981
966 #endif // !NDEBUG 982 #endif // !NDEBUG
967 983
968 } // namespace WTF 984 } // namespace WTF
969 985
OLDNEW
« no previous file with comments | « Source/wtf/PartitionAlloc.h ('k') | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698