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#include "ecmascript/mem/gc_key_stats.h"
17
18#include <iostream>
19#include <cstring>
20
21#ifdef ENABLE_HISYSEVENT
22#include "hisysevent.h"
23#endif
24#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
25#include <sys/resource.h>
26#endif
27
28#include "ecmascript/mem/heap-inl.h"
29#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
30
31namespace panda::ecmascript {
32using PGOProfilerManager = pgo::PGOProfilerManager;
33using Clock = std::chrono::high_resolution_clock;
34
35bool GCKeyStats::CheckIfMainThread() const
36{
37#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
38    return getpid() == syscall(SYS_gettid);
39#else
40    return true;
41#endif
42}
43
44bool GCKeyStats::CheckIfKeyPauseTime() const
45{
46    return gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::TotalGC) >= KEY_PAUSE_TIME;
47}
48
49void GCKeyStats::AddGCStatsToKey()
50{
51    LOG_GC(DEBUG) << "GCKeyStats AddGCStatsToKey!";
52
53    recordCount_++;
54
55    AddRecordDataStats(RecordKeyData::GC_TOTAL_MEM_USED,
56        SizeToIntKB(gcStats_->GetRecordData(RecordData::END_OBJ_SIZE)));
57    AddRecordDataStats(RecordKeyData::GC_TOTAL_MEM_COMMITTED,
58        SizeToIntKB(gcStats_->GetRecordData(RecordData::END_COMMIT_SIZE)));
59    AddRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_USED,
60        SizeToIntKB(gcStats_->GetRecordData(RecordData::YOUNG_ALIVE_SIZE)));
61    AddRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_COMMITTED,
62        SizeToIntKB(gcStats_->GetRecordData(RecordData::YOUNG_COMMIT_SIZE)));
63    AddRecordDataStats(RecordKeyData::GC_OLD_MEM_USED,
64        SizeToIntKB(gcStats_->GetRecordData(RecordData::OLD_ALIVE_SIZE)));
65    AddRecordDataStats(RecordKeyData::GC_OLD_MEM_COMMITTED,
66        SizeToIntKB(gcStats_->GetRecordData(RecordData::OLD_COMMIT_SIZE)));
67
68    AddRecordDataStats(RecordKeyData::GC_HUGE_MEM_USED,
69        SizeToIntKB(heap_->GetHugeObjectSpace()->GetHeapObjectSize()));
70    AddRecordDataStats(RecordKeyData::GC_HUGE_MEM_COMMITTED,
71        SizeToIntKB(heap_->GetHugeObjectSpace()->GetCommittedSize()));
72
73    AddRecordKeyDuration(RecordKeyDuration::GC_TOTAL_TIME,
74        gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::TotalGC));
75    AddRecordKeyDuration(RecordKeyDuration::GC_MARK_TIME,
76        gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::Mark));
77    AddRecordKeyDuration(RecordKeyDuration::GC_EVACUATE_TIME,
78        gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::Evacuate));
79
80    if (CheckLastSendTimeIfSend() && CheckCountIfSend()) {
81        SendSysEvent();
82        PrintKeyStatisticResult();
83        InitializeRecordList();
84    }
85}
86
87void GCKeyStats::SendSysEvent() const
88{
89#ifdef ENABLE_HISYSEVENT
90    int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::ARKTS_RUNTIME,
91        "ARK_STATS_GC",
92        OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC,
93        "BUNDLE_NAME", PGOProfilerManager::GetInstance()->GetBundleName(),
94        "PID", getpid(),
95        "TID", syscall(SYS_gettid),
96        "GC_TOTAL_COUNT", gcCount_,
97        "GC_TOTAL_TIME", static_cast<int>(GetRecordKeyDuration(RecordKeyDuration::GC_TOTAL_TIME)),
98        "GC_MARK_TIME", static_cast<int>(GetRecordKeyDuration(RecordKeyDuration::GC_MARK_TIME)),
99        "GC_EVACUATE_TIME", static_cast<int>(GetRecordKeyDuration(RecordKeyDuration::GC_EVACUATE_TIME)),
100        "GC_LONG_TIME", recordCount_,
101        "GC_TOTAL_MEM_USED", GetRecordDataStats(RecordKeyData::GC_TOTAL_MEM_USED),
102        "GC_TOTAL_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_TOTAL_MEM_COMMITTED),
103        "GC_ACTIVE_MEM_USED", GetRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_USED),
104        "GC_ACTIVE_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_COMMITTED),
105        "GC_OLD_MEM_USED", GetRecordDataStats(RecordKeyData::GC_OLD_MEM_USED),
106        "GC_OLD_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_OLD_MEM_COMMITTED),
107        "GC_HUGE_MEM_USED", GetRecordDataStats(RecordKeyData::GC_HUGE_MEM_USED),
108        "GC_HUGE_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_HUGE_MEM_COMMITTED));
109    if (ret != 0) {
110        LOG_GC(ERROR) << "GCKeyStats HiSysEventWrite Failed! ret = " << ret;
111    }
112#endif
113}
114
115void GCKeyStats::SendSysEventBeforeDump(std::string type, size_t limitSize, size_t activeMemory) const
116{
117#ifdef ENABLE_HISYSEVENT
118    int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::FRAMEWORK,
119        "ARK_STATS_DUMP",
120        OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
121        "PID", getprocpid(),
122        "TID", syscall(SYS_gettid),
123        "PROCESS_NAME", PGOProfilerManager::GetInstance()->GetBundleName(),
124        "LIMITSIZE", limitSize,
125        "ACTIVE_MEMORY", activeMemory,
126        "TYPE", type);
127    if (ret != 0) {
128        LOG_GC(ERROR) << "GCKeyStats SendSysEventBeforeDump Failed! ret = " << ret;
129    }
130#else
131    LOG_GC(INFO) << "GCKeyStats type: " << type << ", limitSize: " << limitSize << ", activeMemory: " << activeMemory;
132#endif
133}
134
135void GCKeyStats::PrintKeyStatisticResult() const
136{
137    LOG_GC(INFO) << "/******************* GCKeyStats HiSysEvent statistic: *******************/";
138}
139
140void GCKeyStats::InitializeRecordList()
141{
142    gcCount_ = 0;
143    recordCount_ = 0;
144    std::fill(recordDurationStats_, recordDurationStats_ + (uint8_t)RecordKeyDuration::NUM_OF_KEY_DURATION, 0.0f);
145    std::fill(recordDataStats_, recordDataStats_ + (uint8_t)RecordKeyData::NUM_OF_KEY_DATA, 0);
146    lastSendTimestamp_ = Clock::now();
147}
148
149} // namespace panda::ecmascript