Home | History | Annotate | Download | only in base
      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 <algorithm>
     18 #include <cstddef>
     19 #include <iomanip>
     20 #include <numeric>
     21 
     22 #include "arena_allocator.h"
     23 #include "logging.h"
     24 #include "mem_map.h"
     25 #include "mutex.h"
     26 #include "thread-inl.h"
     27 #include "systrace.h"
     28 
     29 namespace art {
     30 
     31 constexpr size_t kMemoryToolRedZoneBytes = 8;
     32 constexpr size_t Arena::kDefaultSize;
     33 
     34 template <bool kCount>
     35 const char* const ArenaAllocatorStatsImpl<kCount>::kAllocNames[] = {
     36   "Misc         ",
     37   "SwitchTbl    ",
     38   "SlowPaths    ",
     39   "GrowBitMap   ",
     40   "STL          ",
     41   "GraphBuilder ",
     42   "Graph        ",
     43   "BasicBlock   ",
     44   "BlockList    ",
     45   "RevPostOrder ",
     46   "LinearOrder  ",
     47   "ConstantsMap ",
     48   "Predecessors ",
     49   "Successors   ",
     50   "Dominated    ",
     51   "Instruction  ",
     52   "InvokeInputs ",
     53   "PhiInputs    ",
     54   "LoopInfo     ",
     55   "LIBackEdges  ",
     56   "TryCatchInf  ",
     57   "UseListNode  ",
     58   "Environment  ",
     59   "EnvVRegs     ",
     60   "EnvLocations ",
     61   "LocSummary   ",
     62   "SsaBuilder   ",
     63   "MoveOperands ",
     64   "CodeBuffer   ",
     65   "StackMaps    ",
     66   "Optimization ",
     67   "GVN          ",
     68   "InductionVar ",
     69   "BCE          ",
     70   "DCE          ",
     71   "LSE          ",
     72   "LICM         ",
     73   "LoopOpt      ",
     74   "SsaLiveness  ",
     75   "SsaPhiElim   ",
     76   "RefTypeProp  ",
     77   "SideEffects  ",
     78   "RegAllocator ",
     79   "RegAllocVldt ",
     80   "StackMapStm  ",
     81   "VectorNode   ",
     82   "CodeGen      ",
     83   "Assembler    ",
     84   "ParallelMove ",
     85   "GraphChecker ",
     86   "Verifier     ",
     87   "CallingConv  ",
     88   "CHA          ",
     89   "Scheduler    ",
     90   "Profile      ",
     91 };
     92 
     93 template <bool kCount>
     94 ArenaAllocatorStatsImpl<kCount>::ArenaAllocatorStatsImpl()
     95     : num_allocations_(0u),
     96       alloc_stats_(kNumArenaAllocKinds, 0u) {
     97 }
     98 
     99 template <bool kCount>
    100 void ArenaAllocatorStatsImpl<kCount>::Copy(const ArenaAllocatorStatsImpl& other) {
    101   num_allocations_ = other.num_allocations_;
    102   std::copy_n(other.alloc_stats_.begin(), kNumArenaAllocKinds, alloc_stats_.begin());
    103 }
    104 
    105 template <bool kCount>
    106 void ArenaAllocatorStatsImpl<kCount>::RecordAlloc(size_t bytes, ArenaAllocKind kind) {
    107   alloc_stats_[kind] += bytes;
    108   ++num_allocations_;
    109 }
    110 
    111 template <bool kCount>
    112 size_t ArenaAllocatorStatsImpl<kCount>::NumAllocations() const {
    113   return num_allocations_;
    114 }
    115 
    116 template <bool kCount>
    117 size_t ArenaAllocatorStatsImpl<kCount>::BytesAllocated() const {
    118   const size_t init = 0u;  // Initial value of the correct type.
    119   return std::accumulate(alloc_stats_.begin(), alloc_stats_.end(), init);
    120 }
    121 
    122 template <bool kCount>
    123 void ArenaAllocatorStatsImpl<kCount>::Dump(std::ostream& os, const Arena* first,
    124                                            ssize_t lost_bytes_adjustment) const {
    125   size_t malloc_bytes = 0u;
    126   size_t lost_bytes = 0u;
    127   size_t num_arenas = 0u;
    128   for (const Arena* arena = first; arena != nullptr; arena = arena->next_) {
    129     malloc_bytes += arena->Size();
    130     lost_bytes += arena->RemainingSpace();
    131     ++num_arenas;
    132   }
    133   // The lost_bytes_adjustment is used to make up for the fact that the current arena
    134   // may not have the bytes_allocated_ updated correctly.
    135   lost_bytes += lost_bytes_adjustment;
    136   const size_t bytes_allocated = BytesAllocated();
    137   os << " MEM: used: " << bytes_allocated << ", allocated: " << malloc_bytes
    138      << ", lost: " << lost_bytes << "\n";
    139   size_t num_allocations = NumAllocations();
    140   if (num_allocations != 0) {
    141     os << "Number of arenas allocated: " << num_arenas << ", Number of allocations: "
    142        << num_allocations << ", avg size: " << bytes_allocated / num_allocations << "\n";
    143   }
    144   os << "===== Allocation by kind\n";
    145   static_assert(arraysize(kAllocNames) == kNumArenaAllocKinds, "arraysize of kAllocNames");
    146   for (int i = 0; i < kNumArenaAllocKinds; i++) {
    147       os << kAllocNames[i] << std::setw(10) << alloc_stats_[i] << "\n";
    148   }
    149 }
    150 
    151 #pragma GCC diagnostic push
    152 #if __clang_major__ >= 4
    153 #pragma GCC diagnostic ignored "-Winstantiation-after-specialization"
    154 #endif
    155 // We're going to use ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations> which needs
    156 // to be explicitly instantiated if kArenaAllocatorCountAllocations is true. Explicit
    157 // instantiation of the specialization ArenaAllocatorStatsImpl<false> does not do anything
    158 // but requires the warning "-Winstantiation-after-specialization" to be turned off.
    159 //
    160 // To avoid bit-rot of the ArenaAllocatorStatsImpl<true>, instantiate it also in debug builds
    161 // (but keep the unnecessary code out of release builds) as we do not usually compile with
    162 // kArenaAllocatorCountAllocations set to true.
    163 template class ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations || kIsDebugBuild>;
    164 #pragma GCC diagnostic pop
    165 
    166 void ArenaAllocatorMemoryTool::DoMakeDefined(void* ptr, size_t size) {
    167   MEMORY_TOOL_MAKE_DEFINED(ptr, size);
    168 }
    169 
    170 void ArenaAllocatorMemoryTool::DoMakeUndefined(void* ptr, size_t size) {
    171   MEMORY_TOOL_MAKE_UNDEFINED(ptr, size);
    172 }
    173 
    174 void ArenaAllocatorMemoryTool::DoMakeInaccessible(void* ptr, size_t size) {
    175   MEMORY_TOOL_MAKE_NOACCESS(ptr, size);
    176 }
    177 
    178 Arena::Arena() : bytes_allocated_(0), memory_(nullptr), size_(0), next_(nullptr) {
    179 }
    180 
    181 class MallocArena FINAL : public Arena {
    182  public:
    183   explicit MallocArena(size_t size = Arena::kDefaultSize);
    184   virtual ~MallocArena();
    185  private:
    186   static constexpr size_t RequiredOverallocation() {
    187     return (alignof(std::max_align_t) < ArenaAllocator::kArenaAlignment)
    188         ? ArenaAllocator::kArenaAlignment - alignof(std::max_align_t)
    189         : 0u;
    190   }
    191 
    192   uint8_t* unaligned_memory_;
    193 };
    194 
    195 MallocArena::MallocArena(size_t size) {
    196   // We need to guarantee kArenaAlignment aligned allocation for the new arena.
    197   // TODO: Use std::aligned_alloc() when it becomes available with C++17.
    198   constexpr size_t overallocation = RequiredOverallocation();
    199   unaligned_memory_ = reinterpret_cast<uint8_t*>(calloc(1, size + overallocation));
    200   CHECK(unaligned_memory_ != nullptr);  // Abort on OOM.
    201   DCHECK_ALIGNED(unaligned_memory_, alignof(std::max_align_t));
    202   if (overallocation == 0u) {
    203     memory_ = unaligned_memory_;
    204   } else {
    205     memory_ = AlignUp(unaligned_memory_, ArenaAllocator::kArenaAlignment);
    206     if (UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
    207       size_t head = memory_ - unaligned_memory_;
    208       size_t tail = overallocation - head;
    209       MEMORY_TOOL_MAKE_NOACCESS(unaligned_memory_, head);
    210       MEMORY_TOOL_MAKE_NOACCESS(memory_ + size, tail);
    211     }
    212   }
    213   DCHECK_ALIGNED(memory_, ArenaAllocator::kArenaAlignment);
    214   size_ = size;
    215 }
    216 
    217 MallocArena::~MallocArena() {
    218   constexpr size_t overallocation = RequiredOverallocation();
    219   if (overallocation != 0u && UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
    220     size_t head = memory_ - unaligned_memory_;
    221     size_t tail = overallocation - head;
    222     MEMORY_TOOL_MAKE_UNDEFINED(unaligned_memory_, head);
    223     MEMORY_TOOL_MAKE_UNDEFINED(memory_ + size_, tail);
    224   }
    225   free(reinterpret_cast<void*>(unaligned_memory_));
    226 }
    227 
    228 class MemMapArena FINAL : public Arena {
    229  public:
    230   MemMapArena(size_t size, bool low_4gb, const char* name);
    231   virtual ~MemMapArena();
    232   void Release() OVERRIDE;
    233 
    234  private:
    235   std::unique_ptr<MemMap> map_;
    236 };
    237 
    238 MemMapArena::MemMapArena(size_t size, bool low_4gb, const char* name) {
    239   // Round up to a full page as that's the smallest unit of allocation for mmap()
    240   // and we want to be able to use all memory that we actually allocate.
    241   size = RoundUp(size, kPageSize);
    242   std::string error_msg;
    243   map_.reset(MemMap::MapAnonymous(
    244       name, nullptr, size, PROT_READ | PROT_WRITE, low_4gb, false, &error_msg));
    245   CHECK(map_.get() != nullptr) << error_msg;
    246   memory_ = map_->Begin();
    247   static_assert(ArenaAllocator::kArenaAlignment <= kPageSize,
    248                 "Arena should not need stronger alignment than kPageSize.");
    249   DCHECK_ALIGNED(memory_, ArenaAllocator::kArenaAlignment);
    250   size_ = map_->Size();
    251 }
    252 
    253 MemMapArena::~MemMapArena() {
    254   // Destroys MemMap via std::unique_ptr<>.
    255 }
    256 
    257 void MemMapArena::Release() {
    258   if (bytes_allocated_ > 0) {
    259     map_->MadviseDontNeedAndZero();
    260     bytes_allocated_ = 0;
    261   }
    262 }
    263 
    264 void Arena::Reset() {
    265   if (bytes_allocated_ > 0) {
    266     memset(Begin(), 0, bytes_allocated_);
    267     bytes_allocated_ = 0;
    268   }
    269 }
    270 
    271 ArenaPool::ArenaPool(bool use_malloc, bool low_4gb, const char* name)
    272     : use_malloc_(use_malloc),
    273       lock_("Arena pool lock", kArenaPoolLock),
    274       free_arenas_(nullptr),
    275       low_4gb_(low_4gb),
    276       name_(name) {
    277   if (low_4gb) {
    278     CHECK(!use_malloc) << "low4gb must use map implementation";
    279   }
    280   if (!use_malloc) {
    281     MemMap::Init();
    282   }
    283 }
    284 
    285 ArenaPool::~ArenaPool() {
    286   ReclaimMemory();
    287 }
    288 
    289 void ArenaPool::ReclaimMemory() {
    290   while (free_arenas_ != nullptr) {
    291     auto* arena = free_arenas_;
    292     free_arenas_ = free_arenas_->next_;
    293     delete arena;
    294   }
    295 }
    296 
    297 void ArenaPool::LockReclaimMemory() {
    298   MutexLock lock(Thread::Current(), lock_);
    299   ReclaimMemory();
    300 }
    301 
    302 Arena* ArenaPool::AllocArena(size_t size) {
    303   Thread* self = Thread::Current();
    304   Arena* ret = nullptr;
    305   {
    306     MutexLock lock(self, lock_);
    307     if (free_arenas_ != nullptr && LIKELY(free_arenas_->Size() >= size)) {
    308       ret = free_arenas_;
    309       free_arenas_ = free_arenas_->next_;
    310     }
    311   }
    312   if (ret == nullptr) {
    313     ret = use_malloc_ ? static_cast<Arena*>(new MallocArena(size)) :
    314         new MemMapArena(size, low_4gb_, name_);
    315   }
    316   ret->Reset();
    317   return ret;
    318 }
    319 
    320 void ArenaPool::TrimMaps() {
    321   if (!use_malloc_) {
    322     ScopedTrace trace(__PRETTY_FUNCTION__);
    323     // Doesn't work for malloc.
    324     MutexLock lock(Thread::Current(), lock_);
    325     for (auto* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
    326       arena->Release();
    327     }
    328   }
    329 }
    330 
    331 size_t ArenaPool::GetBytesAllocated() const {
    332   size_t total = 0;
    333   MutexLock lock(Thread::Current(), lock_);
    334   for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
    335     total += arena->GetBytesAllocated();
    336   }
    337   return total;
    338 }
    339 
    340 void ArenaPool::FreeArenaChain(Arena* first) {
    341   if (UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
    342     for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
    343       MEMORY_TOOL_MAKE_UNDEFINED(arena->memory_, arena->bytes_allocated_);
    344     }
    345   }
    346   if (first != nullptr) {
    347     Arena* last = first;
    348     while (last->next_ != nullptr) {
    349       last = last->next_;
    350     }
    351     Thread* self = Thread::Current();
    352     MutexLock lock(self, lock_);
    353     last->next_ = free_arenas_;
    354     free_arenas_ = first;
    355   }
    356 }
    357 
    358 size_t ArenaAllocator::BytesAllocated() const {
    359   return ArenaAllocatorStats::BytesAllocated();
    360 }
    361 
    362 size_t ArenaAllocator::BytesUsed() const {
    363   size_t total = ptr_ - begin_;
    364   if (arena_head_ != nullptr) {
    365     for (Arena* cur_arena = arena_head_->next_; cur_arena != nullptr;
    366          cur_arena = cur_arena->next_) {
    367      total += cur_arena->GetBytesAllocated();
    368     }
    369   }
    370   return total;
    371 }
    372 
    373 ArenaAllocator::ArenaAllocator(ArenaPool* pool)
    374   : pool_(pool),
    375     begin_(nullptr),
    376     end_(nullptr),
    377     ptr_(nullptr),
    378     arena_head_(nullptr) {
    379 }
    380 
    381 void ArenaAllocator::UpdateBytesAllocated() {
    382   if (arena_head_ != nullptr) {
    383     // Update how many bytes we have allocated into the arena so that the arena pool knows how
    384     // much memory to zero out.
    385     arena_head_->bytes_allocated_ = ptr_ - begin_;
    386   }
    387 }
    388 
    389 void* ArenaAllocator::AllocWithMemoryTool(size_t bytes, ArenaAllocKind kind) {
    390   // We mark all memory for a newly retrieved arena as inaccessible and then
    391   // mark only the actually allocated memory as defined. That leaves red zones
    392   // and padding between allocations marked as inaccessible.
    393   size_t rounded_bytes = RoundUp(bytes + kMemoryToolRedZoneBytes, 8);
    394   ArenaAllocatorStats::RecordAlloc(rounded_bytes, kind);
    395   uint8_t* ret;
    396   if (UNLIKELY(rounded_bytes > static_cast<size_t>(end_ - ptr_))) {
    397     ret = AllocFromNewArenaWithMemoryTool(rounded_bytes);
    398   } else {
    399     ret = ptr_;
    400     ptr_ += rounded_bytes;
    401   }
    402   MEMORY_TOOL_MAKE_DEFINED(ret, bytes);
    403   // Check that the memory is already zeroed out.
    404   DCHECK(std::all_of(ret, ret + bytes, [](uint8_t val) { return val == 0u; }));
    405   return ret;
    406 }
    407 
    408 void* ArenaAllocator::AllocWithMemoryToolAlign16(size_t bytes, ArenaAllocKind kind) {
    409   // We mark all memory for a newly retrieved arena as inaccessible and then
    410   // mark only the actually allocated memory as defined. That leaves red zones
    411   // and padding between allocations marked as inaccessible.
    412   size_t rounded_bytes = bytes + kMemoryToolRedZoneBytes;
    413   DCHECK_ALIGNED(rounded_bytes, 8);  // `bytes` is 16-byte aligned, red zone is 8-byte aligned.
    414   uintptr_t padding =
    415       ((reinterpret_cast<uintptr_t>(ptr_) + 15u) & 15u) - reinterpret_cast<uintptr_t>(ptr_);
    416   ArenaAllocatorStats::RecordAlloc(rounded_bytes, kind);
    417   uint8_t* ret;
    418   if (UNLIKELY(padding + rounded_bytes > static_cast<size_t>(end_ - ptr_))) {
    419     static_assert(kArenaAlignment >= 16, "Expecting sufficient alignment for new Arena.");
    420     ret = AllocFromNewArenaWithMemoryTool(rounded_bytes);
    421   } else {
    422     ptr_ += padding;  // Leave padding inaccessible.
    423     ret = ptr_;
    424     ptr_ += rounded_bytes;
    425   }
    426   MEMORY_TOOL_MAKE_DEFINED(ret, bytes);
    427   // Check that the memory is already zeroed out.
    428   DCHECK(std::all_of(ret, ret + bytes, [](uint8_t val) { return val == 0u; }));
    429   return ret;
    430 }
    431 
    432 ArenaAllocator::~ArenaAllocator() {
    433   // Reclaim all the arenas by giving them back to the thread pool.
    434   UpdateBytesAllocated();
    435   pool_->FreeArenaChain(arena_head_);
    436 }
    437 
    438 uint8_t* ArenaAllocator::AllocFromNewArena(size_t bytes) {
    439   Arena* new_arena = pool_->AllocArena(std::max(Arena::kDefaultSize, bytes));
    440   DCHECK(new_arena != nullptr);
    441   DCHECK_LE(bytes, new_arena->Size());
    442   if (static_cast<size_t>(end_ - ptr_) > new_arena->Size() - bytes) {
    443     // The old arena has more space remaining than the new one, so keep using it.
    444     // This can happen when the requested size is over half of the default size.
    445     DCHECK(arena_head_ != nullptr);
    446     new_arena->bytes_allocated_ = bytes;  // UpdateBytesAllocated() on the new_arena.
    447     new_arena->next_ = arena_head_->next_;
    448     arena_head_->next_ = new_arena;
    449   } else {
    450     UpdateBytesAllocated();
    451     new_arena->next_ = arena_head_;
    452     arena_head_ = new_arena;
    453     // Update our internal data structures.
    454     begin_ = new_arena->Begin();
    455     DCHECK_ALIGNED(begin_, kAlignment);
    456     ptr_ = begin_ + bytes;
    457     end_ = new_arena->End();
    458   }
    459   return new_arena->Begin();
    460 }
    461 
    462 uint8_t* ArenaAllocator::AllocFromNewArenaWithMemoryTool(size_t bytes) {
    463   uint8_t* ret = AllocFromNewArena(bytes);
    464   uint8_t* noaccess_begin = ret + bytes;
    465   uint8_t* noaccess_end;
    466   if (ret == arena_head_->Begin()) {
    467     DCHECK(ptr_ - bytes == ret);
    468     noaccess_end = end_;
    469   } else {
    470     // We're still using the old arena but `ret` comes from a new one just after it.
    471     DCHECK(arena_head_->next_ != nullptr);
    472     DCHECK(ret == arena_head_->next_->Begin());
    473     DCHECK_EQ(bytes, arena_head_->next_->GetBytesAllocated());
    474     noaccess_end = arena_head_->next_->End();
    475   }
    476   MEMORY_TOOL_MAKE_NOACCESS(noaccess_begin, noaccess_end - noaccess_begin);
    477   return ret;
    478 }
    479 
    480 bool ArenaAllocator::Contains(const void* ptr) const {
    481   if (ptr >= begin_ && ptr < end_) {
    482     return true;
    483   }
    484   for (const Arena* cur_arena = arena_head_; cur_arena != nullptr; cur_arena = cur_arena->next_) {
    485     if (cur_arena->Contains(ptr)) {
    486       return true;
    487     }
    488   }
    489   return false;
    490 }
    491 
    492 MemStats::MemStats(const char* name,
    493                    const ArenaAllocatorStats* stats,
    494                    const Arena* first_arena,
    495                    ssize_t lost_bytes_adjustment)
    496     : name_(name),
    497       stats_(stats),
    498       first_arena_(first_arena),
    499       lost_bytes_adjustment_(lost_bytes_adjustment) {
    500 }
    501 
    502 void MemStats::Dump(std::ostream& os) const {
    503   os << name_ << " stats:\n";
    504   stats_->Dump(os, first_arena_, lost_bytes_adjustment_);
    505 }
    506 
    507 // Dump memory usage stats.
    508 MemStats ArenaAllocator::GetMemStats() const {
    509   ssize_t lost_bytes_adjustment =
    510       (arena_head_ == nullptr) ? 0 : (end_ - ptr_) - arena_head_->RemainingSpace();
    511   return MemStats("ArenaAllocator", this, arena_head_, lost_bytes_adjustment);
    512 }
    513 
    514 }  // namespace art
    515