• 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 gcReason)112     void SetGCReason(GCReason gcReason)
113     {
114         gcReason_ = gcReason;
115     }
116 
GetGCReason()117     GCReason GetGCReason() const
118     {
119         return gcReason_;
120     }
121 
SetMarkReason(MarkReason markReason)122     void SetMarkReason(MarkReason markReason)
123     {
124         markReason_ = markReason;
125     }
126 
GetMarkReason()127     MarkReason GetMarkReason() const
128     {
129         return markReason_;
130     }
131 
GetLongGCStats()132     LongGCStats *GetLongGCStats()
133     {
134         return longGCStats_;
135     }
136 
137     bool IsLongGC(GCReason gcReason, bool gcIsSensitive, bool gcIsInBackground, float gcTotalTime);
138 
GetGCTypeName()139     const char *GetGCTypeName()
140     {
141         switch (gcType_) {
142             case GCType::PARTIAL_YOUNG_GC:
143                 return "HPP YoungGC";
144             case GCType::PARTIAL_OLD_GC:
145                 return "HPP OldGC";
146             case GCType::COMPRESS_GC:
147                 return "CompressGC";
148             case GCType::SHARED_GC:
149                 return "SharedGC";
150             case GCType::SHARED_PARTIAL_GC:
151                 return "SharedPartialGC";
152             case GCType::SHARED_FULL_GC:
153                 return "SharedCompressGC";
154             default:
155                 return "UnknownType";
156         }
157     }
158 
159     static const char *GCReasonToString(GCReason reason);
160     const char *GCReasonToString();
161     static const char *MarkReasonToString(MarkReason reason);
162     const char *MarkReasonToString();
163 
GetAvgSurvivalRate()164     double GetAvgSurvivalRate()
165     {
166         double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) /
167                             GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
168         double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) /
169                               GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
170         return std::min(copiedRate + promotedRate, 1.0);
171     }
172 
173     virtual void RecordGCSpeed();
174     virtual void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason);
175     virtual void RecordStatisticAfterGC();
176 
177     class Scope : public ClockScope {
178     public:
179         enum ScopeId : uint8_t {
180 #define DEFINE_SCOPE(scope) scope,
181             SCOPE_LIST(DEFINE_SCOPE)
182 #undef DEFINE_SCOPE
183             SCOPE_NUM,
184         };
185 
Scope(ScopeId id,GCStats * stats)186         Scope(ScopeId id, GCStats* stats) : id_(id), stats_(stats)
187         {
188             if (id_ == ScopeId::ConcurrentMark) {
189                 stats_->NotifyConcurrentMark();
190             }
191         }
~Scope()192         ~Scope()
193         {
194             float duration = stats_->PrintTimeMilliseconds(stats_->TimeToMicroseconds(GetPauseTime()));
195             stats_->SetScopeId(id_, duration);
196         }
197 
198     private:
199         ScopeId id_;
200         GCStats* stats_;
201     };
202 
GetScopeDuration(int pos)203     float GetScopeDuration(int pos) const
204     {
205         return scopeDuration_[pos];
206     }
207 
IncreaseTotalDuration(float duration)208     void IncreaseTotalDuration(float duration)
209     {
210         gcDuration_ += duration;
211     }
212 
GetGCCount()213     size_t GetGCCount()
214     {
215         return GetRecordData(RecordData::SEMI_COUNT) + GetRecordData(RecordData::YOUNG_COUNT) +
216             GetRecordData(RecordData::OLD_COUNT) + GetRecordData(RecordData::COMPRESS_COUNT) +
217             GetRecordData(RecordData::SHARED_COUNT);
218     }
219 
GetGCDuration()220     size_t GetGCDuration() const
221     {
222         return static_cast<size_t>(gcDuration_);
223     }
224 
225     virtual size_t GetAccumulatedAllocateSize();
GetAccumulatedFreeSize()226     size_t GetAccumulatedFreeSize() const
227     {
228         return accumulatedFreeSize_;
229     }
230 
IncreaseFullGCLongTimeCount()231     void IncreaseFullGCLongTimeCount()
232     {
233         fullGCLongTimeCount_ += 1;
234     }
235 
GetFullGCLongTimeCount()236     size_t GetFullGCLongTimeCount() const
237     {
238         return fullGCLongTimeCount_;
239     }
240 
241 protected:
242     bool CheckIfNeedPrint(GCType type);
243     void PrintVerboseGCStatistic();
244     void PrintGCDurationStatistic();
245     void PrintGCSummaryStatistic(GCType type = GCType::START);
246     void InitializeRecordList();
247     float GetConcurrrentMarkDuration();
248     void GCFinishTrace();
249     virtual void ProcessBeforeLongGCStats();
250     virtual void ProcessAfterLongGCStats();
GetRecordDurationIndex(RecordDuration durationIdx)251     int GetRecordDurationIndex(RecordDuration durationIdx)
252     {
253         return (int)durationIdx - (int)RecordDuration::FIRST_DATA;
254     }
255 
GetRecordDuration(RecordDuration durationIdx)256     float GetRecordDuration(RecordDuration durationIdx)
257     {
258         return recordDuration_[GetRecordDurationIndex(durationIdx)];
259     }
260 
SetRecordDuration(RecordDuration durationIdx,float value)261     void SetRecordDuration(RecordDuration durationIdx, float value)
262     {
263         recordDuration_[GetRecordDurationIndex(durationIdx)] = value;
264     }
265 
IncreaseRecordDuration(RecordDuration durationIdx,float value)266     void IncreaseRecordDuration(RecordDuration durationIdx, float value)
267     {
268         recordDuration_[GetRecordDurationIndex(durationIdx)] += value;
269     }
270 
GetRecordDataIndex(RecordData dataIdx)271     int GetRecordDataIndex(RecordData dataIdx)
272     {
273         return (int)dataIdx - (int)RecordData::FIRST_DATA;
274     }
275 
276     void IncreaseRecordData(RecordData dataIdx, size_t value = 1)
277     {
278         recordData_[GetRecordDataIndex(dataIdx)] += value;
279     }
280 
SetScopeId(int pos,float duration)281     void SetScopeId(int pos, float duration)
282     {
283         scopeDuration_[pos] = duration;
284     }
285 
NotifyConcurrentMark()286     void NotifyConcurrentMark()
287     {
288         concurrentMark_ = true;
289     }
290 
IncreaseAccumulatedFreeSize(size_t size)291     void IncreaseAccumulatedFreeSize(size_t size)
292     {
293         accumulatedFreeSize_ += size;
294     }
295 
TimeToMicroseconds(Duration time)296     size_t TimeToMicroseconds(Duration time)
297     {
298         return std::chrono::duration_cast<std::chrono::microseconds>(time).count();
299     }
300 
PrintTimeMilliseconds(uint64_t ms)301     float PrintTimeMilliseconds(uint64_t ms)
302     {
303         return (float)ms / THOUSAND;
304     }
305 
sizeToMB(size_t size)306     float sizeToMB(size_t size)
307     {
308         return (float)size / 1_MB;
309     }
310 
sizeToKB(size_t size)311     float sizeToKB(size_t size)
312     {
313         return (float)size / 1_KB;
314     }
315 
316     const Heap *heap_ {nullptr};
317     float gcDuration_ = 0.0f;
318     size_t longPauseTime_ = 0;
319     size_t fullGCLongTimeCount_ = 0;
320     size_t accumulatedFreeSize_ = 0;
321 
322     static constexpr size_t DEFAULT_UPDATE_REFERENCE_SPEED = 10_MB;
323     static constexpr size_t DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED = 1_KB;
324     static constexpr size_t DEFAULT_OLD_EVACUATE_SPACE_SPEED = 600_KB;
325     static constexpr size_t DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED = 3_KB;
326 
327     GCType gcType_ {GCType::START};
328     GCReason gcReason_ {GCReason::OTHER};
329     MarkReason markReason_ {MarkReason::OTHER};
330     float scopeDuration_[Scope::ScopeId::SCOPE_NUM] {0.0f};
331     size_t recordData_[(uint8_t)RecordData::NUM_OF_DATA] {0};
332     size_t gcSpeed_ [(uint8_t)SpeedData::NUM_OF_SPEED] = {
333         DEFAULT_UPDATE_REFERENCE_SPEED, DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED,
334         DEFAULT_OLD_EVACUATE_SPACE_SPEED, DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED};
335     float recordDuration_[(uint8_t)RecordDuration::NUM_OF_DURATION] {0.0f};
336     bool concurrentMark_ {false};
337 
338     static constexpr uint32_t THOUSAND = 1000;
339 
340     NO_COPY_SEMANTIC(GCStats);
341     NO_MOVE_SEMANTIC(GCStats);
342 private:
343     LongGCStats *longGCStats_;
344 };
345 
346 class SharedGCStats : public GCStats {
347 public:
SharedGCStats(const SharedHeap * sHeap,bool enableGCTracer)348     SharedGCStats(const SharedHeap *sHeap, bool enableGCTracer)
349         : GCStats(nullptr), sHeap_(sHeap), enableGCTracer_(enableGCTracer)
350     {
351         SetRecordData(RecordData::SHARED_COUNT, 0);
352     }
353     ~SharedGCStats() = default;
354 
355     void PrintStatisticResult() override;
356     void PrintGCMemoryStatistic() override;
357     void PrintGCStatistic() override;
358 
359     void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason) override;
360     void RecordStatisticAfterGC() override;
361     size_t GetAccumulatedAllocateSize() override;
362 private:
363     void PrintSharedGCDuration();
364     void PrintSharedGCSummaryStatistic();
365     void SharedGCFinishTrace();
366     void ProcessAfterLongGCStats() override;
367     void ProcessBeforeLongGCStats() override;
368 
369     const SharedHeap *sHeap_ {nullptr};
370     bool enableGCTracer_ {false};
371 };
372 }  // namespace panda::ecmascript
373 
374 #endif  // ECMASCRIPT_MEM_GC_STATS_H
375