• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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