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 
Allocator()39   Allocator() {}
~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   kAllocatorTagLambdaBoxTable,
56   kAllocatorTagMaps,
57   kAllocatorTagLOS,
58   kAllocatorTagSafeMap,
59   kAllocatorTagLOSMaps,
60   kAllocatorTagReferenceTable,
61   kAllocatorTagHeapBitmap,
62   kAllocatorTagHeapBitmapLOS,
63   kAllocatorTagMonitorPool,
64   kAllocatorTagLOSFreeList,
65   kAllocatorTagVerifier,
66   kAllocatorTagRememberedSet,
67   kAllocatorTagModUnionCardSet,
68   kAllocatorTagModUnionReferenceArray,
69   kAllocatorTagJNILibraries,
70   kAllocatorTagCompileTimeClassPath,
71   kAllocatorTagOatFile,
72   kAllocatorTagDexFileVerifier,
73   kAllocatorTagRosAlloc,
74   kAllocatorTagCount,  // Must always be last element.
75 };
76 std::ostream& operator<<(std::ostream& os, const AllocatorTag& tag);
77 
78 namespace TrackedAllocators {
79 
80 // Running count of number of bytes used for this kind of allocation. Increased by allocations,
81 // decreased by deallocations.
82 extern Atomic<size_t> g_bytes_used[kAllocatorTagCount];
83 
84 // Largest value of bytes used seen.
85 extern volatile size_t g_max_bytes_used[kAllocatorTagCount];
86 
87 // Total number of bytes allocated of this kind.
88 extern Atomic<uint64_t> g_total_bytes_used[kAllocatorTagCount];
89 
90 void Dump(std::ostream& os);
91 
RegisterAllocation(AllocatorTag tag,size_t bytes)92 inline void RegisterAllocation(AllocatorTag tag, size_t bytes) {
93   g_total_bytes_used[tag].FetchAndAddSequentiallyConsistent(bytes);
94   size_t new_bytes = g_bytes_used[tag].FetchAndAddSequentiallyConsistent(bytes) + bytes;
95   if (g_max_bytes_used[tag] < new_bytes) {
96     g_max_bytes_used[tag] = new_bytes;
97   }
98 }
99 
RegisterFree(AllocatorTag tag,size_t bytes)100 inline void RegisterFree(AllocatorTag tag, size_t bytes) {
101   g_bytes_used[tag].FetchAndSubSequentiallyConsistent(bytes);
102 }
103 
104 }  // namespace TrackedAllocators
105 
106 // Tracking allocator for use with STL types, tracks how much memory is used.
107 template<class T, AllocatorTag kTag>
108 class TrackingAllocatorImpl : public std::allocator<T> {
109  public:
110   typedef typename std::allocator<T>::value_type value_type;
111   typedef typename std::allocator<T>::size_type size_type;
112   typedef typename std::allocator<T>::difference_type difference_type;
113   typedef typename std::allocator<T>::pointer pointer;
114   typedef typename std::allocator<T>::const_pointer const_pointer;
115   typedef typename std::allocator<T>::reference reference;
116   typedef typename std::allocator<T>::const_reference const_reference;
117 
118   // Used internally by STL data structures.
119   template <class U>
TrackingAllocatorImpl(const TrackingAllocatorImpl<U,kTag> & alloc ATTRIBUTE_UNUSED)120   TrackingAllocatorImpl(const TrackingAllocatorImpl<U, kTag>& alloc ATTRIBUTE_UNUSED) noexcept {}
121 
122   // Used internally by STL data structures.
TrackingAllocatorImpl()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>
deallocate(PT p,size_type n)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 
GetTag()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