OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/child_discardable_shared_memory_manager.h" | 5 #include "content/child/child_discardable_shared_memory_manager.h" |
6 | 6 |
| 7 #include "base/debug/crash_logging.h" |
7 #include "base/memory/discardable_shared_memory.h" | 8 #include "base/memory/discardable_shared_memory.h" |
8 #include "base/process/process_metrics.h" | 9 #include "base/process/process_metrics.h" |
| 10 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/trace_event/trace_event.h" |
9 #include "content/common/child_process_messages.h" | 12 #include "content/common/child_process_messages.h" |
10 | 13 |
11 namespace content { | 14 namespace content { |
12 namespace { | 15 namespace { |
13 | 16 |
14 // Default allocation size. | 17 // Default allocation size. |
15 const size_t kAllocationSize = 4 * 1024 * 1024; | 18 const size_t kAllocationSize = 4 * 1024 * 1024; |
16 | 19 |
17 class DiscardableMemoryShmemChunkImpl | 20 class DiscardableMemoryShmemChunkImpl |
18 : public base::DiscardableMemoryShmemChunk { | 21 : public base::DiscardableMemoryShmemChunk { |
(...skipping 17 matching lines...) Expand all Loading... |
36 ChildDiscardableSharedMemoryManager* manager_; | 39 ChildDiscardableSharedMemoryManager* manager_; |
37 scoped_ptr<DiscardableSharedMemoryHeap::Span> span_; | 40 scoped_ptr<DiscardableSharedMemoryHeap::Span> span_; |
38 | 41 |
39 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmemChunkImpl); | 42 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmemChunkImpl); |
40 }; | 43 }; |
41 | 44 |
42 } // namespace | 45 } // namespace |
43 | 46 |
44 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager( | 47 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager( |
45 ThreadSafeSender* sender) | 48 ThreadSafeSender* sender) |
46 : heap_(base::GetPageSize()), sender_(sender) { | 49 : heap_(base::GetPageSize()), sender_(sender), bytes_allocated_(0) { |
47 } | 50 } |
48 | 51 |
49 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() { | 52 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() { |
| 53 if (bytes_allocated_) |
| 54 BytesAllocatedChanged(0); |
50 } | 55 } |
51 | 56 |
52 scoped_ptr<base::DiscardableMemoryShmemChunk> | 57 scoped_ptr<base::DiscardableMemoryShmemChunk> |
53 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( | 58 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( |
54 size_t size) { | 59 size_t size) { |
55 base::AutoLock lock(lock_); | 60 base::AutoLock lock(lock_); |
56 | 61 |
57 DCHECK_NE(size, 0u); | 62 DCHECK_NE(size, 0u); |
58 | 63 |
59 // Round up to multiple of page size. | 64 // Round up to multiple of page size. |
60 size_t pages = (size + base::GetPageSize() - 1) / base::GetPageSize(); | 65 size_t pages = (size + base::GetPageSize() - 1) / base::GetPageSize(); |
61 | 66 |
62 for (;;) { | 67 for (;;) { |
63 // Search free list for available space. | 68 // Search free list for available space. |
64 scoped_ptr<DiscardableSharedMemoryHeap::Span> free_span = | 69 scoped_ptr<DiscardableSharedMemoryHeap::Span> free_span = |
65 heap_.SearchFreeList(pages); | 70 heap_.SearchFreeList(pages); |
66 if (!free_span.get()) | 71 if (!free_span.get()) |
67 break; | 72 break; |
68 | 73 |
69 // Attempt to lock |free_span|. Delete span and search free list again | 74 // Attempt to lock |free_span|. Delete span and search free list again |
70 // if locking failed. | 75 // if locking failed. |
71 if (free_span->shared_memory()->Lock( | 76 if (free_span->shared_memory()->Lock( |
72 free_span->start() * base::GetPageSize() - | 77 free_span->start() * base::GetPageSize() - |
73 reinterpret_cast<size_t>(free_span->shared_memory()->memory()), | 78 reinterpret_cast<size_t>(free_span->shared_memory()->memory()), |
74 free_span->length() * base::GetPageSize()) == | 79 free_span->length() * base::GetPageSize()) == |
75 base::DiscardableSharedMemory::FAILED) { | 80 base::DiscardableSharedMemory::FAILED) { |
76 DCHECK(!free_span->shared_memory()->IsMemoryResident()); | 81 DCHECK(!free_span->shared_memory()->IsMemoryResident()); |
77 // We have to release free memory before |free_span| can be destroyed. | 82 // We have to release free memory before |free_span| can be destroyed. |
78 heap_.ReleaseFreeMemory(); | 83 size_t bytes_released = heap_.ReleaseFreeMemory(); |
| 84 DCHECK_NE(bytes_released, 0u); |
| 85 DCHECK_LE(bytes_released, bytes_allocated_); |
| 86 bytes_allocated_ -= bytes_released; |
| 87 BytesAllocatedChanged(bytes_allocated_); |
79 DCHECK(!free_span->shared_memory()); | 88 DCHECK(!free_span->shared_memory()); |
80 continue; | 89 continue; |
81 } | 90 } |
82 | 91 |
83 return make_scoped_ptr( | 92 return make_scoped_ptr( |
84 new DiscardableMemoryShmemChunkImpl(this, free_span.Pass())); | 93 new DiscardableMemoryShmemChunkImpl(this, free_span.Pass())); |
85 } | 94 } |
86 | 95 |
87 // Release free memory and free up the address space. Failing to do this | 96 // Release free memory and free up the address space. Failing to do this |
88 // can result in the child process running out of address space. | 97 // can result in the child process running out of address space. |
89 heap_.ReleaseFreeMemory(); | 98 size_t bytes_released = heap_.ReleaseFreeMemory(); |
| 99 if (bytes_released) { |
| 100 DCHECK_LE(bytes_released, bytes_allocated_); |
| 101 bytes_allocated_ -= bytes_released; |
| 102 BytesAllocatedChanged(bytes_allocated_); |
| 103 } |
90 | 104 |
91 size_t pages_to_allocate = | 105 size_t pages_to_allocate = |
92 std::max(kAllocationSize / base::GetPageSize(), pages); | 106 std::max(kAllocationSize / base::GetPageSize(), pages); |
93 size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize(); | 107 size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize(); |
94 | 108 |
95 // Ask parent process to allocate a new discardable shared memory segment. | 109 // Ask parent process to allocate a new discardable shared memory segment. |
96 scoped_ptr<base::DiscardableSharedMemory> shared_memory( | 110 scoped_ptr<base::DiscardableSharedMemory> shared_memory( |
97 AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes)); | 111 AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes)); |
98 | 112 |
| 113 // Note: use mapped size rather than |allocation_size_in_bytes| as |
| 114 // the latter only represent the amount of memory available for usage. |
| 115 bytes_allocated_ += shared_memory->mapped_size(); |
| 116 BytesAllocatedChanged(bytes_allocated_); |
| 117 |
99 // Create span for allocated memory. | 118 // Create span for allocated memory. |
100 scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span( | 119 scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span( |
101 heap_.Grow(shared_memory.Pass(), allocation_size_in_bytes)); | 120 heap_.Grow(shared_memory.Pass(), allocation_size_in_bytes)); |
102 | 121 |
103 // Unlock and insert any left over memory into free list. | 122 // Unlock and insert any left over memory into free list. |
104 if (pages < pages_to_allocate) { | 123 if (pages < pages_to_allocate) { |
105 scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover = | 124 scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover = |
106 heap_.Split(new_span.get(), pages); | 125 heap_.Split(new_span.get(), pages); |
107 leftover->shared_memory()->Unlock( | 126 leftover->shared_memory()->Unlock( |
108 leftover->start() * base::GetPageSize() - | 127 leftover->start() * base::GetPageSize() - |
109 reinterpret_cast<size_t>(leftover->shared_memory()->memory()), | 128 reinterpret_cast<size_t>(leftover->shared_memory()->memory()), |
110 leftover->length() * base::GetPageSize()); | 129 leftover->length() * base::GetPageSize()); |
111 heap_.MergeIntoFreeList(leftover.Pass()); | 130 heap_.MergeIntoFreeList(leftover.Pass()); |
112 } | 131 } |
113 | 132 |
114 return make_scoped_ptr( | 133 return make_scoped_ptr( |
115 new DiscardableMemoryShmemChunkImpl(this, new_span.Pass())); | 134 new DiscardableMemoryShmemChunkImpl(this, new_span.Pass())); |
116 } | 135 } |
117 | 136 |
118 void ChildDiscardableSharedMemoryManager::ReleaseFreeMemory() { | 137 void ChildDiscardableSharedMemoryManager::ReleaseFreeMemory() { |
119 base::AutoLock lock(lock_); | 138 base::AutoLock lock(lock_); |
120 | 139 |
121 heap_.ReleaseFreeMemory(); | 140 size_t bytes_released = heap_.ReleaseFreeMemory(); |
| 141 if (bytes_released) { |
| 142 DCHECK_LE(bytes_released, bytes_allocated_); |
| 143 bytes_allocated_ -= bytes_released; |
| 144 BytesAllocatedChanged(bytes_allocated_); |
| 145 } |
122 } | 146 } |
123 | 147 |
124 bool ChildDiscardableSharedMemoryManager::LockSpan( | 148 bool ChildDiscardableSharedMemoryManager::LockSpan( |
125 DiscardableSharedMemoryHeap::Span* span) { | 149 DiscardableSharedMemoryHeap::Span* span) { |
126 base::AutoLock lock(lock_); | 150 base::AutoLock lock(lock_); |
127 | 151 |
128 if (!span->shared_memory()) | 152 if (!span->shared_memory()) |
129 return false; | 153 return false; |
130 | 154 |
131 size_t offset = span->start() * base::GetPageSize() - | 155 size_t offset = span->start() * base::GetPageSize() - |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 sender_->Send( | 211 sender_->Send( |
188 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory( | 212 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory( |
189 size, &handle)); | 213 size, &handle)); |
190 CHECK(base::SharedMemory::IsHandleValid(handle)); | 214 CHECK(base::SharedMemory::IsHandleValid(handle)); |
191 scoped_ptr<base::DiscardableSharedMemory> memory( | 215 scoped_ptr<base::DiscardableSharedMemory> memory( |
192 new base::DiscardableSharedMemory(handle)); | 216 new base::DiscardableSharedMemory(handle)); |
193 CHECK(memory->Map(size)); | 217 CHECK(memory->Map(size)); |
194 return memory.Pass(); | 218 return memory.Pass(); |
195 } | 219 } |
196 | 220 |
| 221 void ChildDiscardableSharedMemoryManager::BytesAllocatedChanged( |
| 222 size_t new_bytes_allocated) const { |
| 223 TRACE_COUNTER_ID1("renderer", "DiscardableMemoryUsage", this, |
| 224 new_bytes_allocated); |
| 225 |
| 226 static const char kDiscardableMemoryUsageKey[] = "dm-usage"; |
| 227 base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey, |
| 228 base::Uint64ToString(new_bytes_allocated)); |
| 229 } |
| 230 |
197 } // namespace content | 231 } // namespace content |
OLD | NEW |