| 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/common/discardable_shared_memory_heap.h" | 5 #include "content/common/discardable_shared_memory_heap.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/memory/discardable_shared_memory.h" | 10 #include "base/memory/discardable_shared_memory.h" |
| 11 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
| 12 #include "base/trace_event/memory_dump_manager.h" | 12 #include "base/trace_event/memory_dump_manager.h" |
| 13 | 13 |
| 14 namespace content { | 14 namespace content { |
| 15 namespace { | 15 namespace { |
| 16 | 16 |
| 17 bool IsPowerOfTwo(size_t x) { | 17 bool IsPowerOfTwo(size_t x) { |
| 18 return (x & (x - 1)) == 0; | 18 return (x & (x - 1)) == 0; |
| 19 } | 19 } |
| 20 | 20 |
| 21 bool IsInFreeList(DiscardableSharedMemoryHeap::Span* span) { | 21 bool IsInFreeList(DiscardableSharedMemoryHeap::Span* span) { |
| 22 return span->previous() || span->next(); | 22 return span->previous() || span->next(); |
| 23 } | 23 } |
| 24 | 24 |
| 25 } // namespace | 25 } // namespace |
| 26 | 26 |
| 27 DiscardableSharedMemoryHeap::Span::Span( | 27 DiscardableSharedMemoryHeap::Span::Span( |
| 28 base::DiscardableSharedMemory* shared_memory, | 28 base::DiscardableSharedMemory* shared_memory, |
| 29 size_t start, | 29 size_t start, |
| 30 size_t length) | 30 size_t length, |
| 31 : shared_memory_(shared_memory), start_(start), length_(length) { | 31 bool is_locked) |
| 32 : shared_memory_(shared_memory), |
| 33 start_(start), |
| 34 length_(length), |
| 35 is_locked_(is_locked) {} |
| 36 |
| 37 DiscardableSharedMemoryHeap::Span::~Span() { |
| 32 } | 38 } |
| 33 | 39 |
| 34 DiscardableSharedMemoryHeap::Span::~Span() { | 40 base::DiscardableSharedMemory::LockResult |
| 41 DiscardableSharedMemoryHeap::Span::Lock(size_t page_size) { |
| 42 const size_t offset = |
| 43 start_ * page_size - reinterpret_cast<size_t>(shared_memory_->memory()); |
| 44 const size_t length = length_ * page_size; |
| 45 base::DiscardableSharedMemory::LockResult result = |
| 46 shared_memory_->Lock(offset, length); |
| 47 is_locked_ = result == base::DiscardableSharedMemory::SUCCESS; |
| 48 return result; |
| 49 } |
| 50 |
| 51 void DiscardableSharedMemoryHeap::Span::Unlock(size_t page_size) { |
| 52 const size_t offset = |
| 53 start_ * page_size - reinterpret_cast<size_t>(shared_memory_->memory()); |
| 54 const size_t length = length_ * page_size; |
| 55 shared_memory_->Unlock(offset, length); |
| 56 is_locked_ = false; |
| 57 } |
| 58 |
| 59 bool DiscardableSharedMemoryHeap::Span::IsMemoryResident() const { |
| 60 return shared_memory_->IsMemoryResident(); |
| 35 } | 61 } |
| 36 | 62 |
| 37 DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment( | 63 DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment( |
| 38 DiscardableSharedMemoryHeap* heap, | 64 DiscardableSharedMemoryHeap* heap, |
| 39 scoped_ptr<base::DiscardableSharedMemory> shared_memory, | 65 scoped_ptr<base::DiscardableSharedMemory> shared_memory, |
| 40 size_t size, | 66 size_t size, |
| 41 int32_t id, | 67 int32_t id, |
| 42 const base::Closure& deleted_callback) | 68 const base::Closure& deleted_callback) |
| 43 : heap_(heap), | 69 : heap_(heap), |
| 44 shared_memory_(shared_memory.Pass()), | 70 shared_memory_(shared_memory.Pass()), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 55 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsUsed() const { | 81 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsUsed() const { |
| 56 return heap_->IsMemoryUsed(shared_memory_.get(), size_); | 82 return heap_->IsMemoryUsed(shared_memory_.get(), size_); |
| 57 } | 83 } |
| 58 | 84 |
| 59 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsResident() const { | 85 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsResident() const { |
| 60 return heap_->IsMemoryResident(shared_memory_.get()); | 86 return heap_->IsMemoryResident(shared_memory_.get()); |
| 61 } | 87 } |
| 62 | 88 |
| 63 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::ContainsSpan( | 89 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::ContainsSpan( |
| 64 Span* span) const { | 90 Span* span) const { |
| 65 return shared_memory_ == span->shared_memory(); | 91 return shared_memory_ == span->shared_memory_; |
| 66 } | 92 } |
| 67 | 93 |
| 68 base::trace_event::MemoryAllocatorDump* | 94 base::trace_event::MemoryAllocatorDump* |
| 69 DiscardableSharedMemoryHeap::ScopedMemorySegment::CreateMemoryAllocatorDump( | 95 DiscardableSharedMemoryHeap::ScopedMemorySegment::CreateMemoryAllocatorDump( |
| 70 Span* span, | 96 Span* span, |
| 71 size_t block_size, | 97 size_t block_size, |
| 72 const char* name, | 98 const char* name, |
| 73 base::trace_event::ProcessMemoryDump* pmd) const { | 99 base::trace_event::ProcessMemoryDump* pmd) const { |
| 74 DCHECK_EQ(shared_memory_, span->shared_memory()); | 100 DCHECK_EQ(shared_memory_, span->shared_memory_); |
| 75 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(name); | 101 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(name); |
| 76 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, | 102 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| 77 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 103 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 78 static_cast<uint64_t>(span->length() * block_size)); | 104 static_cast<uint64_t>(span->length() * block_size)); |
| 79 | 105 |
| 80 pmd->AddSuballocation( | 106 pmd->AddSuballocation( |
| 81 dump->guid(), | 107 dump->guid(), |
| 82 base::StringPrintf("discardable/segment_%d/allocated_objects", id_)); | 108 base::StringPrintf("discardable/segment_%d/allocated_objects", id_)); |
| 83 return dump; | 109 return dump; |
| 84 } | 110 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 112 const base::Closure& deleted_callback) { | 138 const base::Closure& deleted_callback) { |
| 113 // Memory must be aligned to block size. | 139 // Memory must be aligned to block size. |
| 114 DCHECK_EQ( | 140 DCHECK_EQ( |
| 115 reinterpret_cast<size_t>(shared_memory->memory()) & (block_size_ - 1), | 141 reinterpret_cast<size_t>(shared_memory->memory()) & (block_size_ - 1), |
| 116 0u); | 142 0u); |
| 117 DCHECK_EQ(size & (block_size_ - 1), 0u); | 143 DCHECK_EQ(size & (block_size_ - 1), 0u); |
| 118 | 144 |
| 119 scoped_ptr<Span> span( | 145 scoped_ptr<Span> span( |
| 120 new Span(shared_memory.get(), | 146 new Span(shared_memory.get(), |
| 121 reinterpret_cast<size_t>(shared_memory->memory()) / block_size_, | 147 reinterpret_cast<size_t>(shared_memory->memory()) / block_size_, |
| 122 size / block_size_)); | 148 size / block_size_, true /* is_locked */)); |
| 123 DCHECK(spans_.find(span->start_) == spans_.end()); | 149 DCHECK(spans_.find(span->start_) == spans_.end()); |
| 124 DCHECK(spans_.find(span->start_ + span->length_ - 1) == spans_.end()); | 150 DCHECK(spans_.find(span->start_ + span->length_ - 1) == spans_.end()); |
| 125 RegisterSpan(span.get()); | 151 RegisterSpan(span.get()); |
| 126 | 152 |
| 127 num_blocks_ += span->length_; | 153 num_blocks_ += span->length_; |
| 128 | 154 |
| 129 // Start tracking if segment is resident by adding it to |memory_segments_|. | 155 // Start tracking if segment is resident by adding it to |memory_segments_|. |
| 130 memory_segments_.push_back(new ScopedMemorySegment( | 156 memory_segments_.push_back(new ScopedMemorySegment( |
| 131 this, shared_memory.Pass(), size, id, deleted_callback)); | 157 this, shared_memory.Pass(), size, id, deleted_callback)); |
| 132 | 158 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 } | 191 } |
| 166 | 192 |
| 167 InsertIntoFreeList(span.Pass()); | 193 InsertIntoFreeList(span.Pass()); |
| 168 } | 194 } |
| 169 | 195 |
| 170 scoped_ptr<DiscardableSharedMemoryHeap::Span> | 196 scoped_ptr<DiscardableSharedMemoryHeap::Span> |
| 171 DiscardableSharedMemoryHeap::Split(Span* span, size_t blocks) { | 197 DiscardableSharedMemoryHeap::Split(Span* span, size_t blocks) { |
| 172 DCHECK(blocks); | 198 DCHECK(blocks); |
| 173 DCHECK_LT(blocks, span->length_); | 199 DCHECK_LT(blocks, span->length_); |
| 174 | 200 |
| 175 scoped_ptr<Span> leftover(new Span( | 201 scoped_ptr<Span> leftover( |
| 176 span->shared_memory_, span->start_ + blocks, span->length_ - blocks)); | 202 new Span(span->shared_memory_, span->start_ + blocks, |
| 203 span->length_ - blocks, true /* is_locked */)); |
| 177 DCHECK_IMPLIES(leftover->length_ > 1, | 204 DCHECK_IMPLIES(leftover->length_ > 1, |
| 178 spans_.find(leftover->start_) == spans_.end()); | 205 spans_.find(leftover->start_) == spans_.end()); |
| 179 RegisterSpan(leftover.get()); | 206 RegisterSpan(leftover.get()); |
| 180 spans_[span->start_ + blocks - 1] = span; | 207 spans_[span->start_ + blocks - 1] = span; |
| 181 span->length_ = blocks; | 208 span->length_ = blocks; |
| 182 return leftover.Pass(); | 209 return leftover.Pass(); |
| 183 } | 210 } |
| 184 | 211 |
| 185 scoped_ptr<DiscardableSharedMemoryHeap::Span> | 212 scoped_ptr<DiscardableSharedMemoryHeap::Span> |
| 186 DiscardableSharedMemoryHeap::SearchFreeLists(size_t blocks, size_t slack) { | 213 DiscardableSharedMemoryHeap::SearchFreeLists(size_t blocks, size_t slack) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 span->RemoveFromList(); | 296 span->RemoveFromList(); |
| 270 return make_scoped_ptr(span); | 297 return make_scoped_ptr(span); |
| 271 } | 298 } |
| 272 | 299 |
| 273 scoped_ptr<DiscardableSharedMemoryHeap::Span> | 300 scoped_ptr<DiscardableSharedMemoryHeap::Span> |
| 274 DiscardableSharedMemoryHeap::Carve(Span* span, size_t blocks) { | 301 DiscardableSharedMemoryHeap::Carve(Span* span, size_t blocks) { |
| 275 scoped_ptr<Span> serving = RemoveFromFreeList(span); | 302 scoped_ptr<Span> serving = RemoveFromFreeList(span); |
| 276 | 303 |
| 277 const int extra = serving->length_ - blocks; | 304 const int extra = serving->length_ - blocks; |
| 278 if (extra) { | 305 if (extra) { |
| 279 scoped_ptr<Span> leftover( | 306 scoped_ptr<Span> leftover(new Span(serving->shared_memory_, |
| 280 new Span(serving->shared_memory_, serving->start_ + blocks, extra)); | 307 serving->start_ + blocks, extra, |
| 308 false /* is_locked */)); |
| 281 DCHECK_IMPLIES(extra > 1, spans_.find(leftover->start_) == spans_.end()); | 309 DCHECK_IMPLIES(extra > 1, spans_.find(leftover->start_) == spans_.end()); |
| 282 RegisterSpan(leftover.get()); | 310 RegisterSpan(leftover.get()); |
| 283 | 311 |
| 284 // No need to coalesce as the previous span of |leftover| was just split | 312 // No need to coalesce as the previous span of |leftover| was just split |
| 285 // and the next span of |leftover| was not previously coalesced with | 313 // and the next span of |leftover| was not previously coalesced with |
| 286 // |span|. | 314 // |span|. |
| 287 InsertIntoFreeList(leftover.Pass()); | 315 InsertIntoFreeList(leftover.Pass()); |
| 288 | 316 |
| 289 serving->length_ = blocks; | 317 serving->length_ = blocks; |
| 290 spans_[serving->start_ + blocks - 1] = serving.get(); | 318 spans_[serving->start_ + blocks - 1] = serving.get(); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 } | 388 } |
| 361 } | 389 } |
| 362 | 390 |
| 363 void DiscardableSharedMemoryHeap::OnMemoryDump( | 391 void DiscardableSharedMemoryHeap::OnMemoryDump( |
| 364 const base::DiscardableSharedMemory* shared_memory, | 392 const base::DiscardableSharedMemory* shared_memory, |
| 365 size_t size, | 393 size_t size, |
| 366 int32_t segment_id, | 394 int32_t segment_id, |
| 367 base::trace_event::ProcessMemoryDump* pmd) { | 395 base::trace_event::ProcessMemoryDump* pmd) { |
| 368 size_t allocated_objects_count = 0; | 396 size_t allocated_objects_count = 0; |
| 369 size_t allocated_objects_size_in_bytes = 0; | 397 size_t allocated_objects_size_in_bytes = 0; |
| 398 size_t locked_size_in_bytes = 0; |
| 370 size_t offset = | 399 size_t offset = |
| 371 reinterpret_cast<size_t>(shared_memory->memory()) / block_size_; | 400 reinterpret_cast<size_t>(shared_memory->memory()) / block_size_; |
| 372 size_t end = offset + size / block_size_; | 401 size_t end = offset + size / block_size_; |
| 373 while (offset < end) { | 402 while (offset < end) { |
| 374 Span* span = spans_[offset]; | 403 Span* span = spans_[offset]; |
| 375 if (!IsInFreeList(span)) { | 404 if (!IsInFreeList(span)) { |
| 376 allocated_objects_count++; | 405 allocated_objects_count++; |
| 377 allocated_objects_size_in_bytes += span->length_ * block_size_; | 406 const size_t span_size = span->length_ * block_size_; |
| 407 allocated_objects_size_in_bytes += span_size; |
| 408 locked_size_in_bytes = span->is_locked_ ? span_size : 0; |
| 378 } | 409 } |
| 379 offset += span->length_; | 410 offset += span->length_; |
| 380 } | 411 } |
| 381 | 412 |
| 382 std::string segment_dump_name = | 413 std::string segment_dump_name = |
| 383 base::StringPrintf("discardable/segment_%d", segment_id); | 414 base::StringPrintf("discardable/segment_%d", segment_id); |
| 384 base::trace_event::MemoryAllocatorDump* segment_dump = | 415 base::trace_event::MemoryAllocatorDump* segment_dump = |
| 385 pmd->CreateAllocatorDump(segment_dump_name); | 416 pmd->CreateAllocatorDump(segment_dump_name); |
| 386 segment_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, | 417 segment_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| 387 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 418 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 388 static_cast<uint64_t>(size)); | 419 static_cast<uint64_t>(size)); |
| 389 | 420 |
| 390 base::trace_event::MemoryAllocatorDump* obj_dump = | 421 base::trace_event::MemoryAllocatorDump* obj_dump = |
| 391 pmd->CreateAllocatorDump(segment_dump_name + "/allocated_objects"); | 422 pmd->CreateAllocatorDump(segment_dump_name + "/allocated_objects"); |
| 392 obj_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount, | 423 obj_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount, |
| 393 base::trace_event::MemoryAllocatorDump::kUnitsObjects, | 424 base::trace_event::MemoryAllocatorDump::kUnitsObjects, |
| 394 static_cast<uint64_t>(allocated_objects_count)); | 425 static_cast<uint64_t>(allocated_objects_count)); |
| 395 obj_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, | 426 obj_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| 396 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 427 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 397 static_cast<uint64_t>(allocated_objects_size_in_bytes)); | 428 static_cast<uint64_t>(allocated_objects_size_in_bytes)); |
| 429 obj_dump->AddScalar("locked_size", |
| 430 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 431 locked_size_in_bytes); |
| 398 | 432 |
| 399 // Emit an ownership edge towards a global allocator dump node. This allows | 433 // Emit an ownership edge towards a global allocator dump node. This allows |
| 400 // to avoid double-counting segments when both browser and child process emit | 434 // to avoid double-counting segments when both browser and child process emit |
| 401 // them. In the special case of single-process-mode, this will be the only | 435 // them. In the special case of single-process-mode, this will be the only |
| 402 // dumper active and the single ownership edge will become a no-op in the UI. | 436 // dumper active and the single ownership edge will become a no-op in the UI. |
| 403 const uint64 tracing_process_id = | 437 const uint64 tracing_process_id = |
| 404 base::trace_event::MemoryDumpManager::GetInstance() | 438 base::trace_event::MemoryDumpManager::GetInstance() |
| 405 ->GetTracingProcessId(); | 439 ->GetTracingProcessId(); |
| 406 base::trace_event::MemoryAllocatorDumpGuid shared_segment_guid = | 440 base::trace_event::MemoryAllocatorDumpGuid shared_segment_guid = |
| 407 GetSegmentGUIDForTracing(tracing_process_id, segment_id); | 441 GetSegmentGUIDForTracing(tracing_process_id, segment_id); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 437 ScopedVector<ScopedMemorySegment>::const_iterator it = | 471 ScopedVector<ScopedMemorySegment>::const_iterator it = |
| 438 std::find_if(memory_segments_.begin(), memory_segments_.end(), | 472 std::find_if(memory_segments_.begin(), memory_segments_.end(), |
| 439 [span](const ScopedMemorySegment* segment) { | 473 [span](const ScopedMemorySegment* segment) { |
| 440 return segment->ContainsSpan(span); | 474 return segment->ContainsSpan(span); |
| 441 }); | 475 }); |
| 442 DCHECK(it != memory_segments_.end()); | 476 DCHECK(it != memory_segments_.end()); |
| 443 return (*it)->CreateMemoryAllocatorDump(span, block_size_, name, pmd); | 477 return (*it)->CreateMemoryAllocatorDump(span, block_size_, name, pmd); |
| 444 } | 478 } |
| 445 | 479 |
| 446 } // namespace content | 480 } // namespace content |
| OLD | NEW |