• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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