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