Add support to create memory allocator dump in base::DiscardableMemory
[chromium-blink-merge.git] / components / html_viewer / discardable_memory_allocator.cc
blob87f58e94d67864aea6fea09ef42604b21c1fd00f
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/html_viewer/discardable_memory_allocator.h"
7 #include "base/memory/discardable_memory.h"
8 #include "base/stl_util.h"
9 #include "base/trace_event/memory_allocator_dump.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "base/trace_event/process_memory_dump.h"
13 namespace html_viewer {
15 // Interface to the rest of the program. These objects are owned outside of the
16 // allocator.
17 class DiscardableMemoryAllocator::DiscardableMemoryChunkImpl
18 : public base::DiscardableMemory {
19 public:
20 DiscardableMemoryChunkImpl(size_t size, DiscardableMemoryAllocator* allocator)
21 : is_locked_(true),
22 size_(size),
23 data_(new uint8_t[size]),
24 allocator_(allocator) {}
26 ~DiscardableMemoryChunkImpl() override {
27 // Either the memory is discarded or the memory chunk is unlocked.
28 DCHECK(data_ || !is_locked_);
29 if (!is_locked_ && data_)
30 allocator_->NotifyDestructed(unlocked_position_);
33 // Overridden from DiscardableMemoryChunk:
34 bool Lock() override {
35 DCHECK(!is_locked_);
36 if (!data_)
37 return false;
39 is_locked_ = true;
40 allocator_->NotifyLocked(unlocked_position_);
41 return true;
44 void Unlock() override {
45 DCHECK(is_locked_);
46 DCHECK(data_);
47 is_locked_ = false;
48 unlocked_position_ = allocator_->NotifyUnlocked(this);
51 void* data() const override {
52 if (data_) {
53 DCHECK(is_locked_);
54 return data_.get();
56 return nullptr;
59 base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
60 const char* name,
61 base::trace_event::ProcessMemoryDump* pmd) const override {
62 base::trace_event::MemoryAllocatorDump* dump =
63 pmd->CreateAllocatorDump(name);
64 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
65 base::trace_event::MemoryAllocatorDump::kUnitsBytes, size_);
67 // Memory is allocated from system allocator (malloc).
68 pmd->AddSuballocation(dump->guid(),
69 base::trace_event::MemoryDumpManager::GetInstance()
70 ->system_allocator_pool_name());
71 return dump;
74 size_t size() const { return size_; }
76 void Discard() {
77 DCHECK(!is_locked_);
78 data_.reset();
81 private:
82 bool is_locked_;
83 size_t size_;
84 scoped_ptr<uint8_t[]> data_;
85 DiscardableMemoryAllocator* allocator_;
87 std::list<DiscardableMemoryChunkImpl*>::iterator unlocked_position_;
89 DISALLOW_IMPLICIT_CONSTRUCTORS(DiscardableMemoryChunkImpl);
92 DiscardableMemoryAllocator::DiscardableMemoryAllocator(
93 size_t desired_max_memory)
94 : desired_max_memory_(desired_max_memory),
95 total_live_memory_(0u),
96 locked_chunks_(0) {
99 DiscardableMemoryAllocator::~DiscardableMemoryAllocator() {
100 DCHECK_EQ(0, locked_chunks_);
101 STLDeleteElements(&live_unlocked_chunks_);
104 scoped_ptr<base::DiscardableMemory>
105 DiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) {
106 base::AutoLock lock(lock_);
107 scoped_ptr<DiscardableMemoryChunkImpl> chunk(
108 new DiscardableMemoryChunkImpl(size, this));
109 total_live_memory_ += size;
110 locked_chunks_++;
112 // Go through the list of unlocked live chunks starting from the least
113 // recently used, freeing as many as we can until we get our size under the
114 // desired maximum.
115 auto it = live_unlocked_chunks_.begin();
116 while (total_live_memory_ > desired_max_memory_ &&
117 it != live_unlocked_chunks_.end()) {
118 total_live_memory_ -= (*it)->size();
119 (*it)->Discard();
120 it = live_unlocked_chunks_.erase(it);
123 return chunk.Pass();
126 std::list<DiscardableMemoryAllocator::DiscardableMemoryChunkImpl*>::iterator
127 DiscardableMemoryAllocator::NotifyUnlocked(DiscardableMemoryChunkImpl* chunk) {
128 base::AutoLock lock(lock_);
129 locked_chunks_--;
130 return live_unlocked_chunks_.insert(live_unlocked_chunks_.end(), chunk);
133 void DiscardableMemoryAllocator::NotifyLocked(
134 std::list<DiscardableMemoryChunkImpl*>::iterator it) {
135 base::AutoLock lock(lock_);
136 locked_chunks_++;
137 live_unlocked_chunks_.erase(it);
140 void DiscardableMemoryAllocator::NotifyDestructed(
141 std::list<DiscardableMemoryChunkImpl*>::iterator it) {
142 base::AutoLock lock(lock_);
143 live_unlocked_chunks_.erase(it);
146 } // namespace html_viewer