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 30namespace maple { 31#define BITS_ALIGN(size) (((size) + 7) & (0xFFFFFFF8)) 32 33constexpr size_t kMemBlockSizeMin = 2 * 1024; 34constexpr size_t kMemBlockMalloc = 1024 * 1024; 35static_assert((kMemBlockMalloc > kMemBlockSizeMin) && ((kMemBlockMalloc % kMemBlockSizeMin) == 0), "mempool error"); 36 37struct MemBlock { 38 MemBlock(uint8_t *startPtr, size_t size) : startPtr(startPtr), memSize(size) {} 39 ~MemBlock() = default; 40 41 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 52class MemPool; 53class StackMemPool; 54class MemPoolCtrler; 55extern MemPoolCtrler memPoolCtrler; 56 57// memory backend 58class SysMemoryManager { 59public: 60 virtual ~SysMemoryManager() = default; 61 virtual uint8_t *RealAllocMemory(size_t size) = 0; 62 virtual void ReleaseMemory() = 0; 63}; 64 65class MallocSysMemoryManager : public SysMemoryManager { 66public: 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 96class MemPoolCtrler { 97 friend MemPool; 98 99public: 100 static bool freeMemInTime; 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 113private: 114 struct MemBlockCmp { 115 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 130class MemPoolStat { 131public: 132 ~MemPoolStat() = default; 133 134protected: 135 void SetName(const std::string &name) 136 { 137 this->name = name; 138 } 139 void SetName(const char *name) 140 { 141 this->name = name; 142 } 143 std::string name; 144}; 145#else 146class MemPoolStat { 147public: 148 virtual ~MemPoolStat() = default; 149 150protected: 151 void SetName(const std::string & /* name */) const {} 152 void SetName(const char /* name */) const {} 153}; 154#endif 155 156// memory front end 157class MemPool : private MemPoolStat { 158 friend MemPoolCtrler; 159 160public: 161 MemPool(MemPoolCtrler &ctl, const std::string &name) : ctrler(ctl) 162 { 163 SetName(name); 164 } 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 177 MemPoolCtrler &GetCtrler() 178 { 179 return ctrler; 180 } 181 182 const MemPoolCtrler &GetCtrler() const 183 { 184 return ctrler; 185 } 186 187 template <class 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> 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> 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 214protected: 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 224using ThreadLocalMemPool = MemPool; 225 226class ThreadShareMemPool : public MemPool { 227public: 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 240class LocalMapleAllocator; 241#ifdef MP_DEBUG 242class StackMemPoolDebug { 243protected: 244 void PushAllocator(const LocalMapleAllocator *alloc) 245 { 246 allocators.push(alloc); 247 } 248 void CheckTopAllocator(const LocalMapleAllocator *alloc) const 249 { 250 CHECK_FATAL(alloc == allocators.top(), "only top allocator allowed"); 251 } 252 void PopAllocator() 253 { 254 allocators.pop(); 255 } 256 std::stack<const LocalMapleAllocator *> allocators; 257}; 258#else 259class StackMemPoolDebug { 260protected: 261 void PushAllocator(const LocalMapleAllocator * /* alloc */) const {} 262 void PopAllocator() const {} 263 void CheckTopAllocator(const LocalMapleAllocator * /* alloc */) const {} 264}; 265#endif 266 267class StackMemPool : public MemPool, private StackMemPoolDebug { 268public: 269 using MemPool::MemPool; 270 friend LocalMapleAllocator; 271 272private: 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