1 /*
2  * Copyright (c) 2021 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_stats.h"
17 
18 #include <iomanip>
19 #include "ecmascript/mem/heap-inl.h"
20 
21 constexpr int DESCRIPTION_LENGTH = 25;
22 constexpr int DATA_LENGTH = 8;
23 
24 #define STATS_DESCRIPTION_FORMAT(description)    \
25     std::left << std::setw(DESCRIPTION_LENGTH) << (description)
26 
27 #define STATS_DATA_FORMAT(data)    \
28     std::setw(DATA_LENGTH) << (data)
29 
30 namespace panda::ecmascript {
PrintStatisticResult()31 void GCStats::PrintStatisticResult()
32 {
33     LOG_GC(INFO) << "/******************* GCStats statistic: *******************/";
34     PrintGCSummaryStatistic(GCType::PARTIAL_EDEN_GC);
35     PrintGCSummaryStatistic(GCType::PARTIAL_YOUNG_GC);
36     PrintGCSummaryStatistic(GCType::PARTIAL_OLD_GC);
37     PrintGCSummaryStatistic(GCType::COMPRESS_GC);
38     PrintGCMemoryStatistic();
39 }
40 
PrintGCStatistic()41 void GCStats::PrintGCStatistic()
42 {
43     ASSERT(heap_ != nullptr);
44     ASSERT(heap_->GetEcmaVM() != nullptr);
45     if (heap_->GetEcmaVM()->GetJSOptions().EnableGCTracer() || CheckIfLongTimePause()) {
46         LOG_GC(INFO) << " [ " << GetGCTypeName() << " ] "
47                         << sizeToMB(recordData_[(uint8_t)RecordData::START_OBJ_SIZE]) << " ("
48                         << sizeToMB(recordData_[(uint8_t)RecordData::START_COMMIT_SIZE]) << ") -> "
49                         << sizeToMB(recordData_[(uint8_t)RecordData::END_OBJ_SIZE]) << " ("
50                         << sizeToMB(recordData_[(uint8_t)RecordData::END_COMMIT_SIZE]) << ") MB, "
51                         << scopeDuration_[Scope::ScopeId::TotalGC] << "(+"
52                         << GetConcurrrentMarkDuration()
53                         << ")ms, " << GCReasonToString(reason_);
54         LOG_GC(INFO) << "IsInBackground: " << heap_->IsInBackground() << "; "
55             << "SensitiveStatus: " << static_cast<int>(heap_->GetSensitiveStatus()) << "; "
56             << "OnStartupEvent: " << heap_->OnStartupEvent() << "; "
57             << "BundleName: " << heap_->GetEcmaVM()->GetBundleName() << ";";
58         // print verbose gc statsistics
59         PrintVerboseGCStatistic();
60     }
61     InitializeRecordList();
62 }
63 
GCReasonToString()64 const char *GCStats::GCReasonToString()
65 {
66     return GCReasonToString(reason_);
67 }
68 
GCReasonToString(GCReason reason)69 const char *GCStats::GCReasonToString(GCReason reason)
70 {
71     switch (reason) {
72         case GCReason::ALLOCATION_LIMIT:
73             return "Memory reach limit";
74         case GCReason::ALLOCATION_FAILED:
75             return "Allocate object failed";
76         case GCReason::IDLE:
77             return "Idle time task";
78         case GCReason::SWITCH_BACKGROUND:
79             return "Switch to background";
80         case GCReason::EXTERNAL_TRIGGER:
81             return "Externally triggered";
82         case GCReason::WORKER_DESTRUCTION:
83             return "Worker Destruction";
84         case GCReason::TRIGGER_BY_JS:
85             return "Trigger by JS";
86         case GCReason::TRIGGER_BY_ARKUI:
87             return "Trigger by ArkUI";
88         case GCReason::TRIGGER_BY_ABILITY:
89             return "Trigger by AbilityRuntime";
90         case GCReason::TRIGGER_BY_MEM_TOOLS:
91             return "Trigger by Mem tools";
92         case GCReason::TRIGGER_BY_TASKPOOL:
93             return "Trigger by taskPool";
94         default:
95             return "Other";
96     }
97 }
98 
GetConcurrrentMarkDuration()99 float GCStats::GetConcurrrentMarkDuration()
100 {
101     return concurrentMark_ ? scopeDuration_[Scope::ScopeId::ConcurrentMark] : 0;
102 }
103 
PrintVerboseGCStatistic()104 void GCStats::PrintVerboseGCStatistic()
105 {
106     PrintGCDurationStatistic();
107     PrintGCMemoryStatistic();
108     PrintGCSummaryStatistic();
109 }
110 
PrintGCMemoryStatistic()111 void GCStats::PrintGCMemoryStatistic()
112 {
113     NativeAreaAllocator *nativeAreaAllocator = heap_->GetNativeAreaAllocator();
114     HeapRegionAllocator *heapRegionAllocator = heap_->GetHeapRegionAllocator();
115     LOG_GC(INFO) << "/****************** GC Memory statistic: *****************/";
116     LOG_GC(INFO) << "AllSpaces        used:"
117                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHeapObjectSize())) << "KB"
118                     << "     committed:"
119                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetCommittedSize())) << "KB\n"
120                     << "EdenSpace        used:"
121                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetEdenSpace()->GetHeapObjectSize())) << "KB"
122                     << "     committed:"
123                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetEdenSpace()->GetCommittedSize())) << "KB\n"
124                     << "ActiveSemiSpace  used:"
125                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNewSpace()->GetHeapObjectSize())) << "KB"
126                     << "     committed:"
127                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNewSpace()->GetCommittedSize())) << "KB\n"
128                     << "OldSpace         used:"
129                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetOldSpace()->GetHeapObjectSize())) << "KB"
130                     << "     committed:"
131                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetOldSpace()->GetCommittedSize())) << "KB\n"
132                     << "HugeObjectSpace  used:"
133                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeObjectSpace()->GetHeapObjectSize())) << "KB"
134                     << "     committed:"
135                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n"
136                     << "NonMovableSpace  used:"
137                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNonMovableSpace()->GetHeapObjectSize())) << "KB"
138                     << "     committed:"
139                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNonMovableSpace()->GetCommittedSize())) << "KB\n"
140                     << "MachineCodeSpace used:"
141                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetMachineCodeSpace()->GetHeapObjectSize())) << "KB"
142                     << "     committed:"
143                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetMachineCodeSpace()->GetCommittedSize())) << "KB\n"
144                     << "HugeMachineCodeSpace used:"
145                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeMachineCodeSpace()->GetHeapObjectSize())) << "KB"
146                     << "     committed:"
147                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeMachineCodeSpace()->GetCommittedSize())) << "KB\n"
148                     << "SnapshotSpace    used:"
149                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetSnapshotSpace()->GetHeapObjectSize())) << "KB"
150                     << "     committed:"
151                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetSnapshotSpace()->GetCommittedSize())) << "KB\n"
152                     << "AppSpawnSpace    used:"
153                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetAppSpawnSpace()->GetHeapObjectSize())) << "KB"
154                     << "     committed:"
155                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetAppSpawnSpace()->GetCommittedSize())) << "KB";
156 
157     LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Anno memory usage size:")
158                     << STATS_DATA_FORMAT(sizeToMB(heapRegionAllocator->GetAnnoMemoryUsage())) << "MB\n"
159                     << STATS_DESCRIPTION_FORMAT("Native memory usage size:")
160                     << STATS_DATA_FORMAT(sizeToMB(nativeAreaAllocator->GetNativeMemoryUsage())) << "MB\n"
161                     << STATS_DESCRIPTION_FORMAT("NativeBindingSize:")
162                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeBindingSize())) << "KB\n"
163                     << STATS_DESCRIPTION_FORMAT("ArrayBufferNativeSize:")
164                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeAreaAllocator()->GetArrayBufferNativeSize()))
165                     << "KB\n"
166                     << STATS_DESCRIPTION_FORMAT("RegExpByteCodeNativeSize:")
167                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeAreaAllocator()->GetRegExpNativeSize())) << "KB\n"
168                     << STATS_DESCRIPTION_FORMAT("ChunkNativeSize:")
169                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeAreaAllocator()->GetChunkNativeSize())) << "KB";
170     switch (gcType_) {
171         case GCType::PARTIAL_EDEN_GC: {
172             size_t commitSize = GetRecordData(RecordData::EDEN_COMMIT_SIZE);
173             double copiedRate = commitSize == 0 ? 0 : (double(GetRecordData(RecordData::EDEN_ALIVE_SIZE)) / commitSize);
174             double premotedRate =
175                 commitSize == 0 ? 0 : (double(GetRecordData(RecordData::EDEN_PROMOTE_SIZE)) / commitSize);
176             double survivalRate = std::min(copiedRate + premotedRate, 1.0);
177             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Eden copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
178                 << STATS_DESCRIPTION_FORMAT("Eden promoted rate:") << STATS_DATA_FORMAT(premotedRate) << "\n"
179                 << STATS_DESCRIPTION_FORMAT("Eden survival rate:") << STATS_DATA_FORMAT(survivalRate);
180             break;
181         }
182         case GCType::PARTIAL_YOUNG_GC: {
183             double copiedRate = double(GetRecordData(RecordData::YOUNG_ALIVE_SIZE)) /
184                                 GetRecordData(RecordData::YOUNG_COMMIT_SIZE);
185             double premotedRate = double(GetRecordData(RecordData::YOUNG_PROMOTE_SIZE)) /
186                                   GetRecordData(RecordData::YOUNG_COMMIT_SIZE);
187             double survivalRate = std::min(copiedRate + premotedRate, 1.0);
188             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Young copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
189                 << STATS_DESCRIPTION_FORMAT("Young promoted rate:") << STATS_DATA_FORMAT(premotedRate) << "\n"
190                 << STATS_DESCRIPTION_FORMAT("Young survival rate:") << STATS_DATA_FORMAT(survivalRate);
191             break;
192         }
193         case GCType::PARTIAL_OLD_GC: {
194             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
195                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::OLD_ALIVE_SIZE)) /
196                                      GetRecordData(RecordData::OLD_COMMIT_SIZE));
197             break;
198         }
199         case GCType::COMPRESS_GC: {
200             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
201                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::COMPRESS_ALIVE_SIZE)) /
202                                      GetRecordData(RecordData::COMPRESS_COMMIT_SIZE));
203             break;
204         }
205         default:
206             break;
207     }
208 }
209 
PrintGCDurationStatistic()210 void GCStats::PrintGCDurationStatistic()
211 {
212     LOG_GC(INFO) << "/***************** GC Duration statistic: ****************/";
213     switch (gcType_) {
214         case GCType::PARTIAL_EDEN_GC:
215         case GCType::PARTIAL_YOUNG_GC:
216         case GCType::PARTIAL_OLD_GC:
217             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
218                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
219                          << STATS_DESCRIPTION_FORMAT("Initialize:")
220                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
221                          << STATS_DESCRIPTION_FORMAT("Mark:")
222                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
223                          << STATS_DESCRIPTION_FORMAT("MarkRoots:")
224                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
225                          << STATS_DESCRIPTION_FORMAT("ConcurrentMark pause:")
226                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ConcurrentMark]) << "ms\n"
227                          << STATS_DESCRIPTION_FORMAT("WaitConcurrentMarkFinish:")
228                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitConcurrentMarkFinished]) << "ms\n"
229                          << STATS_DESCRIPTION_FORMAT("ReMark:")
230                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ReMark]) << "ms\n"
231                          << STATS_DESCRIPTION_FORMAT("ProcessSharedGCRSetWorkList:")
232                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessSharedGCRSetWorkList]) << "ms\n"
233                          << STATS_DESCRIPTION_FORMAT("Sweep:")
234                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
235                          << STATS_DESCRIPTION_FORMAT("ClearNativeObject:")
236                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ClearNativeObject]) << "ms\n"
237                          << STATS_DESCRIPTION_FORMAT("Evacuate:")
238                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Evacuate]) << "ms\n"
239                          << STATS_DESCRIPTION_FORMAT("UpdateReference:")
240                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateReference]) << "ms\n"
241                          << STATS_DESCRIPTION_FORMAT("UpdateWeekRef:")
242                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateWeekRef]) << "ms\n"
243                          << STATS_DESCRIPTION_FORMAT("UpdateRoot:")
244                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateRoot]) << "ms\n"
245                          << STATS_DESCRIPTION_FORMAT("ProceeWorkload:")
246                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProceeWorkload]) << "ms\n"
247                          << STATS_DESCRIPTION_FORMAT("EvacuateSpace:")
248                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::EvacuateSpace]) << "ms\n"
249                          << STATS_DESCRIPTION_FORMAT("EvacuateRegion:")
250                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::EvacuateRegion]) << "ms\n"
251                          << STATS_DESCRIPTION_FORMAT("WaitFinish:")
252                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitFinish]) << "ms\n"
253                          << STATS_DESCRIPTION_FORMAT("Finish:")
254                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
255             break;
256         case GCType::COMPRESS_GC:
257             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
258                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
259                          << STATS_DESCRIPTION_FORMAT("ProcessSharedGCRSetWorkList:")
260                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessSharedGCRSetWorkList]) << "ms\n"
261                          << STATS_DESCRIPTION_FORMAT("Initialize:")
262                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
263                          << STATS_DESCRIPTION_FORMAT("Mark:")
264                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
265                          << STATS_DESCRIPTION_FORMAT("MarkRoots:")
266                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
267                          << STATS_DESCRIPTION_FORMAT("Sweep:")
268                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
269                          << STATS_DESCRIPTION_FORMAT("Finish:")
270                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
271             break;
272         default:
273             break;
274     }
275 }
276 
CheckIfNeedPrint(GCType type)277 bool GCStats::CheckIfNeedPrint(GCType type)
278 {
279     uint32_t gcCount = 0;
280     switch (type) {
281         case GCType::PARTIAL_EDEN_GC:
282             gcCount = GetRecordData(RecordData::EDEN_COUNT);
283             break;
284         case GCType::PARTIAL_YOUNG_GC:
285             gcCount = GetRecordData(RecordData::YOUNG_COUNT);
286             break;
287         case GCType::PARTIAL_OLD_GC:
288             gcCount = GetRecordData(RecordData::OLD_COUNT);
289             break;
290         case GCType::COMPRESS_GC:
291             gcCount = GetRecordData(RecordData::COMPRESS_COUNT);
292             break;
293         default:
294             break;
295     }
296 
297     if (gcCount > 0) {
298         return true;
299     }
300     return false;
301 }
302 
PrintGCSummaryStatistic(GCType type)303 void GCStats::PrintGCSummaryStatistic(GCType type)
304 {
305     if (type != GCType::START && !CheckIfNeedPrint(type)) {
306         return;
307     } else {
308         type = type == GCType::START ? gcType_ : type;
309     }
310     LOG_GC(INFO) << "/***************** GC summary statistic: *****************/";
311     switch (type) {
312         case GCType::PARTIAL_EDEN_GC: {
313             size_t commitSize = GetRecordData(RecordData::EDEN_TOTAL_COMMIT);
314             double copiedRate =
315                 commitSize == 0 ? 0 : (double(GetRecordData(RecordData::EDEN_TOTAL_ALIVE)) / commitSize);
316             double promotedRate =
317                 commitSize == 0 ? 0 : (double(GetRecordData(RecordData::EDEN_TOTAL_PROMOTE)) / commitSize);
318             double survivalRate =  std::min(copiedRate + promotedRate, 1.0);
319             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("EdenGC occurs count")
320                 << STATS_DATA_FORMAT(GetRecordData(RecordData::EDEN_COUNT)) << "\n"
321                 << STATS_DESCRIPTION_FORMAT("EdenGC max pause:")
322                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::EDEN_MAX_PAUSE)) << "ms\n"
323                 << STATS_DESCRIPTION_FORMAT("EdenGC min pause:")
324                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::EDEN_MIN_PAUSE)) << "ms\n"
325                 << STATS_DESCRIPTION_FORMAT("EdenGC average pause:")
326                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::EDEN_TOTAL_PAUSE) /
327                                      GetRecordData(RecordData::EDEN_COUNT)) << "ms\n"
328                 << STATS_DESCRIPTION_FORMAT("Eden average copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
329                 << STATS_DESCRIPTION_FORMAT("Eden average promoted rate:") << STATS_DATA_FORMAT(promotedRate) << "\n"
330                 << STATS_DESCRIPTION_FORMAT("Eden average survival rate:") << STATS_DATA_FORMAT(survivalRate);
331             break;
332         }
333         case GCType::PARTIAL_YOUNG_GC: {
334             double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) /
335                                 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
336             double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) /
337                                   GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
338             double survivalRate =  std::min(copiedRate + promotedRate, 1.0);
339             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("YoungGC occurs count")
340                 << STATS_DATA_FORMAT(GetRecordData(RecordData::YOUNG_COUNT)) << "\n"
341                 << STATS_DESCRIPTION_FORMAT("YoungGC max pause:")
342                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE)) << "ms\n"
343                 << STATS_DESCRIPTION_FORMAT("YoungGC min pause:")
344                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE)) << "ms\n"
345                 << STATS_DESCRIPTION_FORMAT("YoungGC average pause:")
346                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_TOTAL_PAUSE) /
347                                      GetRecordData(RecordData::YOUNG_COUNT)) << "ms\n"
348                 << STATS_DESCRIPTION_FORMAT("Young average copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
349                 << STATS_DESCRIPTION_FORMAT("Young average promoted rate:") << STATS_DATA_FORMAT(promotedRate) << "\n"
350                 << STATS_DESCRIPTION_FORMAT("Young average survival rate:") << STATS_DATA_FORMAT(survivalRate);
351             break;
352         }
353         case GCType::PARTIAL_OLD_GC: {
354             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("OldGC occurs count")
355                 << STATS_DATA_FORMAT(GetRecordData(RecordData::OLD_COUNT)) << "\n"
356                 << STATS_DESCRIPTION_FORMAT("OldGC max pause:")
357                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_MAX_PAUSE)) << "ms\n"
358                 << STATS_DESCRIPTION_FORMAT("OldGC min pause:")
359                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_MIN_PAUSE)) << "ms\n"
360                 << STATS_DESCRIPTION_FORMAT("OldGC average pause:")
361                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_TOTAL_PAUSE) /
362                                      GetRecordData(RecordData::OLD_COUNT)) << "ms\n"
363                 << STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
364                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::OLD_TOTAL_ALIVE)) /
365                                      GetRecordData(RecordData::OLD_TOTAL_COMMIT));
366             break;
367         }
368         case GCType::COMPRESS_GC: {
369             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("CompressGC occurs count")
370                 << STATS_DATA_FORMAT(GetRecordData(RecordData::COMPRESS_COUNT)) << "\n"
371                 << STATS_DESCRIPTION_FORMAT("CompressGC max pause:")
372                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE)) << "ms\n"
373                 << STATS_DESCRIPTION_FORMAT("CompressGC min pause:")
374                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE)) << "ms\n"
375                 << STATS_DESCRIPTION_FORMAT("CompressGC average pause:")
376                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_TOTAL_PAUSE) /
377                                      GetRecordData(RecordData::COMPRESS_COUNT)) << "ms\n"
378                 << STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
379                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::COMPRESS_TOTAL_ALIVE)) /
380                                      GetRecordData(RecordData::COMPRESS_TOTAL_COMMIT));
381             break;
382         }
383         default:
384             break;
385     }
386 }
387 
GetAccumulatedAllocateSize()388 size_t GCStats::GetAccumulatedAllocateSize()
389 {
390     return accumulatedFreeSize_ + heap_->GetHeapObjectSize();
391 }
392 
RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason)393 void GCStats::RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason)
394 {
395     SetRecordData(RecordData::START_OBJ_SIZE, heap_->GetHeapObjectSize());
396     SetRecordData(RecordData::START_COMMIT_SIZE, heap_->GetCommittedSize());
397     SetRecordData(RecordData::START_EDEN_OBJ_SIZE, heap_->GetEdenSpace()->GetHeapObjectSize());
398     SetRecordData(RecordData::START_YOUNG_OBJ_SIZE, heap_->GetNewSpace()->GetHeapObjectSize());
399     SetRecordData(RecordData::START_NATIVE_POINTER_NUM, heap_->GetNativePointerListSize());
400     gcType_ = GetGCType(gcType);
401     reason_ = reason;
402 
403     switch (gcType_) {
404         case GCType::PARTIAL_EDEN_GC: {
405             size_t edenCommitSize = heap_->GetEdenSpace()->GetCommittedSize();
406             SetRecordData(RecordData::EDEN_COMMIT_SIZE, edenCommitSize);
407             IncreaseRecordData(RecordData::EDEN_TOTAL_COMMIT, edenCommitSize);
408             break;
409         }
410         case GCType::PARTIAL_YOUNG_GC: {
411             size_t youngCommitSize =
412                 heap_->GetNewSpace()->GetCommittedSize() + heap_->GetEdenSpace()->GetCommittedSize();
413             SetRecordData(RecordData::YOUNG_COMMIT_SIZE, youngCommitSize);
414             IncreaseRecordData(RecordData::YOUNG_TOTAL_COMMIT, youngCommitSize);
415             break;
416         }
417         case GCType::PARTIAL_OLD_GC: {
418             size_t oldCommitSize = heap_->GetCommittedSize();
419             SetRecordData(RecordData::OLD_COMMIT_SIZE, oldCommitSize);
420             IncreaseRecordData(RecordData::OLD_TOTAL_COMMIT, oldCommitSize);
421             break;
422         }
423         case GCType::COMPRESS_GC: {
424             size_t compressCommitSize = heap_->GetCommittedSize();
425             SetRecordData(RecordData::COMPRESS_COMMIT_SIZE, compressCommitSize);
426             IncreaseRecordData(RecordData::COMPRESS_TOTAL_COMMIT, compressCommitSize);
427             break;
428         }
429         default:
430             break;
431     }
432 }
433 
RecordStatisticAfterGC()434 void GCStats::RecordStatisticAfterGC()
435 {
436     SetRecordData(RecordData::END_OBJ_SIZE, heap_->GetHeapObjectSize());
437     SetRecordData(RecordData::END_COMMIT_SIZE, heap_->GetCommittedSize());
438 
439     float duration = scopeDuration_[Scope::ScopeId::TotalGC];
440     switch (gcType_) {
441         case GCType::PARTIAL_EDEN_GC: {
442             if (GetRecordData(RecordData::EDEN_COUNT) == 0) {
443                 SetRecordDuration(RecordDuration::EDEN_MIN_PAUSE, duration);
444                 SetRecordDuration(RecordDuration::EDEN_MAX_PAUSE, duration);
445             } else {
446                 SetRecordDuration(RecordDuration::EDEN_MIN_PAUSE,
447                     std::min(GetRecordDuration(RecordDuration::EDEN_MIN_PAUSE), duration));
448                 SetRecordDuration(RecordDuration::EDEN_MAX_PAUSE,
449                     std::max(GetRecordDuration(RecordDuration::EDEN_MAX_PAUSE), duration));
450             }
451             IncreaseRecordData(RecordData::EDEN_COUNT);
452             IncreaseRecordDuration(RecordDuration::EDEN_TOTAL_PAUSE, duration);
453             size_t edenToYoungSize = heap_->GetEdenToYoungSize();
454             SetRecordData(RecordData::EDEN_ALIVE_SIZE, edenToYoungSize);
455             IncreaseRecordData(RecordData::EDEN_TOTAL_ALIVE, edenToYoungSize);
456             size_t promotedSize = heap_->GetPromotedSize();
457             SetRecordData(RecordData::EDEN_PROMOTE_SIZE, promotedSize);
458             IncreaseRecordData(RecordData::EDEN_TOTAL_PROMOTE, promotedSize);
459             break;
460         }
461         case GCType::PARTIAL_YOUNG_GC: {
462             if (GetRecordData(RecordData::YOUNG_COUNT) == 0) {
463                 SetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE, duration);
464                 SetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE, duration);
465             } else {
466                 SetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE,
467                     std::min(GetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE), duration));
468                 SetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE,
469                     std::max(GetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE), duration));
470             }
471             IncreaseRecordData(RecordData::YOUNG_COUNT);
472             IncreaseRecordDuration(RecordDuration::YOUNG_TOTAL_PAUSE, duration);
473             size_t youngAliveSize = heap_->GetNewSpace()->GetHeapObjectSize();
474             SetRecordData(RecordData::YOUNG_ALIVE_SIZE, youngAliveSize);
475             IncreaseRecordData(RecordData::YOUNG_TOTAL_ALIVE, youngAliveSize);
476             size_t promotedSize = heap_->GetPromotedSize();
477             SetRecordData(RecordData::YOUNG_PROMOTE_SIZE, promotedSize);
478             IncreaseRecordData(RecordData::YOUNG_TOTAL_PROMOTE, promotedSize);
479             break;
480         }
481         case GCType::PARTIAL_OLD_GC: {
482             if (GetRecordData(RecordData::OLD_COUNT) == 0) {
483                 SetRecordDuration(RecordDuration::OLD_MIN_PAUSE, duration);
484                 SetRecordDuration(RecordDuration::OLD_MAX_PAUSE, duration);
485             } else {
486                 SetRecordDuration(RecordDuration::OLD_MIN_PAUSE,
487                     std::min(GetRecordDuration(RecordDuration::OLD_MIN_PAUSE), duration));
488                 SetRecordDuration(RecordDuration::OLD_MAX_PAUSE,
489                     std::max(GetRecordDuration(RecordDuration::OLD_MAX_PAUSE), duration));
490             }
491             IncreaseRecordData(RecordData::OLD_COUNT);
492             IncreaseRecordDuration(RecordDuration::OLD_TOTAL_PAUSE, duration);
493             size_t oldAliveSize = heap_->GetHeapObjectSize();
494             SetRecordData(RecordData::OLD_ALIVE_SIZE, oldAliveSize);
495             IncreaseRecordData(RecordData::OLD_TOTAL_ALIVE, oldAliveSize);
496             break;
497         }
498         case GCType::COMPRESS_GC: {
499             if (GetRecordData(RecordData::COMPRESS_COUNT) == 0) {
500                 SetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE, duration);
501                 SetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE, duration);
502             } else {
503                 SetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE,
504                     std::min(GetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE), duration));
505                 SetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE,
506                     std::max(GetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE), duration));
507             }
508             IncreaseRecordData(RecordData::COMPRESS_COUNT);
509             IncreaseRecordDuration(RecordDuration::COMPRESS_TOTAL_PAUSE, duration);
510             size_t compressAliveSize = heap_->GetHeapObjectSize();
511             SetRecordData(RecordData::COMPRESS_ALIVE_SIZE, compressAliveSize);
512             IncreaseRecordData(RecordData::COMPRESS_TOTAL_ALIVE, compressAliveSize);
513             break;
514         }
515         default:
516             break;
517     }
518     RecordGCSpeed();
519 
520     if (gcType_ == GCType::COMPRESS_GC && scopeDuration_[Scope::ScopeId::TotalGC] > longPauseTime_) {
521         IncreaseFullGCLongTimeCount();
522     }
523     IncreaseTotalDuration(scopeDuration_[Scope::ScopeId::TotalGC]);
524     IncreaseAccumulatedFreeSize(GetRecordData(RecordData::START_OBJ_SIZE) -
525                                 GetRecordData(RecordData::END_OBJ_SIZE));
526 }
527 
RecordGCSpeed()528 void GCStats::RecordGCSpeed()
529 {
530     double survivalRate = GetAvgSurvivalRate();
531     size_t clearNativeSpeed = GetRecordData(RecordData::START_NATIVE_POINTER_NUM) /
532                               scopeDuration_[Scope::ScopeId::ClearNativeObject];
533 
534     if (gcType_ == GCType::PARTIAL_EDEN_GC) {
535         gcSpeed_[(uint8_t)SpeedData::MARK_SPEED] =
536             GetRecordData(RecordData::START_EDEN_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Mark];
537         size_t evacuateSpeed = survivalRate * GetRecordData(RecordData::START_EDEN_OBJ_SIZE) /
538                                scopeDuration_[Scope::ScopeId::EvacuateSpace];
539         gcSpeed_[(uint8_t)SpeedData::EDEN_EVACUATE_SPACE_SPEED] =
540             (evacuateSpeed + gcSpeed_[(uint8_t)SpeedData::EDEN_EVACUATE_SPACE_SPEED]) / 2;  // 2 means half
541         gcSpeed_[(uint8_t)SpeedData::EDEN_CLEAR_NATIVE_OBJ_SPEED] =
542             (clearNativeSpeed + gcSpeed_[(uint8_t)SpeedData::EDEN_CLEAR_NATIVE_OBJ_SPEED]) / 2;  // 2 means half
543         size_t updateReferenceSpeed = GetRecordData(RecordData::START_OBJ_SIZE) /
544                                       scopeDuration_[Scope::ScopeId::UpdateReference];
545         gcSpeed_[(uint8_t)SpeedData::EDEN_UPDATE_REFERENCE_SPEED] =
546             (updateReferenceSpeed + gcSpeed_[(uint8_t)SpeedData::EDEN_UPDATE_REFERENCE_SPEED]) / 2;  // 2 means half
547     } else if (gcType_ == GCType::PARTIAL_YOUNG_GC) {
548         size_t objSize =
549             GetRecordData(RecordData::START_YOUNG_OBJ_SIZE) + GetRecordData(RecordData::START_EDEN_OBJ_SIZE);
550         gcSpeed_[(uint8_t)SpeedData::MARK_SPEED] = objSize / scopeDuration_[Scope::ScopeId::Mark];
551         size_t evacuateSpeed = survivalRate * objSize / scopeDuration_[Scope::ScopeId::EvacuateSpace];
552         gcSpeed_[(uint8_t)SpeedData::YOUNG_EVACUATE_SPACE_SPEED] =
553             (evacuateSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_EVACUATE_SPACE_SPEED]) / 2;  // 2 means half
554         gcSpeed_[(uint8_t)SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED] =
555             (clearNativeSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED]) / 2;  // 2 means half
556         size_t updateReferenceSpeed = GetRecordData(RecordData::START_OBJ_SIZE) /
557                                       scopeDuration_[Scope::ScopeId::UpdateReference];
558         gcSpeed_[(uint8_t)SpeedData::YOUNG_UPDATE_REFERENCE_SPEED] =
559             (updateReferenceSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_UPDATE_REFERENCE_SPEED]) / 2;  // 2 means half
560     } else if (gcType_ == GCType::PARTIAL_OLD_GC) {
561         gcSpeed_[(uint8_t)SpeedData::MARK_SPEED] =
562             GetRecordData(RecordData::START_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Mark];
563         size_t sweepSpeed = GetRecordData(RecordData::START_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Sweep];
564         gcSpeed_[(uint8_t)SpeedData::SWEEP_SPEED] =
565             (sweepSpeed + gcSpeed_[(uint8_t)SpeedData::SWEEP_SPEED]) / 2;  // 2 means half
566         gcSpeed_[(uint8_t)SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED] =
567             (clearNativeSpeed + gcSpeed_[(uint8_t)SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED]) / 2;  // 2 means half
568 
569         size_t evacuateSpaceSpeed = (survivalRate * (GetRecordData(RecordData::START_YOUNG_OBJ_SIZE) +
570             GetRecordData(RecordData::START_EDEN_OBJ_SIZE)) + GetRecordData(RecordData::COLLECT_REGION_SET_SIZE)) /
571             scopeDuration_[Scope::ScopeId::EvacuateSpace];
572         gcSpeed_[(uint8_t)SpeedData::OLD_EVACUATE_SPACE_SPEED] =
573             (evacuateSpaceSpeed + gcSpeed_[(uint8_t)SpeedData::OLD_EVACUATE_SPACE_SPEED]) / 2;  // 2 means half
574 
575         size_t updateReferenceSpeed = GetRecordData(RecordData::START_OBJ_SIZE) /
576                                     scopeDuration_[Scope::ScopeId::UpdateReference];
577         gcSpeed_[(uint8_t)SpeedData::UPDATE_REFERENCE_SPEED] =
578             (updateReferenceSpeed + gcSpeed_[(uint8_t)SpeedData::UPDATE_REFERENCE_SPEED]) / 2;  // 2 means half
579     }
580 }
581 
GetGCType(TriggerGCType gcType)582 GCType GCStats::GetGCType(TriggerGCType gcType)
583 {
584     if (heap_ && !heap_->IsReadyToConcurrentMark()) {
585         switch (heap_->GetMarkType()) {
586             case MarkType::MARK_EDEN:
587                 return GCType::PARTIAL_EDEN_GC;
588             case MarkType::MARK_YOUNG:
589                 return GCType::PARTIAL_YOUNG_GC;
590             case MarkType::MARK_FULL:
591                 return GCType::PARTIAL_OLD_GC;
592             default:
593                 return GCType::OTHER;
594         }
595     }
596     switch (gcType) {
597         case TriggerGCType::EDEN_GC:
598             return GCType::PARTIAL_EDEN_GC;
599         case TriggerGCType::YOUNG_GC:
600             return GCType::PARTIAL_YOUNG_GC;
601         case TriggerGCType::OLD_GC:
602             return GCType::PARTIAL_OLD_GC;
603         case TriggerGCType::FULL_GC:
604             return GCType::COMPRESS_GC;
605         case TriggerGCType::SHARED_GC:
606             return GCType::SHARED_GC;
607         case TriggerGCType::SHARED_FULL_GC:
608             return GCType::SHARED_FULL_GC;
609         default:
610             return GCType::OTHER;
611     }
612 }
613 
InitializeRecordList()614 void GCStats::InitializeRecordList()
615 {
616     for (float &duration : scopeDuration_) {
617         duration = 0.0f;
618     }
619     concurrentMark_ = false;
620 }
621 
CheckIfLongTimePause()622 bool GCStats::CheckIfLongTimePause()
623 {
624     if (scopeDuration_[Scope::ScopeId::TotalGC] > longPauseTime_) {
625         LOG_GC(INFO) << "Has checked a long time gc";
626         return true;
627     }
628     return false;
629 }
630 
PrintStatisticResult()631 void SharedGCStats::PrintStatisticResult()
632 {
633     LOG_GC(INFO) << "/******************* SharedGCStats statistic: *******************/";
634     PrintSharedGCSummaryStatistic();
635     PrintGCMemoryStatistic();
636 }
637 
PrintGCStatistic()638 void SharedGCStats::PrintGCStatistic()
639 {
640     if (enableGCTracer_) {
641         LOG_GC(INFO) << " [ " << GetGCTypeName() << " ] "
642                      << sizeToMB(recordData_[(uint8_t)RecordData::START_OBJ_SIZE]) << " ("
643                      << sizeToMB(recordData_[(uint8_t)RecordData::START_COMMIT_SIZE]) << ") -> "
644                      << sizeToMB(recordData_[(uint8_t)RecordData::END_OBJ_SIZE]) << " ("
645                      << sizeToMB(recordData_[(uint8_t)RecordData::END_COMMIT_SIZE]) << ") MB, "
646                      << scopeDuration_[Scope::ScopeId::TotalGC] << "ms, " << GCReasonToString(reason_);
647         PrintSharedGCDuration();
648         PrintGCMemoryStatistic();
649         PrintSharedGCSummaryStatistic();
650     }
651     InitializeRecordList();
652 }
653 
PrintSharedGCSummaryStatistic()654 void SharedGCStats::PrintSharedGCSummaryStatistic()
655 {
656     LOG_GC(INFO) << "/***************** GC summary statistic: *****************/";
657     LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("SharedGC occurs count")
658                  << STATS_DATA_FORMAT(GetRecordData(RecordData::SHARED_COUNT)) << "\n"
659                  << STATS_DESCRIPTION_FORMAT("SharedGC max pause:")
660                  << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_MAX_PAUSE)) << "ms\n"
661                  << STATS_DESCRIPTION_FORMAT("SharedGC min pause:")
662                  << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_MIN_PAUSE)) << "ms\n"
663                  << STATS_DESCRIPTION_FORMAT("SharedGC average pause:")
664                  << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_TOTAL_PAUSE) /
665                                       GetRecordData(RecordData::SHARED_COUNT)) << "ms\n"
666                  << STATS_DESCRIPTION_FORMAT("SharedHeap average alive rate:")
667                  << STATS_DATA_FORMAT(double(GetRecordData(RecordData::SHARED_TOTAL_ALIVE)) /
668                                       GetRecordData(RecordData::SHARED_TOTAL_COMMIT));
669 }
670 
PrintGCMemoryStatistic()671 void SharedGCStats::PrintGCMemoryStatistic()
672 {
673     NativeAreaAllocator *nativeAreaAllocator = sHeap_->GetNativeAreaAllocator();
674     HeapRegionAllocator *heapRegionAllocator = sHeap_->GetHeapRegionAllocator();
675     LOG_GC(INFO) << "/****************** GC Memory statistic: *****************/";
676     LOG_GC(INFO) << "AllSpaces         used:"
677                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHeapObjectSize())) << "KB"
678                  << "     committed:"
679                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetCommittedSize())) << "KB\n"
680                  << "SharedOldSpace         used:"
681                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetOldSpace()->GetHeapObjectSize())) << "KB"
682                  << "     committed:"
683                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetOldSpace()->GetCommittedSize())) << "KB\n"
684                  << "SharedNonMovableSpace  used:"
685                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNonMovableSpace()->GetHeapObjectSize())) << "KB"
686                  << "     committed:"
687                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNonMovableSpace()->GetCommittedSize())) << "KB\n"
688                  << "SharedHugeObjectSpace  used:"
689                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetHeapObjectSize())) << "KB"
690                  << "     committed:"
691                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n"
692                  << "SharedAppSpawnSpace    used:"
693                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetAppSpawnSpace()->GetHeapObjectSize())) << "KB"
694                  << "     committed:"
695                  << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetAppSpawnSpace()->GetCommittedSize())) << "KB";
696 
697     LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Anno memory usage size:")
698                  << STATS_DATA_FORMAT(sizeToMB(heapRegionAllocator->GetAnnoMemoryUsage())) << "MB\n"
699                  << STATS_DESCRIPTION_FORMAT("Native memory usage size:")
700                  << STATS_DATA_FORMAT(sizeToMB(nativeAreaAllocator->GetNativeMemoryUsage())) << "MB\n";
701 
702     LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
703         << STATS_DATA_FORMAT(double(GetRecordData(RecordData::SHARED_ALIVE_SIZE)) /
704                                     GetRecordData(RecordData::SHARED_COMMIT_SIZE));
705 }
706 
PrintSharedGCDuration()707 void SharedGCStats::PrintSharedGCDuration()
708 {
709     LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
710         << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
711         << STATS_DESCRIPTION_FORMAT("Initialize:")
712         << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
713         << STATS_DESCRIPTION_FORMAT("Mark:")
714         << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
715         << STATS_DESCRIPTION_FORMAT("Sweep:")
716         << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
717         << STATS_DESCRIPTION_FORMAT("Finish:")
718         << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms\n"
719         << STATS_DESCRIPTION_FORMAT("SuspendAll:")
720         << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::SuspendAll]) << "ms\n"
721         << STATS_DESCRIPTION_FORMAT("ResumeAll:")
722         << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ResumeAll]) << "ms";
723 }
724 
GetAccumulatedAllocateSize()725 size_t SharedGCStats::GetAccumulatedAllocateSize()
726 {
727     return accumulatedFreeSize_ + sHeap_->GetHeapObjectSize();
728 }
729 
RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason)730 void SharedGCStats::RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason)
731 {
732     size_t commitSize = sHeap_->GetCommittedSize();
733     SetRecordData(RecordData::START_OBJ_SIZE, sHeap_->GetHeapObjectSize());
734     SetRecordData(RecordData::START_COMMIT_SIZE, commitSize);
735     SetRecordData(RecordData::SHARED_COMMIT_SIZE, commitSize);
736     IncreaseRecordData(RecordData::SHARED_TOTAL_COMMIT, commitSize);
737     gcType_ = GetGCType(gcType);
738     reason_ = reason;
739 }
740 
RecordStatisticAfterGC()741 void SharedGCStats::RecordStatisticAfterGC()
742 {
743     SetRecordData(RecordData::END_OBJ_SIZE, sHeap_->GetHeapObjectSize());
744     SetRecordData(RecordData::END_COMMIT_SIZE, sHeap_->GetCommittedSize());
745 
746     float duration = scopeDuration_[Scope::ScopeId::TotalGC];
747     if (GetRecordData(RecordData::SHARED_COUNT) == 0) {
748         SetRecordDuration(RecordDuration::SHARED_MIN_PAUSE, duration);
749         SetRecordDuration(RecordDuration::SHARED_MAX_PAUSE, duration);
750     } else {
751         SetRecordDuration(RecordDuration::SHARED_MIN_PAUSE,
752             std::min(GetRecordDuration(RecordDuration::SHARED_MIN_PAUSE), duration));
753         SetRecordDuration(RecordDuration::SHARED_MAX_PAUSE,
754             std::max(GetRecordDuration(RecordDuration::SHARED_MAX_PAUSE), duration));
755     }
756     IncreaseRecordData(RecordData::SHARED_COUNT);
757     IncreaseRecordDuration(RecordDuration::SHARED_TOTAL_PAUSE, duration);
758     size_t heapAliveSize = sHeap_->GetHeapObjectSize();
759     SetRecordData(RecordData::SHARED_ALIVE_SIZE, heapAliveSize);
760     IncreaseRecordData(RecordData::SHARED_TOTAL_ALIVE, heapAliveSize);
761 
762     IncreaseTotalDuration(scopeDuration_[Scope::ScopeId::TotalGC]);
763     IncreaseAccumulatedFreeSize(GetRecordData(RecordData::START_OBJ_SIZE) -
764                                 GetRecordData(RecordData::END_OBJ_SIZE));
765 }
766 }  // namespace panda::ecmascript
767