Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #ifndef MUSE_GLOBAL_ALLOCATOR_H
23 : #define MUSE_GLOBAL_ALLOCATOR_H
24 :
25 : #include <cstdint>
26 : #include <vector>
27 : #include <list>
28 : #include <string>
29 :
30 : namespace muse {
31 : #define OBJECT_ALLOCATOR(Module, ClassName) \
32 : public: \
33 : static muse::ObjectAllocator& allocator() { \
34 : static muse::ObjectAllocator a(#Module, #ClassName, muse::ObjectAllocator::destroyer<ClassName>); \
35 : return a; \
36 : } \
37 : static void* operator new(size_t sz) { \
38 : return muse::ObjectAllocator::enabled() ? allocator().alloc(sz) : ::operator new(sz); \
39 : } \
40 : static void operator delete(void* ptr) { \
41 : if (muse::ObjectAllocator::enabled()) { \
42 : allocator().free(ptr); \
43 : } else { \
44 : ::operator delete(ptr); \
45 : } \
46 : } \
47 : static void* operator new[](size_t sz) { \
48 : return muse::ObjectAllocator::enabled() ? allocator().not_supported("new[]") : ::operator new[](sz); \
49 : } \
50 : static void* operator new(size_t sz, void* ptr) { \
51 : return muse::ObjectAllocator::enabled() ? allocator().not_supported("new(size_t, void*)") : ::operator new(sz, ptr); \
52 : } \
53 : static void operator delete[](void* ptr) { \
54 : if (muse::ObjectAllocator::enabled()) { \
55 : allocator().not_supported("delete[]"); \
56 : } else { \
57 : ::operator delete[](ptr); \
58 : } \
59 : } \
60 : private:
61 :
62 : class ObjectAllocator
63 : {
64 : public:
65 :
66 : using destroyer_t = void (*)(void*);
67 :
68 : ObjectAllocator(const char* module, const char* name, destroyer_t dtor);
69 : ~ObjectAllocator();
70 :
71 : static size_t DEFAULT_BLOCK_SIZE;
72 :
73 : const char* module() const;
74 : const char* name() const;
75 :
76 : void* alloc(size_t size);
77 : void free(void* ptr);
78 : void cleanup();
79 :
80 : template<class T>
81 11 : static void destroyer(void* ptr)
82 : {
83 11 : T* p = reinterpret_cast<T*>(ptr);
84 11 : p->~T();
85 11 : }
86 :
87 : void* not_supported(const char* info);
88 :
89 : struct Info
90 : {
91 : std::string module;
92 : std::string name;
93 : size_t chunkSize = 0;
94 : size_t blockCount = 0;
95 : size_t totalChunks = 0;
96 : size_t freeChunks = 0;
97 :
98 : uint64_t totalAllocatedCount = 0;
99 : uint64_t totalFreeCount = 0;
100 :
101 0 : uint64_t usedChunks() const { return totalChunks - freeChunks; }
102 0 : uint64_t allocatedBytes() const { return totalChunks * chunkSize; }
103 : };
104 :
105 : Info stateInfo() const;
106 :
107 1268972 : static bool enabled() { return s_used; }
108 : static void used();
109 : static void unused();
110 :
111 : static int s_used;
112 : private:
113 :
114 : struct Chunk {
115 : /**
116 : * When a chunk is free, the `next` contains the
117 : * address of the next chunk in a list.
118 : *
119 : * When it's allocated, this space is used by
120 : * the user.
121 : */
122 : Chunk* next = nullptr;
123 : };
124 :
125 : struct Block {
126 : Chunk* begin = nullptr;
127 : size_t chunkCount = 0;
128 : size_t chunkSize = 0;
129 : };
130 :
131 : Block allocateBlock(size_t chunkSize) const;
132 :
133 : const char* m_module = nullptr;
134 : const char* m_name = nullptr;
135 : size_t m_chunkSize = 0;
136 : destroyer_t m_dtor = nullptr;
137 : Chunk* m_free = nullptr;
138 : std::vector<Block> m_blocks;
139 :
140 : struct Statistic
141 : {
142 : uint64_t totalAllocatedCount = 0;
143 : uint64_t totalFreeCount = 0;
144 : };
145 :
146 : Statistic m_statistic;
147 : };
148 :
149 : class AllocatorsRegister
150 : {
151 : public:
152 :
153 6 : static AllocatorsRegister* instance()
154 : {
155 211 : static AllocatorsRegister r;
156 6 : return &r;
157 : }
158 :
159 : void reg(ObjectAllocator* a);
160 : void unreg(ObjectAllocator* a);
161 :
162 : void cleanupAll(const std::string& module);
163 :
164 : void printStatistic(const std::string& title);
165 : void printState(const std::string& title);
166 :
167 : private:
168 : std::list<ObjectAllocator*> m_allocators;
169 : };
170 : }
171 :
172 : #endif // MUSE_GLOBAL_ALLOCATOR_H
|