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