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