Home | History | Annotate | Download | only in dex
      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