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