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