| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2014 Google Inc. All rights reserved. | 2 * Copyright (C) 2014 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 12 matching lines...) Expand all Loading... |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 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 "platform/PurgeableVector.h" | 31 #include "platform/PurgeableVector.h" |
| 32 | 32 |
| 33 #include "public/platform/Platform.h" | 33 #include "base/memory/discardable_memory.h" |
| 34 #include "public/platform/WebDiscardableMemory.h" | 34 #include "base/memory/discardable_memory_allocator.h" |
| 35 #include "public/platform/WebProcessMemoryDump.h" | 35 #include "public/platform/WebProcessMemoryDump.h" |
| 36 #include "wtf/Assertions.h" | 36 #include "wtf/Assertions.h" |
| 37 #include "wtf/OwnPtr.h" | 37 #include "wtf/OwnPtr.h" |
| 38 #include "wtf/PassOwnPtr.h" | 38 #include "wtf/PassOwnPtr.h" |
| 39 #include "wtf/text/StringUTF8Adaptor.h" |
| 39 #include "wtf/text/WTFString.h" | 40 #include "wtf/text/WTFString.h" |
| 40 | 41 |
| 41 #include <cstring> | 42 #include <cstring> |
| 43 #include <utility> |
| 42 | 44 |
| 43 namespace blink { | 45 namespace blink { |
| 44 | 46 |
| 45 // WebDiscardableMemory allocations are expensive and page-grained. We only use | 47 // DiscardableMemory allocations are expensive and page-grained. We only use |
| 46 // them when there's a reasonable amount of memory to be saved by the OS | 48 // them when there's a reasonable amount of memory to be saved by the OS |
| 47 // discarding the memory. | 49 // discarding the memory. |
| 48 static const size_t minimumDiscardableAllocationSize = 4 * 4096; | 50 static const size_t minimumDiscardableAllocationSize = 4 * 4096; |
| 49 | 51 |
| 50 PurgeableVector::PurgeableVector(PurgeableOption purgeable) | 52 PurgeableVector::PurgeableVector(PurgeableOption purgeable) |
| 51 : m_discardableCapacity(0) | 53 : m_discardableCapacity(0) |
| 52 , m_discardableSize(0) | 54 , m_discardableSize(0) |
| 53 , m_isPurgeable(purgeable == Purgeable) | 55 , m_isPurgeable(purgeable == Purgeable) |
| 54 , m_locksCount(1) // The buffer is locked at creation. | 56 , m_locksCount(1) // The buffer is locked at creation. |
| 55 { | 57 { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 77 m_vector.reserveCapacity(capacity); | 79 m_vector.reserveCapacity(capacity); |
| 78 } | 80 } |
| 79 | 81 |
| 80 moveDataFromDiscardableToVector(); | 82 moveDataFromDiscardableToVector(); |
| 81 } | 83 } |
| 82 | 84 |
| 83 void PurgeableVector::onMemoryDump(const String& dumpName, WebProcessMemoryDump*
memoryDump) const | 85 void PurgeableVector::onMemoryDump(const String& dumpName, WebProcessMemoryDump*
memoryDump) const |
| 84 { | 86 { |
| 85 ASSERT(!(m_discardable && m_vector.size())); | 87 ASSERT(!(m_discardable && m_vector.size())); |
| 86 if (m_discardable) { | 88 if (m_discardable) { |
| 87 WebMemoryAllocatorDump* dump = m_discardable->createMemoryAllocatorDump(
dumpName, memoryDump); | 89 WebMemoryAllocatorDump* dump = memoryDump->createDiscardableMemoryAlloca
torDump( |
| 90 StringUTF8Adaptor(dumpName).asStringPiece().as_string(), m_discardab
le.get()); |
| 88 dump->addScalar("discardable_size", "bytes", m_discardableSize); | 91 dump->addScalar("discardable_size", "bytes", m_discardableSize); |
| 89 } else if (m_vector.size()) { | 92 } else if (m_vector.size()) { |
| 90 WebMemoryAllocatorDump* dump = memoryDump->createMemoryAllocatorDump(dum
pName); | 93 WebMemoryAllocatorDump* dump = memoryDump->createMemoryAllocatorDump(dum
pName); |
| 91 dump->addScalar("size", "bytes", m_vector.size()); | 94 dump->addScalar("size", "bytes", m_vector.size()); |
| 92 memoryDump->addSuballocation(dump->guid(), String(WTF::Partitions::kAllo
catedObjectPoolName)); | 95 memoryDump->addSuballocation(dump->guid(), String(WTF::Partitions::kAllo
catedObjectPoolName)); |
| 93 } | 96 } |
| 94 } | 97 } |
| 95 | 98 |
| 96 void PurgeableVector::moveDataFromDiscardableToVector() | 99 void PurgeableVector::moveDataFromDiscardableToVector() |
| 97 { | 100 { |
| 98 if (m_discardable) { | 101 if (m_discardable) { |
| 99 m_vector.append(static_cast<const char*>(m_discardable->data()), m_disca
rdableSize); | 102 m_vector.append(static_cast<const char*>(m_discardable->data()), m_disca
rdableSize); |
| 100 clearDiscardable(); | 103 clearDiscardable(); |
| 101 } | 104 } |
| 102 } | 105 } |
| 103 | 106 |
| 104 void PurgeableVector::clearDiscardable() | 107 void PurgeableVector::clearDiscardable() |
| 105 { | 108 { |
| 106 m_discardable.clear(); | 109 m_discardable = nullptr; |
| 107 m_discardableCapacity = 0; | 110 m_discardableCapacity = 0; |
| 108 m_discardableSize = 0; | 111 m_discardableSize = 0; |
| 109 } | 112 } |
| 110 | 113 |
| 111 void PurgeableVector::append(const char* data, size_t length) | 114 void PurgeableVector::append(const char* data, size_t length) |
| 112 { | 115 { |
| 113 ASSERT(isLocked()); | 116 ASSERT(isLocked()); |
| 114 | 117 |
| 115 if (!m_isPurgeable) { | 118 if (!m_isPurgeable) { |
| 116 m_vector.append(data, length); | 119 m_vector.append(data, length); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 bool PurgeableVector::lock() | 186 bool PurgeableVector::lock() |
| 184 { | 187 { |
| 185 ++m_locksCount; | 188 ++m_locksCount; |
| 186 if (m_locksCount > 1) | 189 if (m_locksCount > 1) |
| 187 return true; | 190 return true; |
| 188 | 191 |
| 189 ASSERT(m_locksCount == 1); | 192 ASSERT(m_locksCount == 1); |
| 190 if (!m_discardable) | 193 if (!m_discardable) |
| 191 return true; | 194 return true; |
| 192 | 195 |
| 193 return m_discardable->lock(); | 196 return m_discardable->Lock(); |
| 194 } | 197 } |
| 195 | 198 |
| 196 void PurgeableVector::unlock() | 199 void PurgeableVector::unlock() |
| 197 { | 200 { |
| 198 ASSERT(isLocked()); | 201 ASSERT(isLocked()); |
| 199 --m_locksCount; | 202 --m_locksCount; |
| 200 if (m_locksCount > 0) | 203 if (m_locksCount > 0) |
| 201 return; | 204 return; |
| 202 | 205 |
| 203 if (!m_vector.isEmpty()) { | 206 if (!m_vector.isEmpty()) { |
| 204 ASSERT(!m_discardable); | 207 ASSERT(!m_discardable); |
| 205 m_isPurgeable = true; | 208 m_isPurgeable = true; |
| 206 if (!reservePurgeableCapacity(m_vector.size(), UseExactCapacity)) | 209 if (!reservePurgeableCapacity(m_vector.size(), UseExactCapacity)) |
| 207 return; | 210 return; |
| 208 } | 211 } |
| 209 | 212 |
| 210 if (m_discardable) | 213 if (m_discardable) |
| 211 m_discardable->unlock(); | 214 m_discardable->Unlock(); |
| 212 } | 215 } |
| 213 | 216 |
| 214 bool PurgeableVector::isLocked() const | 217 bool PurgeableVector::isLocked() const |
| 215 { | 218 { |
| 216 ASSERT(m_locksCount >= 0); | 219 ASSERT(m_locksCount >= 0); |
| 217 return m_locksCount > 0; | 220 return m_locksCount > 0; |
| 218 } | 221 } |
| 219 | 222 |
| 220 bool PurgeableVector::reservePurgeableCapacity(size_t capacity, PurgeableAllocat
ionStrategy allocationStrategy) | 223 bool PurgeableVector::reservePurgeableCapacity(size_t capacity, PurgeableAllocat
ionStrategy allocationStrategy) |
| 221 { | 224 { |
| 222 ASSERT(m_isPurgeable); | 225 ASSERT(m_isPurgeable); |
| 223 | 226 |
| 224 if (m_discardable && m_discardableCapacity >= capacity) { | 227 if (m_discardable && m_discardableCapacity >= capacity) { |
| 225 ASSERT(!m_vector.capacity()); | 228 ASSERT(!m_vector.capacity()); |
| 226 return true; | 229 return true; |
| 227 } | 230 } |
| 228 | 231 |
| 229 if (capacity < minimumDiscardableAllocationSize) | 232 if (capacity < minimumDiscardableAllocationSize) |
| 230 return false; | 233 return false; |
| 231 | 234 |
| 232 if (allocationStrategy == UseExponentialGrowth) | 235 if (allocationStrategy == UseExponentialGrowth) |
| 233 capacity = adjustPurgeableCapacity(capacity); | 236 capacity = adjustPurgeableCapacity(capacity); |
| 234 | 237 |
| 235 OwnPtr<WebDiscardableMemory> discardable = adoptPtr( | 238 scoped_ptr<base::DiscardableMemory> discardable = |
| 236 Platform::current()->allocateAndLockDiscardableMemory(capacity)); | 239 base::DiscardableMemoryAllocator::GetInstance()->AllocateLockedDiscardab
leMemory(capacity); |
| 237 if (!discardable) { | 240 ASSERT(discardable); |
| 238 // Discardable memory is not supported. | |
| 239 m_isPurgeable = false; | |
| 240 return false; | |
| 241 } | |
| 242 | 241 |
| 243 m_discardableCapacity = capacity; | 242 m_discardableCapacity = capacity; |
| 244 // Copy the data that was either in the previous purgeable buffer or in the
vector to the new | 243 // Copy the data that was either in the previous purgeable buffer or in the
vector to the new |
| 245 // purgeable buffer. | 244 // purgeable buffer. |
| 246 if (m_discardable) { | 245 if (m_discardable) { |
| 247 memcpy(discardable->data(), m_discardable->data(), m_discardableSize); | 246 memcpy(discardable->data(), m_discardable->data(), m_discardableSize); |
| 248 } else { | 247 } else { |
| 249 memcpy(discardable->data(), m_vector.data(), m_vector.size()); | 248 memcpy(discardable->data(), m_vector.data(), m_vector.size()); |
| 250 m_discardableSize = m_vector.size(); | 249 m_discardableSize = m_vector.size(); |
| 251 m_vector.clear(); | 250 m_vector.clear(); |
| 252 } | 251 } |
| 253 | 252 |
| 254 m_discardable.swap(discardable); | 253 m_discardable = std::move(discardable); |
| 255 ASSERT(!m_vector.capacity()); | 254 ASSERT(!m_vector.capacity()); |
| 256 return true; | 255 return true; |
| 257 } | 256 } |
| 258 | 257 |
| 259 size_t PurgeableVector::adjustPurgeableCapacity(size_t capacity) const | 258 size_t PurgeableVector::adjustPurgeableCapacity(size_t capacity) const |
| 260 { | 259 { |
| 261 ASSERT(capacity >= minimumDiscardableAllocationSize); | 260 ASSERT(capacity >= minimumDiscardableAllocationSize); |
| 262 | 261 |
| 263 const float growthFactor = 1.5; | 262 const float growthFactor = 1.5; |
| 264 size_t newCapacity = std::max(capacity, static_cast<size_t>(m_discardableCap
acity * growthFactor)); | 263 size_t newCapacity = std::max(capacity, static_cast<size_t>(m_discardableCap
acity * growthFactor)); |
| 265 | 264 |
| 266 // Discardable memory has page-granularity so align to the next page here to
minimize | 265 // Discardable memory has page-granularity so align to the next page here to
minimize |
| 267 // fragmentation. | 266 // fragmentation. |
| 268 // Since the page size is only used below to minimize fragmentation it's sti
ll safe to use it | 267 // Since the page size is only used below to minimize fragmentation it's sti
ll safe to use it |
| 269 // even if it gets out of sync (e.g. due to the use of huge pages). | 268 // even if it gets out of sync (e.g. due to the use of huge pages). |
| 270 const size_t kPageSize = 4096; | 269 const size_t kPageSize = 4096; |
| 271 newCapacity = (newCapacity + kPageSize - 1) & ~(kPageSize - 1); | 270 newCapacity = (newCapacity + kPageSize - 1) & ~(kPageSize - 1); |
| 272 | 271 |
| 273 return std::max(capacity, newCapacity); // Overflow check. | 272 return std::max(capacity, newCapacity); // Overflow check. |
| 274 } | 273 } |
| 275 | 274 |
| 276 } // namespace blink | 275 } // namespace blink |
| OLD | NEW |