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 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 double wasteRatio = (double) waste / (double) pageSize; | 91 double wasteRatio = (double) waste / (double) pageSize; |
92 if (wasteRatio < bestWasteRatio) { | 92 if (wasteRatio < bestWasteRatio) { |
93 bestWasteRatio = wasteRatio; | 93 bestWasteRatio = wasteRatio; |
94 bestPages = i; | 94 bestPages = i; |
95 } | 95 } |
96 } | 96 } |
97 ASSERT(bestPages > 0); | 97 ASSERT(bestPages > 0); |
98 return bestPages; | 98 return bestPages; |
99 } | 99 } |
100 | 100 |
101 static void parititonAllocBaseInit(PartitionRootBase* root) | 101 static void parititonAllocBaseInit(PartitionRootBase* root, NotifyCommittedMemor yChangedFunction notifyCommittedMemoryChangedFunction) |
102 { | 102 { |
103 ASSERT(!root->initialized); | 103 ASSERT(!root->initialized); |
104 | 104 |
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->totalSizeOfCommittedPages = 0; |
116 root->totalSizeOfSuperPages = 0; | 116 root->totalSizeOfSuperPages = 0; |
117 root->totalSizeOfDirectMappedPages = 0; | 117 root->totalSizeOfDirectMappedPages = 0; |
118 root->nextSuperPage = 0; | 118 root->nextSuperPage = 0; |
119 root->nextPartitionPage = 0; | 119 root->nextPartitionPage = 0; |
120 root->nextPartitionPageEnd = 0; | 120 root->nextPartitionPageEnd = 0; |
121 root->firstExtent = 0; | 121 root->firstExtent = 0; |
122 root->currentExtent = 0; | 122 root->currentExtent = 0; |
123 | 123 |
124 memset(&root->globalEmptyPageRing, '\0', sizeof(root->globalEmptyPageRing)); | 124 memset(&root->globalEmptyPageRing, '\0', sizeof(root->globalEmptyPageRing)); |
125 root->globalEmptyPageRingIndex = 0; | 125 root->globalEmptyPageRingIndex = 0; |
126 | 126 |
127 // This is a "magic" value so we can test if a root pointer is valid. | 127 // This is a "magic" value so we can test if a root pointer is valid. |
128 root->invertedSelf = ~reinterpret_cast<uintptr_t>(root); | 128 root->invertedSelf = ~reinterpret_cast<uintptr_t>(root); |
129 | |
130 root->notifyCommittedMemoryChangedFunction = notifyCommittedMemoryChangedFun ction; | |
129 } | 131 } |
130 | 132 |
131 static void partitionBucketInitBase(PartitionBucket* bucket, PartitionRootBase* root) | 133 static void partitionBucketInitBase(PartitionBucket* bucket, PartitionRootBase* root) |
132 { | 134 { |
133 bucket->activePagesHead = &PartitionRootGeneric::gSeedPage; | 135 bucket->activePagesHead = &PartitionRootGeneric::gSeedPage; |
134 bucket->freePagesHead = 0; | 136 bucket->freePagesHead = 0; |
135 bucket->numFullPages = 0; | 137 bucket->numFullPages = 0; |
136 bucket->numSystemPagesPerSlotSpan = partitionBucketNumSystemPages(bucket->sl otSize); | 138 bucket->numSystemPagesPerSlotSpan = partitionBucketNumSystemPages(bucket->sl otSize); |
137 } | 139 } |
138 | 140 |
139 void partitionAllocInit(PartitionRoot* root, size_t numBuckets, size_t maxAlloca tion) | 141 void partitionAllocInit(PartitionRoot* root, size_t numBuckets, size_t maxAlloca tion, NotifyCommittedMemoryChangedFunction notifyCommittedMemoryChangedFunction) |
140 { | 142 { |
141 parititonAllocBaseInit(root); | 143 parititonAllocBaseInit(root, notifyCommittedMemoryChangedFunction); |
142 | 144 |
143 root->numBuckets = numBuckets; | 145 root->numBuckets = numBuckets; |
144 root->maxAllocation = maxAllocation; | 146 root->maxAllocation = maxAllocation; |
145 size_t i; | 147 size_t i; |
146 for (i = 0; i < root->numBuckets; ++i) { | 148 for (i = 0; i < root->numBuckets; ++i) { |
147 PartitionBucket* bucket = &root->buckets()[i]; | 149 PartitionBucket* bucket = &root->buckets()[i]; |
148 if (!i) | 150 if (!i) |
149 bucket->slotSize = kAllocationGranularity; | 151 bucket->slotSize = kAllocationGranularity; |
150 else | 152 else |
151 bucket->slotSize = i << kBucketShift; | 153 bucket->slotSize = i << kBucketShift; |
152 partitionBucketInitBase(bucket, root); | 154 partitionBucketInitBase(bucket, root); |
153 } | 155 } |
154 } | 156 } |
155 | 157 |
156 void partitionAllocGenericInit(PartitionRootGeneric* root) | 158 void partitionAllocGenericInit(PartitionRootGeneric* root, NotifyCommittedMemory ChangedFunction notifyCommittedMemoryChangedFunction) |
157 { | 159 { |
158 parititonAllocBaseInit(root); | 160 parititonAllocBaseInit(root, notifyCommittedMemoryChangedFunction); |
159 | 161 |
160 root->lock = 0; | 162 root->lock = 0; |
161 | 163 |
162 // Precalculate some shift and mask constants used in the hot path. | 164 // Precalculate some shift and mask constants used in the hot path. |
163 // Example: malloc(41) == 101001 binary. | 165 // Example: malloc(41) == 101001 binary. |
164 // Order is 6 (1 << 6-1)==32 is highest bit set. | 166 // Order is 6 (1 << 6-1)==32 is highest bit set. |
165 // orderIndex is the next three MSB == 010 == 2. | 167 // orderIndex is the next three MSB == 010 == 2. |
166 // subOrderIndexMask is a mask for the remaining bits == 11 (masking to 01 f or the subOrderIndex). | 168 // subOrderIndexMask is a mask for the remaining bits == 11 (masking to 01 f or the subOrderIndex). |
167 size_t order; | 169 size_t order; |
168 for (order = 0; order <= kBitsPerSizet; ++order) { | 170 for (order = 0; order <= kBitsPerSizet; ++order) { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
321 #if !CPU(64BIT) | 323 #if !CPU(64BIT) |
322 // Check whether this OOM is due to a lot of super pages that are allocated | 324 // Check whether this OOM is due to a lot of super pages that are allocated |
323 // but not committed, probably due to http://crbug.com/421387. | 325 // but not committed, probably due to http://crbug.com/421387. |
324 if (root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages - root- >totalSizeOfCommittedPages > kReasonableSizeOfUnusedPages) { | 326 if (root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages - root- >totalSizeOfCommittedPages > kReasonableSizeOfUnusedPages) { |
325 partitionOutOfMemoryWithLotsOfUncommitedPages(); | 327 partitionOutOfMemoryWithLotsOfUncommitedPages(); |
326 } | 328 } |
327 #endif | 329 #endif |
328 IMMEDIATE_CRASH(); | 330 IMMEDIATE_CRASH(); |
329 } | 331 } |
330 | 332 |
333 static void partitionIncreaseCommittedPages(PartitionRootBase* root, size_t len) | |
haraken
2015/04/05 15:01:52
I added two separate functions (for increase and d
| |
334 { | |
335 root->totalSizeOfCommittedPages += len; | |
336 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
337 if (root->notifyCommittedMemoryChangedFunction) | |
338 root->notifyCommittedMemoryChangedFunction(); | |
339 } | |
340 | |
341 static void partitionDecreaseCommittedPages(PartitionRootBase* root, size_t len) | |
342 { | |
343 root->totalSizeOfCommittedPages -= len; | |
344 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
345 if (root->notifyCommittedMemoryChangedFunction) | |
346 root->notifyCommittedMemoryChangedFunction(); | |
347 } | |
348 | |
331 static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) | 349 static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) |
332 { | 350 { |
333 decommitSystemPages(addr, len); | 351 decommitSystemPages(addr, len); |
334 ASSERT(root->totalSizeOfCommittedPages >= len); | 352 partitionDecreaseCommittedPages(root, len); |
335 root->totalSizeOfCommittedPages -= len; | |
336 } | 353 } |
337 | 354 |
338 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) | 355 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) |
339 { | 356 { |
340 recommitSystemPages(addr, len); | 357 recommitSystemPages(addr, len); |
341 root->totalSizeOfCommittedPages += len; | 358 partitionIncreaseCommittedPages(root, len); |
342 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
343 } | 359 } |
344 | 360 |
345 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages) | 361 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages) |
346 { | 362 { |
347 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize)); | 363 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize)); |
348 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize)); | 364 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize)); |
349 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); | 365 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); |
350 size_t totalSize = kPartitionPageSize * numPartitionPages; | 366 size_t totalSize = kPartitionPageSize * numPartitionPages; |
351 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift; | 367 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift; |
352 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { | 368 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { |
353 // In this case, we can still hand out pages from the current super page | 369 // In this case, we can still hand out pages from the current super page |
354 // allocation. | 370 // allocation. |
355 char* ret = root->nextPartitionPage; | 371 char* ret = root->nextPartitionPage; |
356 root->nextPartitionPage += totalSize; | 372 root->nextPartitionPage += totalSize; |
357 root->totalSizeOfCommittedPages += totalSize; | 373 partitionIncreaseCommittedPages(root, totalSize); |
358 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages); | |
359 return ret; | 374 return ret; |
360 } | 375 } |
361 | 376 |
362 // Need a new super page. We want to allocate super pages in a continguous | 377 // Need a new super page. We want to allocate super pages in a continguous |
363 // address region as much as possible. This is important for not causing | 378 // address region as much as possible. This is important for not causing |
364 // page table bloat and not fragmenting address spaces in 32 bit architectur es. | 379 // page table bloat and not fragmenting address spaces in 32 bit architectur es. |
365 char* requestedAddress = root->nextSuperPage; | 380 char* requestedAddress = root->nextSuperPage; |
366 char* superPage = reinterpret_cast<char*>(allocPages(requestedAddress, kSupe rPageSize, kSuperPageSize, PageAccessible)); | 381 char* superPage = reinterpret_cast<char*>(allocPages(requestedAddress, kSupe rPageSize, kSuperPageSize, PageAccessible)); |
367 if (UNLIKELY(!superPage)) | 382 if (UNLIKELY(!superPage)) |
368 return 0; | 383 return 0; |
369 | 384 |
370 root->totalSizeOfSuperPages += kSuperPageSize; | 385 root->totalSizeOfSuperPages += kSuperPageSize; |
371 root->totalSizeOfCommittedPages += totalSize; | 386 partitionIncreaseCommittedPages(root, totalSize); |
372 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
373 | 387 |
374 root->nextSuperPage = superPage + kSuperPageSize; | 388 root->nextSuperPage = superPage + kSuperPageSize; |
375 char* ret = superPage + kPartitionPageSize; | 389 char* ret = superPage + kPartitionPageSize; |
376 root->nextPartitionPage = ret + totalSize; | 390 root->nextPartitionPage = ret + totalSize; |
377 root->nextPartitionPageEnd = root->nextSuperPage - kPartitionPageSize; | 391 root->nextPartitionPageEnd = root->nextSuperPage - kPartitionPageSize; |
378 // Make the first partition page in the super page a guard page, but leave a | 392 // Make the first partition page in the super page a guard page, but leave a |
379 // hole in the middle. | 393 // hole in the middle. |
380 // This is where we put page metadata and also a tiny amount of extent | 394 // This is where we put page metadata and also a tiny amount of extent |
381 // metadata. | 395 // metadata. |
382 setSystemPagesInaccessible(superPage, kSystemPageSize); | 396 setSystemPagesInaccessible(superPage, kSystemPageSize); |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
605 // - The first few system pages are the partition page in which the super | 619 // - The first few system pages are the partition page in which the super |
606 // page metadata is stored. We fault just one system page out of a partition | 620 // page metadata is stored. We fault just one system page out of a partition |
607 // page sized clump. | 621 // page sized clump. |
608 // - We add a trailing guard page. | 622 // - We add a trailing guard page. |
609 size_t mapSize = size + kPartitionPageSize + kSystemPageSize; | 623 size_t mapSize = size + kPartitionPageSize + kSystemPageSize; |
610 // Round up to the allocation granularity. | 624 // Round up to the allocation granularity. |
611 mapSize += kPageAllocationGranularityOffsetMask; | 625 mapSize += kPageAllocationGranularityOffsetMask; |
612 mapSize &= kPageAllocationGranularityBaseMask; | 626 mapSize &= kPageAllocationGranularityBaseMask; |
613 | 627 |
614 size_t committedPageSize = size + kSystemPageSize; | 628 size_t committedPageSize = size + kSystemPageSize; |
615 root->totalSizeOfCommittedPages += committedPageSize; | |
616 root->totalSizeOfDirectMappedPages += committedPageSize; | 629 root->totalSizeOfDirectMappedPages += committedPageSize; |
617 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | 630 partitionIncreaseCommittedPages(root, committedPageSize); |
618 | 631 |
619 // TODO: we may want to let the operating system place these allocations | 632 // TODO: we may want to let the operating system place these allocations |
620 // where it pleases. On 32-bit, this might limit address space | 633 // where it pleases. On 32-bit, this might limit address space |
621 // fragmentation and on 64-bit, this might have useful savings for TLB | 634 // fragmentation and on 64-bit, this might have useful savings for TLB |
622 // and page table overhead. | 635 // and page table overhead. |
623 // TODO: if upsizing realloc()s are common on large sizes, we could | 636 // TODO: if upsizing realloc()s are common on large sizes, we could |
624 // consider over-allocating address space on 64-bit, "just in case". | 637 // consider over-allocating address space on 64-bit, "just in case". |
625 // TODO: consider pre-populating page tables (e.g. MAP_POPULATE on Linux, | 638 // TODO: consider pre-populating page tables (e.g. MAP_POPULATE on Linux, |
626 // MADV_WILLNEED on POSIX). | 639 // MADV_WILLNEED on POSIX). |
627 // TODO: these pages will be zero-filled. Consider internalizing an | 640 // TODO: these pages will be zero-filled. Consider internalizing an |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
670 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) | 683 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) |
671 { | 684 { |
672 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize; | 685 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize; |
673 | 686 |
674 // Add on the size of the trailing guard page and preceeding partition | 687 // Add on the size of the trailing guard page and preceeding partition |
675 // page. | 688 // page. |
676 unmapSize += kPartitionPageSize + kSystemPageSize; | 689 unmapSize += kPartitionPageSize + kSystemPageSize; |
677 | 690 |
678 PartitionRootBase* root = partitionPageToRoot(page); | 691 PartitionRootBase* root = partitionPageToRoot(page); |
679 size_t uncommittedPageSize = page->bucket->slotSize + kSystemPageSize; | 692 size_t uncommittedPageSize = page->bucket->slotSize + kSystemPageSize; |
680 ASSERT(root->totalSizeOfCommittedPages >= uncommittedPageSize); | 693 partitionDecreaseCommittedPages(root, uncommittedPageSize); |
681 root->totalSizeOfCommittedPages -= uncommittedPageSize; | |
682 ASSERT(root->totalSizeOfDirectMappedPages >= uncommittedPageSize); | 694 ASSERT(root->totalSizeOfDirectMappedPages >= uncommittedPageSize); |
683 root->totalSizeOfDirectMappedPages -= uncommittedPageSize; | 695 root->totalSizeOfDirectMappedPages -= uncommittedPageSize; |
684 | 696 |
685 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); | 697 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); |
686 | 698 |
687 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | 699 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); |
688 // Account for the mapping starting a partition page before the actual | 700 // Account for the mapping starting a partition page before the actual |
689 // allocation address. | 701 // allocation address. |
690 ptr -= kPartitionPageSize; | 702 ptr -= kPartitionPageSize; |
691 | 703 |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1041 printf("total live: %zu bytes\n", totalLive); | 1053 printf("total live: %zu bytes\n", totalLive); |
1042 printf("total resident: %zu bytes\n", totalResident); | 1054 printf("total resident: %zu bytes\n", totalResident); |
1043 printf("total freeable: %zu bytes\n", totalFreeable); | 1055 printf("total freeable: %zu bytes\n", totalFreeable); |
1044 fflush(stdout); | 1056 fflush(stdout); |
1045 } | 1057 } |
1046 | 1058 |
1047 #endif // !NDEBUG | 1059 #endif // !NDEBUG |
1048 | 1060 |
1049 } // namespace WTF | 1061 } // namespace WTF |
1050 | 1062 |
OLD | NEW |