Home | History | Annotate | Download | only in utils
      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 #ifndef ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
     18 #define ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
     19 
     20 #include <stdint.h>
     21 #include <stddef.h>
     22 
     23 #include "base/macros.h"
     24 #include "base/mutex.h"
     25 #include "mem_map.h"
     26 #include "utils.h"
     27 #include "utils/debug_stack.h"
     28 
     29 namespace art {
     30 
     31 class Arena;
     32 class ArenaPool;
     33 class ArenaAllocator;
     34 class ArenaStack;
     35 class ScopedArenaAllocator;
     36 class MemStats;
     37 
     38 template <typename T>
     39 class ArenaAllocatorAdapter;
     40 
     41 static constexpr bool kArenaAllocatorCountAllocations = false;
     42 
     43 // Type of allocation for memory tuning.
     44 enum ArenaAllocKind {
     45   kArenaAllocMisc,
     46   kArenaAllocBB,
     47   kArenaAllocLIR,
     48   kArenaAllocLIRResourceMask,
     49   kArenaAllocMIR,
     50   kArenaAllocDFInfo,
     51   kArenaAllocGrowableArray,
     52   kArenaAllocGrowableBitMap,
     53   kArenaAllocDalvikToSSAMap,
     54   kArenaAllocDebugInfo,
     55   kArenaAllocSuccessor,
     56   kArenaAllocRegAlloc,
     57   kArenaAllocData,
     58   kArenaAllocPredecessors,
     59   kArenaAllocSTL,
     60   kNumArenaAllocKinds
     61 };
     62 
     63 template <bool kCount>
     64 class ArenaAllocatorStatsImpl;
     65 
     66 template <>
     67 class ArenaAllocatorStatsImpl<false> {
     68  public:
     69   ArenaAllocatorStatsImpl() = default;
     70   ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default;
     71   ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete;
     72 
     73   void Copy(const ArenaAllocatorStatsImpl& other) { UNUSED(other); }
     74   void RecordAlloc(size_t bytes, ArenaAllocKind kind) { UNUSED(bytes); UNUSED(kind); }
     75   size_t NumAllocations() const { return 0u; }
     76   size_t BytesAllocated() const { return 0u; }
     77   void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const {
     78     UNUSED(os); UNUSED(first); UNUSED(lost_bytes_adjustment);
     79   }
     80 };
     81 
     82 template <bool kCount>
     83 class ArenaAllocatorStatsImpl {
     84  public:
     85   ArenaAllocatorStatsImpl();
     86   ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default;
     87   ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete;
     88 
     89   void Copy(const ArenaAllocatorStatsImpl& other);
     90   void RecordAlloc(size_t bytes, ArenaAllocKind kind);
     91   size_t NumAllocations() const;
     92   size_t BytesAllocated() const;
     93   void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const;
     94 
     95  private:
     96   size_t num_allocations_;
     97   // TODO: Use std::array<size_t, kNumArenaAllocKinds> from C++11 when we upgrade the STL.
     98   size_t alloc_stats_[kNumArenaAllocKinds];  // Bytes used by various allocation kinds.
     99 
    100   static const char* const kAllocNames[];
    101 };
    102 
    103 typedef ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations> ArenaAllocatorStats;
    104 
    105 class Arena {
    106  public:
    107   static constexpr size_t kDefaultSize = 128 * KB;
    108   explicit Arena(size_t size = kDefaultSize);
    109   ~Arena();
    110   void Reset();
    111   uint8_t* Begin() {
    112     return memory_;
    113   }
    114 
    115   uint8_t* End() {
    116     return memory_ + size_;
    117   }
    118 
    119   size_t Size() const {
    120     return size_;
    121   }
    122 
    123   size_t RemainingSpace() const {
    124     return Size() - bytes_allocated_;
    125   }
    126 
    127  private:
    128   size_t bytes_allocated_;
    129   uint8_t* memory_;
    130   size_t size_;
    131   MemMap* map_;
    132   Arena* next_;
    133   friend class ArenaPool;
    134   friend class ArenaAllocator;
    135   friend class ArenaStack;
    136   friend class ScopedArenaAllocator;
    137   template <bool kCount> friend class ArenaAllocatorStatsImpl;
    138   DISALLOW_COPY_AND_ASSIGN(Arena);
    139 };
    140 
    141 class ArenaPool {
    142  public:
    143   ArenaPool();
    144   ~ArenaPool();
    145   Arena* AllocArena(size_t size);
    146   void FreeArenaChain(Arena* first);
    147 
    148  private:
    149   Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
    150   Arena* free_arenas_ GUARDED_BY(lock_);
    151   DISALLOW_COPY_AND_ASSIGN(ArenaPool);
    152 };
    153 
    154 class ArenaAllocator : private DebugStackRefCounter, private ArenaAllocatorStats {
    155  public:
    156   explicit ArenaAllocator(ArenaPool* pool);
    157   ~ArenaAllocator();
    158 
    159   // Get adapter for use in STL containers. See arena_containers.h .
    160   ArenaAllocatorAdapter<void> Adapter(ArenaAllocKind kind = kArenaAllocSTL);
    161 
    162   // Returns zeroed memory.
    163   void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE {
    164     if (UNLIKELY(running_on_valgrind_)) {
    165       return AllocValgrind(bytes, kind);
    166     }
    167     bytes = RoundUp(bytes, 8);
    168     if (UNLIKELY(ptr_ + bytes > end_)) {
    169       // Obtain a new block.
    170       ObtainNewArenaForAllocation(bytes);
    171       if (UNLIKELY(ptr_ == nullptr)) {
    172         return nullptr;
    173       }
    174     }
    175     ArenaAllocatorStats::RecordAlloc(bytes, kind);
    176     uint8_t* ret = ptr_;
    177     ptr_ += bytes;
    178     return ret;
    179   }
    180 
    181   template <typename T> T* AllocArray(size_t length) {
    182     return static_cast<T*>(Alloc(length * sizeof(T), kArenaAllocMisc));
    183   }
    184 
    185   void* AllocValgrind(size_t bytes, ArenaAllocKind kind);
    186   void ObtainNewArenaForAllocation(size_t allocation_size);
    187   size_t BytesAllocated() const;
    188   MemStats GetMemStats() const;
    189 
    190  private:
    191   void UpdateBytesAllocated();
    192 
    193   ArenaPool* pool_;
    194   uint8_t* begin_;
    195   uint8_t* end_;
    196   uint8_t* ptr_;
    197   Arena* arena_head_;
    198   bool running_on_valgrind_;
    199 
    200   template <typename U>
    201   friend class ArenaAllocatorAdapter;
    202 
    203   DISALLOW_COPY_AND_ASSIGN(ArenaAllocator);
    204 };  // ArenaAllocator
    205 
    206 class MemStats {
    207  public:
    208   MemStats(const char* name, const ArenaAllocatorStats* stats, const Arena* first_arena,
    209            ssize_t lost_bytes_adjustment = 0);
    210   void Dump(std::ostream& os) const;
    211 
    212  private:
    213   const char* const name_;
    214   const ArenaAllocatorStats* const stats_;
    215   const Arena* const first_arena_;
    216   const ssize_t lost_bytes_adjustment_;
    217 };  // MemStats
    218 
    219 }  // namespace art
    220 
    221 #endif  // ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
    222