• 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_evacuation.h"
21 
22 namespace panda::ecmascript {
MemController(Heap * heap)23 MemController::MemController(Heap *heap) : heap_(heap), allocTimeMs_(GetSystemTimeInMs()) {}
24 
CalculateAllocLimit(size_t currentSize,size_t minSize,size_t maxSize,size_t newSpaceCapacity,double factor) const25 double MemController::CalculateAllocLimit(size_t currentSize, size_t minSize, size_t maxSize, size_t newSpaceCapacity,
26                                           double factor) const
27 {
28     const uint64_t limit = std::max(static_cast<uint64_t>(currentSize * factor),
29                                     static_cast<uint64_t>(currentSize) + MIN_AllOC_LIMIT_GROWING_STEP) +
30                            newSpaceCapacity;
31 
32     const uint64_t limitAboveMinSize = std::max<uint64_t>(limit, minSize);
33     const uint64_t halfToMaxSize = (static_cast<uint64_t>(currentSize) + maxSize) / 2;
34     const auto result = static_cast<size_t>(std::min(limitAboveMinSize, halfToMaxSize));
35     return result;
36 }
37 
CalculateGrowingFactor(double gcSpeed,double mutatorSpeed)38 double MemController::CalculateGrowingFactor(double gcSpeed, double mutatorSpeed)
39 {
40     static constexpr double minGrowingFactor = 1.3;
41     static constexpr double maxGrowingFactor = 4.0;
42     static constexpr double targetMutatorUtilization = 0.97;
43     if (gcSpeed == 0 || mutatorSpeed == 0) {
44         return maxGrowingFactor;
45     }
46 
47     const double speedRatio = gcSpeed / mutatorSpeed;
48 
49     const double a = speedRatio * (1 - targetMutatorUtilization);
50     const double b = speedRatio * (1 - targetMutatorUtilization) -  targetMutatorUtilization;
51 
52     double factor = (a < b * maxGrowingFactor) ? a / b : maxGrowingFactor;
53     factor = std::min(maxGrowingFactor, factor);
54     factor = std::max(factor, minGrowingFactor);
55     OPTIONAL_LOG(heap_->GetEcmaVM(), ERROR, ECMASCRIPT) << "CalculateGrowingFactor gcSpeed"
56         << gcSpeed << " mutatorSpeed" << mutatorSpeed << " factor" << factor;
57     return factor;
58 }
59 
StartCalculationBeforeGC()60 void MemController::StartCalculationBeforeGC()
61 {
62     startCounter_++;
63     if (startCounter_ != 1) {
64         return;
65     }
66 
67     // It's unnecessary to calculate newSpaceAllocAccumulatorSize. newSpaceAllocBytesSinceGC can be calculated directly.
68     size_t newSpaceAllocBytesSinceGC = heap_->GetNewSpace()->GetAllocatedSizeSinceGC();
69     size_t hugeObjectAllocSizeSinceGC = heap_->GetHugeObjectSpace()->GetHeapObjectSize() - hugeObjectAllocSizeSinceGC_;
70     size_t oldSpaceAllocAccumulatorSize = heap_->GetOldSpace()->GetTotalAllocatedSize();
71     size_t nonMovableSpaceAllocAccumulatorSize = heap_->GetNonMovableSpace()->GetTotalAllocatedSize();
72     size_t codeSpaceAllocAccumulatorSize = heap_->GetMachineCodeSpace()->GetTotalAllocatedSize();
73     double currentTimeInMs = GetSystemTimeInMs();
74     gcStartTime_ = currentTimeInMs;
75     size_t oldSpaceAllocSize = oldSpaceAllocAccumulatorSize - oldSpaceAllocAccumulatorSize_;
76     size_t nonMovableSpaceAllocSize = nonMovableSpaceAllocAccumulatorSize - nonMovableSpaceAllocAccumulatorSize_;
77     size_t codeSpaceAllocSize = codeSpaceAllocAccumulatorSize - codeSpaceAllocAccumulatorSize_;
78 
79     double duration = currentTimeInMs - allocTimeMs_;
80     allocTimeMs_ = currentTimeInMs;
81     oldSpaceAllocAccumulatorSize_ = oldSpaceAllocAccumulatorSize;
82     nonMovableSpaceAllocAccumulatorSize_ = nonMovableSpaceAllocAccumulatorSize;
83     codeSpaceAllocAccumulatorSize_ = codeSpaceAllocAccumulatorSize;
84 
85     allocDurationSinceGc_ += duration;
86     newSpaceAllocSizeSinceGC_ += newSpaceAllocBytesSinceGC;
87     oldSpaceAllocSizeSinceGC_ += oldSpaceAllocSize;
88     oldSpaceAllocSizeSinceGC_ += hugeObjectAllocSizeSinceGC;
89     nonMovableSpaceAllocSizeSinceGC_ += nonMovableSpaceAllocSize;
90     codeSpaceAllocSizeSinceGC_ += codeSpaceAllocSize;
91 }
92 
StopCalculationAfterGC(TriggerGCType gcType)93 void MemController::StopCalculationAfterGC(TriggerGCType gcType)
94 {
95     startCounter_--;
96     if (startCounter_ != 0) {
97         return;
98     }
99 
100     gcEndTime_ = GetSystemTimeInMs();
101     allocTimeMs_ = gcEndTime_;
102     if (allocDurationSinceGc_ > 0) {
103         oldSpaceAllocSizeSinceGC_ += heap_->GetEvacuation()->GetPromotedSize();
104         recordedNewSpaceAllocations_.Push(MakeBytesAndDuration(newSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
105         recordedOldSpaceAllocations_.Push(MakeBytesAndDuration(oldSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
106         recordedNonmovableSpaceAllocations_.Push(
107             MakeBytesAndDuration(nonMovableSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
108         recordedCodeSpaceAllocations_.Push(MakeBytesAndDuration(codeSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
109     }
110     allocDurationSinceGc_ = 0.0;
111     newSpaceAllocSizeSinceGC_ = 0;
112     oldSpaceAllocSizeSinceGC_ = 0;
113     nonMovableSpaceAllocSizeSinceGC_ = 0;
114     codeSpaceAllocSizeSinceGC_ = 0;
115 
116     hugeObjectAllocSizeSinceGC_ = heap_->GetHugeObjectSpace()->GetHeapObjectSize();
117 
118     double duration = gcEndTime_ - gcStartTime_;
119     switch (gcType) {
120         case TriggerGCType::SEMI_GC:
121         case TriggerGCType::OLD_GC: {
122             if (heap_->IsFullMark()) {
123                 if (heap_->ConcurrentMarkingEnable()) {
124                     duration += heap_->GetConcurrentMarker()->GetDuration();
125                 }
126                 recordedMarkCompacts_.Push(MakeBytesAndDuration(heap_->GetHeapObjectSize(), duration));
127             }
128             break;
129         }
130         case TriggerGCType::FULL_GC: {
131             recordedMarkCompacts_.Push(MakeBytesAndDuration(heap_->GetHeapObjectSize(), duration));
132             break;
133         }
134         default:
135             break;
136     }
137 }
138 
RecordAfterConcurrentMark(const bool isFull,const ConcurrentMarker * marker)139 void MemController::RecordAfterConcurrentMark(const bool isFull, const ConcurrentMarker *marker)
140 {
141     double duration = marker->GetDuration();
142     if (isFull) {
143         recordedConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
144     } else {
145         recordedSemiConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
146     }
147 }
148 
CalculateMarkCompactSpeedPerMS()149 double MemController::CalculateMarkCompactSpeedPerMS()
150 {
151     markCompactSpeedCache_ = CalculateAverageSpeed(recordedMarkCompacts_);
152     if (markCompactSpeedCache_ > 0) {
153         return markCompactSpeedCache_;
154     }
155     return 0;
156 }
157 
CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration,LENGTH> & buffer,const BytesAndDuration & initial,const double timeMs)158 double MemController::CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer,
159                                             const BytesAndDuration &initial, const double timeMs)
160 {
161     BytesAndDuration sum = buffer.Sum(
162         [timeMs](BytesAndDuration a, BytesAndDuration b) {
163             if (timeMs != 0 && a.second >= timeMs) {
164                 return a;
165             }
166             return std::make_pair(a.first + b.first, a.second + b.second);
167         },
168         initial);
169     uint64_t bytes = sum.first;
170     double durations = sum.second;
171     if (durations == 0.0) {
172         return 0;
173     }
174     double speed = bytes / durations;
175     const int maxSpeed = 1024 * 1024 * 1024;
176     const int minSpeed = 1;
177     if (speed >= maxSpeed) {
178         return maxSpeed;
179     }
180     if (speed <= minSpeed) {
181         return minSpeed;
182     }
183     return speed;
184 }
185 
CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration,LENGTH> & buffer)186 double MemController::CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer)
187 {
188     return CalculateAverageSpeed(buffer, MakeBytesAndDuration(0, 0), 0);
189 }
190 
GetCurrentOldSpaceAllocationThroughtputPerMS(double timeMs) const191 double MemController::GetCurrentOldSpaceAllocationThroughtputPerMS(double timeMs) const
192 {
193     size_t allocatedSize = oldSpaceAllocSizeSinceGC_;
194     double duration = allocDurationSinceGc_;
195     return CalculateAverageSpeed(recordedOldSpaceAllocations_,
196                                  MakeBytesAndDuration(allocatedSize, duration), timeMs);
197 }
198 
GetNewSpaceAllocationThroughtPerMS() const199 double MemController::GetNewSpaceAllocationThroughtPerMS() const
200 {
201     return CalculateAverageSpeed(recordedNewSpaceAllocations_);
202 }
203 
GetNewSpaceConcurrentMarkSpeedPerMS() const204 double MemController::GetNewSpaceConcurrentMarkSpeedPerMS() const
205 {
206     return CalculateAverageSpeed(recordedSemiConcurrentMarks_);
207 }
208 
GetOldSpaceAllocationThroughtPerMS() const209 double MemController::GetOldSpaceAllocationThroughtPerMS() const
210 {
211     return CalculateAverageSpeed(recordedOldSpaceAllocations_);
212 }
213 
GetFullSpaceConcurrentMarkSpeedPerMS() const214 double MemController::GetFullSpaceConcurrentMarkSpeedPerMS() const
215 {
216     return CalculateAverageSpeed(recordedConcurrentMarks_);
217 }
218 }  // namespace panda::ecmascript
219