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
27namespace panda::ecmascript {
28using Clock = std::chrono::high_resolution_clock;
29class Heap;
30class GCStats;
31
32enum 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
45enum 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
53class GCKeyStats {
54static constexpr size_t KEY_PAUSE_TIME = 20; // ms
55static constexpr int NEED_SEND_TIMES = 200;
56static constexpr int MIN_SEND_INTERVAL = 60; // seconds
57public:
58    explicit GCKeyStats(const Heap *heap) : heap_(heap) {}
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
68    void IncGCCount()
69    {
70        gcCount_++;
71    }
72
73    void AddRecordDataStats(RecordKeyData idx, int value)
74    {
75        recordDataStats_[GetRecordDataStatsIndex(idx)] += value;
76    }
77
78    int GetRecordDataStats(RecordKeyData idx) const
79    {
80        return recordDataStats_[GetRecordDataStatsIndex(idx)];
81    }
82
83    void AddRecordKeyDuration(RecordKeyDuration idx, float value)
84    {
85        recordDurationStats_[GetRecordKeyDurationIndex(idx)] += value;
86    }
87
88    float GetRecordKeyDuration(RecordKeyDuration idx) const
89    {
90        return recordDurationStats_[GetRecordKeyDurationIndex(idx)];
91    }
92
93private:
94    void SendSysEvent() const;
95    void InitializeRecordList();
96    void PrintKeyStatisticResult() const;
97
98    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
105    bool CheckCountIfSend() const
106    {
107        return recordCount_ >= NEED_SEND_TIMES;
108    }
109
110    int GetRecordDataStatsIndex(RecordKeyData dataIdx) const
111    {
112        return (int)dataIdx - (int)RecordKeyData::FIRST_DATA;
113    }
114
115    int GetRecordKeyDurationIndex(RecordKeyDuration dataIdx) const
116    {
117        return (int)dataIdx - (int)RecordKeyDuration::FIRST_DATA;
118    }
119
120    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