blob: 5a91d27ef5d8f830ca35a7c8f4826f66268770c7 [file] [log] [blame]
buzbee862a7602013-04-05 10:58:54 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "compiler_internals.h"
18#include "dex_file-inl.h"
19#include "arena_allocator.h"
20#include "base/logging.h"
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070021#include "base/mutex.h"
Ian Rogers02ed4c02013-09-06 13:10:04 -070022#include "thread-inl.h"
buzbee862a7602013-04-05 10:58:54 -070023
24namespace art {
25
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070026// Memmap is a bit slower than malloc according to my measurements.
27static constexpr bool kUseMemMap = false;
28static constexpr bool kUseMemSet = true && kUseMemMap;
29
buzbee862a7602013-04-05 10:58:54 -070030static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = {
31 "Misc ",
32 "BasicBlock ",
33 "LIR ",
34 "MIR ",
35 "DataFlow ",
36 "GrowList ",
37 "GrowBitMap ",
38 "Dalvik2SSA ",
39 "DebugInfo ",
40 "Successor ",
41 "RegAlloc ",
42 "Data ",
43 "Preds ",
44};
45
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070046Arena::Arena(size_t size)
47 : bytes_allocated_(0),
48 map_(nullptr),
49 next_(nullptr) {
50 if (kUseMemMap) {
51 map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE);
52 memory_ = map_->Begin();
53 size_ = map_->Size();
54 } else {
55 memory_ = reinterpret_cast<uint8_t*>(calloc(1, size));
56 size_ = size;
Ian Rogerse7a5b7d2013-04-18 20:09:02 -070057 }
Ian Rogerse7a5b7d2013-04-18 20:09:02 -070058}
59
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070060Arena::~Arena() {
61 if (kUseMemMap) {
62 delete map_;
63 } else {
64 free(reinterpret_cast<void*>(memory_));
65 }
buzbee862a7602013-04-05 10:58:54 -070066}
67
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070068void Arena::Reset() {
69 if (bytes_allocated_) {
70 if (kUseMemSet || !kUseMemMap) {
71 memset(Begin(), 0, bytes_allocated_);
buzbeea5abf702013-04-12 14:39:29 -070072 } else {
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070073 madvise(Begin(), bytes_allocated_, MADV_DONTNEED);
buzbeea5abf702013-04-12 14:39:29 -070074 }
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070075 bytes_allocated_ = 0;
buzbee862a7602013-04-05 10:58:54 -070076 }
buzbee862a7602013-04-05 10:58:54 -070077}
78
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -070079ArenaPool::ArenaPool()
80 : lock_("Arena pool lock"),
81 free_arenas_(nullptr) {
82}
83
84ArenaPool::~ArenaPool() {
85 while (free_arenas_ != nullptr) {
86 auto* arena = free_arenas_;
87 free_arenas_ = free_arenas_->next_;
88 delete arena;
89 }
90}
91
92Arena* ArenaPool::AllocArena(size_t size) {
93 Thread* self = Thread::Current();
94 Arena* ret = nullptr;
95 {
96 MutexLock lock(self, lock_);
97 if (free_arenas_ != nullptr && LIKELY(free_arenas_->Size() >= size)) {
98 ret = free_arenas_;
99 free_arenas_ = free_arenas_->next_;
100 }
101 }
102 if (ret == nullptr) {
103 ret = new Arena(size);
104 }
105 ret->Reset();
106 return ret;
107}
108
109void ArenaPool::FreeArena(Arena* arena) {
110 Thread* self = Thread::Current();
111 {
112 MutexLock lock(self, lock_);
113 arena->next_ = free_arenas_;
114 free_arenas_ = arena;
115 }
116}
117
118size_t ArenaAllocator::BytesAllocated() const {
buzbee862a7602013-04-05 10:58:54 -0700119 size_t total = 0;
120 for (int i = 0; i < kNumAllocKinds; i++) {
121 total += alloc_stats_[i];
122 }
Mathieu Chartierf6c4b3b2013-08-24 16:11:37 -0700123 return total;
124}
125
126ArenaAllocator::ArenaAllocator(ArenaPool* pool)
127 : pool_(pool),
128 begin_(nullptr),
129 end_(nullptr),
130 ptr_(nullptr),
131 arena_head_(nullptr),
132 num_allocations_(0) {
133 memset(&alloc_stats_[0], 0, sizeof(alloc_stats_));
134}
135
136void ArenaAllocator::UpdateBytesAllocated() {
137 if (arena_head_ != nullptr) {
138 // Update how many bytes we have allocated into the arena so that the arena pool knows how
139 // much memory to zero out.
140 arena_head_->bytes_allocated_ = ptr_ - begin_;
141 }
142}
143
144ArenaAllocator::~ArenaAllocator() {
145 // Reclaim all the arenas by giving them back to the thread pool.
146 UpdateBytesAllocated();
147 while (arena_head_ != nullptr) {
148 Arena* arena = arena_head_;
149 arena_head_ = arena_head_->next_;
150 pool_->FreeArena(arena);
151 }
152}
153
154void ArenaAllocator::ObtainNewArenaForAllocation(size_t allocation_size) {
155 UpdateBytesAllocated();
156 Arena* new_arena = pool_->AllocArena(std::max(Arena::kDefaultSize, allocation_size));
157 new_arena->next_ = arena_head_;
158 arena_head_ = new_arena;
159 // Update our internal data structures.
160 ptr_ = begin_ = new_arena->Begin();
161 end_ = new_arena->End();
162}
163
164// Dump memory usage stats.
165void ArenaAllocator::DumpMemStats(std::ostream& os) const {
166 size_t malloc_bytes = 0;
167 // Start out with how many lost bytes we have in the arena we are currently allocating into.
168 size_t lost_bytes(end_ - ptr_);
169 size_t num_arenas = 0;
170 for (Arena* arena = arena_head_; arena != nullptr; arena = arena->next_) {
171 malloc_bytes += arena->Size();
172 if (arena != arena_head_) {
173 lost_bytes += arena->RemainingSpace();
174 }
175 ++num_arenas;
176 }
177 const size_t bytes_allocated = BytesAllocated();
178 os << " MEM: used: " << bytes_allocated << ", allocated: " << malloc_bytes
179 << ", lost: " << lost_bytes << "\n";
180 if (num_allocations_ != 0) {
181 os << "Number of arenas allocated: " << num_arenas << ", Number of allocations: "
182 << num_allocations_ << ", avg size: " << bytes_allocated / num_allocations_ << "\n";
183 }
buzbee862a7602013-04-05 10:58:54 -0700184 os << "===== Allocation by kind\n";
185 for (int i = 0; i < kNumAllocKinds; i++) {
186 os << alloc_names[i] << std::setw(10) << alloc_stats_[i] << "\n";
187 }
188}
189
190} // namespace art