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 
31 namespace panda::ecmascript {
32 using PGOProfilerManager = pgo::PGOProfilerManager;
33 using Clock = std::chrono::high_resolution_clock;
34 
CheckIfMainThread() const35 bool 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 
CheckIfKeyPauseTime() const44 bool GCKeyStats::CheckIfKeyPauseTime() const
45 {
46     return gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::TotalGC) >= KEY_PAUSE_TIME;
47 }
48 
AddGCStatsToKey()49 void 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 
SendSysEvent() const87 void 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 
SendSysEventBeforeDump(std::string type, size_t limitSize, size_t activeMemory) const115 void 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 
PrintKeyStatisticResult() const135 void GCKeyStats::PrintKeyStatisticResult() const
136 {
137     LOG_GC(INFO) << "/******************* GCKeyStats HiSysEvent statistic: *******************/";
138 }
139 
InitializeRecordList()140 void 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