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 13 matching lines...) Expand all Loading... |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 #include "wtf/PartitionAlloc.h" | 32 #include "wtf/PartitionAlloc.h" |
33 | 33 |
| 34 #include "wtf/Alias.h" |
| 35 #include "wtf/Partitions.h" |
| 36 |
34 #include <string.h> | 37 #include <string.h> |
35 | 38 |
36 #ifndef NDEBUG | 39 #ifndef NDEBUG |
37 #include <stdio.h> | 40 #include <stdio.h> |
38 #endif | 41 #endif |
39 | 42 |
40 // Two partition pages are used as guard / metadata page so make sure the super | 43 // Two partition pages are used as guard / metadata page so make sure the super |
41 // page size is bigger. | 44 // page size is bigger. |
42 static_assert(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, "ok super page
size"); | 45 static_assert(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, "ok super page
size"); |
43 static_assert(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), "ok super page m
ultiple"); | 46 static_assert(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), "ok super page m
ultiple"); |
44 // Four system pages gives us room to hack out a still-guard-paged piece | 47 // Four system pages gives us room to hack out a still-guard-paged piece |
45 // of metadata in the middle of a guard partition page. | 48 // of metadata in the middle of a guard partition page. |
46 static_assert(WTF::kSystemPageSize * 4 <= WTF::kPartitionPageSize, "ok partition
page size"); | 49 static_assert(WTF::kSystemPageSize * 4 <= WTF::kPartitionPageSize, "ok partition
page size"); |
47 static_assert(!(WTF::kPartitionPageSize % WTF::kSystemPageSize), "ok partition p
age multiple"); | 50 static_assert(!(WTF::kPartitionPageSize % WTF::kSystemPageSize), "ok partition p
age multiple"); |
48 static_assert(sizeof(WTF::PartitionPage) <= WTF::kPageMetadataSize, "PartitionPa
ge should not be too big"); | 51 static_assert(sizeof(WTF::PartitionPage) <= WTF::kPageMetadataSize, "PartitionPa
ge should not be too big"); |
49 static_assert(sizeof(WTF::PartitionBucket) <= WTF::kPageMetadataSize, "Partition
Bucket should not be too big"); | 52 static_assert(sizeof(WTF::PartitionBucket) <= WTF::kPageMetadataSize, "Partition
Bucket should not be too big"); |
50 static_assert(sizeof(WTF::PartitionSuperPageExtentEntry) <= WTF::kPageMetadataSi
ze, "PartitionSuperPageExtentEntry should not be too big"); | 53 static_assert(sizeof(WTF::PartitionSuperPageExtentEntry) <= WTF::kPageMetadataSi
ze, "PartitionSuperPageExtentEntry should not be too big"); |
51 static_assert(WTF::kPageMetadataSize * WTF::kNumPartitionPagesPerSuperPage <= WT
F::kSystemPageSize, "page metadata fits in hole"); | 54 static_assert(WTF::kPageMetadataSize * WTF::kNumPartitionPagesPerSuperPage <= WT
F::kSystemPageSize, "page metadata fits in hole"); |
52 // Check that some of our zanier calculations worked out as expected. | 55 // Check that some of our zanier calculations worked out as expected. |
53 static_assert(WTF::kGenericSmallestBucket == 8, "generic smallest bucket"); | 56 static_assert(WTF::kGenericSmallestBucket == 8, "generic smallest bucket"); |
54 static_assert(WTF::kGenericMaxBucketed == 983040, "generic max bucketed"); | 57 static_assert(WTF::kGenericMaxBucketed == 983040, "generic max bucketed"); |
55 | 58 |
56 namespace WTF { | 59 namespace WTF { |
57 | 60 |
58 int PartitionRootBase::gInitializedLock = 0; | 61 int PartitionRootBase::gInitializedLock = 0; |
59 bool PartitionRootBase::gInitialized = false; | 62 bool PartitionRootBase::gInitialized = false; |
60 PartitionPage PartitionRootBase::gSeedPage; | 63 PartitionPage PartitionRootBase::gSeedPage; |
61 PartitionBucket PartitionRootBase::gPagedBucket; | 64 PartitionBucket PartitionRootBase::gPagedBucket; |
| 65 size_t (*PartitionRootBase::gMemoryUsageReportFunction)() = nullptr; |
62 | 66 |
63 static uint16_t partitionBucketNumSystemPages(size_t size) | 67 static uint16_t partitionBucketNumSystemPages(size_t size) |
64 { | 68 { |
65 // This works out reasonably for the current bucket sizes of the generic | 69 // This works out reasonably for the current bucket sizes of the generic |
66 // allocator, and the current values of partition page size and constants. | 70 // allocator, and the current values of partition page size and constants. |
67 // Specifically, we have enough room to always pack the slots perfectly into | 71 // Specifically, we have enough room to always pack the slots perfectly into |
68 // some number of system pages. The only waste is the waste associated with | 72 // some number of system pages. The only waste is the waste associated with |
69 // unfaulted pages (i.e. wasted address space). | 73 // unfaulted pages (i.e. wasted address space). |
70 // TODO: we end up using a lot of system pages for very small sizes. For | 74 // TODO: we end up using a lot of system pages for very small sizes. For |
71 // example, we'll use 12 system pages for slot size 24. The slot size is | 75 // example, we'll use 12 system pages for slot size 24. The slot size is |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 | 135 |
132 static void partitionBucketInitBase(PartitionBucket* bucket, PartitionRootBase*
root) | 136 static void partitionBucketInitBase(PartitionBucket* bucket, PartitionRootBase*
root) |
133 { | 137 { |
134 bucket->activePagesHead = &PartitionRootGeneric::gSeedPage; | 138 bucket->activePagesHead = &PartitionRootGeneric::gSeedPage; |
135 bucket->emptyPagesHead = 0; | 139 bucket->emptyPagesHead = 0; |
136 bucket->decommittedPagesHead = 0; | 140 bucket->decommittedPagesHead = 0; |
137 bucket->numFullPages = 0; | 141 bucket->numFullPages = 0; |
138 bucket->numSystemPagesPerSlotSpan = partitionBucketNumSystemPages(bucket->sl
otSize); | 142 bucket->numSystemPagesPerSlotSpan = partitionBucketNumSystemPages(bucket->sl
otSize); |
139 } | 143 } |
140 | 144 |
| 145 void partitionAllocGlobalInit(size_t (*memoryUsageReportFunc)()) |
| 146 { |
| 147 PartitionRootBase::gMemoryUsageReportFunction = memoryUsageReportFunc; |
| 148 } |
| 149 |
141 void partitionAllocInit(PartitionRoot* root, size_t numBuckets, size_t maxAlloca
tion) | 150 void partitionAllocInit(PartitionRoot* root, size_t numBuckets, size_t maxAlloca
tion) |
142 { | 151 { |
143 partitionAllocBaseInit(root); | 152 partitionAllocBaseInit(root); |
144 | 153 |
145 root->numBuckets = numBuckets; | 154 root->numBuckets = numBuckets; |
146 root->maxAllocation = maxAllocation; | 155 root->maxAllocation = maxAllocation; |
147 size_t i; | 156 size_t i; |
148 for (i = 0; i < root->numBuckets; ++i) { | 157 for (i = 0; i < root->numBuckets; ++i) { |
149 PartitionBucket* bucket = &root->buckets()[i]; | 158 PartitionBucket* bucket = &root->buckets()[i]; |
150 if (!i) | 159 if (!i) |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 return !foundLeak; | 301 return !foundLeak; |
293 } | 302 } |
294 | 303 |
295 #if !CPU(64BIT) | 304 #if !CPU(64BIT) |
296 static NEVER_INLINE void partitionOutOfMemoryWithLotsOfUncommitedPages() | 305 static NEVER_INLINE void partitionOutOfMemoryWithLotsOfUncommitedPages() |
297 { | 306 { |
298 IMMEDIATE_CRASH(); | 307 IMMEDIATE_CRASH(); |
299 } | 308 } |
300 #endif | 309 #endif |
301 | 310 |
302 static NEVER_INLINE void partitionOutOfMemory(const PartitionRootBase* root) | 311 static NEVER_INLINE void partitionOutOfMemoryUsing2G() |
| 312 { |
| 313 const void* signature = (void*)&partitionOutOfMemoryUsing2G; |
| 314 alias(signature); |
| 315 IMMEDIATE_CRASH(); |
| 316 } |
| 317 |
| 318 static NEVER_INLINE void partitionOutOfMemoryUsing1G() |
| 319 { |
| 320 const void* signature = (void*)&partitionOutOfMemoryUsing1G; |
| 321 alias(signature); |
| 322 IMMEDIATE_CRASH(); |
| 323 } |
| 324 |
| 325 static NEVER_INLINE void partitionOutOfMemoryUsing512M() |
| 326 { |
| 327 const void* signature = (void*)&partitionOutOfMemoryUsing512M; |
| 328 alias(signature); |
| 329 IMMEDIATE_CRASH(); |
| 330 } |
| 331 |
| 332 static NEVER_INLINE void partitionOutOfMemoryUsing256M() |
| 333 { |
| 334 const void* signature = (void*)&partitionOutOfMemoryUsing256M; |
| 335 alias(signature); |
| 336 IMMEDIATE_CRASH(); |
| 337 } |
| 338 |
| 339 static NEVER_INLINE void partitionOutOfMemoryUsing128M() |
| 340 { |
| 341 const void* signature = (void*)&partitionOutOfMemoryUsing128M; |
| 342 alias(signature); |
| 343 IMMEDIATE_CRASH(); |
| 344 } |
| 345 |
| 346 static NEVER_INLINE void partitionOutOfMemoryUsing64M() |
| 347 { |
| 348 const void* signature = (void*)&partitionOutOfMemoryUsing64M; |
| 349 alias(signature); |
| 350 IMMEDIATE_CRASH(); |
| 351 } |
| 352 |
| 353 static NEVER_INLINE void partitionOutOfMemoryUsing32M() |
| 354 { |
| 355 const void* signature = (void*)&partitionOutOfMemoryUsing32M; |
| 356 alias(signature); |
| 357 IMMEDIATE_CRASH(); |
| 358 } |
| 359 |
| 360 static NEVER_INLINE void partitionOutOfMemoryUsing16M() |
| 361 { |
| 362 const void* signature = (void*)&partitionOutOfMemoryUsing16M; |
| 363 alias(signature); |
| 364 IMMEDIATE_CRASH(); |
| 365 } |
| 366 |
| 367 static NEVER_INLINE void partitionOutOfMemoryUsingLessThan16M() |
| 368 { |
| 369 const void* signature = (void*)&partitionOutOfMemoryUsingLessThan16M; |
| 370 alias(signature); |
| 371 IMMEDIATE_CRASH(); |
| 372 } |
| 373 |
| 374 static void partitionOutOfMemory(const PartitionRootBase* root) |
303 { | 375 { |
304 #if !CPU(64BIT) | 376 #if !CPU(64BIT) |
305 // Check whether this OOM is due to a lot of super pages that are allocated | 377 // Check whether this OOM is due to a lot of super pages that are allocated |
306 // but not committed, probably due to http://crbug.com/421387. | 378 // but not committed, probably due to http://crbug.com/421387. |
307 if (root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages - root-
>totalSizeOfCommittedPages > kReasonableSizeOfUnusedPages) { | 379 if (root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages - root-
>totalSizeOfCommittedPages > kReasonableSizeOfUnusedPages) { |
308 partitionOutOfMemoryWithLotsOfUncommitedPages(); | 380 partitionOutOfMemoryWithLotsOfUncommitedPages(); |
309 } | 381 } |
310 #endif | 382 #endif |
311 IMMEDIATE_CRASH(); | 383 volatile size_t totalUsage = (*PartitionRootBase::gMemoryUsageReportFunction
)(); |
| 384 if (totalUsage >= 2UL * 1024 * 1024 * 1024) |
| 385 partitionOutOfMemoryUsing2G(); |
| 386 if (totalUsage >= 1UL * 1024 * 1024 * 1024) |
| 387 partitionOutOfMemoryUsing1G(); |
| 388 if (totalUsage >= 512 * 1024 * 1024) |
| 389 partitionOutOfMemoryUsing512M(); |
| 390 if (totalUsage >= 256 * 1024 * 1024) |
| 391 partitionOutOfMemoryUsing256M(); |
| 392 if (totalUsage >= 128 * 1024 * 1024) |
| 393 partitionOutOfMemoryUsing128M(); |
| 394 if (totalUsage >= 64 * 1024 * 1024) |
| 395 partitionOutOfMemoryUsing64M(); |
| 396 if (totalUsage >= 32 * 1024 * 1024) |
| 397 partitionOutOfMemoryUsing32M(); |
| 398 if (totalUsage >= 16 * 1024 * 1024) |
| 399 partitionOutOfMemoryUsing16M(); |
| 400 partitionOutOfMemoryUsingLessThan16M(); |
312 } | 401 } |
313 | 402 |
314 static NEVER_INLINE void partitionExcessiveAllocationSize() | 403 static NEVER_INLINE void partitionExcessiveAllocationSize() |
315 { | 404 { |
316 IMMEDIATE_CRASH(); | 405 IMMEDIATE_CRASH(); |
317 } | 406 } |
318 | 407 |
319 static NEVER_INLINE void partitionBucketFull() | 408 static NEVER_INLINE void partitionBucketFull() |
320 { | 409 { |
321 IMMEDIATE_CRASH(); | 410 IMMEDIATE_CRASH(); |
(...skipping 1074 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1396 partitionStats.totalDiscardableBytes += memoryStats[i].discardableBy
tes; | 1485 partitionStats.totalDiscardableBytes += memoryStats[i].discardableBy
tes; |
1397 if (!isLightDump) | 1486 if (!isLightDump) |
1398 partitionStatsDumper->partitionsDumpBucketStats(partitionName, &
memoryStats[i]); | 1487 partitionStatsDumper->partitionsDumpBucketStats(partitionName, &
memoryStats[i]); |
1399 } | 1488 } |
1400 } | 1489 } |
1401 partitionStatsDumper->partitionDumpTotals(partitionName, &partitionStats); | 1490 partitionStatsDumper->partitionDumpTotals(partitionName, &partitionStats); |
1402 } | 1491 } |
1403 | 1492 |
1404 } // namespace WTF | 1493 } // namespace WTF |
1405 | 1494 |
OLD | NEW |