1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBPANDABASE_MEM_ALLOC_TRACKER_H 17 #define LIBPANDABASE_MEM_ALLOC_TRACKER_H 18 19 #include <list> 20 #include <map> 21 #include <atomic> 22 #include <memory> 23 #include <iostream> 24 #include <vector> 25 #include <unordered_map> 26 #include "space.h" 27 #include "os/mutex.h" 28 #include "utils/span.h" 29 30 WEAK_FOR_LTO_START 31 32 namespace panda { 33 34 class AllocTracker { 35 public: 36 AllocTracker() = default; 37 virtual ~AllocTracker() = default; 38 39 virtual void TrackAlloc(void *addr, size_t size, SpaceType space) = 0; 40 virtual void TrackFree(void *addr) = 0; 41 Dump()42 virtual void Dump() {} Dump(std::ostream & out)43 virtual void Dump([[maybe_unused]] std::ostream &out) {} DumpMemLeaks(std::ostream & out)44 virtual void DumpMemLeaks([[maybe_unused]] std::ostream &out) {} 45 46 NO_COPY_SEMANTIC(AllocTracker); 47 NO_MOVE_SEMANTIC(AllocTracker); 48 }; 49 50 class SimpleAllocTracker final : public AllocTracker { 51 public: TrackAlloc(void * addr,size_t size,SpaceType space)52 void TrackAlloc(void *addr, size_t size, [[maybe_unused]] SpaceType space) override 53 { 54 os::memory::LockHolder lock(lock_); 55 internal_alloc_counter_++; 56 total_allocated_ += size; 57 current_allocated_ += size; 58 peak_allocated_ = std::max(peak_allocated_, current_allocated_); 59 auto ins_result = allocated_addresses_.insert({addr, AllocInfo(internal_alloc_counter_, size)}); 60 ASSERT(ins_result.second); 61 static_cast<void>(ins_result); // Fix compilation in release 62 } 63 TrackFree(void * addr)64 void TrackFree(void *addr) override 65 { 66 os::memory::LockHolder lock(lock_); 67 internal_free_counter_++; 68 auto it = allocated_addresses_.find(addr); 69 ASSERT(it != allocated_addresses_.end()); 70 size_t size = it->second.GetSize(); 71 allocated_addresses_.erase(it); 72 current_allocated_ -= size; 73 } 74 Dump()75 void Dump() override 76 { 77 Dump(std::cout); 78 } 79 Dump(std::ostream & out)80 void Dump(std::ostream &out) override 81 { 82 out << "Internal memory allocations:\n"; 83 out << "allocations count: " << internal_alloc_counter_ << "\n"; 84 out << " total allocated: " << total_allocated_ << "\n"; 85 out << " peak allocated: " << peak_allocated_ << "\n"; 86 } 87 DumpMemLeaks(std::ostream & out)88 void DumpMemLeaks(std::ostream &out) override 89 { 90 out << "=== Allocated Internal Memory: ===" << std::endl; 91 for (auto it : allocated_addresses_) { 92 out << std::hex << it.first << ", allocation #" << std::dec << it.second.GetAllocNumber() << std::endl; 93 } 94 out << "==================================" << std::endl; 95 } 96 97 private: 98 class AllocInfo { 99 public: AllocInfo(size_t alloc_number,size_t size)100 AllocInfo(size_t alloc_number, size_t size) : alloc_number_(alloc_number), size_(size) {} 101 GetAllocNumber()102 size_t GetAllocNumber() const 103 { 104 return alloc_number_; 105 } 106 GetSize()107 size_t GetSize() const 108 { 109 return size_; 110 } 111 112 private: 113 size_t alloc_number_; 114 size_t size_; 115 }; 116 117 private: 118 size_t internal_alloc_counter_ = 0; 119 size_t internal_free_counter_ = 0; 120 size_t total_allocated_ = 0; 121 size_t current_allocated_ = 0; 122 size_t peak_allocated_ = 0; 123 std::unordered_map<void *, AllocInfo> allocated_addresses_; 124 os::memory::Mutex lock_; 125 }; 126 127 class DetailAllocTracker final : public AllocTracker { 128 public: 129 static constexpr uint32_t ALLOC_TAG = 1; 130 static constexpr uint32_t FREE_TAG = 2; 131 132 void TrackAlloc(void *addr, size_t size, SpaceType space) override; 133 void TrackFree(void *addr) override; 134 135 void Dump() override; 136 void Dump(std::ostream &out) override; 137 void DumpMemLeaks(std::ostream &out) override; 138 139 private: 140 using Stacktrace = std::vector<uintptr_t>; 141 142 class AllocInfo { 143 public: AllocInfo(uint32_t id,uint32_t size,uint32_t space,uint32_t stacktrace_id)144 AllocInfo(uint32_t id, uint32_t size, uint32_t space, uint32_t stacktrace_id) 145 : id_(id), size_(size), space_(space), stacktrace_id_(stacktrace_id) 146 { 147 } 148 GetTag()149 uint32_t GetTag() const 150 { 151 return tag_; 152 } 153 GetId()154 uint32_t GetId() const 155 { 156 return id_; 157 } 158 GetSize()159 uint32_t GetSize() const 160 { 161 return size_; 162 } 163 GetSpace()164 uint32_t GetSpace() const 165 { 166 return space_; 167 } 168 GetStacktraceId()169 uint32_t GetStacktraceId() const 170 { 171 return stacktrace_id_; 172 } 173 174 private: 175 const uint32_t tag_ = ALLOC_TAG; 176 uint32_t id_; 177 uint32_t size_; 178 uint32_t space_; 179 uint32_t stacktrace_id_; 180 }; 181 182 class FreeInfo { 183 public: FreeInfo(uint32_t alloc_id)184 explicit FreeInfo(uint32_t alloc_id) : alloc_id_(alloc_id) {} 185 GetTag()186 uint32_t GetTag() const 187 { 188 return tag_; 189 } 190 GetAllocId()191 uint32_t GetAllocId() const 192 { 193 return alloc_id_; 194 } 195 196 private: 197 const uint32_t tag_ = FREE_TAG; 198 uint32_t alloc_id_; 199 }; 200 201 void AllocArena() REQUIRES(mutex_); 202 uint32_t WriteStacks(std::ostream &out, std::map<uint32_t, uint32_t> *id_map) REQUIRES(mutex_); 203 204 private: 205 std::atomic<size_t> alloc_counter_ = 0; 206 uint32_t cur_id_ GUARDED_BY(mutex_) = 0; 207 Span<uint8_t> cur_arena_ GUARDED_BY(mutex_); 208 std::list<std::unique_ptr<uint8_t[]>> arenas_ GUARDED_BY(mutex_); // NOLINT(modernize-avoid-c-arrays) 209 std::list<Stacktrace> stacktraces_ GUARDED_BY(mutex_); 210 std::map<void *, AllocInfo *> cur_allocs_ GUARDED_BY(mutex_); 211 os::memory::Mutex mutex_; 212 }; 213 214 } // namespace panda 215 216 WEAK_FOR_LTO_END 217 218 #endif // LIBPANDABASE_MEM_ALLOC_TRACKER_H 219