1 /* 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" 21 #include "base/mutex.h" 22 23 namespace art { 24 25 // Memmap is a bit slower than malloc according to my measurements. 26 static constexpr bool kUseMemMap = false; 27 static constexpr bool kUseMemSet = true && kUseMemMap; 28 29 static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = { 30 "Misc ", 31 "BasicBlock ", 32 "LIR ", 33 "MIR ", 34 "DataFlow ", 35 "GrowList ", 36 "GrowBitMap ", 37 "Dalvik2SSA ", 38 "DebugInfo ", 39 "Successor ", 40 "RegAlloc ", 41 "Data ", 42 "Preds ", 43 }; 44 45 Arena::Arena(size_t size) 46 : bytes_allocated_(0), 47 map_(nullptr), 48 next_(nullptr) { 49 if (kUseMemMap) { 50 map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE); 51 memory_ = map_->Begin(); 52 size_ = map_->Size(); 53 } else { 54 memory_ = reinterpret_cast<uint8_t*>(calloc(1, size)); 55 size_ = size; 56 } 57 } 58 59 Arena::~Arena() { 60 if (kUseMemMap) { 61 delete map_; 62 } else { 63 free(reinterpret_cast<void*>(memory_)); 64 } 65 } 66 67 void Arena::Reset() { 68 if (bytes_allocated_) { 69 if (kUseMemSet || !kUseMemMap) { 70 memset(Begin(), 0, bytes_allocated_); 71 } else { 72 madvise(Begin(), bytes_allocated_, MADV_DONTNEED); 73 } 74 bytes_allocated_ = 0; 75 } 76 } 77 78 ArenaPool::ArenaPool() 79 : lock_("Arena pool lock"), 80 free_arenas_(nullptr) { 81 } 82 83 ArenaPool::~ArenaPool() { 84 while (free_arenas_ != nullptr) { 85 auto* arena = free_arenas_; 86 free_arenas_ = free_arenas_->next_; 87 delete arena; 88 } 89 } 90 91 Arena* ArenaPool::AllocArena(size_t size) { 92 Thread* self = Thread::Current(); 93 Arena* ret = nullptr; 94 { 95 MutexLock lock(self, lock_); 96 if (free_arenas_ != nullptr && LIKELY(free_arenas_->Size() >= size)) { 97 ret = free_arenas_; 98 free_arenas_ = free_arenas_->next_; 99 } 100 } 101 if (ret == nullptr) { 102 ret = new Arena(size); 103 } 104 ret->Reset(); 105 return ret; 106 } 107 108 void ArenaPool::FreeArena(Arena* arena) { 109 Thread* self = Thread::Current(); 110 { 111 MutexLock lock(self, lock_); 112 arena->next_ = free_arenas_; 113 free_arenas_ = arena; 114 } 115 } 116 117 size_t ArenaAllocator::BytesAllocated() const { 118 size_t total = 0; 119 for (int i = 0; i < kNumAllocKinds; i++) { 120 total += alloc_stats_[i]; 121 } 122 return total; 123 } 124 125 ArenaAllocator::ArenaAllocator(ArenaPool* pool) 126 : pool_(pool), 127 begin_(nullptr), 128 end_(nullptr), 129 ptr_(nullptr), 130 arena_head_(nullptr), 131 num_allocations_(0) { 132 memset(&alloc_stats_[0], 0, sizeof(alloc_stats_)); 133 } 134 135 void ArenaAllocator::UpdateBytesAllocated() { 136 if (arena_head_ != nullptr) { 137 // Update how many bytes we have allocated into the arena so that the arena pool knows how 138 // much memory to zero out. 139 arena_head_->bytes_allocated_ = ptr_ - begin_; 140 } 141 } 142 143 ArenaAllocator::~ArenaAllocator() { 144 // Reclaim all the arenas by giving them back to the thread pool. 145 UpdateBytesAllocated(); 146 while (arena_head_ != nullptr) { 147 Arena* arena = arena_head_; 148 arena_head_ = arena_head_->next_; 149 pool_->FreeArena(arena); 150 } 151 } 152 153 void ArenaAllocator::ObtainNewArenaForAllocation(size_t allocation_size) { 154 UpdateBytesAllocated(); 155 Arena* new_arena = pool_->AllocArena(std::max(Arena::kDefaultSize, allocation_size)); 156 new_arena->next_ = arena_head_; 157 arena_head_ = new_arena; 158 // Update our internal data structures. 159 ptr_ = begin_ = new_arena->Begin(); 160 end_ = new_arena->End(); 161 } 162 163 // Dump memory usage stats. 164 void ArenaAllocator::DumpMemStats(std::ostream& os) const { 165 size_t malloc_bytes = 0; 166 // Start out with how many lost bytes we have in the arena we are currently allocating into. 167 size_t lost_bytes(end_ - ptr_); 168 size_t num_arenas = 0; 169 for (Arena* arena = arena_head_; arena != nullptr; arena = arena->next_) { 170 malloc_bytes += arena->Size(); 171 if (arena != arena_head_) { 172 lost_bytes += arena->RemainingSpace(); 173 } 174 ++num_arenas; 175 } 176 const size_t bytes_allocated = BytesAllocated(); 177 os << " MEM: used: " << bytes_allocated << ", allocated: " << malloc_bytes 178 << ", lost: " << lost_bytes << "\n"; 179 if (num_allocations_ != 0) { 180 os << "Number of arenas allocated: " << num_arenas << ", Number of allocations: " 181 << num_allocations_ << ", avg size: " << bytes_allocated / num_allocations_ << "\n"; 182 } 183 os << "===== Allocation by kind\n"; 184 for (int i = 0; i < kNumAllocKinds; i++) { 185 os << alloc_names[i] << std::setw(10) << alloc_stats_[i] << "\n"; 186 } 187 } 188 189 } // namespace art 190