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