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 
22 #include "atomic.h"
23 #include "base/macros.h"
24 #include "base/mutex.h"
25 #include "utils.h"
26 
27 namespace art {
28 
29 static constexpr bool kEnableTrackingAllocator = false;
30 
31 class Allocator {
32  public:
33   static Allocator* GetMallocAllocator();
34   static Allocator* GetNoopAllocator();
35 
Allocator()36   Allocator() {}
~Allocator()37   virtual ~Allocator() {}
38 
39   virtual void* Alloc(size_t) = 0;
40   virtual void Free(void*) = 0;
41 
42  private:
43   DISALLOW_COPY_AND_ASSIGN(Allocator);
44 };
45 
46 // Used by TrackedAllocators.
47 enum AllocatorTag {
48   kAllocatorTagHeap,
49   kAllocatorTagMonitorList,
50   kAllocatorTagClassTable,
51   kAllocatorTagInternTable,
52   kAllocatorTagMaps,
53   kAllocatorTagLOS,
54   kAllocatorTagSafeMap,
55   kAllocatorTagLOSMaps,
56   kAllocatorTagReferenceTable,
57   kAllocatorTagHeapBitmap,
58   kAllocatorTagHeapBitmapLOS,
59   kAllocatorTagMonitorPool,
60   kAllocatorTagLOSFreeList,
61   kAllocatorTagVerifier,
62   kAllocatorTagRememberedSet,
63   kAllocatorTagModUnionCardSet,
64   kAllocatorTagModUnionReferenceArray,
65   kAllocatorTagJNILibrarires,
66   kAllocatorTagCompileTimeClassPath,
67   kAllocatorTagOatFile,
68   kAllocatorTagDexFileVerifier,
69   kAllocatorTagCount,  // Must always be last element.
70 };
71 std::ostream& operator<<(std::ostream& os, const AllocatorTag& tag);
72 
73 class TrackedAllocators {
74  public:
75   static bool Add(uint32_t tag, AtomicInteger* bytes_used);
76   static void Dump(std::ostream& os);
RegisterAllocation(AllocatorTag tag,uint64_t bytes)77   static void RegisterAllocation(AllocatorTag tag, uint64_t bytes) {
78     total_bytes_used_[tag].FetchAndAddSequentiallyConsistent(bytes);
79     uint64_t new_bytes = bytes_used_[tag].FetchAndAddSequentiallyConsistent(bytes) + bytes;
80     max_bytes_used_[tag].StoreRelaxed(std::max(max_bytes_used_[tag].LoadRelaxed(), new_bytes));
81   }
RegisterFree(AllocatorTag tag,uint64_t bytes)82   static void RegisterFree(AllocatorTag tag, uint64_t bytes) {
83     bytes_used_[tag].FetchAndSubSequentiallyConsistent(bytes);
84   }
85 
86  private:
87   static Atomic<uint64_t> bytes_used_[kAllocatorTagCount];
88   static Atomic<uint64_t> max_bytes_used_[kAllocatorTagCount];
89   static Atomic<uint64_t> total_bytes_used_[kAllocatorTagCount];
90 };
91 
92 // Tracking allocator, tracks how much memory is used.
93 template<class T, AllocatorTag kTag>
94 class TrackingAllocatorImpl : public std::allocator<T> {
95  public:
96   typedef typename std::allocator<T>::value_type value_type;
97   typedef typename std::allocator<T>::size_type size_type;
98   typedef typename std::allocator<T>::difference_type difference_type;
99   typedef typename std::allocator<T>::pointer pointer;
100   typedef typename std::allocator<T>::const_pointer const_pointer;
101   typedef typename std::allocator<T>::reference reference;
102   typedef typename std::allocator<T>::const_reference const_reference;
103 
104   // Used internally by STL data structures.
105   template <class U>
TrackingAllocatorImpl(const TrackingAllocatorImpl<U,kTag> & alloc)106   TrackingAllocatorImpl(const TrackingAllocatorImpl<U, kTag>& alloc) throw() {
107   }
108 
109   // Used internally by STL data structures.
throw()110   TrackingAllocatorImpl() throw() {
111     COMPILE_ASSERT(kTag < kAllocatorTagCount, must_be_less_than_count);
112   }
113 
114   // Enables an allocator for objects of one type to allocate storage for objects of another type.
115   // Used internally by STL data structures.
116   template <class U>
117   struct rebind {
118     typedef TrackingAllocatorImpl<U, kTag> other;
119   };
120 
121   pointer allocate(size_type n, const_pointer hint = 0) {
122     const size_t size = n * sizeof(T);
123     TrackedAllocators::RegisterAllocation(GetTag(), size);
124     return reinterpret_cast<pointer>(malloc(size));
125   }
126 
127   template <typename PT>
deallocate(PT p,size_type n)128   void deallocate(PT p, size_type n) {
129     const size_t size = n * sizeof(T);
130     TrackedAllocators::RegisterFree(GetTag(), size);
131     free(p);
132   }
133 
GetTag()134   static AllocatorTag GetTag() {
135     return kTag;
136   }
137 };
138 
139 template<class T, AllocatorTag kTag>
140 // C++ doesn't allow template typedefs. This is a workaround template typedef which is
141 // TrackingAllocatorImpl<T> if kEnableTrackingAllocator is true, std::allocator<T> otherwise.
142 class TrackingAllocator : public TypeStaticIf<kEnableTrackingAllocator,
143                                               TrackingAllocatorImpl<T, kTag>,
144                                               std::allocator<T>>::type {
145 };
146 
147 template<class Key, class T, AllocatorTag kTag, class Compare = std::less<Key>>
148 class AllocationTrackingMultiMap : public std::multimap<
149     Key, T, Compare, TrackingAllocator<std::pair<Key, T>, kTag>> {
150 };
151 
152 }  // namespace art
153 
154 #endif  // ART_RUNTIME_BASE_ALLOCATOR_H_
155