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 #ifdef ENABLE_HISYSEVENT
19 #include "hisysevent.h"
20 #endif
21 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
22 #include <sys/resource.h>
23 #endif
24
25 #include "ecmascript/mem/heap-inl.h"
26 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
27 #include "ecmascript/platform/dfx_hisys_event.h"
28
29 namespace panda::ecmascript {
30 using PGOProfilerManager = pgo::PGOProfilerManager;
31 using Clock = std::chrono::high_resolution_clock;
32
CheckIfMainThread() const33 bool GCKeyStats::CheckIfMainThread() const
34 {
35 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
36 return getpid() == syscall(SYS_gettid);
37 #else
38 return true;
39 #endif
40 }
41
CheckIfKeyPauseTime() const42 bool GCKeyStats::CheckIfKeyPauseTime() const
43 {
44 return gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::TotalGC) >= KEY_PAUSE_TIME;
45 }
46
AddGCStatsToKey()47 void GCKeyStats::AddGCStatsToKey()
48 {
49 LOG_GC(DEBUG) << "GCKeyStats AddGCStatsToKey!";
50
51 recordCount_++;
52
53 AddRecordDataStats(RecordKeyData::GC_TOTAL_MEM_USED,
54 SizeToIntKB(gcStats_->GetRecordData(RecordData::END_OBJ_SIZE)));
55 AddRecordDataStats(RecordKeyData::GC_TOTAL_MEM_COMMITTED,
56 SizeToIntKB(gcStats_->GetRecordData(RecordData::END_COMMIT_SIZE)));
57 AddRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_USED,
58 SizeToIntKB(gcStats_->GetRecordData(RecordData::YOUNG_ALIVE_SIZE)));
59 AddRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_COMMITTED,
60 SizeToIntKB(gcStats_->GetRecordData(RecordData::YOUNG_COMMIT_SIZE)));
61 AddRecordDataStats(RecordKeyData::GC_OLD_MEM_USED,
62 SizeToIntKB(gcStats_->GetRecordData(RecordData::OLD_ALIVE_SIZE)));
63 AddRecordDataStats(RecordKeyData::GC_OLD_MEM_COMMITTED,
64 SizeToIntKB(gcStats_->GetRecordData(RecordData::OLD_COMMIT_SIZE)));
65
66 AddRecordDataStats(RecordKeyData::GC_HUGE_MEM_USED,
67 SizeToIntKB(heap_->GetHugeObjectSpace()->GetHeapObjectSize()));
68 AddRecordDataStats(RecordKeyData::GC_HUGE_MEM_COMMITTED,
69 SizeToIntKB(heap_->GetHugeObjectSpace()->GetCommittedSize()));
70
71 AddRecordKeyDuration(RecordKeyDuration::GC_TOTAL_TIME,
72 gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::TotalGC));
73 AddRecordKeyDuration(RecordKeyDuration::GC_MARK_TIME,
74 gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::Mark));
75 AddRecordKeyDuration(RecordKeyDuration::GC_EVACUATE_TIME,
76 gcStats_->GetScopeDuration(GCStats::Scope::ScopeId::Evacuate));
77
78 if (CheckLastSendTimeIfSend() && CheckCountIfSend()) {
79 SendSysEvent();
80 PrintKeyStatisticResult();
81 InitializeRecordList();
82 }
83 }
84
SendSysEvent() const85 void GCKeyStats::SendSysEvent() const
86 {
87 #ifdef ENABLE_HISYSEVENT
88 int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::ARKTS_RUNTIME,
89 "ARK_STATS_GC",
90 OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC,
91 "BUNDLE_NAME", PGOProfilerManager::GetInstance()->GetBundleName(),
92 "PID", getpid(),
93 "TID", syscall(SYS_gettid),
94 "GC_TOTAL_COUNT", gcCount_,
95 "GC_TOTAL_TIME", static_cast<int>(GetRecordKeyDuration(RecordKeyDuration::GC_TOTAL_TIME)),
96 "GC_MARK_TIME", static_cast<int>(GetRecordKeyDuration(RecordKeyDuration::GC_MARK_TIME)),
97 "GC_EVACUATE_TIME", static_cast<int>(GetRecordKeyDuration(RecordKeyDuration::GC_EVACUATE_TIME)),
98 "GC_LONG_TIME", recordCount_,
99 "GC_TOTAL_MEM_USED", GetRecordDataStats(RecordKeyData::GC_TOTAL_MEM_USED),
100 "GC_TOTAL_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_TOTAL_MEM_COMMITTED),
101 "GC_ACTIVE_MEM_USED", GetRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_USED),
102 "GC_ACTIVE_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_ACTIVE_MEM_COMMITTED),
103 "GC_OLD_MEM_USED", GetRecordDataStats(RecordKeyData::GC_OLD_MEM_USED),
104 "GC_OLD_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_OLD_MEM_COMMITTED),
105 "GC_HUGE_MEM_USED", GetRecordDataStats(RecordKeyData::GC_HUGE_MEM_USED),
106 "GC_HUGE_MEM_COMMITTED", GetRecordDataStats(RecordKeyData::GC_HUGE_MEM_COMMITTED));
107 if (ret != 0) {
108 LOG_GC(ERROR) << "GCKeyStats HiSysEventWrite Failed! ret = " << ret;
109 }
110 #endif
111 }
112
SendSysEventBeforeDump(std::string type,size_t limitSize,size_t activeMemory) const113 void GCKeyStats::SendSysEventBeforeDump(std::string type, size_t limitSize, size_t activeMemory) const
114 {
115 #ifdef ENABLE_HISYSEVENT
116 int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::FRAMEWORK,
117 "ARK_STATS_DUMP",
118 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
119 "PID", getprocpid(),
120 "TID", syscall(SYS_gettid),
121 "PROCESS_NAME", PGOProfilerManager::GetInstance()->GetBundleName(),
122 "LIMITSIZE", limitSize,
123 "ACTIVE_MEMORY", activeMemory,
124 "TYPE", type);
125 if (ret != 0) {
126 LOG_GC(ERROR) << "GCKeyStats SendSysEventBeforeDump Failed! ret = " << ret;
127 }
128 #else
129 LOG_GC(INFO) << "GCKeyStats type: " << type << ", limitSize: " << limitSize << ", activeMemory: " << activeMemory;
130 #endif
131 }
132
PrintKeyStatisticResult() const133 void GCKeyStats::PrintKeyStatisticResult() const
134 {
135 LOG_GC(INFO) << "/******************* GCKeyStats HiSysEvent statistic: *******************/";
136 }
137
InitializeRecordList()138 void GCKeyStats::InitializeRecordList()
139 {
140 gcCount_ = 0;
141 recordCount_ = 0;
142 std::fill(recordDurationStats_, recordDurationStats_ + (uint8_t)RecordKeyDuration::NUM_OF_KEY_DURATION, 0.0f);
143 std::fill(recordDataStats_, recordDataStats_ + (uint8_t)RecordKeyData::NUM_OF_KEY_DATA, 0);
144 lastSendTimestamp_ = Clock::now();
145 }
146
147 /*
148 | The Judgment criteria of Long GC
149 | IsInBackground | IsSensitive or Idle | GCTime |
150 | -----------------| ---------------------|---------|
151 | false | Sensitive | 33 |
152 | false | !Sensitive & !Idle | 33 |
153 | true | Idle | 200 |
154 | true | !Idle | 200 |
155 | true | Idle | 500 |
156 */
ProcessLongGCEvent()157 void GCKeyStats::ProcessLongGCEvent()
158 {
159 if (!DFXHiSysEvent::IsEnableDFXHiSysEvent() || !heap_->GetEcmaVM()->GetJSOptions().IsEnableDFXHiSysEvent()) {
160 return;
161 }
162 LongGCStats *longGCStats = gcStats_->GetLongGCStats();
163 GCReason gcReason = gcStats_->GetGCReason();
164 bool gcIsSensitive = longGCStats->GetGCIsSensitive();
165 bool gcIsInBackground = longGCStats->GetGCIsInBackground();
166 float gcTotalTime = longGCStats->GetGCTotalTime();
167 if (gcIsSensitive) {
168 if (gcTotalTime > GC_SENSITIVE_LONG_TIME) {
169 DFXHiSysEvent::SendLongGCEvent(longGCStats);
170 longGCStats->Reset();
171 }
172 } else {
173 if (IsIdle(gcReason)) {
174 if (!gcIsInBackground && gcTotalTime > GC_IDLE_LONG_TIME) {
175 longGCStats->SetCpuLoad(DFXHiSysEvent::GetCpuUsage());
176 DFXHiSysEvent::SendLongGCEvent(longGCStats);
177 longGCStats->Reset();
178 } else if (gcIsInBackground && gcTotalTime > GC_BACKGROUD_IDLE_LONG_TIME) {
179 longGCStats->SetCpuLoad(DFXHiSysEvent::GetCpuUsage());
180 DFXHiSysEvent::SendLongGCEvent(longGCStats);
181 longGCStats->Reset();
182 }
183 } else {
184 if (!gcIsInBackground && gcTotalTime > GC_NOT_SENSITIVE_LONG_TIME) {
185 DFXHiSysEvent::SendLongGCEvent(longGCStats);
186 longGCStats->Reset();
187 } else if (gcIsInBackground && gcTotalTime > GC_BACKGROUD_LONG_TIME) {
188 longGCStats->SetCpuLoad(DFXHiSysEvent::GetCpuUsage());
189 DFXHiSysEvent::SendLongGCEvent(longGCStats);
190 longGCStats->Reset();
191 }
192 }
193 }
194 }
195 } // namespace panda::ecmascript