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