1 /** 2 * Copyright (c) 2021-2022 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 LIBPANDABASE_MEM_MMAP_MEM_POOL_H 17 #define LIBPANDABASE_MEM_MMAP_MEM_POOL_H 18 19 #include "libpandabase/mem/mem_pool.h" 20 #include "libpandabase/mem/mem.h" 21 #include "libpandabase/os/mem.h" 22 #include "libpandabase/os/mutex.h" 23 #include "libpandabase/mem/space.h" 24 25 #include <map> 26 #include <tuple> 27 28 namespace panda { 29 30 class MMapMemPoolTest; 31 namespace mem::test { 32 class InternalAllocatorTest; 33 } // namespace mem::test 34 35 class MmapPool { 36 public: 37 using FreePoolsIter = std::multimap<size_t, MmapPool *>::iterator; MmapPool(Pool pool,FreePoolsIter free_pools_iter)38 explicit MmapPool(Pool pool, FreePoolsIter free_pools_iter) : pool_(pool), free_pools_iter_(free_pools_iter) {} 39 40 ~MmapPool() = default; 41 42 DEFAULT_COPY_SEMANTIC(MmapPool); 43 DEFAULT_MOVE_SEMANTIC(MmapPool); 44 GetSize()45 size_t GetSize() 46 { 47 return pool_.GetSize(); 48 } 49 SetSize(size_t size)50 void SetSize(size_t size) 51 { 52 pool_ = Pool(size, GetMem()); 53 } 54 GetMem()55 void *GetMem() 56 { 57 return pool_.GetMem(); 58 } 59 60 // A free pool will be store in the free_pools_, and it's iterator will be recorded in the free_pools_iter_. 61 // If the free_pools_iter_ is equal to the end of free_pools_, the pool is used. IsUsed(FreePoolsIter end_iter)62 bool IsUsed(FreePoolsIter end_iter) 63 { 64 return free_pools_iter_ == end_iter; 65 } 66 GetFreePoolsIter()67 FreePoolsIter GetFreePoolsIter() 68 { 69 return free_pools_iter_; 70 } 71 SetFreePoolsIter(FreePoolsIter free_pools_iter)72 void SetFreePoolsIter(FreePoolsIter free_pools_iter) 73 { 74 free_pools_iter_ = free_pools_iter; 75 } 76 77 private: 78 Pool pool_; 79 // record the iterator of the pool in the multimap 80 FreePoolsIter free_pools_iter_; 81 }; 82 83 class MmapPoolMap { 84 public: 85 MmapPoolMap() = default; 86 ~MmapPoolMap()87 ~MmapPoolMap() 88 { 89 for (auto &pool : pool_map_) { 90 delete pool.second; 91 } 92 } 93 94 DEFAULT_COPY_SEMANTIC(MmapPoolMap); 95 DEFAULT_MOVE_SEMANTIC(MmapPoolMap); 96 97 // Find a free pool with enough size in the map. Split the pool, if the pool size is larger than required size. 98 Pool PopFreePool(size_t size); 99 100 // push the unused pool to the map. 101 void PushFreePool(Pool pool); 102 103 // Add a new pool to the map. This pool will be marked as used. 104 void AddNewPool(Pool pool); 105 106 // Get the sum of all free pools size. 107 size_t GetAllSize() const; 108 109 /** 110 * To check if we can alloc enough pools from free pools 111 * @param pools_num the number of pools we need 112 * @param pool_size the size of the pool we need 113 * @return true if we can make sure that we have enough space in free pools to alloc pools we need 114 */ 115 bool HaveEnoughFreePools(size_t pools_num, size_t pool_size) const; 116 117 private: 118 std::map<void *, MmapPool *> pool_map_; 119 std::multimap<size_t, MmapPool *> free_pools_; 120 }; 121 122 class MmapMemPool : public MemPool<MmapMemPool> { 123 public: 124 NO_COPY_SEMANTIC(MmapMemPool); 125 NO_MOVE_SEMANTIC(MmapMemPool); 126 ~MmapMemPool() override; 127 128 /** 129 * Get min address in pool 130 * @return min address in pool 131 */ GetMinObjectAddress()132 uintptr_t GetMinObjectAddress() const 133 { 134 return min_object_memory_addr_; 135 } 136 GetAddressOfMinObjectAddress()137 void *GetAddressOfMinObjectAddress() 138 { 139 return static_cast<void *>(&min_object_memory_addr_); 140 } 141 142 /** 143 * Get max address in pool 144 * @return max address in pool 145 */ GetMaxObjectAddress()146 uintptr_t GetMaxObjectAddress() const 147 { 148 return min_object_memory_addr_ + mmaped_object_memory_size_; 149 } 150 GetTotalObjectSize()151 size_t GetTotalObjectSize() const 152 { 153 return mmaped_object_memory_size_; 154 } 155 156 /** 157 * Get start address of pool for input address in this pool 158 * @param addr address in pool 159 * @return start address of pool 160 */ GetStartAddrPoolForAddr(const void * addr)161 void *GetStartAddrPoolForAddr(const void *addr) const 162 { 163 return GetStartAddrPoolForAddrImpl(addr); 164 } 165 166 size_t GetObjectSpaceFreeBytes() const; 167 168 // To check if we can alloc enough pools in object space 169 bool HaveEnoughPoolsInObjectSpace(size_t pools_num, size_t pool_size) const; 170 171 /** 172 * @return used bytes count in object space (so exclude bytes in free pools) 173 */ 174 size_t GetObjectUsedBytes() const; 175 SetUseCompilerSpaceSizeLimit(bool use_limit)176 void SetUseCompilerSpaceSizeLimit(bool use_limit) 177 { 178 use_compiler_space_size_limit_ = use_limit; 179 } 180 181 private: 182 template <class ArenaT = Arena> 183 ArenaT *AllocArenaImpl(size_t size, SpaceType space_type, AllocatorType allocator_type, const void *allocator_addr); 184 template <class ArenaT = Arena> 185 void FreeArenaImpl(ArenaT *arena); 186 187 void *AllocRawMemImpl(size_t size, SpaceType type); 188 void *AllocRawMemCompilerImpl(size_t size); 189 void *AllocRawMemInternalImpl(size_t size); 190 void *AllocRawMemCodeImpl(size_t size); 191 void *AllocRawMemObjectImpl(size_t size, SpaceType type); 192 void FreeRawMemImpl(void *mem, size_t size); 193 194 Pool AllocPoolImpl(size_t size, SpaceType space_type, AllocatorType allocator_type, const void *allocator_addr); 195 void FreePoolImpl(void *mem, size_t size); 196 197 AllocatorInfo GetAllocatorInfoForAddrImpl(const void *addr) const; 198 SpaceType GetSpaceTypeForAddrImpl(const void *addr) const; 199 void *GetStartAddrPoolForAddrImpl(const void *addr) const; 200 201 Pool AllocPoolUnsafe(size_t size, SpaceType space_type, AllocatorType allocator_type, const void *allocator_addr); 202 void FreePoolUnsafe(void *mem, size_t size); 203 204 void AddToNonObjectPoolsMap(std::tuple<Pool, AllocatorInfo, SpaceType> pool_info); 205 void RemoveFromNonObjectPoolsMap(void *pool_addr); 206 std::tuple<Pool, AllocatorInfo, SpaceType> FindAddrInNonObjectPoolsMap(const void *addr) const; 207 208 MmapMemPool(); 209 210 // A super class for raw memory allocation for spaces. 211 class SpaceMemory { 212 public: Initialize(uintptr_t min_addr,size_t max_size)213 void Initialize(uintptr_t min_addr, size_t max_size) 214 { 215 min_address_ = min_addr; 216 max_size_ = max_size; 217 cur_alloc_offset_ = 0U; 218 } 219 GetMinAddress()220 uintptr_t GetMinAddress() const 221 { 222 return min_address_; 223 } 224 GetMaxSize()225 size_t GetMaxSize() const 226 { 227 return max_size_; 228 } 229 GetOccupiedMemorySize()230 size_t GetOccupiedMemorySize() const 231 { 232 return cur_alloc_offset_; 233 } 234 GetFreeSpace()235 inline size_t GetFreeSpace() const 236 { 237 ASSERT(max_size_ >= cur_alloc_offset_); 238 return max_size_ - cur_alloc_offset_; 239 } 240 AllocRawMem(size_t size,MmapPoolMap * pool_map)241 void *AllocRawMem(size_t size, MmapPoolMap *pool_map) 242 { 243 if (UNLIKELY(GetFreeSpace() < size)) { 244 return nullptr; 245 } 246 void *mem = ToVoidPtr(min_address_ + cur_alloc_offset_); 247 cur_alloc_offset_ += size; 248 pool_map->AddNewPool(Pool(size, mem)); 249 return mem; 250 } 251 252 private: 253 uintptr_t min_address_ {0U}; /// < Min address for the space 254 size_t max_size_ {0U}; /// < Max size in bytes for the space 255 size_t cur_alloc_offset_ {0U}; /// < A value of occupied memory from the min_address_ 256 }; 257 258 uintptr_t min_object_memory_addr_ {0U}; // < Minimal address of the mmaped object memory 259 size_t mmaped_object_memory_size_ {0U}; // < Size of whole the mmaped object memory 260 261 SpaceMemory common_space_; 262 263 PoolMap pool_map_; /// < Pool map for object pools with all required information for quick search 264 265 MmapPoolMap common_space_pools_; 266 267 size_t code_space_current_size_ {0}; 268 size_t compiler_space_current_size_ {0}; 269 size_t internal_space_current_size_ {0}; 270 271 size_t code_space_max_size_ {0}; 272 size_t compiler_space_max_size_ {0}; 273 size_t internal_space_max_size_ {0}; 274 275 bool use_compiler_space_size_limit_ {false}; 276 277 // Map for non object pools allocated via mmap 278 std::map<const void *, std::tuple<Pool, AllocatorInfo, SpaceType>> non_object_mmaped_pools_; 279 // AllocRawMem is called both from alloc and externally 280 mutable os::memory::RecursiveMutex lock_; 281 282 friend class PoolManager; 283 friend class MemPool<MmapMemPool>; 284 friend class MMapMemPoolTest; 285 friend class mem::test::InternalAllocatorTest; 286 }; 287 288 } // namespace panda 289 290 #endif // LIBPANDABASE_MEM_MMAP_MEM_POOL_H 291