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