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