| 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 18 matching lines...) Expand all Loading... |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #include "wtf/Partitions.h" | 31 #include "wtf/Partitions.h" |
| 32 | 32 |
| 33 #include "base/debug/alias.h" | 33 #include "base/debug/alias.h" |
| 34 #include "wtf/MainThread.h" | 34 #include "wtf/MainThread.h" |
| 35 #include "wtf/PartitionAllocator.h" | 35 #include "wtf/PartitionAllocator.h" |
| 36 | 36 |
| 37 namespace WTF { | 37 namespace WTF { |
| 38 | 38 |
| 39 const char* const Partitions::kAllocatedObjectPoolName = "partition_alloc/alloca
ted_objects"; | 39 const char* const Partitions::kAllocatedObjectPoolName = |
| 40 "partition_alloc/allocated_objects"; |
| 40 | 41 |
| 41 SpinLock Partitions::s_initializationLock; | 42 SpinLock Partitions::s_initializationLock; |
| 42 bool Partitions::s_initialized = false; | 43 bool Partitions::s_initialized = false; |
| 43 | 44 |
| 44 PartitionAllocatorGeneric Partitions::m_fastMallocAllocator; | 45 PartitionAllocatorGeneric Partitions::m_fastMallocAllocator; |
| 45 PartitionAllocatorGeneric Partitions::m_bufferAllocator; | 46 PartitionAllocatorGeneric Partitions::m_bufferAllocator; |
| 46 SizeSpecificPartitionAllocator<3328> Partitions::m_nodeAllocator; | 47 SizeSpecificPartitionAllocator<3328> Partitions::m_nodeAllocator; |
| 47 SizeSpecificPartitionAllocator<1024> Partitions::m_layoutAllocator; | 48 SizeSpecificPartitionAllocator<1024> Partitions::m_layoutAllocator; |
| 48 HistogramEnumerationFunction Partitions::m_histogramEnumeration = nullptr; | 49 HistogramEnumerationFunction Partitions::m_histogramEnumeration = nullptr; |
| 49 | 50 |
| 50 void Partitions::initialize(HistogramEnumerationFunction histogramEnumeration) | 51 void Partitions::initialize(HistogramEnumerationFunction histogramEnumeration) { |
| 51 { | 52 SpinLock::Guard guard(s_initializationLock); |
| 52 SpinLock::Guard guard(s_initializationLock); | |
| 53 | 53 |
| 54 if (!s_initialized) { | 54 if (!s_initialized) { |
| 55 partitionAllocGlobalInit(&Partitions::handleOutOfMemory); | 55 partitionAllocGlobalInit(&Partitions::handleOutOfMemory); |
| 56 m_fastMallocAllocator.init(); | 56 m_fastMallocAllocator.init(); |
| 57 m_bufferAllocator.init(); | 57 m_bufferAllocator.init(); |
| 58 m_nodeAllocator.init(); | 58 m_nodeAllocator.init(); |
| 59 m_layoutAllocator.init(); | 59 m_layoutAllocator.init(); |
| 60 m_histogramEnumeration = histogramEnumeration; | 60 m_histogramEnumeration = histogramEnumeration; |
| 61 s_initialized = true; | 61 s_initialized = true; |
| 62 } | 62 } |
| 63 } | 63 } |
| 64 | 64 |
| 65 void Partitions::shutdown() | 65 void Partitions::shutdown() { |
| 66 { | 66 SpinLock::Guard guard(s_initializationLock); |
| 67 SpinLock::Guard guard(s_initializationLock); | |
| 68 | 67 |
| 69 // We could ASSERT here for a memory leak within the partition, but it leads | 68 // We could ASSERT here for a memory leak within the partition, but it leads |
| 70 // to very hard to diagnose ASSERTs, so it's best to leave leak checking for | 69 // to very hard to diagnose ASSERTs, so it's best to leave leak checking for |
| 71 // the valgrind and heapcheck bots, which run without partitions. | 70 // the valgrind and heapcheck bots, which run without partitions. |
| 72 if (s_initialized) { | 71 if (s_initialized) { |
| 73 (void) m_layoutAllocator.shutdown(); | 72 (void)m_layoutAllocator.shutdown(); |
| 74 (void) m_nodeAllocator.shutdown(); | 73 (void)m_nodeAllocator.shutdown(); |
| 75 (void) m_bufferAllocator.shutdown(); | 74 (void)m_bufferAllocator.shutdown(); |
| 76 (void) m_fastMallocAllocator.shutdown(); | 75 (void)m_fastMallocAllocator.shutdown(); |
| 77 } | 76 } |
| 78 } | 77 } |
| 79 | 78 |
| 80 void Partitions::decommitFreeableMemory() | 79 void Partitions::decommitFreeableMemory() { |
| 81 { | 80 RELEASE_ASSERT(isMainThread()); |
| 82 RELEASE_ASSERT(isMainThread()); | 81 if (!s_initialized) |
| 83 if (!s_initialized) | 82 return; |
| 84 return; | |
| 85 | 83 |
| 86 partitionPurgeMemoryGeneric(bufferPartition(), PartitionPurgeDecommitEmptyPa
ges); | 84 partitionPurgeMemoryGeneric(bufferPartition(), |
| 87 partitionPurgeMemoryGeneric(fastMallocPartition(), PartitionPurgeDecommitEmp
tyPages); | 85 PartitionPurgeDecommitEmptyPages); |
| 88 partitionPurgeMemory(nodePartition(), PartitionPurgeDecommitEmptyPages); | 86 partitionPurgeMemoryGeneric(fastMallocPartition(), |
| 89 partitionPurgeMemory(layoutPartition(), PartitionPurgeDecommitEmptyPages); | 87 PartitionPurgeDecommitEmptyPages); |
| 88 partitionPurgeMemory(nodePartition(), PartitionPurgeDecommitEmptyPages); |
| 89 partitionPurgeMemory(layoutPartition(), PartitionPurgeDecommitEmptyPages); |
| 90 } | 90 } |
| 91 | 91 |
| 92 void Partitions::reportMemoryUsageHistogram() | 92 void Partitions::reportMemoryUsageHistogram() { |
| 93 { | 93 static size_t supportedMaxSizeInMB = 4 * 1024; |
| 94 static size_t supportedMaxSizeInMB = 4 * 1024; | 94 static size_t observedMaxSizeInMB = 0; |
| 95 static size_t observedMaxSizeInMB = 0; | |
| 96 | 95 |
| 97 if (!m_histogramEnumeration) | 96 if (!m_histogramEnumeration) |
| 98 return; | 97 return; |
| 99 // We only report the memory in the main thread. | 98 // We only report the memory in the main thread. |
| 100 if (!isMainThread()) | 99 if (!isMainThread()) |
| 101 return; | 100 return; |
| 102 // +1 is for rounding up the sizeInMB. | 101 // +1 is for rounding up the sizeInMB. |
| 103 size_t sizeInMB = Partitions::totalSizeOfCommittedPages() / 1024 / 1024 + 1; | 102 size_t sizeInMB = Partitions::totalSizeOfCommittedPages() / 1024 / 1024 + 1; |
| 104 if (sizeInMB >= supportedMaxSizeInMB) | 103 if (sizeInMB >= supportedMaxSizeInMB) |
| 105 sizeInMB = supportedMaxSizeInMB - 1; | 104 sizeInMB = supportedMaxSizeInMB - 1; |
| 106 if (sizeInMB > observedMaxSizeInMB) { | 105 if (sizeInMB > observedMaxSizeInMB) { |
| 107 // Send a UseCounter only when we see the highest memory usage | 106 // Send a UseCounter only when we see the highest memory usage |
| 108 // we've ever seen. | 107 // we've ever seen. |
| 109 m_histogramEnumeration("PartitionAlloc.CommittedSize", sizeInMB, support
edMaxSizeInMB); | 108 m_histogramEnumeration("PartitionAlloc.CommittedSize", sizeInMB, |
| 110 observedMaxSizeInMB = sizeInMB; | 109 supportedMaxSizeInMB); |
| 111 } | 110 observedMaxSizeInMB = sizeInMB; |
| 111 } |
| 112 } | 112 } |
| 113 | 113 |
| 114 void Partitions::dumpMemoryStats(bool isLightDump, PartitionStatsDumper* partiti
onStatsDumper) | 114 void Partitions::dumpMemoryStats(bool isLightDump, |
| 115 { | 115 PartitionStatsDumper* partitionStatsDumper) { |
| 116 // Object model and rendering partitions are not thread safe and can be | 116 // Object model and rendering partitions are not thread safe and can be |
| 117 // accessed only on the main thread. | 117 // accessed only on the main thread. |
| 118 ASSERT(isMainThread()); | 118 ASSERT(isMainThread()); |
| 119 | 119 |
| 120 decommitFreeableMemory(); | 120 decommitFreeableMemory(); |
| 121 partitionDumpStatsGeneric(fastMallocPartition(), "fast_malloc", isLightDump,
partitionStatsDumper); | 121 partitionDumpStatsGeneric(fastMallocPartition(), "fast_malloc", isLightDump, |
| 122 partitionDumpStatsGeneric(bufferPartition(), "buffer", isLightDump, partitio
nStatsDumper); | 122 partitionStatsDumper); |
| 123 partitionDumpStats(nodePartition(), "node", isLightDump, partitionStatsDumpe
r); | 123 partitionDumpStatsGeneric(bufferPartition(), "buffer", isLightDump, |
| 124 partitionDumpStats(layoutPartition(), "layout", isLightDump, partitionStatsD
umper); | 124 partitionStatsDumper); |
| 125 partitionDumpStats(nodePartition(), "node", isLightDump, |
| 126 partitionStatsDumper); |
| 127 partitionDumpStats(layoutPartition(), "layout", isLightDump, |
| 128 partitionStatsDumper); |
| 125 } | 129 } |
| 126 | 130 |
| 127 static NEVER_INLINE void partitionsOutOfMemoryUsing2G() | 131 static NEVER_INLINE void partitionsOutOfMemoryUsing2G() { |
| 128 { | 132 size_t signature = 2UL * 1024 * 1024 * 1024; |
| 129 size_t signature = 2UL * 1024 * 1024 * 1024; | 133 base::debug::Alias(&signature); |
| 130 base::debug::Alias(&signature); | 134 IMMEDIATE_CRASH(); |
| 131 IMMEDIATE_CRASH(); | |
| 132 } | 135 } |
| 133 | 136 |
| 134 static NEVER_INLINE void partitionsOutOfMemoryUsing1G() | 137 static NEVER_INLINE void partitionsOutOfMemoryUsing1G() { |
| 135 { | 138 size_t signature = 1UL * 1024 * 1024 * 1024; |
| 136 size_t signature = 1UL * 1024 * 1024 * 1024; | 139 base::debug::Alias(&signature); |
| 137 base::debug::Alias(&signature); | 140 IMMEDIATE_CRASH(); |
| 138 IMMEDIATE_CRASH(); | |
| 139 } | 141 } |
| 140 | 142 |
| 141 static NEVER_INLINE void partitionsOutOfMemoryUsing512M() | 143 static NEVER_INLINE void partitionsOutOfMemoryUsing512M() { |
| 142 { | 144 size_t signature = 512 * 1024 * 1024; |
| 143 size_t signature = 512 * 1024 * 1024; | 145 base::debug::Alias(&signature); |
| 144 base::debug::Alias(&signature); | 146 IMMEDIATE_CRASH(); |
| 145 IMMEDIATE_CRASH(); | |
| 146 } | 147 } |
| 147 | 148 |
| 148 static NEVER_INLINE void partitionsOutOfMemoryUsing256M() | 149 static NEVER_INLINE void partitionsOutOfMemoryUsing256M() { |
| 149 { | 150 size_t signature = 256 * 1024 * 1024; |
| 150 size_t signature = 256 * 1024 * 1024; | 151 base::debug::Alias(&signature); |
| 151 base::debug::Alias(&signature); | 152 IMMEDIATE_CRASH(); |
| 152 IMMEDIATE_CRASH(); | |
| 153 } | 153 } |
| 154 | 154 |
| 155 static NEVER_INLINE void partitionsOutOfMemoryUsing128M() | 155 static NEVER_INLINE void partitionsOutOfMemoryUsing128M() { |
| 156 { | 156 size_t signature = 128 * 1024 * 1024; |
| 157 size_t signature = 128 * 1024 * 1024; | 157 base::debug::Alias(&signature); |
| 158 base::debug::Alias(&signature); | 158 IMMEDIATE_CRASH(); |
| 159 IMMEDIATE_CRASH(); | |
| 160 } | 159 } |
| 161 | 160 |
| 162 static NEVER_INLINE void partitionsOutOfMemoryUsing64M() | 161 static NEVER_INLINE void partitionsOutOfMemoryUsing64M() { |
| 163 { | 162 size_t signature = 64 * 1024 * 1024; |
| 164 size_t signature = 64 * 1024 * 1024; | 163 base::debug::Alias(&signature); |
| 165 base::debug::Alias(&signature); | 164 IMMEDIATE_CRASH(); |
| 166 IMMEDIATE_CRASH(); | |
| 167 } | 165 } |
| 168 | 166 |
| 169 static NEVER_INLINE void partitionsOutOfMemoryUsing32M() | 167 static NEVER_INLINE void partitionsOutOfMemoryUsing32M() { |
| 170 { | 168 size_t signature = 32 * 1024 * 1024; |
| 171 size_t signature = 32 * 1024 * 1024; | 169 base::debug::Alias(&signature); |
| 172 base::debug::Alias(&signature); | 170 IMMEDIATE_CRASH(); |
| 173 IMMEDIATE_CRASH(); | |
| 174 } | 171 } |
| 175 | 172 |
| 176 static NEVER_INLINE void partitionsOutOfMemoryUsing16M() | 173 static NEVER_INLINE void partitionsOutOfMemoryUsing16M() { |
| 177 { | 174 size_t signature = 16 * 1024 * 1024; |
| 178 size_t signature = 16 * 1024 * 1024; | 175 base::debug::Alias(&signature); |
| 179 base::debug::Alias(&signature); | 176 IMMEDIATE_CRASH(); |
| 180 IMMEDIATE_CRASH(); | |
| 181 } | 177 } |
| 182 | 178 |
| 183 static NEVER_INLINE void partitionsOutOfMemoryUsingLessThan16M() | 179 static NEVER_INLINE void partitionsOutOfMemoryUsingLessThan16M() { |
| 184 { | 180 size_t signature = 16 * 1024 * 1024 - 1; |
| 185 size_t signature = 16 * 1024 * 1024 - 1; | 181 base::debug::Alias(&signature); |
| 186 base::debug::Alias(&signature); | 182 IMMEDIATE_CRASH(); |
| 187 IMMEDIATE_CRASH(); | |
| 188 } | 183 } |
| 189 | 184 |
| 190 void Partitions::handleOutOfMemory() | 185 void Partitions::handleOutOfMemory() { |
| 191 { | 186 volatile size_t totalUsage = totalSizeOfCommittedPages(); |
| 192 volatile size_t totalUsage = totalSizeOfCommittedPages(); | |
| 193 | 187 |
| 194 if (totalUsage >= 2UL * 1024 * 1024 * 1024) | 188 if (totalUsage >= 2UL * 1024 * 1024 * 1024) |
| 195 partitionsOutOfMemoryUsing2G(); | 189 partitionsOutOfMemoryUsing2G(); |
| 196 if (totalUsage >= 1UL * 1024 * 1024 * 1024) | 190 if (totalUsage >= 1UL * 1024 * 1024 * 1024) |
| 197 partitionsOutOfMemoryUsing1G(); | 191 partitionsOutOfMemoryUsing1G(); |
| 198 if (totalUsage >= 512 * 1024 * 1024) | 192 if (totalUsage >= 512 * 1024 * 1024) |
| 199 partitionsOutOfMemoryUsing512M(); | 193 partitionsOutOfMemoryUsing512M(); |
| 200 if (totalUsage >= 256 * 1024 * 1024) | 194 if (totalUsage >= 256 * 1024 * 1024) |
| 201 partitionsOutOfMemoryUsing256M(); | 195 partitionsOutOfMemoryUsing256M(); |
| 202 if (totalUsage >= 128 * 1024 * 1024) | 196 if (totalUsage >= 128 * 1024 * 1024) |
| 203 partitionsOutOfMemoryUsing128M(); | 197 partitionsOutOfMemoryUsing128M(); |
| 204 if (totalUsage >= 64 * 1024 * 1024) | 198 if (totalUsage >= 64 * 1024 * 1024) |
| 205 partitionsOutOfMemoryUsing64M(); | 199 partitionsOutOfMemoryUsing64M(); |
| 206 if (totalUsage >= 32 * 1024 * 1024) | 200 if (totalUsage >= 32 * 1024 * 1024) |
| 207 partitionsOutOfMemoryUsing32M(); | 201 partitionsOutOfMemoryUsing32M(); |
| 208 if (totalUsage >= 16 * 1024 * 1024) | 202 if (totalUsage >= 16 * 1024 * 1024) |
| 209 partitionsOutOfMemoryUsing16M(); | 203 partitionsOutOfMemoryUsing16M(); |
| 210 partitionsOutOfMemoryUsingLessThan16M(); | 204 partitionsOutOfMemoryUsingLessThan16M(); |
| 211 } | 205 } |
| 212 | 206 |
| 213 } // namespace WTF | 207 } // namespace WTF |
| OLD | NEW |