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