• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Arena(size_t size)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 
~Arena()59 Arena::~Arena() {
60   if (kUseMemMap) {
61     delete map_;
62   } else {
63     free(reinterpret_cast<void*>(memory_));
64   }
65 }
66 
Reset()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 
ArenaPool()78 ArenaPool::ArenaPool()
79     : lock_("Arena pool lock"),
80       free_arenas_(nullptr) {
81 }
82 
~ArenaPool()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 
AllocArena(size_t size)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 
FreeArena(Arena * arena)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 
BytesAllocated() const117 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 
ArenaAllocator(ArenaPool * pool)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 
UpdateBytesAllocated()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 
~ArenaAllocator()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 
ObtainNewArenaForAllocation(size_t allocation_size)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.
DumpMemStats(std::ostream & os) const164 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