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   size_t GetBytesAllocated() const {
    128     return bytes_allocated_;
    129   }
    130 
    131  private:
    132   size_t bytes_allocated_;
    133   uint8_t* memory_;
    134   size_t size_;
    135   MemMap* map_;
    136   Arena* next_;
    137   friend class ArenaPool;
    138   friend class ArenaAllocator;
    139   friend class ArenaStack;
    140   friend class ScopedArenaAllocator;
    141   template <bool kCount> friend class ArenaAllocatorStatsImpl;
    142   DISALLOW_COPY_AND_ASSIGN(Arena);
    143 };
    144 
    145 class ArenaPool {
    146  public:
    147   ArenaPool();
    148   ~ArenaPool();
    149   Arena* AllocArena(size_t size) LOCKS_EXCLUDED(lock_);
    150   void FreeArenaChain(Arena* first) LOCKS_EXCLUDED(lock_);
    151   size_t GetBytesAllocated() const LOCKS_EXCLUDED(lock_);
    152 
    153  private:
    154   mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
    155   Arena* free_arenas_ GUARDED_BY(lock_);
    156   DISALLOW_COPY_AND_ASSIGN(ArenaPool);
    157 };
    158 
    159 class ArenaAllocator : private DebugStackRefCounter, private ArenaAllocatorStats {
    160  public:
    161   explicit ArenaAllocator(ArenaPool* pool);
    162   ~ArenaAllocator();
    163 
    164   // Get adapter for use in STL containers. See arena_containers.h .
    165   ArenaAllocatorAdapter<void> Adapter(ArenaAllocKind kind = kArenaAllocSTL);
    166 
    167   // Returns zeroed memory.
    168   void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE {
    169     if (UNLIKELY(running_on_valgrind_)) {
    170       return AllocValgrind(bytes, kind);
    171     }
    172     bytes = RoundUp(bytes, 8);
    173     if (UNLIKELY(ptr_ + bytes > end_)) {
    174       // Obtain a new block.
    175       ObtainNewArenaForAllocation(bytes);
    176       if (UNLIKELY(ptr_ == nullptr)) {
    177         return nullptr;
    178       }
    179     }
    180     ArenaAllocatorStats::RecordAlloc(bytes, kind);
    181     uint8_t* ret = ptr_;
    182     ptr_ += bytes;
    183     return ret;
    184   }
    185 
    186   template <typename T> T* AllocArray(size_t length) {
    187     return static_cast<T*>(Alloc(length * sizeof(T), kArenaAllocMisc));
    188   }
    189 
    190   void* AllocValgrind(size_t bytes, ArenaAllocKind kind);
    191   void ObtainNewArenaForAllocation(size_t allocation_size);
    192   size_t BytesAllocated() const;
    193   MemStats GetMemStats() const;
    194 
    195  private:
    196   void UpdateBytesAllocated();
    197 
    198   ArenaPool* pool_;
    199   uint8_t* begin_;
    200   uint8_t* end_;
    201   uint8_t* ptr_;
    202   Arena* arena_head_;
    203   bool running_on_valgrind_;
    204 
    205   template <typename U>
    206   friend class ArenaAllocatorAdapter;
    207 
    208   DISALLOW_COPY_AND_ASSIGN(ArenaAllocator);
    209 };  // ArenaAllocator
    210 
    211 class MemStats {
    212  public:
    213   MemStats(const char* name, const ArenaAllocatorStats* stats, const Arena* first_arena,
    214            ssize_t lost_bytes_adjustment = 0);
    215   void Dump(std::ostream& os) const;
    216 
    217  private:
    218   const char* const name_;
    219   const ArenaAllocatorStats* const stats_;
    220   const Arena* const first_arena_;
    221   const ssize_t lost_bytes_adjustment_;
    222 };  // MemStats
    223 
    224 }  // namespace art
    225 
    226 #endif  // ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
    227