1 /* 2 * Copyright (c) 2025 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 COMMON_COMPONENTS_HEAP_ALLOCATOR_REGION_LIST_H 17 #define COMMON_COMPONENTS_HEAP_ALLOCATOR_REGION_LIST_H 18 19 #include "common_components/heap/allocator/region_desc.h" 20 21 namespace common { 22 class RegionList { 23 public: RegionList(const char * name)24 RegionList(const char* name) : listName_(name) {} 25 26 void PrependRegion(RegionDesc* region, RegionDesc::RegionType type); 27 void PrependRegionLocked(RegionDesc* region, RegionDesc::RegionType type); 28 29 void MergeRegionList(RegionList& regionList, RegionDesc::RegionType regionType); 30 void MergeRegionListWithoutHead(RegionList& regionList, RegionDesc::RegionType regionType); 31 DeleteRegion(RegionDesc * del)32 void DeleteRegion(RegionDesc* del) 33 { 34 if (del == nullptr) { 35 return; 36 } 37 38 std::lock_guard<std::mutex> lock(listMutex_); 39 DeleteRegionLocked(del); 40 } 41 TryDeleteRegion(RegionDesc * del,RegionDesc::RegionType oldType,RegionDesc::RegionType newType)42 bool TryDeleteRegion(RegionDesc* del, RegionDesc::RegionType oldType, RegionDesc::RegionType newType) 43 { 44 if (del == nullptr) { 45 return false; 46 } 47 48 CHECK_CC(oldType != newType); 49 std::lock_guard<std::mutex> lock(listMutex_); 50 if (del->GetRegionType() == oldType) { 51 DeleteRegionLocked(del); 52 del->SetRegionType(newType); 53 return true; 54 } 55 return false; 56 } 57 58 void DumpRegionSummary() const; 59 #ifndef NDEBUG 60 void DumpRegionList(const char*); 61 #endif 62 DecCounts(size_t nRegion,size_t nUnit)63 void DecCounts(size_t nRegion, size_t nUnit) 64 { 65 if (regionCount_ >= nRegion && unitCount_ >= nUnit) { 66 regionCount_ -= nRegion; 67 unitCount_ -= nUnit; 68 } else { 69 LOG_COMMON(FATAL) << "region list error count " << 70 regionCount_ << "-" << nRegion << " " << unitCount_ << "-" << nUnit; 71 } 72 } 73 IncCounts(size_t nRegion,size_t nUnit)74 void IncCounts(size_t nRegion, size_t nUnit) 75 { 76 CHECK_CC((nRegion <= std::numeric_limits<size_t>::max() - regionCount_) && 77 (nUnit <= std::numeric_limits<size_t>::max() - unitCount_)); 78 regionCount_ += nRegion; 79 unitCount_ += nUnit; 80 } 81 GetHeadRegion()82 RegionDesc* GetHeadRegion() const { return listHead_; } 83 ClearList()84 void ClearList() 85 { 86 listHead_ = nullptr; 87 listTail_ = nullptr; 88 regionCount_ = 0; 89 unitCount_ = 0; 90 } 91 GetTailRegion()92 RegionDesc* GetTailRegion() { return listTail_; } 93 TakeHeadRegion()94 RegionDesc* TakeHeadRegion() 95 { 96 std::lock_guard<std::mutex> lg(listMutex_); 97 if (listHead_ == nullptr) { 98 return nullptr; 99 } 100 RegionDesc* currentHead = listHead_; 101 DeleteRegionLocked(currentHead); 102 return currentHead; 103 } 104 GetUnitCount()105 size_t GetUnitCount() const { return unitCount_; } 106 GetRegionCount()107 size_t GetRegionCount() const { return regionCount_; } 108 109 size_t GetAllocatedSize(bool usedPageSize = true) const 110 { 111 if (usedPageSize) { 112 return GetUnitCount() * RegionDesc::UNIT_SIZE; 113 } 114 return CountAllocatedSize(); 115 } 116 VisitAllRegions(const std::function<void (RegionDesc *)> & visitor)117 void VisitAllRegions(const std::function<void(RegionDesc*)>& visitor) 118 { 119 std::lock_guard<std::mutex> lock(listMutex_); 120 for (RegionDesc* node = listHead_; node != nullptr; node = node->GetNextRegion()) { 121 visitor(node); 122 } 123 } 124 SetElementType(RegionDesc::RegionType type)125 void SetElementType(RegionDesc::RegionType type) 126 { 127 std::lock_guard<std::mutex> lock(listMutex_); 128 for (RegionDesc* node = listHead_; node != nullptr; node = node->GetNextRegion()) { 129 node->SetRegionType(type); 130 } 131 } 132 GetListMutex()133 std::mutex& GetListMutex() { return listMutex_; } 134 MoveTo(RegionList & targetList)135 void MoveTo(RegionList& targetList) 136 { 137 std::lock_guard<std::mutex> lock(listMutex_); 138 targetList.AssignWith(*this); 139 this->ClearList(); 140 } 141 CopyListTo(RegionList & dstList)142 void CopyListTo(RegionList& dstList) 143 { 144 std::lock_guard<std::mutex> lock(listMutex_); 145 dstList.listHead_ = this->listHead_; 146 dstList.listTail_ = this->listTail_; 147 dstList.regionCount_ = this->regionCount_; 148 dstList.unitCount_ = this->unitCount_; 149 } 150 AllocFromFreeListInLock()151 uintptr_t AllocFromFreeListInLock() 152 { 153 RegionDesc* region = GetHeadRegion(); 154 if (region == nullptr) { 155 return 0; 156 } 157 return region->AllocPinnedFromFreeList(); 158 } 159 160 protected: 161 std::mutex listMutex_; 162 size_t regionCount_ = 0; 163 size_t unitCount_ = 0; 164 RegionDesc* listHead_ = nullptr; // the start region for iteration, i.e., the first region 165 RegionDesc* listTail_ = nullptr; // help to merge region list 166 const char* listName_ = nullptr; 167 168 private: 169 void DeleteRegionLocked(RegionDesc* del); 170 AssignWith(const RegionList & srcList)171 void AssignWith(const RegionList& srcList) 172 { 173 std::lock_guard<std::mutex> lock(listMutex_); 174 listHead_ = srcList.listHead_; 175 listTail_ = srcList.listTail_; 176 regionCount_ = srcList.regionCount_; 177 unitCount_ = srcList.unitCount_; 178 } 179 180 // allocated-size of tl-region list must be calculated on the fly. CountAllocatedSize()181 size_t CountAllocatedSize() const 182 { 183 size_t allocCnt = 0; 184 std::lock_guard<std::mutex> lock(const_cast<RegionList*>(this)->listMutex_); 185 for (RegionDesc* region = listHead_; region != nullptr; region = region->GetNextRegion()) { 186 allocCnt += region->GetRegionAllocatedSize(); 187 } 188 return allocCnt; 189 } 190 191 #ifndef NDEBUG VerifyRegion(RegionDesc * region)192 void VerifyRegion(RegionDesc* region) 193 { 194 RegionDesc* prev = region->GetPrevRegion(); 195 RegionDesc* next = region->GetNextRegion(); 196 if (prev != nullptr && prev->GetNextRegion() != region) { 197 LOG_COMMON(FATAL) << "illegal region node"; 198 UNREACHABLE_CC(); 199 } 200 201 if (next != nullptr && next->GetPrevRegion() != region) { 202 LOG_COMMON(FATAL) << "illegal region node"; 203 UNREACHABLE_CC(); 204 } 205 } 206 #endif 207 }; 208 209 class RegionCache : public RegionList { 210 public: RegionCache(const char * name)211 RegionCache(const char* name) : RegionList(name) {} 212 TryPrependRegion(RegionDesc * region,RegionDesc::RegionType type)213 bool TryPrependRegion(RegionDesc *region, RegionDesc::RegionType type) 214 { 215 std::lock_guard<std::mutex> lock(listMutex_); 216 if (active_) { 217 PrependRegionLocked(region, type); 218 return true; 219 } 220 return false; 221 } 222 ActivateRegionCache()223 void ActivateRegionCache() 224 { 225 std::lock_guard<std::mutex> lock(listMutex_); 226 active_ = true; 227 } 228 DeactivateRegionCache()229 void DeactivateRegionCache() 230 { 231 std::lock_guard<std::mutex> lock(listMutex_); 232 for (RegionDesc* node = listHead_; node != nullptr; node = node->GetNextRegion()) { 233 node->ClearMarkingCopyLine(); 234 } 235 active_ = false; 236 } 237 private: 238 bool active_ = false; 239 }; 240 } // namespace common 241 #endif // COMMON_COMPONENTS_HEAP_ALLOCATOR_REGION_LIST_H 242