• 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_GC_STATS_H
17 #define ECMASCRIPT_MEM_GC_STATS_H
18 
19 #include <chrono>
20 #include <cstring>
21 #include <ctime>
22 
23 #include "ecmascript/common.h"
24 #include "ecmascript/mem/clock_scope.h"
25 #include "ecmascript/mem/mem_common.h"
26 #include "libpandabase/macros.h"
27 
28 namespace panda::ecmascript {
29 class Heap;
30 class SharedHeap;
31 
32 enum class GCType : int {
33     STW_YOUNG_GC = 0,
34     PARTIAL_EDEN_GC,
35     PARTIAL_YOUNG_GC,
36     PARTIAL_OLD_GC,
37     COMPRESS_GC,
38     SHARED_GC,
39     OTHER,
40     START,
41 };
42 
43 enum class RecordData : uint8_t {
44 #define DEFINE_SCOPE(scope) scope,
45     RECORD_DATA(DEFINE_SCOPE)
46 #undef DEFINE_SCOPE
47     NUM_OF_DATA,
48     FIRST_DATA = START_OBJ_SIZE,
49     END_RECORD_OVERWRITE = COLLECT_REGION_SET_SIZE,
50 };
51 
52 enum class SpeedData : uint8_t {
53 #define DEFINE_SCOPE(scope) scope,
54     TRACE_GC_SPEED(DEFINE_SCOPE)
55 #undef DEFINE_SCOPE
56     NUM_OF_SPEED,
57 };
58 
59 enum class RecordDuration : uint8_t {
60 #define DEFINE_SCOPE(scope) scope,
61     RECORD_DURATION(DEFINE_SCOPE)
62 #undef DEFINE_SCOPE
63     NUM_OF_DURATION,
64     FIRST_DATA = SEMI_MIN_PAUSE,
65 };
66 
67 #define TRACE_GC(scope_id, gc_stats)    \
68     [[maybe_unused]] GCStats::Scope sp(scope_id, gc_stats)
69 
70 class GCStats {
71     using Duration = std::chrono::duration<uint64_t, std::nano>;
72 
73 public:
GCStats(const Heap * heap)74     explicit GCStats(const Heap *heap) : heap_(heap) {}
GCStats(const Heap * heap,size_t longPuaseTime)75     GCStats(const Heap *heap, size_t longPuaseTime) : heap_(heap),
76         longPauseTime_(longPuaseTime) {}
77     virtual ~GCStats() = default;
78 
79     virtual void PrintStatisticResult();
80     virtual void PrintGCMemoryStatistic();
81     bool CheckIfLongTimePause();
82     virtual void PrintGCStatistic();
83 
GetGCSpeed(SpeedData data)84     float GetGCSpeed(SpeedData data)
85     {
86         return gcSpeed_[(uint8_t)data];
87     }
88 
SetRecordData(RecordData dataIdx,size_t value)89     void SetRecordData(RecordData dataIdx, size_t value)
90     {
91         recordData_[GetRecordDataIndex(dataIdx)] = value;
92     }
93 
GetRecordData(RecordData dataIdx)94     size_t GetRecordData(RecordData dataIdx)
95     {
96         return recordData_[GetRecordDataIndex(dataIdx)];
97     }
98 
SetGCReason(GCReason reason)99     void SetGCReason(GCReason reason)
100     {
101         reason_ = reason;
102     }
103 
GetGCReason()104     GCReason GetGCReason() const
105     {
106         return reason_;
107     }
108 
GetGCTypeName()109     const char *GetGCTypeName()
110     {
111         switch (gcType_) {
112             case GCType::STW_YOUNG_GC:
113                 return "STWYoungGC";
114             case GCType::PARTIAL_EDEN_GC:
115                 return "HPP EdenGC";
116             case GCType::PARTIAL_YOUNG_GC:
117                 return "HPP YoungGC";
118             case GCType::PARTIAL_OLD_GC:
119                 return "HPP OldGC";
120             case GCType::COMPRESS_GC:
121                 return "CompressGC";
122             case GCType::SHARED_GC:
123                 return "SharedGC";
124             default:
125                 return "UnknownType";
126         }
127     }
128 
129     const char *GCReasonToString();
130 
GetAvgSurvivalRate()131     double GetAvgSurvivalRate()
132     {
133         if (gcType_ == GCType::PARTIAL_EDEN_GC) {
134             size_t commitSize = GetRecordData(RecordData::EDEN_TOTAL_COMMIT);
135             if (commitSize == 0) {
136                 return 0;
137             }
138             double copiedRate = double(GetRecordData(RecordData::EDEN_TOTAL_ALIVE)) / commitSize;
139             double promotedRate = double(GetRecordData(RecordData::EDEN_TOTAL_PROMOTE)) / commitSize;
140             return std::min(copiedRate + promotedRate, 1.0);
141         }
142         double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) /
143                             GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
144         double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) /
145                               GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
146         return std::min(copiedRate + promotedRate, 1.0);
147     }
148 
149     virtual void RecordGCSpeed();
150     virtual void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason);
151     virtual void RecordStatisticAfterGC();
152 
153     class Scope : public ClockScope {
154     public:
155         enum ScopeId : uint8_t {
156 #define DEFINE_SCOPE(scope) scope,
157             SCOPE_LIST(DEFINE_SCOPE)
158 #undef DEFINE_SCOPE
159             SCOPE_NUM,
160         };
161 
Scope(ScopeId id,GCStats * stats)162         Scope(ScopeId id, GCStats* stats) : id_(id), stats_(stats)
163         {
164             if (id_ == ScopeId::ConcurrentMark) {
165                 stats_->NotifyConcurrentMark();
166             }
167         }
~Scope()168         ~Scope()
169         {
170             float duration = stats_->PrintTimeMilliseconds(stats_->TimeToMicroseconds(GetPauseTime()));
171             stats_->SetScopeId(id_, duration);
172         }
173 
174     private:
175         ScopeId id_;
176         GCStats* stats_;
177     };
178 
GetScopeDuration(int pos)179     float GetScopeDuration(int pos) const
180     {
181         return scopeDuration_[pos];
182     }
183 
IncreaseTotalDuration(float duration)184     void IncreaseTotalDuration(float duration)
185     {
186         gcDuration_ += duration;
187     }
188 
GetGCCount()189     size_t GetGCCount()
190     {
191         return GetRecordData(RecordData::SEMI_COUNT) + GetRecordData(RecordData::YOUNG_COUNT) +
192             GetRecordData(RecordData::OLD_COUNT) + GetRecordData(RecordData::COMPRESS_COUNT) +
193             GetRecordData(RecordData::SHARED_COUNT);
194     }
195 
GetGCDuration()196     size_t GetGCDuration() const
197     {
198         return static_cast<size_t>(gcDuration_);
199     }
200 
201     virtual size_t GetAccumulatedAllocateSize();
GetAccumulatedFreeSize()202     size_t GetAccumulatedFreeSize() const
203     {
204         return accumulatedFreeSize_;
205     }
206 
IncreaseFullGCLongTimeCount()207     void IncreaseFullGCLongTimeCount()
208     {
209         fullGCLongTimeCount_ += 1;
210     }
211 
GetFullGCLongTimeCount()212     size_t GetFullGCLongTimeCount() const
213     {
214         return fullGCLongTimeCount_;
215     }
216 
217 protected:
218     bool CheckIfNeedPrint(GCType type);
219     void PrintVerboseGCStatistic();
220     void PrintGCDurationStatistic();
221     void PrintGCSummaryStatistic(GCType type = GCType::START);
222     GCType GetGCType(TriggerGCType gcType);
223     void InitializeRecordList();
224     float GetConcurrrentMarkDuration();
225 
GetRecordDurationIndex(RecordDuration durationIdx)226     int GetRecordDurationIndex(RecordDuration durationIdx)
227     {
228         return (int)durationIdx - (int)RecordDuration::FIRST_DATA;
229     }
230 
GetRecordDuration(RecordDuration durationIdx)231     float GetRecordDuration(RecordDuration durationIdx)
232     {
233         return recordDuration_[GetRecordDurationIndex(durationIdx)];
234     }
235 
SetRecordDuration(RecordDuration durationIdx,float value)236     void SetRecordDuration(RecordDuration durationIdx, float value)
237     {
238         recordDuration_[GetRecordDurationIndex(durationIdx)] = value;
239     }
240 
IncreaseRecordDuration(RecordDuration durationIdx,float value)241     void IncreaseRecordDuration(RecordDuration durationIdx, float value)
242     {
243         recordDuration_[GetRecordDurationIndex(durationIdx)] += value;
244     }
245 
GetRecordDataIndex(RecordData dataIdx)246     int GetRecordDataIndex(RecordData dataIdx)
247     {
248         return (int)dataIdx - (int)RecordData::FIRST_DATA;
249     }
250 
251     void IncreaseRecordData(RecordData dataIdx, size_t value = 1)
252     {
253         recordData_[GetRecordDataIndex(dataIdx)] += value;
254     }
255 
SetScopeId(int pos,float duration)256     void SetScopeId(int pos, float duration)
257     {
258         scopeDuration_[pos] = duration;
259     }
260 
NotifyConcurrentMark()261     void NotifyConcurrentMark()
262     {
263         concurrentMark_ = true;
264     }
265 
IncreaseAccumulatedFreeSize(size_t size)266     void IncreaseAccumulatedFreeSize(size_t size)
267     {
268         accumulatedFreeSize_ += size;
269     }
270 
TimeToMicroseconds(Duration time)271     size_t TimeToMicroseconds(Duration time)
272     {
273         return std::chrono::duration_cast<std::chrono::microseconds>(time).count();
274     }
275 
PrintTimeMilliseconds(uint64_t ms)276     float PrintTimeMilliseconds(uint64_t ms)
277     {
278         return (float)ms / THOUSAND;
279     }
280 
sizeToMB(size_t size)281     float sizeToMB(size_t size)
282     {
283         return (float)size / 1_MB;
284     }
285 
sizeToKB(size_t size)286     float sizeToKB(size_t size)
287     {
288         return (float)size / 1_KB;
289     }
290 
291     const Heap *heap_ {nullptr};
292     float gcDuration_ = 0.0f;
293     size_t longPauseTime_ = 0;
294     size_t fullGCLongTimeCount_ = 0;
295     size_t accumulatedFreeSize_ = 0;
296 
297     static constexpr size_t DEFAULT_UPDATE_REFERENCE_SPEED = 10_MB;
298     static constexpr size_t DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED = 1_KB;
299     static constexpr size_t DEFAULT_OLD_EVACUATE_SPACE_SPEED = 600_KB;
300     static constexpr size_t DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED = 3_KB;
301 
302     GCType gcType_ {GCType::START};
303     GCReason reason_ {GCReason::OTHER};
304     float scopeDuration_[Scope::ScopeId::SCOPE_NUM] {0.0f};
305     size_t recordData_[(uint8_t)RecordData::NUM_OF_DATA] {0};
306     size_t gcSpeed_ [(uint8_t)SpeedData::NUM_OF_SPEED] = {
307         DEFAULT_UPDATE_REFERENCE_SPEED, DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED,
308         DEFAULT_OLD_EVACUATE_SPACE_SPEED, DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED};
309     float recordDuration_[(uint8_t)RecordDuration::NUM_OF_DURATION] {0.0f};
310     bool concurrentMark_ {false};
311 
312     static constexpr uint32_t THOUSAND = 1000;
313 
314     NO_COPY_SEMANTIC(GCStats);
315     NO_MOVE_SEMANTIC(GCStats);
316 };
317 
318 class SharedGCStats : public GCStats {
319 public:
SharedGCStats(const SharedHeap * sHeap,bool enableGCTracer)320     SharedGCStats(const SharedHeap *sHeap, bool enableGCTracer)
321         : GCStats(nullptr), sHeap_(sHeap), enableGCTracer_(enableGCTracer)
322     {
323         SetRecordData(RecordData::SHARED_COUNT, 0);
324     }
325     ~SharedGCStats() = default;
326 
327     void PrintStatisticResult() override;
328     void PrintGCMemoryStatistic() override;
329     void PrintGCStatistic() override;
330 
331     void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason) override;
332     void RecordStatisticAfterGC() override;
333     size_t GetAccumulatedAllocateSize() override;
334 private:
335     void PrintSharedGCDuration();
336     void PrintSharedGCSummaryStatistic();
337 
338     const SharedHeap *sHeap_ {nullptr};
339     bool enableGCTracer_ {false};
340 };
341 }  // namespace panda::ecmascript
342 
343 #endif  // ECMASCRIPT_MEM_GC_STATS_H
344