• 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 
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