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/atomic_sequence_num.h" | |
9 #include "base/memory/discardable_shared_memory.h" | 10 #include "base/memory/discardable_shared_memory.h" |
11 #include "base/strings/stringprintf.h" | |
10 | 12 |
11 namespace content { | 13 namespace content { |
12 namespace { | 14 namespace { |
13 | 15 |
16 const char kMemoryAllocatorHeapNamePrefix[] = "segment_%zu"; | |
17 const char kMemoryAllocatorName[] = "discardable"; | |
18 | |
19 // Global atomic to generate unique discardable shared memory IDs. | |
20 base::StaticAtomicSequenceNumber g_next_discardable_shared_memory_id; | |
21 | |
14 bool IsPowerOfTwo(size_t x) { | 22 bool IsPowerOfTwo(size_t x) { |
15 return (x & (x - 1)) == 0; | 23 return (x & (x - 1)) == 0; |
16 } | 24 } |
17 | 25 |
18 bool IsInFreeList(DiscardableSharedMemoryHeap::Span* span) { | 26 bool IsInFreeList(DiscardableSharedMemoryHeap::Span* span) { |
19 return span->previous() || span->next(); | 27 return span->previous() || span->next(); |
20 } | 28 } |
21 | 29 |
22 } // namespace | 30 } // namespace |
23 | 31 |
24 DiscardableSharedMemoryHeap::Span::Span( | 32 DiscardableSharedMemoryHeap::Span::Span( |
25 base::DiscardableSharedMemory* shared_memory, | 33 base::DiscardableSharedMemory* shared_memory, |
26 size_t start, | 34 size_t start, |
27 size_t length) | 35 size_t length) |
28 : shared_memory_(shared_memory), start_(start), length_(length) { | 36 : shared_memory_(shared_memory), start_(start), length_(length) { |
29 } | 37 } |
30 | 38 |
31 DiscardableSharedMemoryHeap::Span::~Span() { | 39 DiscardableSharedMemoryHeap::Span::~Span() { |
32 } | 40 } |
33 | 41 |
34 DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment( | 42 DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment( |
35 DiscardableSharedMemoryHeap* heap, | 43 DiscardableSharedMemoryHeap* heap, |
36 scoped_ptr<base::DiscardableSharedMemory> shared_memory, | 44 scoped_ptr<base::DiscardableSharedMemory> shared_memory, |
37 size_t size, | 45 size_t size, |
46 DiscardableSharedMemoryId id, | |
38 const base::Closure& deleted_callback) | 47 const base::Closure& deleted_callback) |
39 : heap_(heap), | 48 : heap_(heap), |
40 shared_memory_(shared_memory.Pass()), | 49 shared_memory_(shared_memory.Pass()), |
41 size_(size), | 50 size_(size), |
51 id_(id), | |
42 deleted_callback_(deleted_callback) { | 52 deleted_callback_(deleted_callback) { |
43 } | 53 } |
44 | 54 |
45 DiscardableSharedMemoryHeap::ScopedMemorySegment::~ScopedMemorySegment() { | 55 DiscardableSharedMemoryHeap::ScopedMemorySegment::~ScopedMemorySegment() { |
46 heap_->ReleaseMemory(shared_memory_.get(), size_); | 56 heap_->ReleaseMemory(shared_memory_.get(), size_); |
47 deleted_callback_.Run(); | 57 deleted_callback_.Run(); |
48 } | 58 } |
49 | 59 |
50 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsUsed() const { | 60 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsUsed() const { |
51 return heap_->IsMemoryUsed(shared_memory_.get(), size_); | 61 return heap_->IsMemoryUsed(shared_memory_.get(), size_); |
52 } | 62 } |
53 | 63 |
54 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsResident() const { | 64 bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsResident() const { |
55 return heap_->IsMemoryResident(shared_memory_.get()); | 65 return heap_->IsMemoryResident(shared_memory_.get()); |
56 } | 66 } |
57 | 67 |
68 void DiscardableSharedMemoryHeap::ScopedMemorySegment::DumpMemoryStatisticsInto( | |
69 base::trace_event::ProcessMemoryDump* pmd) const { | |
70 heap_->DumpSegmentStatistics(shared_memory_.get(), size_, id_, pmd); | |
71 } | |
72 | |
58 DiscardableSharedMemoryHeap::DiscardableSharedMemoryHeap(size_t block_size) | 73 DiscardableSharedMemoryHeap::DiscardableSharedMemoryHeap(size_t block_size) |
59 : block_size_(block_size), num_blocks_(0), num_free_blocks_(0) { | 74 : block_size_(block_size), num_blocks_(0), num_free_blocks_(0) { |
60 DCHECK_NE(block_size_, 0u); | 75 DCHECK_NE(block_size_, 0u); |
61 DCHECK(IsPowerOfTwo(block_size_)); | 76 DCHECK(IsPowerOfTwo(block_size_)); |
62 } | 77 } |
63 | 78 |
64 DiscardableSharedMemoryHeap::~DiscardableSharedMemoryHeap() { | 79 DiscardableSharedMemoryHeap::~DiscardableSharedMemoryHeap() { |
65 memory_segments_.clear(); | 80 memory_segments_.clear(); |
66 DCHECK_EQ(num_blocks_, 0u); | 81 DCHECK_EQ(num_blocks_, 0u); |
67 DCHECK_EQ(num_free_blocks_, 0u); | 82 DCHECK_EQ(num_free_blocks_, 0u); |
(...skipping 17 matching lines...) Expand all Loading... | |
85 scoped_ptr<Span> span( | 100 scoped_ptr<Span> span( |
86 new Span(shared_memory.get(), | 101 new Span(shared_memory.get(), |
87 reinterpret_cast<size_t>(shared_memory->memory()) / block_size_, | 102 reinterpret_cast<size_t>(shared_memory->memory()) / block_size_, |
88 size / block_size_)); | 103 size / block_size_)); |
89 DCHECK(spans_.find(span->start_) == spans_.end()); | 104 DCHECK(spans_.find(span->start_) == spans_.end()); |
90 DCHECK(spans_.find(span->start_ + span->length_ - 1) == spans_.end()); | 105 DCHECK(spans_.find(span->start_ + span->length_ - 1) == spans_.end()); |
91 RegisterSpan(span.get()); | 106 RegisterSpan(span.get()); |
92 | 107 |
93 num_blocks_ += span->length_; | 108 num_blocks_ += span->length_; |
94 | 109 |
110 DiscardableSharedMemoryId new_id = | |
111 g_next_discardable_shared_memory_id.GetNext(); | |
reveman
2015/04/27 13:28:11
Please pass the ID as a parameter instead. ChildDi
ssid
2015/04/27 14:27:01
Oh i dint realize, thanks.
| |
112 | |
95 // Start tracking if segment is resident by adding it to |memory_segments_|. | 113 // Start tracking if segment is resident by adding it to |memory_segments_|. |
96 memory_segments_.push_back(new ScopedMemorySegment(this, shared_memory.Pass(), | 114 memory_segments_.push_back(new ScopedMemorySegment( |
97 size, deleted_callback)); | 115 this, shared_memory.Pass(), size, new_id, deleted_callback)); |
98 | 116 |
99 return span.Pass(); | 117 return span.Pass(); |
100 } | 118 } |
101 | 119 |
102 void DiscardableSharedMemoryHeap::MergeIntoFreeLists(scoped_ptr<Span> span) { | 120 void DiscardableSharedMemoryHeap::MergeIntoFreeLists(scoped_ptr<Span> span) { |
103 DCHECK(span->shared_memory_); | 121 DCHECK(span->shared_memory_); |
104 | 122 |
105 // First add length of |span| to |num_free_blocks_|. | 123 // First add length of |span| to |num_free_blocks_|. |
106 num_free_blocks_ += span->length_; | 124 num_free_blocks_ += span->length_; |
107 | 125 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
205 } | 223 } |
206 | 224 |
207 size_t DiscardableSharedMemoryHeap::GetSize() const { | 225 size_t DiscardableSharedMemoryHeap::GetSize() const { |
208 return num_blocks_ * block_size_; | 226 return num_blocks_ * block_size_; |
209 } | 227 } |
210 | 228 |
211 size_t DiscardableSharedMemoryHeap::GetSizeOfFreeLists() const { | 229 size_t DiscardableSharedMemoryHeap::GetSizeOfFreeLists() const { |
212 return num_free_blocks_ * block_size_; | 230 return num_free_blocks_ * block_size_; |
213 } | 231 } |
214 | 232 |
233 bool DiscardableSharedMemoryHeap::DumpMemoryStatisticsInto( | |
234 base::trace_event::ProcessMemoryDump* pmd) { | |
235 std::for_each(memory_segments_.begin(), memory_segments_.end(), | |
236 [pmd](const ScopedMemorySegment* segment) { | |
237 segment->DumpMemoryStatisticsInto(pmd); | |
238 }); | |
239 return true; | |
240 } | |
241 | |
215 void DiscardableSharedMemoryHeap::InsertIntoFreeList( | 242 void DiscardableSharedMemoryHeap::InsertIntoFreeList( |
216 scoped_ptr<DiscardableSharedMemoryHeap::Span> span) { | 243 scoped_ptr<DiscardableSharedMemoryHeap::Span> span) { |
217 DCHECK(!IsInFreeList(span.get())); | 244 DCHECK(!IsInFreeList(span.get())); |
218 size_t index = std::min(span->length_, arraysize(free_spans_)) - 1; | 245 size_t index = std::min(span->length_, arraysize(free_spans_)) - 1; |
219 free_spans_[index].Append(span.release()); | 246 free_spans_[index].Append(span.release()); |
220 } | 247 } |
221 | 248 |
222 scoped_ptr<DiscardableSharedMemoryHeap::Span> | 249 scoped_ptr<DiscardableSharedMemoryHeap::Span> |
223 DiscardableSharedMemoryHeap::RemoveFromFreeList(Span* span) { | 250 DiscardableSharedMemoryHeap::RemoveFromFreeList(Span* span) { |
224 DCHECK(IsInFreeList(span)); | 251 DCHECK(IsInFreeList(span)); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
309 | 336 |
310 // If |span| is in the free list, remove it and update |num_free_blocks_|. | 337 // If |span| is in the free list, remove it and update |num_free_blocks_|. |
311 if (IsInFreeList(span)) { | 338 if (IsInFreeList(span)) { |
312 DCHECK_GE(num_free_blocks_, span->length_); | 339 DCHECK_GE(num_free_blocks_, span->length_); |
313 num_free_blocks_ -= span->length_; | 340 num_free_blocks_ -= span->length_; |
314 RemoveFromFreeList(span); | 341 RemoveFromFreeList(span); |
315 } | 342 } |
316 } | 343 } |
317 } | 344 } |
318 | 345 |
346 void DiscardableSharedMemoryHeap::DumpSegmentStatistics( | |
347 const base::DiscardableSharedMemory* shared_memory, | |
348 size_t segment_size, | |
reveman
2015/04/27 13:28:11
nit: s/segment_size/size/ to be consistent with Re
ssid
2015/04/27 14:27:01
Done.
| |
349 DiscardableSharedMemoryId id, | |
350 base::trace_event::ProcessMemoryDump* pmd) { | |
351 std::string segment_id = | |
reveman
2015/04/27 13:28:11
nit: maybe heap_name instead
ssid
2015/04/27 14:27:01
Done.
| |
352 base::StringPrintf(kMemoryAllocatorHeapNamePrefix, id); | |
353 base::trace_event::MemoryAllocatorDump* segment_dump = | |
reveman
2015/04/27 13:28:11
fyi, "dump" is enough if the cleans things up, up
ssid
2015/04/27 14:27:01
Done.
| |
354 pmd->CreateAllocatorDump(kMemoryAllocatorName, segment_id.c_str()); | |
reveman
2015/04/27 13:28:11
What if this fails? Looks like other dump provider
ssid
2015/04/27 14:27:01
The check is unnecessary, will be removed in other
reveman
2015/04/27 15:08:58
Acknowledged.
| |
355 | |
356 size_t allocated_objects_count = 0; | |
357 size_t allocated_objects_size_in_bytes = 0; | |
358 size_t offset = | |
359 reinterpret_cast<size_t>(shared_memory->memory()) / block_size_; | |
360 size_t end = offset + segment_size / block_size_; | |
361 while (offset < end) { | |
362 Span* span = spans_[offset]; | |
363 if (!IsInFreeList(span)) { | |
364 allocated_objects_count++; | |
365 allocated_objects_size_in_bytes += span->length_; | |
366 } | |
367 offset += span->length_; | |
368 } | |
369 | |
370 segment_dump->set_physical_size_in_bytes(static_cast<uint64>(segment_size)); | |
371 segment_dump->set_allocated_objects_count( | |
372 static_cast<uint64>(allocated_objects_count)); | |
373 segment_dump->set_allocated_objects_size_in_bytes( | |
374 static_cast<uint64>(allocated_objects_size_in_bytes)); | |
reveman
2015/04/27 13:28:11
are these static_casts really needed?
ssid
2015/04/27 14:27:01
yes, since windows build gives conversion error fr
reveman
2015/04/27 15:08:58
hm, I would expect size_t to uint64 to always be o
| |
375 } | |
376 | |
319 } // namespace content | 377 } // namespace content |
OLD | NEW |