• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 MEMPOOL_INCLUDE_MEMPOOL_H
17 #define MEMPOOL_INCLUDE_MEMPOOL_H
18 #include <list>
19 #include <set>
20 #include <forward_list>
21 #include <unordered_set>
22 #include <stack>
23 #include <map>
24 #include <string>
25 #include <mutex>
26 #include "mir_config.h"
27 #include "mpl_logging.h"
28 #include "thread_env.h"
29 
30 namespace maple {
31 #define BITS_ALIGN(size) (((size) + 7) & (0xFFFFFFF8))
32 
33 constexpr size_t kMemBlockSizeMin = 2 * 1024;
34 constexpr size_t kMemBlockMalloc = 1024 * 1024;
35 static_assert((kMemBlockMalloc > kMemBlockSizeMin) && ((kMemBlockMalloc % kMemBlockSizeMin) == 0), "mempool error");
36 
37 struct MemBlock {
MemBlockMemBlock38     MemBlock(uint8_t *startPtr, size_t size) : startPtr(startPtr), memSize(size) {}
39     ~MemBlock() = default;
40 
EndPtrMemBlock41     uint8_t *EndPtr() const
42     {
43         return startPtr + memSize;
44     }
45 
46     uint8_t *startPtr = nullptr;
47     size_t memSize = 0;
48     MemBlock *nextMemBlock = nullptr;
49 };
50 
51 // Class declaration
52 class MemPool;
53 class StackMemPool;
54 class MemPoolCtrler;
55 extern MemPoolCtrler memPoolCtrler;
56 
57 // memory backend
58 class SysMemoryManager {
59 public:
60     virtual ~SysMemoryManager() = default;
61     virtual uint8_t *RealAllocMemory(size_t size) = 0;
62     virtual void ReleaseMemory() = 0;
63 };
64 
65 class MallocSysMemoryManager : public SysMemoryManager {
66 public:
RealAllocMemory(size_t size)67     uint8_t *RealAllocMemory(size_t size) override
68     {
69         if (size == 0) {
70             return nullptr;
71         }
72         void *block = malloc(size);
73         CHECK_FATAL(block != nullptr, "malloc failed");
74         mallocMemories.push_front(block);
75         return reinterpret_cast<uint8_t *>(block);
76     }
~MallocSysMemoryManager()77     ~MallocSysMemoryManager() override
78     {
79         for (void *ptr : mallocMemories) {
80             free(ptr);
81         }
82         mallocMemories.clear();
83     }
ReleaseMemory()84     void ReleaseMemory() override
85     {
86         for (void *ptr : mallocMemories) {
87             free(ptr);
88         }
89         mallocMemories.clear();
90     }
91     std::forward_list<void *> mallocMemories;
92 };
93 
94 // memory middle end
95 class MemPoolCtrler {
96     friend MemPool;
97 
98 public:
99     static bool freeMemInTime;
MemPoolCtrler()100     MemPoolCtrler() : sysMemoryMgr(new MallocSysMemoryManager()) {}
101 
102     ~MemPoolCtrler();
103 
104     MemPool *NewMemPool(const std::string &, bool isLocalPool);
105     void DeleteMemPool(MemPool *memPool) const;
HaveRace()106     bool HaveRace() const
107     {
108         return ThreadEnv::IsMeParallel() && (this == &maple::memPoolCtrler);
109     }
110 
111     MemBlock *AllocMemBlock(const MemPool &pool, size_t size);
112     MemBlock *AllocFixMemBlock(const MemPool &pool);
113     MemBlock *AllocBigMemBlock(const MemPool &pool, size_t size) const;
114     void FreeFixedSizeMemBlockMemory();
115 
116 private:
117     struct MemBlockCmp {
operatorMemBlockCmp118         bool operator()(const MemBlock *l, const MemBlock *r) const
119         {
120             return l->memSize > r->memSize;
121         }
122     };
123 
124     void FreeMem();
125     void FreeMemBlocks(const MemPool &pool, MemBlock *fixedMemHead, MemBlock *bigMemHead);
126 
127     std::mutex ctrlerMutex;  // this mutex is used to protect memPools
128     MemBlock *fixedFreeMemBlocks = nullptr;
129     std::unique_ptr<SysMemoryManager> sysMemoryMgr;
130 };
131 
132 #ifdef MP_DEUG
133 class MemPoolStat {
134 public:
135     ~MemPoolStat() = default;
136 
137 protected:
SetName(const std::string & name)138     void SetName(const std::string &name)
139     {
140         this->name = name;
141     }
SetName(const char * name)142     void SetName(const char *name)
143     {
144         this->name = name;
145     }
146     std::string name;
147 };
148 #else
149 class MemPoolStat {
150 public:
151     virtual ~MemPoolStat() = default;
152 
153 protected:
SetName(const std::string &)154     void SetName(const std::string & /* name */) const {}
SetName(const char)155     void SetName(const char /* name */) const {}
156 };
157 #endif
158 
159 // memory front end
160 class MemPool : private MemPoolStat {
161     friend MemPoolCtrler;
162 
163 public:
MemPool(MemPoolCtrler & ctl,const std::string & name)164     MemPool(MemPoolCtrler &ctl, const std::string &name) : ctrler(ctl)
165     {
166         SetName(name);
167     }
MemPool(MemPoolCtrler & ctl,const char * name)168     MemPool(MemPoolCtrler &ctl, const char *name) : ctrler(ctl)
169     {
170         SetName(name);
171     }
172 
173     ~MemPool();
174 
175     virtual void *Malloc(size_t size);
176     void *Calloc(size_t size);
177     void *Realloc(const void *ptr, size_t oldSize, size_t newSize);
178     virtual void ReleaseContainingMem();
179 
GetCtrler()180     MemPoolCtrler &GetCtrler()
181     {
182         return ctrler;
183     }
184 
GetCtrler()185     const MemPoolCtrler &GetCtrler() const
186     {
187         return ctrler;
188     }
189 
190     template <class T>
Clone(const T & t)191     T *Clone(const T &t)
192     {
193         void *p = Malloc(sizeof(T));
194         DEBUG_ASSERT(p != nullptr, "ERROR: New error");
195         p = new (p) T(t);
196         return static_cast<T *>(p);
197     }
198 
199     template <class T, typename... Arguments>
New(Arguments &&...args)200     T *New(Arguments &&... args)
201     {
202         void *p = Malloc(sizeof(T));
203         DEBUG_ASSERT(p != nullptr, "ERROR: New error");
204         p = new (p) T(std::forward<Arguments>(args)...);
205         return static_cast<T *>(p);
206     }
207 
208     template <class T>
NewArray(size_t num)209     T *NewArray(size_t num)
210     {
211         void *p = Malloc(sizeof(T) * num);
212         DEBUG_ASSERT(p != nullptr, "ERROR: NewArray error");
213         p = new (p) T[num];
214         return static_cast<T *>(p);
215     }
216 
217 protected:
218     MemPoolCtrler &ctrler;  // Hookup controller object
219     uint8_t *endPtr = nullptr;
220     uint8_t *curPtr = nullptr;
221     MemBlock *fixedMemHead = nullptr;
222     MemBlock *bigMemHead = nullptr;
223 
224     uint8_t *AllocNewMemBlock(size_t bytes);
225 };
226 
227 using ThreadLocalMemPool = MemPool;
228 
229 class ThreadShareMemPool : public MemPool {
230 public:
231     using MemPool::MemPool;
232     virtual ~ThreadShareMemPool() = default;
Malloc(size_t size)233     void *Malloc(size_t size) override
234     {
235         ParallelGuard guard(poolMutex, ctrler.HaveRace());
236         return MemPool::Malloc(size);
237     }
ReleaseContainingMem()238     void ReleaseContainingMem() override
239     {
240         ParallelGuard guard(poolMutex, ctrler.HaveRace());
241         MemPool::ReleaseContainingMem();
242     }
243 
244 private:
245     std::mutex poolMutex;  // this mutex is used to protect memPools
246 };
247 
248 class LocalMapleAllocator;
249 #ifdef MP_DEBUG
250 class StackMemPoolDebug {
251 protected:
PushAllocator(const LocalMapleAllocator * alloc)252     void PushAllocator(const LocalMapleAllocator *alloc)
253     {
254         allocators.push(alloc);
255     }
CheckTopAllocator(const LocalMapleAllocator * alloc)256     void CheckTopAllocator(const LocalMapleAllocator *alloc) const
257     {
258         CHECK_FATAL(alloc == allocators.top(), "only top allocator allowed");
259     }
PopAllocator()260     void PopAllocator()
261     {
262         allocators.pop();
263     }
264     std::stack<const LocalMapleAllocator *> allocators;
265 };
266 #else
267 class StackMemPoolDebug {
268 protected:
PushAllocator(const LocalMapleAllocator *)269     void PushAllocator(const LocalMapleAllocator * /* alloc */) const {}
PopAllocator()270     void PopAllocator() const {}
CheckTopAllocator(const LocalMapleAllocator *)271     void CheckTopAllocator(const LocalMapleAllocator * /* alloc */) const {}
272 };
273 #endif
274 
275 class StackMemPool : public MemPool, private StackMemPoolDebug {
276 public:
277     using MemPool::MemPool;
278     friend LocalMapleAllocator;
279 
280 private:
281     // all malloc requested from LocalMapleAllocator
282     void *Malloc(size_t size) override;
283     uint8_t *AllocTailMemBlock(size_t size);
284 
285     // these methods should be called from LocalMapleAllocator
286     template <class T>
287     T *Clone(const T &t) = delete;
288 
289     template <class T, typename... Arguments>
290     T *New(Arguments &&... args) = delete;
291 
292     template <class T>
293     T *NewArray(size_t num) = delete;
294 
295     // reuse mempool fixedMemHead, bigMemHead, (curPtr, endPtr for fixed memory)
296     MemBlock *fixedMemStackTop = nullptr;
297     MemBlock *bigMemStackTop = nullptr;
298     uint8_t *bigCurPtr = nullptr;
299     uint8_t *bigEndPtr = nullptr;
300     MemBlock *AllocMemBlockBySize(size_t size);
301     void ResetStackTop(const LocalMapleAllocator *alloc, uint8_t *fixedCurPtrMark, MemBlock *fixedStackTopMark,
302                        uint8_t *bigCurPtrMark, MemBlock *bigStackTopMark) noexcept;
303 };
304 }  // namespace maple
305 #endif  // MEMPOOL_INCLUDE_MEMPOOL_H
306