• 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 };
63 
64 class MallocSysMemoryManager : public SysMemoryManager {
65 public:
RealAllocMemory(size_t size)66     uint8_t *RealAllocMemory(size_t size) override
67     {
68         if (size == 0) {
69             return nullptr;
70         }
71         void *block = malloc(size);
72         CHECK_FATAL(block != nullptr, "malloc failed");
73 
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     }
83     std::forward_list<void *> mallocMemories;
84 };
85 
86 // memory middle end
87 class MemPoolCtrler {
88     friend MemPool;
89 
90 public:
91     static bool freeMemInTime;
MemPoolCtrler()92     MemPoolCtrler() : sysMemoryMgr(new MallocSysMemoryManager()) {}
93 
94     ~MemPoolCtrler();
95 
96     MemPool *NewMemPool(const std::string &, bool isLocalPool);
97     void DeleteMemPool(MemPool *memPool) const;
HaveRace()98     bool HaveRace() const
99     {
100         return ThreadEnv::IsMeParallel() && (this == &maple::memPoolCtrler);
101     }
102 
103     MemBlock *AllocMemBlock(const MemPool &pool, size_t size);
104     MemBlock *AllocFixMemBlock(const MemPool &pool);
105     MemBlock *AllocBigMemBlock(const MemPool &pool, size_t size) const;
106 
107 private:
108     struct MemBlockCmp {
operatorMemBlockCmp109         bool operator()(const MemBlock *l, const MemBlock *r) const
110         {
111             return l->memSize > r->memSize;
112         }
113     };
114 
115     void FreeMem();
116     void FreeMemBlocks(const MemPool &pool, MemBlock *fixedMemHead, MemBlock *bigMemHead);
117 
118     std::mutex ctrlerMutex;  // this mutex is used to protect memPools
119     MemBlock *fixedFreeMemBlocks = nullptr;
120     std::unique_ptr<SysMemoryManager> sysMemoryMgr;
121 };
122 
123 #ifdef MP_DEUG
124 class MemPoolStat {
125 public:
126     ~MemPoolStat() = default;
127 
128 protected:
SetName(const std::string & name)129     void SetName(const std::string &name)
130     {
131         this->name = name;
132     }
SetName(const char * name)133     void SetName(const char *name)
134     {
135         this->name = name;
136     }
137     std::string name;
138 };
139 #else
140 class MemPoolStat {
141 public:
142     virtual ~MemPoolStat() = default;
143 
144 protected:
SetName(const std::string &)145     void SetName(const std::string & /* name */) const {}
SetName(const char)146     void SetName(const char /* name */) const {}
147 };
148 #endif
149 
150 // memory front end
151 class MemPool : private MemPoolStat {
152     friend MemPoolCtrler;
153 
154 public:
MemPool(MemPoolCtrler & ctl,const std::string & name)155     MemPool(MemPoolCtrler &ctl, const std::string &name) : ctrler(ctl)
156     {
157         SetName(name);
158     }
MemPool(MemPoolCtrler & ctl,const char * name)159     MemPool(MemPoolCtrler &ctl, const char *name) : ctrler(ctl)
160     {
161         SetName(name);
162     }
163 
164     ~MemPool();
165 
166     virtual void *Malloc(size_t size);
167     void *Calloc(size_t size);
168     void *Realloc(const void *ptr, size_t oldSize, size_t newSize);
169     virtual void ReleaseContainingMem();
170 
GetCtrler()171     MemPoolCtrler &GetCtrler()
172     {
173         return ctrler;
174     }
175 
GetCtrler()176     const MemPoolCtrler &GetCtrler() const
177     {
178         return ctrler;
179     }
180 
181     template <class T>
Clone(const T & t)182     T *Clone(const T &t)
183     {
184         void *p = Malloc(sizeof(T));
185         DEBUG_ASSERT(p != nullptr, "ERROR: New error");
186         p = new (p) T(t);
187         return static_cast<T *>(p);
188     }
189 
190     template <class T, typename... Arguments>
New(Arguments &&...args)191     T *New(Arguments &&... args)
192     {
193         void *p = Malloc(sizeof(T));
194         DEBUG_ASSERT(p != nullptr, "ERROR: New error");
195         p = new (p) T(std::forward<Arguments>(args)...);
196         return static_cast<T *>(p);
197     }
198 
199     template <class T>
NewArray(size_t num)200     T *NewArray(size_t num)
201     {
202         void *p = Malloc(sizeof(T) * num);
203         DEBUG_ASSERT(p != nullptr, "ERROR: NewArray error");
204         p = new (p) T[num];
205         return static_cast<T *>(p);
206     }
207 
208 protected:
209     MemPoolCtrler &ctrler;  // Hookup controller object
210     uint8_t *endPtr = nullptr;
211     uint8_t *curPtr = nullptr;
212     MemBlock *fixedMemHead = nullptr;
213     MemBlock *bigMemHead = nullptr;
214 
215     uint8_t *AllocNewMemBlock(size_t bytes);
216 };
217 
218 using ThreadLocalMemPool = MemPool;
219 
220 class ThreadShareMemPool : public MemPool {
221 public:
222     using MemPool::MemPool;
223     virtual ~ThreadShareMemPool() = default;
Malloc(size_t size)224     void *Malloc(size_t size) override
225     {
226         ParallelGuard guard(poolMutex, ctrler.HaveRace());
227         return MemPool::Malloc(size);
228     }
ReleaseContainingMem()229     void ReleaseContainingMem() override
230     {
231         ParallelGuard guard(poolMutex, ctrler.HaveRace());
232         MemPool::ReleaseContainingMem();
233     }
234 
235 private:
236     std::mutex poolMutex;  // this mutex is used to protect memPools
237 };
238 
239 class LocalMapleAllocator;
240 #ifdef MP_DEBUG
241 class StackMemPoolDebug {
242 protected:
PushAllocator(const LocalMapleAllocator * alloc)243     void PushAllocator(const LocalMapleAllocator *alloc)
244     {
245         allocators.push(alloc);
246     }
CheckTopAllocator(const LocalMapleAllocator * alloc)247     void CheckTopAllocator(const LocalMapleAllocator *alloc) const
248     {
249         CHECK_FATAL(alloc == allocators.top(), "only top allocator allowed");
250     }
PopAllocator()251     void PopAllocator()
252     {
253         allocators.pop();
254     }
255     std::stack<const LocalMapleAllocator *> allocators;
256 };
257 #else
258 class StackMemPoolDebug {
259 protected:
PushAllocator(const LocalMapleAllocator *)260     void PushAllocator(const LocalMapleAllocator * /* alloc */) const {}
PopAllocator()261     void PopAllocator() const {}
CheckTopAllocator(const LocalMapleAllocator *)262     void CheckTopAllocator(const LocalMapleAllocator * /* alloc */) const {}
263 };
264 #endif
265 
266 class StackMemPool : public MemPool, private StackMemPoolDebug {
267 public:
268     using MemPool::MemPool;
269     friend LocalMapleAllocator;
270 
271 private:
272     // all malloc requested from LocalMapleAllocator
273     void *Malloc(size_t size) override;
274     uint8_t *AllocTailMemBlock(size_t size);
275 
276     // these methods should be called from LocalMapleAllocator
277     template <class T>
278     T *Clone(const T &t) = delete;
279 
280     template <class T, typename... Arguments>
281     T *New(Arguments &&... args) = delete;
282 
283     template <class T>
284     T *NewArray(size_t num) = delete;
285 
286     // reuse mempool fixedMemHead, bigMemHead, (curPtr, endPtr for fixed memory)
287     MemBlock *fixedMemStackTop = nullptr;
288     MemBlock *bigMemStackTop = nullptr;
289     uint8_t *bigCurPtr = nullptr;
290     uint8_t *bigEndPtr = nullptr;
291     MemBlock *AllocMemBlockBySize(size_t size);
292     void ResetStackTop(const LocalMapleAllocator *alloc, uint8_t *fixedCurPtrMark, MemBlock *fixedStackTopMark,
293                        uint8_t *bigCurPtrMark, MemBlock *bigStackTopMark) noexcept;
294 };
295 }  // namespace maple
296 #endif  // MEMPOOL_INCLUDE_MEMPOOL_H
297