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 #ifndef ART_RUNTIME_BASE_ALLOCATOR_H_
     18 #define ART_RUNTIME_BASE_ALLOCATOR_H_
     19 
     20 #include <map>
     21 #include <set>
     22 #include <unordered_map>
     23 
     24 #include "atomic.h"
     25 #include "base/hash_map.h"
     26 #include "base/macros.h"
     27 #include "base/mutex.h"
     28 #include "base/type_static_if.h"
     29 
     30 namespace art {
     31 
     32 static constexpr bool kEnableTrackingAllocator = false;
     33 
     34 class Allocator {
     35  public:
     36   static Allocator* GetMallocAllocator();
     37   static Allocator* GetNoopAllocator();
     38 
     39   Allocator() {}
     40   virtual ~Allocator() {}
     41 
     42   virtual void* Alloc(size_t) = 0;
     43   virtual void Free(void*) = 0;
     44 
     45  private:
     46   DISALLOW_COPY_AND_ASSIGN(Allocator);
     47 };
     48 
     49 // Used by TrackedAllocators.
     50 enum AllocatorTag {
     51   kAllocatorTagHeap,
     52   kAllocatorTagMonitorList,
     53   kAllocatorTagClassTable,
     54   kAllocatorTagInternTable,
     55   kAllocatorTagMaps,
     56   kAllocatorTagLOS,
     57   kAllocatorTagSafeMap,
     58   kAllocatorTagLOSMaps,
     59   kAllocatorTagReferenceTable,
     60   kAllocatorTagHeapBitmap,
     61   kAllocatorTagHeapBitmapLOS,
     62   kAllocatorTagMonitorPool,
     63   kAllocatorTagLOSFreeList,
     64   kAllocatorTagVerifier,
     65   kAllocatorTagRememberedSet,
     66   kAllocatorTagModUnionCardSet,
     67   kAllocatorTagModUnionReferenceArray,
     68   kAllocatorTagJNILibraries,
     69   kAllocatorTagCompileTimeClassPath,
     70   kAllocatorTagOatFile,
     71   kAllocatorTagDexFileVerifier,
     72   kAllocatorTagRosAlloc,
     73   kAllocatorTagCount,  // Must always be last element.
     74 };
     75 std::ostream& operator<<(std::ostream& os, const AllocatorTag& tag);
     76 
     77 namespace TrackedAllocators {
     78 
     79 // Running count of number of bytes used for this kind of allocation. Increased by allocations,
     80 // decreased by deallocations.
     81 extern Atomic<size_t> g_bytes_used[kAllocatorTagCount];
     82 
     83 // Largest value of bytes used seen.
     84 extern volatile size_t g_max_bytes_used[kAllocatorTagCount];
     85 
     86 // Total number of bytes allocated of this kind.
     87 extern Atomic<uint64_t> g_total_bytes_used[kAllocatorTagCount];
     88 
     89 void Dump(std::ostream& os);
     90 
     91 inline void RegisterAllocation(AllocatorTag tag, size_t bytes) {
     92   g_total_bytes_used[tag].FetchAndAddSequentiallyConsistent(bytes);
     93   size_t new_bytes = g_bytes_used[tag].FetchAndAddSequentiallyConsistent(bytes) + bytes;
     94   if (g_max_bytes_used[tag] < new_bytes) {
     95     g_max_bytes_used[tag] = new_bytes;
     96   }
     97 }
     98 
     99 inline void RegisterFree(AllocatorTag tag, size_t bytes) {
    100   g_bytes_used[tag].FetchAndSubSequentiallyConsistent(bytes);
    101 }
    102 
    103 }  // namespace TrackedAllocators
    104 
    105 // Tracking allocator for use with STL types, tracks how much memory is used.
    106 template<class T, AllocatorTag kTag>
    107 class TrackingAllocatorImpl : public std::allocator<T> {
    108  public:
    109   typedef typename std::allocator<T>::value_type value_type;
    110   typedef typename std::allocator<T>::size_type size_type;
    111   typedef typename std::allocator<T>::difference_type difference_type;
    112   typedef typename std::allocator<T>::pointer pointer;
    113   typedef typename std::allocator<T>::const_pointer const_pointer;
    114   typedef typename std::allocator<T>::reference reference;
    115   typedef typename std::allocator<T>::const_reference const_reference;
    116 
    117   // Used internally by STL data structures.
    118   template <class U>
    119   TrackingAllocatorImpl( // NOLINT, implicit
    120       const TrackingAllocatorImpl<U, kTag>& alloc ATTRIBUTE_UNUSED) noexcept {}
    121 
    122   // Used internally by STL data structures.
    123   TrackingAllocatorImpl() noexcept {
    124     static_assert(kTag < kAllocatorTagCount, "kTag must be less than kAllocatorTagCount");
    125   }
    126 
    127   // Enables an allocator for objects of one type to allocate storage for objects of another type.
    128   // Used internally by STL data structures.
    129   template <class U>
    130   struct rebind {
    131     typedef TrackingAllocatorImpl<U, kTag> other;
    132   };
    133 
    134   pointer allocate(size_type n, const_pointer hint ATTRIBUTE_UNUSED = 0) {
    135     const size_t size = n * sizeof(T);
    136     TrackedAllocators::RegisterAllocation(GetTag(), size);
    137     return reinterpret_cast<pointer>(malloc(size));
    138   }
    139 
    140   template <typename PT>
    141   void deallocate(PT p, size_type n) {
    142     const size_t size = n * sizeof(T);
    143     TrackedAllocators::RegisterFree(GetTag(), size);
    144     free(p);
    145   }
    146 
    147   static constexpr AllocatorTag GetTag() {
    148     return kTag;
    149   }
    150 };
    151 
    152 template<class T, AllocatorTag kTag>
    153 // C++ doesn't allow template typedefs. This is a workaround template typedef which is
    154 // TrackingAllocatorImpl<T> if kEnableTrackingAllocator is true, std::allocator<T> otherwise.
    155 using TrackingAllocator = typename TypeStaticIf<kEnableTrackingAllocator,
    156                                                 TrackingAllocatorImpl<T, kTag>,
    157                                                 std::allocator<T>>::type;
    158 
    159 template<class Key, class T, AllocatorTag kTag, class Compare = std::less<Key>>
    160 using AllocationTrackingMultiMap = std::multimap<
    161     Key, T, Compare, TrackingAllocator<std::pair<const Key, T>, kTag>>;
    162 
    163 template<class Key, AllocatorTag kTag, class Compare = std::less<Key>>
    164 using AllocationTrackingSet = std::set<Key, Compare, TrackingAllocator<Key, kTag>>;
    165 
    166 template<class Key,
    167          class T,
    168          AllocatorTag kTag,
    169          class Hash = std::hash<Key>,
    170          class Pred = std::equal_to<Key>>
    171 using AllocationTrackingUnorderedMap = std::unordered_map<
    172     Key, T, Hash, Pred, TrackingAllocator<std::pair<const Key, T>, kTag>>;
    173 
    174 template<class Key,
    175          class T,
    176          class EmptyFn,
    177          AllocatorTag kTag,
    178          class Hash = std::hash<Key>,
    179          class Pred = std::equal_to<Key>>
    180 using AllocationTrackingHashMap = HashMap<
    181     Key, T, EmptyFn, Hash, Pred, TrackingAllocator<std::pair<Key, T>, kTag>>;
    182 }  // namespace art
    183 
    184 #endif  // ART_RUNTIME_BASE_ALLOCATOR_H_
    185