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