• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H_
17 #define PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H_
18 
19 #include "runtime/mem/frame_allocator.h"
20 
21 #include <cstring>
22 
23 #include "libpandabase/mem/pool_manager.h"
24 #include "libpandabase/utils/logger.h"
25 
26 namespace panda::mem {
27 
28 using StackFrameAllocator = FrameAllocator<>;
29 
30 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
31 #define LOG_FRAME_ALLOCATOR(level) LOG(level, ALLOC) << "FrameAllocator: "
32 
33 template <Alignment AlignmenT, bool UseMemsetT>
FrameAllocator()34 inline FrameAllocator<AlignmenT, UseMemsetT>::FrameAllocator()
35 {
36     LOG_FRAME_ALLOCATOR(DEBUG) << "Initializing of FrameAllocator";
37     mem_pool_alloc_ = PoolManager::GetMmapMemPool();
38     cur_arena_ = mem_pool_alloc_->AllocArena<FramesArena>(FIRST_ARENA_SIZE, SpaceType::SPACE_TYPE_INTERNAL,
39                                                           AllocatorType::FRAME_ALLOCATOR, this);
40     last_alloc_arena_ = cur_arena_;
41     biggest_arena_size_ = FIRST_ARENA_SIZE;
42     arena_size_need_to_grow_ = true;
43     LOG_FRAME_ALLOCATOR(INFO) << "Initializing of FrameAllocator finished";
44 }
45 
46 template <Alignment AlignmenT, bool UseMemsetT>
~FrameAllocator()47 inline FrameAllocator<AlignmenT, UseMemsetT>::~FrameAllocator()
48 {
49     LOG_FRAME_ALLOCATOR(DEBUG) << "Destroying of FrameAllocator";
50     while (last_alloc_arena_ != nullptr) {
51         LOG_FRAME_ALLOCATOR(DEBUG) << "Free arena at addr " << std::hex << last_alloc_arena_;
52         FramesArena *prev_arena = last_alloc_arena_->GetPrevArena();
53         mem_pool_alloc_->FreeArena<FramesArena>(last_alloc_arena_);
54         last_alloc_arena_ = prev_arena;
55     }
56     cur_arena_ = nullptr;
57     LOG_FRAME_ALLOCATOR(INFO) << "Destroying of FrameAllocator finished";
58 }
59 
60 template <Alignment AlignmenT, bool UseMemsetT>
TryAllocateNewArena(size_t size)61 inline bool FrameAllocator<AlignmenT, UseMemsetT>::TryAllocateNewArena(size_t size)
62 {
63     size_t arena_size = GetNextArenaSize(size);
64     LOG_FRAME_ALLOCATOR(DEBUG) << "Try to allocate a new arena with size " << arena_size;
65     auto new_arena = mem_pool_alloc_->AllocArena<FramesArena>(arena_size, SpaceType::SPACE_TYPE_INTERNAL,
66                                                               AllocatorType::FRAME_ALLOCATOR, this);
67     if (new_arena == nullptr) {
68         LOG_FRAME_ALLOCATOR(DEBUG) << "Couldn't get memory for a new arena";
69         arena_size_need_to_grow_ = false;
70         return false;
71     }
72     last_alloc_arena_->LinkNext(new_arena);
73     new_arena->LinkPrev(last_alloc_arena_);
74     last_alloc_arena_ = new_arena;
75     empty_arenas_count_++;
76     LOG_FRAME_ALLOCATOR(DEBUG) << "Successfully allocate new arena with addr " << std::hex << new_arena;
77     return true;
78 }
79 
80 template <Alignment AlignmenT, bool UseMemsetT>
Alloc(size_t size)81 inline void *FrameAllocator<AlignmenT, UseMemsetT>::Alloc(size_t size)
82 {
83     ASSERT(AlignUp(size, GetAlignmentInBytes(AlignmenT)) == size);
84     // Try to get free memory from current arenas
85     void *mem = TryToAllocate(size);
86 
87     if (UNLIKELY(mem == nullptr)) {
88         LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate " << size << " bytes for a new frame in current arenas";
89         if (!TryAllocateNewArena(size)) {
90             LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate a new arena, return nullptr";
91             return nullptr;
92         }
93         mem = TryToAllocate(size);
94         if (mem == nullptr) {
95             LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate memory in a totally free arena, change default arenas sizes";
96             return nullptr;
97         }
98     }
99 
100     ASSERT(AlignUp(ToUintPtr(mem), GetAlignmentInBytes(AlignmenT)) == ToUintPtr(mem));
101     LOG_FRAME_ALLOCATOR(INFO) << "Allocated memory at addr " << std::hex << mem;
102     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
103     if constexpr (UseMemsetT) {
104         (void)memset_s(mem, size, 0x00, size);
105     }
106     return mem;
107 }
108 
109 template <Alignment AlignmenT, bool UseMemsetT>
Free(void * mem)110 inline void FrameAllocator<AlignmenT, UseMemsetT>::Free(void *mem)
111 {
112     ASSERT(cur_arena_ != nullptr);  // must has been initialized!
113     ASSERT(ToUintPtr(mem) == AlignUp(ToUintPtr(mem), GetAlignmentInBytes(AlignmenT)));
114     if (cur_arena_->InArena(mem)) {
115         cur_arena_->Free(mem);
116     } else {
117         ASSERT(cur_arena_->GetOccupiedSize() == 0);
118         ASSERT(cur_arena_->GetPrevArena() != nullptr);
119 
120         cur_arena_ = cur_arena_->GetPrevArena();
121         ASSERT(cur_arena_->InArena(mem));
122         cur_arena_->Free(mem);
123         if (UNLIKELY((empty_arenas_count_ + 1) > FRAME_ALLOC_MAX_FREE_ARENAS_THRESHOLD)) {
124             FreeLastArena();
125         } else {
126             empty_arenas_count_++;
127         }
128     }
129     LOG_FRAME_ALLOCATOR(INFO) << "Free memory at addr " << std::hex << mem;
130 }
131 
132 template <Alignment AlignmenT, bool UseMemsetT>
TryToAllocate(size_t size)133 inline void *FrameAllocator<AlignmenT, UseMemsetT>::TryToAllocate(size_t size)
134 {
135     // Try to allocate memory in the current arena:
136     ASSERT(cur_arena_ != nullptr);
137     void *mem = cur_arena_->Alloc(size);
138     if (LIKELY(mem != nullptr)) {
139         return mem;
140     }
141     // We don't have enough memory in current arena, try to allocate in the next one:
142     FramesArena *next_arena = cur_arena_->GetNextArena();
143     if (next_arena == nullptr) {
144         LOG_FRAME_ALLOCATOR(DEBUG) << "TryToPush failed - we don't have a free arena";
145         return nullptr;
146     }
147     mem = next_arena->Alloc(size);
148     if (LIKELY(mem != nullptr)) {
149         ASSERT(empty_arenas_count_ > 0);
150         empty_arenas_count_--;
151         cur_arena_ = next_arena;
152         return mem;
153     }
154     LOG_FRAME_ALLOCATOR(DEBUG) << "Couldn't allocate " << size << " bytes of memory in the totally free arena."
155                                << " Change initial sizes of arenas";
156     return nullptr;
157 }
158 
159 template <Alignment AlignmenT, bool UseMemsetT>
GetNextArenaSize(size_t size)160 inline size_t FrameAllocator<AlignmenT, UseMemsetT>::GetNextArenaSize(size_t size)
161 {
162     if (arena_size_need_to_grow_) {
163         biggest_arena_size_ += ARENA_SIZE_GREW_LEVEL;
164         if (biggest_arena_size_ < size) {
165             biggest_arena_size_ = RoundUp(size, ARENA_SIZE_GREW_LEVEL);
166         }
167     } else {
168         arena_size_need_to_grow_ = true;
169     }
170     return biggest_arena_size_;
171 }
172 
173 template <Alignment AlignmenT, bool UseMemsetT>
FreeLastArena()174 inline void FrameAllocator<AlignmenT, UseMemsetT>::FreeLastArena()
175 {
176     ASSERT(last_alloc_arena_ != nullptr);
177     FramesArena *arena_to_free = last_alloc_arena_;
178     last_alloc_arena_ = arena_to_free->GetPrevArena();
179     if (arena_to_free == cur_arena_) {
180         cur_arena_ = last_alloc_arena_;
181     }
182     if (last_alloc_arena_ == nullptr) {
183         LOG_FRAME_ALLOCATOR(DEBUG) << "Clear the last arena in the list";
184     } else {
185         last_alloc_arena_->ClearNextLink();
186     }
187     LOG_FRAME_ALLOCATOR(DEBUG) << "Free the arena at addr " << std::hex << arena_to_free;
188     mem_pool_alloc_->FreeArena<FramesArena>(arena_to_free);
189     arena_size_need_to_grow_ = false;
190 }
191 
192 template <Alignment AlignmenT, bool UseMemsetT>
Contains(void * mem)193 inline bool FrameAllocator<AlignmenT, UseMemsetT>::Contains(void *mem)
194 {
195     auto cur_arena = cur_arena_;
196     while (cur_arena != nullptr) {
197         LOG_FRAME_ALLOCATOR(DEBUG) << "check InAllocator arena at addr " << std::hex << cur_arena;
198         if (cur_arena->InArena(mem)) {
199             return true;
200         }
201         cur_arena = cur_arena->GetPrevArena();
202     }
203     return false;
204 }
205 
206 #undef LOG_FRAME_ALLOCATOR
207 
208 }  // namespace panda::mem
209 #endif  // PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H_
210