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