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 later only represent the amount of memory available for usage. | |
Avi (use Gerrit)
2015/02/26 16:21:15
... the latter only represents ...
reveman
2015/02/26 16:55:44
Done.
| |
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 |