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