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_H_ 17 #define PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_H_ 18 19 #include <securec.h> 20 #include <array> 21 22 #include "libpandabase/mem/arena.h" 23 #include "libpandabase/mem/mem.h" 24 #include "libpandabase/mem/mmap_mem_pool-inl.h" 25 26 namespace panda::mem { 27 28 // Allocation flow looks like that: 29 // 30 // Allocate arenas for frames Frames free Return arenas Second allocated arena 31 // (stage 1) (stage 2) (stage 3) will be bigger than the 32 // second at stage 1 33 // |-----| |-----| |-----| 34 // | | | | | | 35 // |-----| | | |-----| | | | | 36 // |xxxxx| | | | | | | | | 37 // |-----| |xxxxx| |xxxxx| |-----| | | | | |-----| |-----| | | 38 // |xxxxx| |xxxxx| |xxxxx| ----> | | | | | | ----> | | ----> |xxxxx| |xxxxx| 39 // |xxxxx| |xxxxx| |xxxxx| | | | | | | | | |xxxxx| |xxxxx| 40 // |xxxxx| |xxxxx| |xxxxx| | | | | | | | | |xxxxx| |xxxxx| 41 // |xxxxx| |xxxxx| |xxxxx| | | | | | | | | |xxxxx| |xxxxx| 42 // |xxxxx| |xxxxx| |xxxxx| |xxxxx| | | | | |xxxxx| |xxxxx| |xxxxx| 43 // |-----| |-----| |-----| |-----| |-----| |-----| |-----| |-----| |-----| 44 45 // Frame allocator uses arenas and works like a stack - 46 // it will give memory from the top and can delete only last allocated memory. 47 template <Alignment AlignmenT = DEFAULT_FRAME_ALIGNMENT, bool UseMemsetT = true> 48 class FrameAllocator { 49 public: 50 FrameAllocator(); 51 ~FrameAllocator(); 52 FrameAllocator(const FrameAllocator &) noexcept = delete; 53 FrameAllocator(FrameAllocator &&) noexcept = default; 54 FrameAllocator &operator=(const FrameAllocator &) noexcept = delete; 55 FrameAllocator &operator=(FrameAllocator &&) noexcept = default; 56 57 [[nodiscard]] void *Alloc(size_t size); 58 59 // We must free objects allocated by this allocator strictly in reverse order 60 void Free(void *mem); 61 62 /** 63 * \brief Returns true if address inside current allocator. 64 */ 65 bool Contains(void *mem); 66 GetAllocatorType()67 static constexpr AllocatorType GetAllocatorType() 68 { 69 return AllocatorType::FRAME_ALLOCATOR; 70 } 71 72 private: 73 using FramesArena = DoubleLinkedAlignedArena<AlignmenT>; 74 static constexpr size_t FIRST_ARENA_SIZE = 256_KB; 75 static_assert(FIRST_ARENA_SIZE % PANDA_POOL_ALIGNMENT_IN_BYTES == 0); 76 static constexpr size_t ARENA_SIZE_GREW_LEVEL = FIRST_ARENA_SIZE; 77 static constexpr size_t FRAME_ALLOC_MIN_FREE_MEMORY_THRESHOLD = FIRST_ARENA_SIZE / 2; 78 static constexpr size_t FRAME_ALLOC_MAX_FREE_ARENAS_THRESHOLD = 1; 79 80 /** 81 * \brief Heuristic for arena size increase. 82 * @return new size 83 */ 84 size_t GetNextArenaSize(size_t size); 85 86 /** 87 * \brief Try to allocate an arena from the memory. 88 * @return true on success, or false on fail 89 */ 90 bool TryAllocateNewArena(size_t size = ARENA_SIZE_GREW_LEVEL); 91 92 /** 93 * \brief Try to allocate memory for a frame in the current arena or in the next one if it exists. 94 * @param size - size of the allocated memory 95 * @return pointer to the allocated memory on success, or nullptr on fail 96 */ 97 void *TryToAllocate(size_t size); 98 99 /** 100 * \brief Free last_allocated_arena_, i.e., free last arena in the list. 101 */ 102 void FreeLastArena(); 103 104 // A pointer to the current arena with the last allocated frame 105 FramesArena *cur_arena_ {nullptr}; 106 107 // A pointer to the last allocated arena (so it is equal to the top arena in the list) 108 FramesArena *last_alloc_arena_ {nullptr}; 109 110 // The biggest arena size during FrameAllocator workflow. Needed for computing a new arena size. 111 size_t biggest_arena_size_ {0}; 112 113 // A marker which tells us if we need to increase the size of a new arena or not. 114 bool arena_size_need_to_grow_ {true}; 115 116 size_t empty_arenas_count_ {0}; 117 118 MmapMemPool *mem_pool_alloc_ {nullptr}; 119 friend class FrameAllocatorTest; 120 }; 121 122 } // namespace panda::mem 123 124 #endif // PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_H_ 125