1 /*
2  * Copyright (c) 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_GC_KEY_STATS_H
17 #define ECMASCRIPT_MEM_GC_KEY_STATS_H
18 
19 #include <ctime>
20 #include <chrono>
21 
22 #include "libpandabase/macros.h"
23 
24 #include "ecmascript/mem/mem_common.h"
25 #include "ecmascript/log_wrapper.h"
26 
27 namespace panda::ecmascript {
28 using Clock = std::chrono::high_resolution_clock;
29 class Heap;
30 class GCStats;
31 
32 enum class RecordKeyData : uint8_t {
33     GC_TOTAL_MEM_USED = 0,
34     GC_TOTAL_MEM_COMMITTED,
35     GC_ACTIVE_MEM_USED,
36     GC_ACTIVE_MEM_COMMITTED,
37     GC_OLD_MEM_USED,
38     GC_OLD_MEM_COMMITTED,
39     GC_HUGE_MEM_USED,
40     GC_HUGE_MEM_COMMITTED,
41     NUM_OF_KEY_DATA,
42     FIRST_DATA = GC_TOTAL_MEM_USED,
43 };
44 
45 enum class RecordKeyDuration : uint8_t {
46     GC_TOTAL_TIME = 0,
47     GC_MARK_TIME,
48     GC_EVACUATE_TIME,
49     NUM_OF_KEY_DURATION,
50     FIRST_DATA = GC_TOTAL_TIME,
51 };
52 
53 class GCKeyStats {
54 static constexpr size_t KEY_PAUSE_TIME = 20; // ms
55 static constexpr int NEED_SEND_TIMES = 200;
56 static constexpr int MIN_SEND_INTERVAL = 60; // seconds
57 public:
GCKeyStats(const Heap *heap)58     explicit GCKeyStats(const Heap *heap) : heap_(heap) {}
GCKeyStats(const Heap *heap, GCStats *gcStats)59     GCKeyStats(const Heap *heap, GCStats *gcStats) : heap_(heap),
60         gcStats_(gcStats) {}
61     ~GCKeyStats() = default;
62 
63     void AddGCStatsToKey();
64     bool CheckIfMainThread() const;
65     bool CheckIfKeyPauseTime() const;
66     void SendSysEventBeforeDump(std::string type, size_t limitSize, size_t activeMemory) const;
67 
IncGCCount()68     void IncGCCount()
69     {
70         gcCount_++;
71     }
72 
AddRecordDataStats(RecordKeyData idx, int value)73     void AddRecordDataStats(RecordKeyData idx, int value)
74     {
75         recordDataStats_[GetRecordDataStatsIndex(idx)] += value;
76     }
77 
GetRecordDataStats(RecordKeyData idx) const78     int GetRecordDataStats(RecordKeyData idx) const
79     {
80         return recordDataStats_[GetRecordDataStatsIndex(idx)];
81     }
82 
AddRecordKeyDuration(RecordKeyDuration idx, float value)83     void AddRecordKeyDuration(RecordKeyDuration idx, float value)
84     {
85         recordDurationStats_[GetRecordKeyDurationIndex(idx)] += value;
86     }
87 
GetRecordKeyDuration(RecordKeyDuration idx) const88     float GetRecordKeyDuration(RecordKeyDuration idx) const
89     {
90         return recordDurationStats_[GetRecordKeyDurationIndex(idx)];
91     }
92 
93 private:
94     void SendSysEvent() const;
95     void InitializeRecordList();
96     void PrintKeyStatisticResult() const;
97 
CheckLastSendTimeIfSend() const98     bool CheckLastSendTimeIfSend() const
99     {
100         return lastSendTimestamp_ == Clock::time_point::min() ||
101             std::chrono::duration_cast<std::chrono::seconds>(Clock::now() - lastSendTimestamp_).count() >=
102             MIN_SEND_INTERVAL;
103     }
104 
CheckCountIfSend() const105     bool CheckCountIfSend() const
106     {
107         return recordCount_ >= NEED_SEND_TIMES;
108     }
109 
GetRecordDataStatsIndex(RecordKeyData dataIdx) const110     int GetRecordDataStatsIndex(RecordKeyData dataIdx) const
111     {
112         return (int)dataIdx - (int)RecordKeyData::FIRST_DATA;
113     }
114 
GetRecordKeyDurationIndex(RecordKeyDuration dataIdx) const115     int GetRecordKeyDurationIndex(RecordKeyDuration dataIdx) const
116     {
117         return (int)dataIdx - (int)RecordKeyDuration::FIRST_DATA;
118     }
119 
SizeToIntKB(size_t size) const120     int SizeToIntKB(size_t size) const
121     {
122         return static_cast<int>(size / 1_KB);
123     }
124 
125     const Heap *heap_;
126     GCStats *gcStats_;
127 
128     int gcCount_{0};
129     int recordCount_{0};
130     Clock::time_point lastSendTimestamp_;
131     float recordDurationStats_[(uint8_t)RecordKeyDuration::NUM_OF_KEY_DURATION]{0.0f};
132     int recordDataStats_[(uint8_t)RecordKeyData::NUM_OF_KEY_DATA]{0};
133 };
134 
135 } // namespace panda::ecmascript
136 #endif // ECMASCRIPT_MEM_GC_KEY_STATS_H