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 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
RegisterAllocation(AllocatorTag tag,size_t bytes)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
RegisterFree(AllocatorTag tag,size_t bytes)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>
TrackingAllocatorImpl(const TrackingAllocatorImpl<U,kTag> & alloc ATTRIBUTE_UNUSED)119 TrackingAllocatorImpl( // NOLINT, implicit
120 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