1 /* 2 * Copyright (c) 2021-2024 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 ECMASCRIPT_MEM_MEM_CONTROLLER_H 17 #define ECMASCRIPT_MEM_MEM_CONTROLLER_H 18 19 #include <chrono> 20 #include <cmath> 21 #include <limits> 22 23 #include "ecmascript/base/gc_ring_buffer.h" 24 #include "ecmascript/mem/heap.h" 25 #include "ecmascript/mem/mem.h" 26 27 namespace panda::ecmascript { 28 29 constexpr static int MILLISECONDS_PER_SECOND = 1000; 30 31 using BytesAndDuration = std::pair<uint64_t, double>; 32 33 class MemController { 34 public: 35 explicit MemController(Heap* heap); 36 MemController() = default; 37 ~MemController() = default; 38 NO_COPY_SEMANTIC(MemController); 39 NO_MOVE_SEMANTIC(MemController); 40 GetSystemTimeInMs()41 static double GetSystemTimeInMs() 42 { 43 double currentTime = 44 std::chrono::duration<double>(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); 45 return currentTime * MILLISECOND_PER_SECOND; 46 } 47 48 size_t CalculateAllocLimit(size_t currentSize, size_t minSize, size_t maxSize, size_t newSpaceCapacity, 49 double factor) const; 50 51 double CalculateGrowingFactor(double gcSpeed, double mutatorSpeed); 52 53 void StartCalculationBeforeGC(); 54 void StopCalculationAfterGC(TriggerGCType gcType); 55 void ResetCalculationWithoutGC(); 56 57 void RecordAllocationForIdle(); 58 double GetIdleNewSpaceAllocationThroughputPerMS() const; 59 double GetIdleOldSpaceAllocationThroughputPerMS() const; 60 bool CheckLowAllocationUsageState() const; 61 62 void RecordAfterConcurrentMark(MarkType markType, const ConcurrentMarker *marker); 63 64 double CalculateMarkCompactSpeedPerMS(); 65 double GetCurrentOldSpaceAllocationThroughputPerMS(double timeMs = THROUGHPUT_TIME_FRAME_MS) const; 66 double GetNewSpaceAllocationThroughputPerMS() const; 67 double GetOldSpaceAllocationThroughputPerMS() const; 68 double GetNewSpaceConcurrentMarkSpeedPerMS() const; 69 double GetFullSpaceConcurrentMarkSpeedPerMS() const; 70 GetAllocTimeMs()71 double GetAllocTimeMs() const 72 { 73 return allocTimeMs_; 74 } 75 GetOldSpaceAllocAccumulatedSize()76 size_t GetOldSpaceAllocAccumulatedSize() const 77 { 78 return oldSpaceAllocAccumulatedSize_; 79 } 80 GetNonMovableSpaceAllocAccumulatedSize()81 size_t GetNonMovableSpaceAllocAccumulatedSize() const 82 { 83 return nonMovableSpaceAllocAccumulatedSize_; 84 } 85 GetCodeSpaceAllocAccumulatedSize()86 size_t GetCodeSpaceAllocAccumulatedSize() const 87 { 88 return codeSpaceAllocAccumulatedSize_; 89 } 90 GetAllocDurationSinceGc()91 double GetAllocDurationSinceGc() const 92 { 93 return allocDurationSinceGc_; 94 } 95 GetNewSpaceAllocSizeSinceGC()96 size_t GetNewSpaceAllocSizeSinceGC() const 97 { 98 return newSpaceAllocSizeSinceGC_; 99 } 100 GetOldSpaceAllocSizeSinceGC()101 size_t GetOldSpaceAllocSizeSinceGC() const 102 { 103 return oldSpaceAllocSizeSinceGC_; 104 } 105 GetNonMovableSpaceAllocSizeSinceGC()106 size_t GetNonMovableSpaceAllocSizeSinceGC() const 107 { 108 return nonMovableSpaceAllocSizeSinceGC_; 109 } 110 GetCodeSpaceAllocSizeSinceGC()111 size_t GetCodeSpaceAllocSizeSinceGC() const 112 { 113 return codeSpaceAllocSizeSinceGC_; 114 } 115 GetHugeObjectAllocSizeSinceGC()116 size_t GetHugeObjectAllocSizeSinceGC() const 117 { 118 return hugeObjectAllocSizeSinceGC_; 119 } 120 AddSurvivalRate(double rate)121 void AddSurvivalRate(double rate) 122 { 123 recordedSurvivalRates_.Push(rate); 124 if (UNLIKELY(std::isnan(predictedSurvivalRate_))) { 125 predictedSurvivalRate_ = rate; 126 } else { 127 predictedSurvivalRate_ = ALPHA * rate + (1 - ALPHA) * predictedSurvivalRate_; 128 } 129 } 130 GetAverageSurvivalRate()131 double GetAverageSurvivalRate() const 132 { 133 int count = recordedSurvivalRates_.Count(); 134 if (count == 0) { 135 return 0; 136 } 137 double result = recordedSurvivalRates_.Sum([](double x, double y) { return x + y;}, 0.0); 138 return result / count; 139 } 140 GetPredictedSurvivalRate()141 double GetPredictedSurvivalRate() const 142 { 143 if (UNLIKELY(std::isnan(predictedSurvivalRate_))) { 144 return 0; 145 } 146 return predictedSurvivalRate_; 147 } 148 ResetRecordedSurvivalRates()149 void ResetRecordedSurvivalRates() 150 { 151 recordedSurvivalRates_.Reset(); 152 } 153 154 private: 155 static constexpr int LENGTH = 10; 156 // Decayed weight for predicting survival rate. 157 static constexpr double ALPHA = 0.8; 158 static double CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer); 159 static double CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer, 160 const BytesAndDuration &initial, const double timeMs); 161 162 Heap* heap_; 163 size_t minAllocLimitGrowingStep_ {0}; 164 165 double gcStartTime_ {0.0}; 166 double gcEndTime_ {0.0}; 167 168 // Time and allocation accumulators. 169 double allocTimeMs_ {0.0}; 170 size_t oldSpaceAllocAccumulatedSize_ {0}; 171 size_t nonMovableSpaceAllocAccumulatedSize_ {0}; 172 size_t codeSpaceAllocAccumulatedSize_ {0}; 173 174 // Duration and allocation size in last gc. 175 double allocDurationSinceGc_ {0.0}; 176 size_t newSpaceAllocSizeSinceGC_ {0}; 177 size_t oldSpaceAllocSizeSinceGC_ {0}; 178 size_t nonMovableSpaceAllocSizeSinceGC_ {0}; 179 size_t codeSpaceAllocSizeSinceGC_ {0}; 180 size_t hugeObjectAllocSizeSinceGC_{0}; 181 182 // Records data at idle time points. 183 double allocTimeMsIdle_ {0.0}; 184 size_t newSpaceRecordLastTimeSizeIdle_ {0}; 185 size_t oldSpaceRecordLastTimeSizeIdle_ {0}; 186 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedIdleNewSpaceAllocations_; 187 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedIdleOldSpaceAllocations_; 188 189 int startCounter_ {0}; 190 double markCompactSpeedCache_ {0.0}; 191 192 double predictedSurvivalRate_ {std::numeric_limits<double>::quiet_NaN()}; 193 194 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedMarkCompacts_; 195 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedNewSpaceAllocations_; 196 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedOldSpaceAllocations_; 197 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedNonmovableSpaceAllocations_; 198 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedCodeSpaceAllocations_; 199 200 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedConcurrentMarks_; 201 base::GCRingBuffer<BytesAndDuration, LENGTH> recordedSemiConcurrentMarks_; 202 base::GCRingBuffer<double, LENGTH> recordedSurvivalRates_; 203 204 static constexpr double THROUGHPUT_TIME_FRAME_MS = 5000; 205 static constexpr int MILLISECOND_PER_SECOND = 1000; 206 }; 207 208 MemController *CreateMemController(Heap *heap, std::string_view gcTriggerType); 209 } // namespace panda::ecmascript 210 #endif // ECMASCRIPT_MEM_MEM_CONTROLLER_H 211