• 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 #include "ecmascript/mem/mem_controller.h"
17 
18 #include "ecmascript/mem/concurrent_marker.h"
19 #include "ecmascript/mem/parallel_evacuator.h"
20 
21 namespace panda::ecmascript {
MemController(Heap * heap)22 MemController::MemController(Heap *heap) : heap_(heap), allocTimeMs_(GetSystemTimeInMs())
23 {
24     minAllocLimitGrowingStep_ = heap->GetEcmaVM()->GetEcmaParamConfiguration().GetMinAllocLimitGrowingStep();
25 }
26 
CalculateAllocLimit(size_t currentSize,size_t minSize,size_t maxSize,size_t newSpaceCapacity,double factor) const27 size_t MemController::CalculateAllocLimit(size_t currentSize, size_t minSize, size_t maxSize, size_t newSpaceCapacity,
28                                           double factor) const
29 {
30     const uint64_t limit = std::max(static_cast<uint64_t>(currentSize * factor),
31                                     static_cast<uint64_t>(currentSize) + minAllocLimitGrowingStep_) +
32                            newSpaceCapacity;
33 
34     const uint64_t limitAboveMinSize = std::max<uint64_t>(limit, minSize);
35     const uint64_t halfToMaxSize = (static_cast<uint64_t>(currentSize) + maxSize) / 2;
36     size_t result = static_cast<size_t>(std::min(limitAboveMinSize, halfToMaxSize));
37     result = static_cast<size_t>(std::min(result, maxSize));
38     return result;
39 }
40 
CalculateGrowingFactor(double gcSpeed,double mutatorSpeed)41 double MemController::CalculateGrowingFactor(double gcSpeed, double mutatorSpeed)
42 {
43     double maxGrowingFactor = 4.0;
44     double halfMaxGrowingFactor = 2.0;
45     double minGrowingFactor = 1.3;
46     double minimumFactor = 1.1;
47     switch (heap_->GetMemGrowingType()) {
48         case MemGrowingType::HIGH_THROUGHPUT:
49             break;
50         case MemGrowingType::CONSERVATIVE:
51             minGrowingFactor = minimumFactor;
52             maxGrowingFactor = halfMaxGrowingFactor;
53             break;
54         case MemGrowingType::PRESSURE:
55             return minimumFactor;
56         default:
57             break;
58     }
59 
60     static constexpr double targetMutatorUtilization = 0.97;
61     if (gcSpeed == 0 || mutatorSpeed == 0) {
62         return maxGrowingFactor;
63     }
64 
65     const double speedRatio = gcSpeed / mutatorSpeed;
66 
67     const double a = speedRatio * (1 - targetMutatorUtilization);
68     const double b = speedRatio * (1 - targetMutatorUtilization) -  targetMutatorUtilization;
69 
70     double factor = (a < b * maxGrowingFactor) ? a / b : maxGrowingFactor;
71     factor = std::min(maxGrowingFactor, factor);
72     factor = std::max(factor, minGrowingFactor);
73     OPTIONAL_LOG(heap_->GetEcmaVM(), INFO) << "CalculateGrowingFactor gcSpeed"
74         << gcSpeed << " mutatorSpeed" << mutatorSpeed << " factor" << factor;
75     return factor;
76 }
77 
StartCalculationBeforeGC()78 void MemController::StartCalculationBeforeGC()
79 {
80     startCounter_++;
81     if (startCounter_ != 1) {
82         return;
83     }
84 
85     auto edenSpace = heap_->GetEdenSpace();
86     size_t edenSpaceAllocBytesSinceGC = edenSpace->GetAllocatedSizeSinceGC(edenSpace->GetTop());
87     // It's unnecessary to calculate newSpaceAllocAccumulatedSize. newSpaceAllocBytesSinceGC can be calculated directly.
88     auto newSpace = heap_->GetNewSpace();
89     size_t newSpaceAllocBytesSinceGC = newSpace->GetAllocatedSizeSinceGC(newSpace->GetTop());
90     size_t hugeObjectAllocSizeSinceGC = heap_->GetHugeObjectSpace()->GetHeapObjectSize() - hugeObjectAllocSizeSinceGC_;
91     size_t oldSpaceAllocAccumulatedSize = heap_->GetOldSpace()->GetTotalAllocatedSize();
92     size_t nonMovableSpaceAllocAccumulatedSize = heap_->GetNonMovableSpace()->GetTotalAllocatedSize();
93     size_t codeSpaceAllocAccumulatedSize = heap_->GetMachineCodeSpace()->GetTotalAllocatedSize();
94     double currentTimeInMs = GetSystemTimeInMs();
95     gcStartTime_ = currentTimeInMs;
96     size_t oldSpaceAllocSize = oldSpaceAllocAccumulatedSize - oldSpaceAllocAccumulatedSize_;
97     size_t nonMovableSpaceAllocSize = nonMovableSpaceAllocAccumulatedSize - nonMovableSpaceAllocAccumulatedSize_;
98     size_t codeSpaceAllocSize = codeSpaceAllocAccumulatedSize - codeSpaceAllocAccumulatedSize_;
99 
100     double duration = currentTimeInMs - allocTimeMs_;
101     allocTimeMs_ = currentTimeInMs;
102     oldSpaceAllocAccumulatedSize_ = oldSpaceAllocAccumulatedSize;
103     nonMovableSpaceAllocAccumulatedSize_ = nonMovableSpaceAllocAccumulatedSize;
104     codeSpaceAllocAccumulatedSize_ = codeSpaceAllocAccumulatedSize;
105 
106     allocDurationSinceGc_ += duration;
107 
108     edenSpaceAllocSizeSinceGC_ += edenSpaceAllocBytesSinceGC;
109     newSpaceAllocSizeSinceGC_ += newSpaceAllocBytesSinceGC;
110     oldSpaceAllocSizeSinceGC_ += oldSpaceAllocSize;
111     oldSpaceAllocSizeSinceGC_ += hugeObjectAllocSizeSinceGC;
112     nonMovableSpaceAllocSizeSinceGC_ += nonMovableSpaceAllocSize;
113     codeSpaceAllocSizeSinceGC_ += codeSpaceAllocSize;
114 }
115 
StopCalculationAfterGC(TriggerGCType gcType)116 void MemController::StopCalculationAfterGC(TriggerGCType gcType)
117 {
118     startCounter_--;
119     if (startCounter_ != 0) {
120         return;
121     }
122 
123     gcEndTime_ = GetSystemTimeInMs();
124     allocTimeMs_ = gcEndTime_;
125     if (allocDurationSinceGc_ > 0) {
126         oldSpaceAllocSizeSinceGC_ += heap_->GetEvacuator()->GetPromotedSize();
127         recordedEdenSpaceAllocations_.Push(MakeBytesAndDuration(edenSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
128         recordedNewSpaceAllocations_.Push(MakeBytesAndDuration(newSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
129         recordedOldSpaceAllocations_.Push(MakeBytesAndDuration(oldSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
130         recordedNonmovableSpaceAllocations_.Push(
131             MakeBytesAndDuration(nonMovableSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
132         recordedCodeSpaceAllocations_.Push(MakeBytesAndDuration(codeSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
133     }
134     allocDurationSinceGc_ = 0.0;
135     edenSpaceAllocSizeSinceGC_ = 0;
136     newSpaceAllocSizeSinceGC_ = 0;
137     oldSpaceAllocSizeSinceGC_ = 0;
138     nonMovableSpaceAllocSizeSinceGC_ = 0;
139     codeSpaceAllocSizeSinceGC_ = 0;
140 
141     hugeObjectAllocSizeSinceGC_ = heap_->GetHugeObjectSpace()->GetHeapObjectSize();
142 
143     double duration = gcEndTime_ - gcStartTime_;
144     switch (gcType) {
145         case TriggerGCType::YOUNG_GC:
146         case TriggerGCType::OLD_GC: {
147             if (heap_->IsConcurrentFullMark()) {
148                 if (heap_->GetConcurrentMarker()->IsEnabled()) {
149                     duration += heap_->GetConcurrentMarker()->GetDuration();
150                 }
151                 recordedMarkCompacts_.Push(MakeBytesAndDuration(heap_->GetHeapObjectSize(), duration));
152             }
153             break;
154         }
155         case TriggerGCType::FULL_GC: {
156             recordedMarkCompacts_.Push(MakeBytesAndDuration(heap_->GetHeapObjectSize(), duration));
157             break;
158         }
159         default:
160             break;
161     }
162 }
163 
RecordAfterConcurrentMark(MarkType markType,const ConcurrentMarker * marker)164 void MemController::RecordAfterConcurrentMark(MarkType markType, const ConcurrentMarker *marker)
165 {
166     double duration = marker->GetDuration();
167     if (markType == MarkType::MARK_FULL) {
168         recordedConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
169     } else if (markType == MarkType::MARK_YOUNG) {
170         recordedSemiConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
171     } else if (markType == MarkType::MARK_EDEN) {
172         recordedEdenConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
173     }
174 }
175 
CalculateMarkCompactSpeedPerMS()176 double MemController::CalculateMarkCompactSpeedPerMS()
177 {
178     markCompactSpeedCache_ = CalculateAverageSpeed(recordedMarkCompacts_);
179     if (markCompactSpeedCache_ > 0) {
180         return markCompactSpeedCache_;
181     }
182     return 0;
183 }
184 
CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration,LENGTH> & buffer,const BytesAndDuration & initial,const double timeMs)185 double MemController::CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer,
186                                             const BytesAndDuration &initial, const double timeMs)
187 {
188     BytesAndDuration sum = buffer.Sum(
189         [timeMs](BytesAndDuration a, BytesAndDuration b) {
190             if (timeMs != 0 && a.second >= timeMs) {
191                 return a;
192             }
193             return std::make_pair(a.first + b.first, a.second + b.second);
194         },
195         initial);
196     uint64_t bytes = sum.first;
197     double durations = sum.second;
198     if (fabs(durations) <= 1e-6) {
199         return 0;
200     }
201     double speed = bytes / durations;
202     const int maxSpeed = static_cast<int>(1_GB);
203     const int minSpeed = 1;
204     if (speed >= maxSpeed) {
205         return maxSpeed;
206     }
207     if (speed <= minSpeed) {
208         return minSpeed;
209     }
210     return speed;
211 }
212 
CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration,LENGTH> & buffer)213 double MemController::CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer)
214 {
215     return CalculateAverageSpeed(buffer, MakeBytesAndDuration(0, 0), 0);
216 }
217 
GetCurrentOldSpaceAllocationThroughputPerMS(double timeMs) const218 double MemController::GetCurrentOldSpaceAllocationThroughputPerMS(double timeMs) const
219 {
220     size_t allocatedSize = oldSpaceAllocSizeSinceGC_;
221     double duration = allocDurationSinceGc_;
222     return CalculateAverageSpeed(recordedOldSpaceAllocations_,
223                                  MakeBytesAndDuration(allocatedSize, duration), timeMs);
224 }
225 
GetEdenSpaceAllocationThroughputPerMS() const226 double MemController::GetEdenSpaceAllocationThroughputPerMS() const
227 {
228     return CalculateAverageSpeed(recordedEdenSpaceAllocations_);
229 }
230 
GetNewSpaceAllocationThroughputPerMS() const231 double MemController::GetNewSpaceAllocationThroughputPerMS() const
232 {
233     return CalculateAverageSpeed(recordedNewSpaceAllocations_);
234 }
235 
GetEdenSpaceConcurrentMarkSpeedPerMS() const236 double MemController::GetEdenSpaceConcurrentMarkSpeedPerMS() const
237 {
238     return CalculateAverageSpeed(recordedEdenConcurrentMarks_);
239 }
240 
GetNewSpaceConcurrentMarkSpeedPerMS() const241 double MemController::GetNewSpaceConcurrentMarkSpeedPerMS() const
242 {
243     return CalculateAverageSpeed(recordedSemiConcurrentMarks_);
244 }
245 
GetOldSpaceAllocationThroughputPerMS() const246 double MemController::GetOldSpaceAllocationThroughputPerMS() const
247 {
248     return CalculateAverageSpeed(recordedOldSpaceAllocations_);
249 }
250 
GetFullSpaceConcurrentMarkSpeedPerMS() const251 double MemController::GetFullSpaceConcurrentMarkSpeedPerMS() const
252 {
253     return CalculateAverageSpeed(recordedConcurrentMarks_);
254 }
255 }  // namespace panda::ecmascript
256