• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 #ifndef PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H
16 #define PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H
17 
18 #include "runtime/mem/frame_allocator.h"
19 
20 #include <cstring>
21 
22 #include "libpandabase/mem/pool_manager.h"
23 #include "libpandabase/utils/logger.h"
24 #include "libpandabase/mem/stack_like_allocator-inl.h"
25 
26 namespace ark::mem {
27 
28 using StackFrameAllocator = StackLikeAllocator<>;
29 
30 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
31 #define LOG_FRAME_ALLOCATOR(level) LOG(level, ALLOC) << "FrameAllocator: "
32 
33 template <Alignment ALIGNMENT, bool USE_MEMSET>
FrameAllocator(bool useMalloc,SpaceType spaceType)34 inline FrameAllocator<ALIGNMENT, USE_MEMSET>::FrameAllocator(bool useMalloc, SpaceType spaceType)
35     : useMalloc_(useMalloc), spaceType_(spaceType)
36 {
37     LOG_FRAME_ALLOCATOR(DEBUG) << "Initializing of FrameAllocator";
38     if (!useMalloc_) {
39         memPoolAlloc_ = PoolManager::GetMmapMemPool();
40     }
41     curArena_ = AllocateArenaImpl(FIRST_ARENA_SIZE);
42     lastAllocArena_ = curArena_;
43     biggestArenaSize_ = FIRST_ARENA_SIZE;
44     arenaSizeNeedToGrow_ = true;
45     LOG_FRAME_ALLOCATOR(DEBUG) << "Initializing of FrameAllocator finished";
46 }
47 
48 template <Alignment ALIGNMENT, bool USE_MEMSET>
~FrameAllocator()49 inline FrameAllocator<ALIGNMENT, USE_MEMSET>::~FrameAllocator()
50 {
51     LOG_FRAME_ALLOCATOR(DEBUG) << "Destroying of FrameAllocator";
52     while (lastAllocArena_ != nullptr) {
53         LOG_FRAME_ALLOCATOR(DEBUG) << "Free arena at addr " << std::hex << lastAllocArena_;
54         FramesArena *prevArena = lastAllocArena_->GetPrevArena();
55         FreeArenaImpl(lastAllocArena_);
56         lastAllocArena_ = prevArena;
57     }
58     curArena_ = nullptr;
59     LOG_FRAME_ALLOCATOR(DEBUG) << "Destroying of FrameAllocator finished";
60 }
61 
62 template <Alignment ALIGNMENT, bool USE_MEMSET>
63 // CC-OFFNXT(G.FUD.06) perf critical
TryAllocateNewArena(size_t size)64 inline bool FrameAllocator<ALIGNMENT, USE_MEMSET>::TryAllocateNewArena(size_t size)
65 {
66     size_t arenaSize = GetNextArenaSize(size);
67     LOG_FRAME_ALLOCATOR(DEBUG) << "Try to allocate a new arena with size " << arenaSize;
68     FramesArena *newArena = AllocateArenaImpl(arenaSize);
69     if (newArena == nullptr) {
70         LOG_FRAME_ALLOCATOR(DEBUG) << "Couldn't get memory for a new arena";
71         arenaSizeNeedToGrow_ = false;
72         return false;
73     }
74     lastAllocArena_->LinkNext(newArena);
75     newArena->LinkPrev(lastAllocArena_);
76     lastAllocArena_ = newArena;
77     emptyArenasCount_++;
78     LOG_FRAME_ALLOCATOR(DEBUG) << "Successfully allocate new arena with addr " << std::hex << newArena;
79     return true;
80 }
81 
82 template <Alignment ALIGNMENT, bool USE_MEMSET>
Alloc(size_t size)83 ALWAYS_INLINE inline void *FrameAllocator<ALIGNMENT, USE_MEMSET>::Alloc(size_t size)
84 {
85     ASSERT(AlignUp(size, GetAlignmentInBytes(ALIGNMENT)) == size);
86     // Try to get free memory from current arenas
87     void *mem = TryToAllocate(size);
88 
89     if (UNLIKELY(mem == nullptr)) {
90         LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate " << size << " bytes for a new frame in current arenas";
91         if (!TryAllocateNewArena(size)) {
92             LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate a new arena, return nullptr";
93             return nullptr;
94         }
95         mem = TryToAllocate(size);
96         if (mem == nullptr) {
97             LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate memory in a totally free arena, change default arenas sizes";
98             return nullptr;
99         }
100     }
101 
102     ASSERT(AlignUp(ToUintPtr(mem), GetAlignmentInBytes(ALIGNMENT)) == ToUintPtr(mem));
103     LOG_FRAME_ALLOCATOR(DEBUG) << "Allocated memory at addr " << std::hex << mem;
104     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
105     if constexpr (USE_MEMSET) {
106         memset_s(mem, size, 0x00, size);
107     }
108     allocatedSize_ += size;
109     return mem;
110 }
111 
112 template <Alignment ALIGNMENT, bool USE_MEMSET>
Free(void * mem)113 ALWAYS_INLINE inline void FrameAllocator<ALIGNMENT, USE_MEMSET>::Free(void *mem)
114 {
115     ASSERT(curArena_ != nullptr);  // must has been initialized!
116     ASSERT(ToUintPtr(mem) == AlignUp(ToUintPtr(mem), GetAlignmentInBytes(ALIGNMENT)));
117     if (curArena_->InArena(mem)) {
118         allocatedSize_ -= ToUintPtr(curArena_->GetTop()) - ToUintPtr(mem);
119         curArena_->Free(mem);
120     } else {
121         ASSERT(curArena_->GetOccupiedSize() == 0);
122         ASSERT(curArena_->GetPrevArena() != nullptr);
123 
124         curArena_ = curArena_->GetPrevArena();
125         ASSERT(curArena_->InArena(mem));
126         allocatedSize_ -= ToUintPtr(curArena_->GetTop()) - ToUintPtr(mem);
127         curArena_->Free(mem);
128         if (UNLIKELY((emptyArenasCount_ + 1) > FRAME_ALLOC_MAX_FREE_ARENAS_THRESHOLD)) {
129             FreeLastArena();
130         } else {
131             emptyArenasCount_++;
132         }
133     }
134     LOG_FRAME_ALLOCATOR(DEBUG) << "Free memory at addr " << std::hex << mem;
135 }
136 
137 template <Alignment ALIGNMENT, bool USE_MEMSET>
138 // CC-OFFNXT(G.FUD.06) perf critical
TryToAllocate(size_t size)139 inline void *FrameAllocator<ALIGNMENT, USE_MEMSET>::TryToAllocate(size_t size)
140 {
141     // Try to allocate memory in the current arena:
142     ASSERT(curArena_ != nullptr);
143     void *mem = curArena_->Alloc(size);
144     if (LIKELY(mem != nullptr)) {
145         return mem;
146     }
147     // We don't have enough memory in current arena, try to allocate in the next one:
148     FramesArena *nextArena = curArena_->GetNextArena();
149     if (nextArena == nullptr) {
150         LOG_FRAME_ALLOCATOR(DEBUG) << "TryToPush failed - we don't have a free arena";
151         return nullptr;
152     }
153     mem = nextArena->Alloc(size);
154     if (LIKELY(mem != nullptr)) {
155         ASSERT(emptyArenasCount_ > 0);
156         emptyArenasCount_--;
157         curArena_ = nextArena;
158         return mem;
159     }
160     LOG_FRAME_ALLOCATOR(DEBUG) << "Couldn't allocate " << size << " bytes of memory in the totally free arena."
161                                << " Change initial sizes of arenas";
162     return nullptr;
163 }
164 
165 template <Alignment ALIGNMENT, bool USE_MEMSET>
GetNextArenaSize(size_t size)166 inline size_t FrameAllocator<ALIGNMENT, USE_MEMSET>::GetNextArenaSize(size_t size)
167 {
168     size_t requestedSize = size + sizeof(FramesArena) + GetAlignmentInBytes(ALIGNMENT);
169     if ((arenaSizeNeedToGrow_) || (biggestArenaSize_ < requestedSize)) {
170         biggestArenaSize_ += ARENA_SIZE_GREW_LEVEL;
171         if (biggestArenaSize_ < requestedSize) {
172             biggestArenaSize_ = RoundUp(requestedSize, ARENA_SIZE_GREW_LEVEL);
173         }
174     } else {
175         arenaSizeNeedToGrow_ = true;
176     }
177     return biggestArenaSize_;
178 }
179 
180 template <Alignment ALIGNMENT, bool USE_MEMSET>
181 // CC-OFFNXT(G.FUD.06) perf critical
FreeLastArena()182 inline void FrameAllocator<ALIGNMENT, USE_MEMSET>::FreeLastArena()
183 {
184     ASSERT(lastAllocArena_ != nullptr);
185     FramesArena *arenaToFree = lastAllocArena_;
186     lastAllocArena_ = arenaToFree->GetPrevArena();
187     if (arenaToFree == curArena_) {
188         curArena_ = lastAllocArena_;
189     }
190     if (lastAllocArena_ == nullptr) {
191         ASSERT(lastAllocArena_ == curArena_);
192         // To fix clang tidy warning
193         // (it suggests that cur_arena_ can be not nullptr when
194         //  last_alloc_arena_ is equal to nullptr)
195         curArena_ = lastAllocArena_;
196         LOG_FRAME_ALLOCATOR(DEBUG) << "Clear the last arena in the list";
197     } else {
198         lastAllocArena_->ClearNextLink();
199     }
200     LOG_FRAME_ALLOCATOR(DEBUG) << "Free the arena at addr " << std::hex << arenaToFree;
201     FreeArenaImpl(arenaToFree);
202     arenaSizeNeedToGrow_ = false;
203 }
204 
205 template <Alignment ALIGNMENT, bool USE_MEMSET>
206 // CC-OFFNXT(G.FMT.07) project code style
207 // CC-OFFNXT(G.FUD.06) perf critical
208 inline typename FrameAllocator<ALIGNMENT, USE_MEMSET>::FramesArena *
AllocateArenaImpl(size_t size)209 FrameAllocator<ALIGNMENT, USE_MEMSET>::AllocateArenaImpl(size_t size)
210 {
211     FramesArena *newArena = nullptr;
212     if (!useMalloc_) {
213         ASSERT(memPoolAlloc_ != nullptr);
214         newArena = memPoolAlloc_->AllocArena<FramesArena>(size, spaceType_, AllocatorType::FRAME_ALLOCATOR, this);
215     } else {
216         auto mem = ark::os::mem::AlignedAlloc(GetAlignmentInBytes(ARENA_DEFAULT_ALIGNMENT), size);
217         if (mem != nullptr) {
218             auto arenaBuffOffs = AlignUp(sizeof(FramesArena), GetAlignmentInBytes(ARENA_DEFAULT_ALIGNMENT));
219             newArena = new (mem) FramesArena(size - arenaBuffOffs, ToVoidPtr(ToUintPtr(mem) + arenaBuffOffs));
220         }
221     }
222     return newArena;
223 }
224 
225 template <Alignment ALIGNMENT, bool USE_MEMSET>
FreeArenaImpl(FramesArena * arena)226 inline void FrameAllocator<ALIGNMENT, USE_MEMSET>::FreeArenaImpl(FramesArena *arena)
227 {
228     ASSERT(arena != nullptr);
229     if (!useMalloc_) {
230         ASSERT(memPoolAlloc_ != nullptr);
231         memPoolAlloc_->FreeArena<FramesArena>(arena);
232     } else {
233         os::mem::AlignedFree(arena);
234     }
235 }
236 
237 template <Alignment ALIGNMENT, bool USE_MEMSET>
Contains(void * mem)238 inline bool FrameAllocator<ALIGNMENT, USE_MEMSET>::Contains(void *mem)
239 {
240     auto curArena = curArena_;
241 
242     while (curArena != nullptr) {
243         LOG_FRAME_ALLOCATOR(DEBUG) << "check InAllocator arena at addr " << std::hex << curArena;
244         if (curArena->InArena(mem)) {
245             return true;
246         }
247         curArena = curArena->GetPrevArena();
248     }
249     return false;
250 }
251 
252 #undef LOG_FRAME_ALLOCATOR
253 
254 }  // namespace ark::mem
255 #endif  // PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H
256