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 "components/discardable_memory/client/child_discardable_shared_memory_m
anager.h" |
6 | 6 |
7 #include <inttypes.h> | 7 #include <inttypes.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/atomic_sequence_num.h" | 12 #include "base/atomic_sequence_num.h" |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/debug/crash_logging.h" | 14 #include "base/debug/crash_logging.h" |
15 #include "base/macros.h" | 15 #include "base/macros.h" |
16 #include "base/memory/discardable_memory.h" | 16 #include "base/memory/discardable_memory.h" |
17 #include "base/memory/discardable_shared_memory.h" | 17 #include "base/memory/discardable_shared_memory.h" |
18 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
19 #include "base/metrics/histogram_macros.h" | 19 #include "base/metrics/histogram_macros.h" |
20 #include "base/process/memory.h" | 20 #include "base/process/memory.h" |
21 #include "base/process/process_metrics.h" | 21 #include "base/process/process_metrics.h" |
22 #include "base/strings/string_number_conversions.h" | 22 #include "base/strings/string_number_conversions.h" |
23 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
24 #include "base/threading/thread_task_runner_handle.h" | 24 #include "base/threading/thread_task_runner_handle.h" |
25 #include "base/trace_event/memory_dump_manager.h" | 25 #include "base/trace_event/memory_dump_manager.h" |
26 #include "base/trace_event/trace_event.h" | 26 #include "base/trace_event/trace_event.h" |
27 #include "content/common/child_process_messages.h" | |
28 | 27 |
29 namespace content { | 28 namespace discardable_memory { |
30 namespace { | 29 namespace { |
31 | 30 |
32 // Default allocation size. | 31 // Default allocation size. |
33 const size_t kAllocationSize = 4 * 1024 * 1024; | 32 const size_t kAllocationSize = 4 * 1024 * 1024; |
34 | 33 |
35 // Global atomic to generate unique discardable shared memory IDs. | 34 // Global atomic to generate unique discardable shared memory IDs. |
36 base::StaticAtomicSequenceNumber g_next_discardable_shared_memory_id; | 35 base::StaticAtomicSequenceNumber g_next_discardable_shared_memory_id; |
37 | 36 |
38 class DiscardableMemoryImpl : public base::DiscardableMemory { | 37 class DiscardableMemoryImpl : public base::DiscardableMemory { |
39 public: | 38 public: |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 | 76 |
78 private: | 77 private: |
79 ChildDiscardableSharedMemoryManager* const manager_; | 78 ChildDiscardableSharedMemoryManager* const manager_; |
80 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span_; | 79 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span_; |
81 bool is_locked_; | 80 bool is_locked_; |
82 | 81 |
83 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryImpl); | 82 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryImpl); |
84 }; | 83 }; |
85 | 84 |
86 void SendDeletedDiscardableSharedMemoryMessage( | 85 void SendDeletedDiscardableSharedMemoryMessage( |
87 scoped_refptr<ThreadSafeSender> sender, | 86 ChildDiscardableSharedMemoryManager::Delegate* delegate, |
88 DiscardableSharedMemoryId id) { | 87 DiscardableSharedMemoryId id) { |
89 sender->Send(new ChildProcessHostMsg_DeletedDiscardableSharedMemory(id)); | 88 delegate->DeletedDiscardableSharedMemory(id); |
90 } | 89 } |
91 | 90 |
92 } // namespace | 91 } // namespace |
93 | 92 |
94 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager( | 93 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager( |
95 ThreadSafeSender* sender) | 94 Delegate* delegate) |
96 : heap_(base::GetPageSize()), sender_(sender) { | 95 : heap_(base::GetPageSize()), delegate_(delegate) { |
97 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | 96 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
98 this, "ChildDiscardableSharedMemoryManager", | 97 this, "ChildDiscardableSharedMemoryManager", |
99 base::ThreadTaskRunnerHandle::Get()); | 98 base::ThreadTaskRunnerHandle::Get()); |
100 } | 99 } |
101 | 100 |
102 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() { | 101 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() { |
103 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | 102 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
104 this); | 103 this); |
105 // TODO(reveman): Determine if this DCHECK can be enabled. crbug.com/430533 | 104 // TODO(reveman): Determine if this DCHECK can be enabled. crbug.com/430533 |
106 // DCHECK_EQ(heap_.GetSize(), heap_.GetSizeOfFreeLists()); | 105 // DCHECK_EQ(heap_.GetSize(), heap_.GetSizeOfFreeLists()); |
107 if (heap_.GetSize()) | 106 if (heap_.GetSize()) |
108 MemoryUsageChanged(0, 0); | 107 MemoryUsageChanged(0, 0); |
109 } | 108 } |
110 | 109 |
111 std::unique_ptr<base::DiscardableMemory> | 110 std::unique_ptr<base::DiscardableMemory> |
112 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( | 111 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( |
113 size_t size) { | 112 size_t size) { |
114 base::AutoLock lock(lock_); | 113 base::AutoLock lock(lock_); |
115 | 114 |
116 DCHECK_NE(size, 0u); | 115 DCHECK_NE(size, 0u); |
117 | 116 |
| 117 auto size_in_kb = static_cast<base::HistogramBase::Sample>(size / 1024); |
118 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.DiscardableAllocationSize", | 118 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.DiscardableAllocationSize", |
119 size / 1024, // In KB | 119 size_in_kb, // In KB |
120 1, | 120 1, |
121 4 * 1024 * 1024, // 4 GB | 121 4 * 1024 * 1024, // 4 GB |
122 50); | 122 50); |
123 | 123 |
124 // Round up to multiple of page size. | 124 // Round up to multiple of page size. |
125 size_t pages = | 125 size_t pages = |
126 std::max((size + base::GetPageSize() - 1) / base::GetPageSize(), | 126 std::max((size + base::GetPageSize() - 1) / base::GetPageSize(), |
127 static_cast<size_t>(1)); | 127 static_cast<size_t>(1)); |
128 | 128 |
129 // Default allocation size in pages. | 129 // Default allocation size in pages. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize(); | 182 size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize(); |
183 | 183 |
184 DiscardableSharedMemoryId new_id = | 184 DiscardableSharedMemoryId new_id = |
185 g_next_discardable_shared_memory_id.GetNext(); | 185 g_next_discardable_shared_memory_id.GetNext(); |
186 | 186 |
187 // Ask parent process to allocate a new discardable shared memory segment. | 187 // Ask parent process to allocate a new discardable shared memory segment. |
188 std::unique_ptr<base::DiscardableSharedMemory> shared_memory( | 188 std::unique_ptr<base::DiscardableSharedMemory> shared_memory( |
189 AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes, new_id)); | 189 AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes, new_id)); |
190 | 190 |
191 // Create span for allocated memory. | 191 // Create span for allocated memory. |
192 std::unique_ptr<DiscardableSharedMemoryHeap::Span> new_span(heap_.Grow( | 192 std::unique_ptr<DiscardableSharedMemoryHeap::Span> new_span( |
193 std::move(shared_memory), allocation_size_in_bytes, new_id, | 193 heap_.Grow(std::move(shared_memory), allocation_size_in_bytes, new_id, |
194 base::Bind(&SendDeletedDiscardableSharedMemoryMessage, sender_, new_id))); | 194 base::Bind(&SendDeletedDiscardableSharedMemoryMessage, |
| 195 delegate_, new_id))); |
195 new_span->set_is_locked(true); | 196 new_span->set_is_locked(true); |
196 | 197 |
197 // Unlock and insert any left over memory into free lists. | 198 // Unlock and insert any left over memory into free lists. |
198 if (pages < pages_to_allocate) { | 199 if (pages < pages_to_allocate) { |
199 std::unique_ptr<DiscardableSharedMemoryHeap::Span> leftover = | 200 std::unique_ptr<DiscardableSharedMemoryHeap::Span> leftover = |
200 heap_.Split(new_span.get(), pages); | 201 heap_.Split(new_span.get(), pages); |
201 leftover->shared_memory()->Unlock( | 202 leftover->shared_memory()->Unlock( |
202 leftover->start() * base::GetPageSize() - | 203 leftover->start() * base::GetPageSize() - |
203 reinterpret_cast<size_t>(leftover->shared_memory()->memory()), | 204 reinterpret_cast<size_t>(leftover->shared_memory()->memory()), |
204 leftover->length() * base::GetPageSize()); | 205 leftover->length() * base::GetPageSize()); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 } | 259 } |
259 | 260 |
260 bool ChildDiscardableSharedMemoryManager::LockSpan( | 261 bool ChildDiscardableSharedMemoryManager::LockSpan( |
261 DiscardableSharedMemoryHeap::Span* span) { | 262 DiscardableSharedMemoryHeap::Span* span) { |
262 base::AutoLock lock(lock_); | 263 base::AutoLock lock(lock_); |
263 | 264 |
264 if (!span->shared_memory()) | 265 if (!span->shared_memory()) |
265 return false; | 266 return false; |
266 | 267 |
267 size_t offset = span->start() * base::GetPageSize() - | 268 size_t offset = span->start() * base::GetPageSize() - |
268 reinterpret_cast<size_t>(span->shared_memory()->memory()); | 269 reinterpret_cast<size_t>(span->shared_memory()->memory()); |
269 size_t length = span->length() * base::GetPageSize(); | 270 size_t length = span->length() * base::GetPageSize(); |
270 | 271 |
271 switch (span->shared_memory()->Lock(offset, length)) { | 272 switch (span->shared_memory()->Lock(offset, length)) { |
272 case base::DiscardableSharedMemory::SUCCESS: | 273 case base::DiscardableSharedMemory::SUCCESS: |
273 span->set_is_locked(true); | 274 span->set_is_locked(true); |
274 return true; | 275 return true; |
275 case base::DiscardableSharedMemory::PURGED: | 276 case base::DiscardableSharedMemory::PURGED: |
276 span->shared_memory()->Unlock(offset, length); | 277 span->shared_memory()->Unlock(offset, length); |
277 span->set_is_locked(false); | 278 span->set_is_locked(false); |
278 return false; | 279 return false; |
279 case base::DiscardableSharedMemory::FAILED: | 280 case base::DiscardableSharedMemory::FAILED: |
280 return false; | 281 return false; |
281 } | 282 } |
282 | 283 |
283 NOTREACHED(); | 284 NOTREACHED(); |
284 return false; | 285 return false; |
285 } | 286 } |
286 | 287 |
287 void ChildDiscardableSharedMemoryManager::UnlockSpan( | 288 void ChildDiscardableSharedMemoryManager::UnlockSpan( |
288 DiscardableSharedMemoryHeap::Span* span) { | 289 DiscardableSharedMemoryHeap::Span* span) { |
289 base::AutoLock lock(lock_); | 290 base::AutoLock lock(lock_); |
290 | 291 |
291 DCHECK(span->shared_memory()); | 292 DCHECK(span->shared_memory()); |
292 size_t offset = span->start() * base::GetPageSize() - | 293 size_t offset = span->start() * base::GetPageSize() - |
293 reinterpret_cast<size_t>(span->shared_memory()->memory()); | 294 reinterpret_cast<size_t>(span->shared_memory()->memory()); |
294 size_t length = span->length() * base::GetPageSize(); | 295 size_t length = span->length() * base::GetPageSize(); |
295 | 296 |
296 span->set_is_locked(false); | 297 span->set_is_locked(false); |
297 return span->shared_memory()->Unlock(offset, length); | 298 return span->shared_memory()->Unlock(offset, length); |
298 } | 299 } |
299 | 300 |
300 void ChildDiscardableSharedMemoryManager::ReleaseSpan( | 301 void ChildDiscardableSharedMemoryManager::ReleaseSpan( |
301 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) { | 302 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) { |
302 base::AutoLock lock(lock_); | 303 base::AutoLock lock(lock_); |
303 | 304 |
(...skipping 19 matching lines...) Expand all Loading... |
323 std::unique_ptr<base::DiscardableSharedMemory> | 324 std::unique_ptr<base::DiscardableSharedMemory> |
324 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( | 325 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( |
325 size_t size, | 326 size_t size, |
326 DiscardableSharedMemoryId id) { | 327 DiscardableSharedMemoryId id) { |
327 TRACE_EVENT2("renderer", | 328 TRACE_EVENT2("renderer", |
328 "ChildDiscardableSharedMemoryManager::" | 329 "ChildDiscardableSharedMemoryManager::" |
329 "AllocateLockedDiscardableSharedMemory", | 330 "AllocateLockedDiscardableSharedMemory", |
330 "size", size, "id", id); | 331 "size", size, "id", id); |
331 | 332 |
332 base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle(); | 333 base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle(); |
333 sender_->Send( | 334 delegate_->AllocateLockedDiscardableSharedMemory(size, id, &handle); |
334 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory( | |
335 size, id, &handle)); | |
336 std::unique_ptr<base::DiscardableSharedMemory> memory( | 335 std::unique_ptr<base::DiscardableSharedMemory> memory( |
337 new base::DiscardableSharedMemory(handle)); | 336 new base::DiscardableSharedMemory(handle)); |
338 if (!memory->Map(size)) | 337 if (!memory->Map(size)) |
339 base::TerminateBecauseOutOfMemory(size); | 338 base::TerminateBecauseOutOfMemory(size); |
340 return memory; | 339 return memory; |
341 } | 340 } |
342 | 341 |
343 void ChildDiscardableSharedMemoryManager::MemoryUsageChanged( | 342 void ChildDiscardableSharedMemoryManager::MemoryUsageChanged( |
344 size_t new_bytes_total, | 343 size_t new_bytes_total, |
345 size_t new_bytes_free) const { | 344 size_t new_bytes_free) const { |
346 static const char kDiscardableMemoryAllocatedKey[] = | 345 static const char kDiscardableMemoryAllocatedKey[] = |
347 "discardable-memory-allocated"; | 346 "discardable-memory-allocated"; |
348 base::debug::SetCrashKeyValue(kDiscardableMemoryAllocatedKey, | 347 base::debug::SetCrashKeyValue(kDiscardableMemoryAllocatedKey, |
349 base::Uint64ToString(new_bytes_total)); | 348 base::Uint64ToString(new_bytes_total)); |
350 | 349 |
351 static const char kDiscardableMemoryFreeKey[] = "discardable-memory-free"; | 350 static const char kDiscardableMemoryFreeKey[] = "discardable-memory-free"; |
352 base::debug::SetCrashKeyValue(kDiscardableMemoryFreeKey, | 351 base::debug::SetCrashKeyValue(kDiscardableMemoryFreeKey, |
353 base::Uint64ToString(new_bytes_free)); | 352 base::Uint64ToString(new_bytes_free)); |
354 } | 353 } |
355 | 354 |
356 } // namespace content | 355 } // namespace discardable_memory |
OLD | NEW |