• 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 #include "mempool.h"
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <iostream>
21 #include <mutex>
22 #include "thread_env.h"
23 #include "securec.h"
24 #include "mpl_logging.h"
25 
26 namespace maple {
27 MemPoolCtrler memPoolCtrler;
28 bool MemPoolCtrler::freeMemInTime = false;
29 
FreeMemBlocks(const MemPool & pool,MemBlock * fixedMemHead,MemBlock * bigMemHead)30 void MemPoolCtrler::FreeMemBlocks(const MemPool &pool, MemBlock *fixedMemHead, MemBlock *bigMemHead)
31 {
32     (void)(pool);
33 
34     MemBlock *fixedTail = nullptr;
35 
36     if (fixedMemHead != nullptr) {
37         fixedTail = fixedMemHead;
38         while (fixedTail->nextMemBlock != nullptr) {
39             fixedTail = fixedTail->nextMemBlock;
40         }
41     }
42 
43     while (bigMemHead != nullptr) {
44         auto *cur = bigMemHead;
45         bigMemHead = bigMemHead->nextMemBlock;
46         free(cur->startPtr);
47         delete cur;
48     }
49 
50     ParallelGuard guard(ctrlerMutex, HaveRace());
51     if (fixedTail != nullptr) {
52         fixedTail->nextMemBlock = fixedFreeMemBlocks;
53         DEBUG_ASSERT(fixedTail->nextMemBlock != fixedTail, "error");
54         fixedFreeMemBlocks = fixedMemHead;
55     }
56 }
57 
58 // Destructor, free all allocated memories
~MemPoolCtrler()59 MemPoolCtrler::~MemPoolCtrler()
60 {
61     FreeMem();
62 }
63 
FreeFixedSizeMemBlockMemory()64 void MemPoolCtrler::FreeFixedSizeMemBlockMemory()
65 {
66     FreeMem();
67     sysMemoryMgr->ReleaseMemory();
68 }
69 
70 // Allocate a new memory pool and register it in controller
NewMemPool(const std::string & name,bool isLocalPool)71 MemPool *MemPoolCtrler::NewMemPool(const std::string &name, bool isLocalPool)
72 {
73     MemPool *memPool = nullptr;
74 
75     if (isLocalPool) {
76         memPool = new ThreadLocalMemPool(*this, name);
77     } else {
78         memPool = new ThreadShareMemPool(*this, name);
79     }
80 
81     return memPool;
82 }
83 
84 // This function will be removed soon, DO NOT call it, just use delete memPool
DeleteMemPool(MemPool * memPool) const85 void MemPoolCtrler::DeleteMemPool(MemPool *memPool) const
86 {
87     delete memPool;
88 }
89 
FreeMem()90 void MemPoolCtrler::FreeMem()
91 {
92     ParallelGuard guard(ctrlerMutex, HaveRace());
93 
94     while (fixedFreeMemBlocks != nullptr) {
95         MemBlock *arena = fixedFreeMemBlocks;
96         fixedFreeMemBlocks = fixedFreeMemBlocks->nextMemBlock;
97         delete arena;
98     }
99 }
100 
AllocMemBlock(const MemPool & pool,size_t size)101 MemBlock *MemPoolCtrler::AllocMemBlock(const MemPool &pool, size_t size)
102 {
103     if (size <= kMemBlockSizeMin) {
104         return AllocFixMemBlock(pool);
105     } else {
106         return AllocBigMemBlock(pool, size);
107     }
108 }
109 
AllocFixMemBlock(const MemPool & pool)110 MemBlock *MemPoolCtrler::AllocFixMemBlock(const MemPool &pool)
111 {
112     (void)(pool);
113     MemBlock *ret = nullptr;
114 
115     ParallelGuard guard(ctrlerMutex, HaveRace());
116     if (fixedFreeMemBlocks != nullptr) {
117         ret = fixedFreeMemBlocks;
118         fixedFreeMemBlocks = fixedFreeMemBlocks->nextMemBlock;
119         return ret;
120     }
121 
122     uint8_t *ptr = sysMemoryMgr->RealAllocMemory(kMemBlockMalloc);
123     // leave one MemBlock to return
124     for (size_t i = 0; i < kMemBlockMalloc / kMemBlockSizeMin - 1; ++i) {
125         auto *block = new MemBlock(ptr, kMemBlockSizeMin);
126         ptr += kMemBlockSizeMin;
127         block->nextMemBlock = fixedFreeMemBlocks;
128         fixedFreeMemBlocks = block;
129     }
130 
131     return new MemBlock(ptr, kMemBlockSizeMin);
132 }
133 
AllocBigMemBlock(const MemPool & pool,size_t size) const134 MemBlock *MemPoolCtrler::AllocBigMemBlock(const MemPool &pool, size_t size) const
135 {
136     DEBUG_ASSERT(size > kMemBlockSizeMin, "Big memory block must be bigger than fixed memory block");
137     (void)(pool);
138 
139     uint8_t *block = reinterpret_cast<uint8_t *>(malloc(size));
140     CHECK_FATAL(block != nullptr, "malloc failed");
141     return new MemBlock(block, size);
142 }
143 
~MemPool()144 MemPool::~MemPool()
145 {
146     ctrler.FreeMemBlocks(*this, fixedMemHead, bigMemHead);
147 }
148 
Malloc(size_t size)149 void *MemPool::Malloc(size_t size)
150 {
151     size = BITS_ALIGN(size);
152     DEBUG_ASSERT(endPtr >= curPtr, "endPtr should >= curPtr");
153     if (size > static_cast<size_t>(endPtr - curPtr)) {
154         return AllocNewMemBlock(size);
155     }
156     uint8_t *retPtr = curPtr;
157     curPtr += size;
158     return retPtr;
159 }
160 
ReleaseContainingMem()161 void MemPool::ReleaseContainingMem()
162 {
163     ctrler.FreeMemBlocks(*this, fixedMemHead, bigMemHead);
164 
165     fixedMemHead = nullptr;
166     bigMemHead = nullptr;
167     endPtr = nullptr;
168     curPtr = nullptr;
169 }
170 
171 // Malloc size of memory from memory pool, then set 0
Calloc(size_t size)172 void *MemPool::Calloc(size_t size)
173 {
174     void *p = Malloc(BITS_ALIGN(size));
175     DEBUG_ASSERT(p != nullptr, "ERROR: Calloc error");
176     errno_t eNum = memset_s(p, BITS_ALIGN(size), 0, BITS_ALIGN(size));
177     CHECK_FATAL(eNum == EOK, "memset_s failed");
178     return p;
179 }
180 
181 // Realloc new size of memory
Realloc(const void * ptr,size_t oldSize,size_t newSize)182 void *MemPool::Realloc(const void *ptr, size_t oldSize, size_t newSize)
183 {
184     void *result = Malloc(newSize);
185     DEBUG_ASSERT(result != nullptr, "ERROR: Realloc error");
186     size_t copySize = ((newSize > oldSize) ? oldSize : newSize);
187     if (copySize != 0 && ptr != nullptr) {
188         errno_t eNum = memcpy_s(result, copySize, ptr, copySize);
189         CHECK_FATAL(eNum == EOK, "memcpy_s failed");
190     }
191     return result;
192 }
193 
AllocNewMemBlock(size_t size)194 uint8_t *MemPool::AllocNewMemBlock(size_t size)
195 {
196     MemBlock **head = nullptr;
197     MemBlock *newMemBlock = ctrler.AllocMemBlock(*this, size);
198     if (newMemBlock->memSize <= kMemBlockSizeMin) {
199         head = &fixedMemHead;
200     } else {
201         head = &bigMemHead;
202     }
203 
204     newMemBlock->nextMemBlock = *head;
205     *head = newMemBlock;
206     CHECK_FATAL(newMemBlock->nextMemBlock != newMemBlock, "error");
207 
208     curPtr = newMemBlock->startPtr + size;
209     endPtr = newMemBlock->startPtr + newMemBlock->memSize;
210     DEBUG_ASSERT(curPtr <= endPtr, "must be");
211 
212     return newMemBlock->startPtr;
213 }
214 
Malloc(size_t size)215 void *StackMemPool::Malloc(size_t size)
216 {
217     size = BITS_ALIGN(size);
218     uint8_t **curPtrPtr = nullptr;
219     uint8_t *curEndPtr = nullptr;
220     if (size <= kMemBlockSizeMin) {
221         curPtrPtr = &curPtr;
222         curEndPtr = endPtr;
223     } else {
224         curPtrPtr = &bigCurPtr;
225         curEndPtr = bigEndPtr;
226     }
227     uint8_t *retPtr = *curPtrPtr;
228     DEBUG_ASSERT(curEndPtr >= *curPtrPtr, "endPtr should >= curPtr");
229     if (size > static_cast<size_t>(curEndPtr - *curPtrPtr)) {
230         retPtr = AllocTailMemBlock(size);
231     }
232     *curPtrPtr = retPtr + size;
233     return retPtr;
234 }
235 
236 // scoped mem pool don't use big mem block for small size, different with normal mempool
AllocMemBlockBySize(size_t size)237 MemBlock *StackMemPool::AllocMemBlockBySize(size_t size)
238 {
239     if (size <= kMemBlockSizeMin) {
240         return ctrler.AllocFixMemBlock(*this);
241     } else {
242         return ctrler.AllocBigMemBlock(*this, size);
243     }
244 }
245 
ResetStackTop(const LocalMapleAllocator * alloc,uint8_t * fixedCurPtrMark,MemBlock * fixedStackTopMark,uint8_t * bigCurPtrMark,MemBlock * bigStackTopMark)246 void StackMemPool::ResetStackTop(const LocalMapleAllocator *alloc, uint8_t *fixedCurPtrMark,
247                                  MemBlock *fixedStackTopMark, uint8_t *bigCurPtrMark,
248                                  MemBlock *bigStackTopMark) noexcept
249 {
250     CheckTopAllocator(alloc);
251     PopAllocator();
252 
253     if (fixedStackTopMark != nullptr) {
254         fixedMemStackTop = fixedStackTopMark;
255         curPtr = fixedCurPtrMark;
256         endPtr = fixedMemStackTop->EndPtr();
257     } else if (fixedMemHead != nullptr) {
258         fixedMemStackTop = fixedMemHead;
259         curPtr = fixedMemStackTop->startPtr;
260         endPtr = fixedMemStackTop->EndPtr();
261     }
262 
263     if (bigStackTopMark != nullptr) {
264         bigMemStackTop = bigStackTopMark;
265         bigCurPtr = bigCurPtrMark;
266         bigEndPtr = bigMemStackTop->EndPtr();
267     } else if (bigMemHead != nullptr) {
268         bigMemStackTop = bigMemHead;
269         bigCurPtr = bigMemStackTop->startPtr;
270         bigEndPtr = bigMemStackTop->EndPtr();
271     }
272 }
273 
AllocTailMemBlock(size_t size)274 uint8_t *StackMemPool::AllocTailMemBlock(size_t size)
275 {
276     MemBlock **head = nullptr;
277     MemBlock **stackTop = nullptr;
278     uint8_t **endPtrPtr = nullptr;
279 
280     if (size <= kMemBlockSizeMin) {
281         head = &fixedMemHead;
282         stackTop = &fixedMemStackTop;
283         endPtrPtr = &endPtr;
284     } else {
285         head = &bigMemHead;
286         stackTop = &bigMemStackTop;
287         endPtrPtr = &bigEndPtr;
288     }
289 
290     if (*stackTop == nullptr) {
291         MemBlock *newMemBlock = AllocMemBlockBySize(size);
292         *stackTop = newMemBlock;
293         *head = newMemBlock;
294         (*stackTop)->nextMemBlock = nullptr;
295     } else {
296         if ((*stackTop)->nextMemBlock != nullptr && (*stackTop)->nextMemBlock->memSize >= size) {
297             *stackTop = (*stackTop)->nextMemBlock;
298         } else {
299             MemBlock *newMemBlock = AllocMemBlockBySize(size);
300             auto *tmp = (*stackTop)->nextMemBlock;
301             (*stackTop)->nextMemBlock = newMemBlock;
302             *stackTop = newMemBlock;
303             newMemBlock->nextMemBlock = tmp;
304         }
305     }
306     *endPtrPtr = (*stackTop)->EndPtr();
307     return (*stackTop)->startPtr;
308 }
309 }  // namespace maple
310