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