• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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