• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
20 #include "ecmascript/mem/heap-inl.h"
21 #include "ecmascript/mem/mem.h"
22 
23 constexpr int DESCRIPTION_LENGTH = 25;
24 constexpr int DATA_LENGTH = 8;
25 
26 #define STATS_DESCRIPTION_FORMAT(description)    \
27     std::left << std::setw(DESCRIPTION_LENGTH) << (description)
28 
29 #define STATS_DATA_FORMAT(data)    \
30     std::setw(DATA_LENGTH) << (data)
31 
32 namespace panda::ecmascript {
PrintStatisticResult()33 void GCStats::PrintStatisticResult()
34 {
35     LOG_GC(INFO) << "/******************* GCStats statistic: *******************/";
36     PrintGCSummaryStatistic(GCType::STW_YOUNG_GC);
37     PrintGCSummaryStatistic(GCType::PARTIAL_YOUNG_GC);
38     PrintGCSummaryStatistic(GCType::PARTIAL_OLD_GC);
39     PrintGCSummaryStatistic(GCType::COMPRESS_GC);
40     PrintGCMemoryStatistic();
41 }
42 
PrintGCStatistic()43 void GCStats::PrintGCStatistic()
44 {
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();
54 
55         // print verbose gc statsistics
56         PrintVerboseGCStatistic();
57     }
58     InitializeRecordList();
59 }
60 
GetGCTypeName()61 const char *GCStats::GetGCTypeName()
62 {
63     switch (gcType_) {
64         case GCType::STW_YOUNG_GC:
65             return "STWYoungGC";
66         case GCType::PARTIAL_YOUNG_GC:
67             return "HPP YoungGC";
68         case GCType::PARTIAL_OLD_GC:
69             return "HPP OldGC";
70         case GCType::COMPRESS_GC:
71             return "CompressGC";
72         default:
73             return "UnknownType";
74     }
75 }
76 
GCReasonToString()77 const char *GCStats::GCReasonToString()
78 {
79     switch (reason_) {
80         case GCReason::ALLOCATION_LIMIT:
81             return "Memory reach limit";
82         case GCReason::ALLOCATION_FAILED:
83             return "Allocate object failed";
84         case GCReason::IDLE:
85             return "Idle time task";
86         case GCReason::SWITCH_BACKGROUND:
87             return "Switch to background";
88         case GCReason::EXTERNAL_TRIGGER:
89             return "Externally triggered";
90         default:
91             return "Other";
92     }
93 }
94 
GetConcurrrentMarkDuration()95 float GCStats::GetConcurrrentMarkDuration()
96 {
97     return concurrentMark_ ? scopeDuration_[Scope::ScopeId::ConcurrentMark] : 0;
98 }
99 
PrintVerboseGCStatistic()100 void GCStats::PrintVerboseGCStatistic()
101 {
102     PrintGCDurationStatistic();
103     PrintGCMemoryStatistic();
104     PrintGCSummaryStatistic();
105 }
106 
PrintGCMemoryStatistic()107 void GCStats::PrintGCMemoryStatistic()
108 {
109     NativeAreaAllocator *nativeAreaAllocator = heap_->GetNativeAreaAllocator();
110     HeapRegionAllocator *heapRegionAllocator = heap_->GetHeapRegionAllocator();
111     LOG_GC(INFO) << "/****************** GC Memory statistic: *****************/";
112     LOG_GC(INFO) << "AllSpaces        used:"
113                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHeapObjectSize())) << "KB"
114                     << "     committed:"
115                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetCommittedSize())) << "KB\n"
116                     << "ActiveSemiSpace  used:"
117                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNewSpace()->GetHeapObjectSize())) << "KB"
118                     << "     committed:"
119                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNewSpace()->GetCommittedSize())) << "KB\n"
120                     << "OldSpace         used:"
121                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetOldSpace()->GetHeapObjectSize())) << "KB"
122                     << "     committed:"
123                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetOldSpace()->GetCommittedSize())) << "KB\n"
124                     << "HugeObjectSpace  used:"
125                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeObjectSpace()->GetHeapObjectSize())) << "KB"
126                     << "     committed:"
127                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n"
128                     << "NonMovableSpace  used:"
129                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNonMovableSpace()->GetHeapObjectSize())) << "KB"
130                     << "     committed:"
131                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNonMovableSpace()->GetCommittedSize())) << "KB\n"
132                     << "MachineCodeSpace used:"
133                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetMachineCodeSpace()->GetHeapObjectSize())) << "KB"
134                     << "     committed:"
135                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetMachineCodeSpace()->GetCommittedSize())) << "KB\n"
136                     << "SnapshotSpace    used:"
137                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetSnapshotSpace()->GetHeapObjectSize())) << "KB"
138                     << "     committed:"
139                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetSnapshotSpace()->GetCommittedSize())) << "KB\n"
140                     << "AppSpawnSpace    used:"
141                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetAppSpawnSpace()->GetHeapObjectSize())) << "KB"
142                     << "     committed:"
143                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetAppSpawnSpace()->GetCommittedSize())) << "KB";
144 
145     LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Anno memory usage size:")
146                     << STATS_DATA_FORMAT(sizeToMB(heapRegionAllocator->GetAnnoMemoryUsage())) << "MB\n"
147                     << STATS_DESCRIPTION_FORMAT("Native memory usage size:")
148                     << STATS_DATA_FORMAT(sizeToMB(nativeAreaAllocator->GetNativeMemoryUsage())) << "MB\n"
149                     << STATS_DESCRIPTION_FORMAT("NativeBindingSize:")
150                     << STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeBindingSize())) << "MB";
151 
152     switch (gcType_) {
153         case GCType::STW_YOUNG_GC: {
154             double copiedRate = double(GetRecordData(RecordData::SEMI_ALIVE_SIZE)) /
155                                 GetRecordData(RecordData::SEMI_COMMIT_SIZE);
156             double premotedRate = double(GetRecordData(RecordData::SEMI_PROMOTE_SIZE)) /
157                                   GetRecordData(RecordData::SEMI_COMMIT_SIZE);
158             double survivalRate = std::min(copiedRate + premotedRate, 1.0);
159             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Young copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
160                 << STATS_DESCRIPTION_FORMAT("Young promoted rate:") << STATS_DATA_FORMAT(premotedRate) << "\n"
161                 << STATS_DESCRIPTION_FORMAT("Young survival rate:") << STATS_DATA_FORMAT(survivalRate);
162             break;
163         }
164         case GCType::PARTIAL_YOUNG_GC: {
165             double copiedRate = double(GetRecordData(RecordData::YOUNG_ALIVE_SIZE)) /
166                                 GetRecordData(RecordData::YOUNG_COMMIT_SIZE);
167             double premotedRate = double(GetRecordData(RecordData::YOUNG_PROMOTE_SIZE)) /
168                                   GetRecordData(RecordData::YOUNG_COMMIT_SIZE);
169             double survivalRate = std::min(copiedRate + premotedRate, 1.0);
170             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Young copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
171                 << STATS_DESCRIPTION_FORMAT("Young promoted rate:") << STATS_DATA_FORMAT(premotedRate) << "\n"
172                 << STATS_DESCRIPTION_FORMAT("Young survival rate:") << STATS_DATA_FORMAT(survivalRate);
173             break;
174         }
175         case GCType::PARTIAL_OLD_GC: {
176             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
177                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::OLD_ALIVE_SIZE)) /
178                                      GetRecordData(RecordData::OLD_COMMIT_SIZE));
179             break;
180         }
181         case GCType::COMPRESS_GC: {
182             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
183                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::COMPRESS_ALIVE_SIZE)) /
184                                      GetRecordData(RecordData::COMPRESS_COMMIT_SIZE));
185             break;
186         }
187         default:
188             break;
189     }
190 }
191 
PrintGCDurationStatistic()192 void GCStats::PrintGCDurationStatistic()
193 {
194     LOG_GC(INFO) << "/***************** GC Duration statistic: ****************/";
195     switch (gcType_) {
196         case GCType::STW_YOUNG_GC:
197             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
198                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
199                          << STATS_DESCRIPTION_FORMAT("Initialize:")
200                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
201                          << STATS_DESCRIPTION_FORMAT("Mark:")
202                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
203                          << STATS_DESCRIPTION_FORMAT("MarkRoots:")
204                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
205                          << STATS_DESCRIPTION_FORMAT("ProcessMarkStack:")
206                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessMarkStack]) << "ms\n"
207                          << STATS_DESCRIPTION_FORMAT("Sweep:")
208                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
209                          << STATS_DESCRIPTION_FORMAT("Finish:")
210                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
211             break;
212         case GCType::PARTIAL_YOUNG_GC:
213         case GCType::PARTIAL_OLD_GC:
214             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
215                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
216                          << STATS_DESCRIPTION_FORMAT("Initialize:")
217                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
218                          << STATS_DESCRIPTION_FORMAT("Mark:")
219                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
220                          << STATS_DESCRIPTION_FORMAT("MarkRoots:")
221                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
222                          << STATS_DESCRIPTION_FORMAT("ConcurrentMark pause:")
223                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ConcurrentMark]) << "ms\n"
224                          << STATS_DESCRIPTION_FORMAT("WaitConcurrentMarkFinish:")
225                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitConcurrentMarkFinished]) << "ms\n"
226                          << STATS_DESCRIPTION_FORMAT("ProcessMarkStack:")
227                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessMarkStack]) << "ms\n"
228                          << STATS_DESCRIPTION_FORMAT("ReMark:")
229                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ReMark]) << "ms\n"
230                          << STATS_DESCRIPTION_FORMAT("Sweep:")
231                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
232                          << STATS_DESCRIPTION_FORMAT("ClearNativeObject:")
233                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ClearNativeObject]) << "ms\n"
234                          << STATS_DESCRIPTION_FORMAT("Evacuate:")
235                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Evacuate]) << "ms\n"
236                          << STATS_DESCRIPTION_FORMAT("UpdateReference:")
237                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateReference]) << "ms\n"
238                          << STATS_DESCRIPTION_FORMAT("EvacuateSpace:")
239                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::EvacuateSpace]) << "ms\n"
240                          << STATS_DESCRIPTION_FORMAT("Finish:")
241                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
242             break;
243         case GCType::COMPRESS_GC:
244             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
245                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
246                          << STATS_DESCRIPTION_FORMAT("Initialize:")
247                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
248                          << STATS_DESCRIPTION_FORMAT("Mark:")
249                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
250                          << STATS_DESCRIPTION_FORMAT("MarkRoots:")
251                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
252                          << STATS_DESCRIPTION_FORMAT("ProcessMarkStack:")
253                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessMarkStack]) << "ms\n"
254                          << STATS_DESCRIPTION_FORMAT("Sweep:")
255                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
256                          << STATS_DESCRIPTION_FORMAT("Finish:")
257                          << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
258             break;
259         default:
260             break;
261     }
262 }
263 
CheckIfNeedPrint(GCType type)264 bool GCStats::CheckIfNeedPrint(GCType type)
265 {
266     uint32_t gcCount = 0;
267     switch (type) {
268         case GCType::STW_YOUNG_GC:
269             gcCount = GetRecordData(RecordData::SEMI_COUNT);
270             break;
271         case GCType::PARTIAL_YOUNG_GC:
272             gcCount = GetRecordData(RecordData::YOUNG_COUNT);
273             break;
274         case GCType::PARTIAL_OLD_GC:
275             gcCount = GetRecordData(RecordData::OLD_COUNT);
276             break;
277         case GCType::COMPRESS_GC:
278             gcCount = GetRecordData(RecordData::COMPRESS_COUNT);
279             break;
280         default:
281             break;
282     }
283 
284     if (gcCount > 0) {
285         return true;
286     }
287     return false;
288 }
289 
PrintGCSummaryStatistic(GCType type)290 void GCStats::PrintGCSummaryStatistic(GCType type)
291 {
292     if (type != GCType::START && !CheckIfNeedPrint(type)) {
293         return;
294     } else {
295         type = type == GCType::START ? gcType_ : type;
296     }
297     LOG_GC(INFO) << "/***************** GC summary statistic: *****************/";
298     switch (type) {
299         case GCType::STW_YOUNG_GC: {
300             double copiedRate = double(GetRecordData(RecordData::SEMI_TOTAL_ALIVE)) /
301                                 GetRecordData(RecordData::SEMI_TOTAL_COMMIT);
302             double promotedRate = double(GetRecordData(RecordData::SEMI_TOTAL_PROMOTE)) /
303                                   GetRecordData(RecordData::SEMI_TOTAL_COMMIT);
304             double survivalRate = std::min(copiedRate + promotedRate, 1.0);
305             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("STWYoungGC occurs count")
306                 << STATS_DATA_FORMAT(GetRecordData(RecordData::SEMI_COUNT)) << "\n"
307                 << STATS_DESCRIPTION_FORMAT("STWYoungGC max pause:")
308                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SEMI_MAX_PAUSE)) << "ms\n"
309                 << STATS_DESCRIPTION_FORMAT("STWYoungGC min pause:")
310                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SEMI_MIN_PAUSE)) << "ms\n"
311                 << STATS_DESCRIPTION_FORMAT("STWYoungGC average pause:")
312                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SEMI_TOTAL_PAUSE) /
313                                      GetRecordData(RecordData::SEMI_COUNT)) << "ms\n"
314                 << STATS_DESCRIPTION_FORMAT("Young average copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
315                 << STATS_DESCRIPTION_FORMAT("Young average promoted rate:") << STATS_DATA_FORMAT(promotedRate) << "\n"
316                 << STATS_DESCRIPTION_FORMAT("Young average survival rate:") << STATS_DATA_FORMAT(survivalRate);
317             break;
318         }
319         case GCType::PARTIAL_YOUNG_GC: {
320             double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) /
321                                 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
322             double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) /
323                                   GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
324             double survivalRate =  std::min(copiedRate + promotedRate, 1.0);
325             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("YoungGC occurs count")
326                 << STATS_DATA_FORMAT(GetRecordData(RecordData::YOUNG_COUNT)) << "\n"
327                 << STATS_DESCRIPTION_FORMAT("YoungGC max pause:")
328                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE)) << "ms\n"
329                 << STATS_DESCRIPTION_FORMAT("YoungGC min pause:")
330                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE)) << "ms\n"
331                 << STATS_DESCRIPTION_FORMAT("YoungGC average pause:")
332                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_TOTAL_PAUSE) /
333                                      GetRecordData(RecordData::YOUNG_COUNT)) << "ms\n"
334                 << STATS_DESCRIPTION_FORMAT("Young average copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
335                 << STATS_DESCRIPTION_FORMAT("Young average promoted rate:") << STATS_DATA_FORMAT(promotedRate) << "\n"
336                 << STATS_DESCRIPTION_FORMAT("Young average survival rate:") << STATS_DATA_FORMAT(survivalRate);
337             break;
338         }
339         case GCType::PARTIAL_OLD_GC: {
340             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("OldGC occurs count")
341                 << STATS_DATA_FORMAT(GetRecordData(RecordData::OLD_COUNT)) << "\n"
342                 << STATS_DESCRIPTION_FORMAT("OldGC max pause:")
343                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_MAX_PAUSE)) << "ms\n"
344                 << STATS_DESCRIPTION_FORMAT("OldGC min pause:")
345                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_MIN_PAUSE)) << "ms\n"
346                 << STATS_DESCRIPTION_FORMAT("OldGC average pause:")
347                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_TOTAL_PAUSE) /
348                                      GetRecordData(RecordData::OLD_COUNT)) << "ms\n"
349                 << STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
350                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::OLD_TOTAL_ALIVE)) /
351                                      GetRecordData(RecordData::OLD_TOTAL_COMMIT));
352             break;
353         }
354         case GCType::COMPRESS_GC: {
355             LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("CompressGC occurs count")
356                 << STATS_DATA_FORMAT(GetRecordData(RecordData::COMPRESS_COUNT)) << "\n"
357                 << STATS_DESCRIPTION_FORMAT("CompressGC max pause:")
358                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE)) << "ms\n"
359                 << STATS_DESCRIPTION_FORMAT("CompressGC min pause:")
360                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE)) << "ms\n"
361                 << STATS_DESCRIPTION_FORMAT("CompressGC average pause:")
362                 << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_TOTAL_PAUSE) /
363                                      GetRecordData(RecordData::COMPRESS_COUNT)) << "ms\n"
364                 << STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
365                 << STATS_DATA_FORMAT(double(GetRecordData(RecordData::COMPRESS_TOTAL_ALIVE)) /
366                                      GetRecordData(RecordData::COMPRESS_TOTAL_COMMIT));
367             break;
368         }
369         default:
370             break;
371     }
372 }
373 
RecordStatisticBeforeGC(TriggerGCType gcType,GCReason reason)374 void GCStats::RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason)
375 {
376     SetRecordData(RecordData::START_OBJ_SIZE, heap_->GetHeapObjectSize());
377     SetRecordData(RecordData::START_COMMIT_SIZE, heap_->GetCommittedSize());
378     SetRecordData(RecordData::START_YOUNG_OBJ_SIZE, heap_->GetNewSpace()->GetHeapObjectSize());
379     SetRecordData(RecordData::START_NATIVE_POINTER_NUM, heap_->GetEcmaVM()->GetNativePointerListSize());
380     gcType_ = GetGCType(gcType);
381     reason_ = reason;
382 
383     switch (gcType_) {
384         case GCType::STW_YOUNG_GC: {
385             size_t semiCommitSize = heap_->GetNewSpace()->GetCommittedSize();
386             SetRecordData(RecordData::SEMI_COMMIT_SIZE, semiCommitSize);
387             IncreaseRecordData(RecordData::SEMI_TOTAL_COMMIT, semiCommitSize);
388             break;
389         }
390         case GCType::PARTIAL_YOUNG_GC: {
391             size_t youngCommitSize = heap_->GetNewSpace()->GetCommittedSize();
392             SetRecordData(RecordData::YOUNG_COMMIT_SIZE, youngCommitSize);
393             IncreaseRecordData(RecordData::YOUNG_TOTAL_COMMIT, youngCommitSize);
394             break;
395         }
396         case GCType::PARTIAL_OLD_GC: {
397             size_t oldCommitSize = heap_->GetCommittedSize();
398             SetRecordData(RecordData::OLD_COMMIT_SIZE, oldCommitSize);
399             IncreaseRecordData(RecordData::OLD_TOTAL_COMMIT, oldCommitSize);
400             break;
401         }
402         case GCType::COMPRESS_GC: {
403             size_t compressCommitSize = heap_->GetCommittedSize();
404             SetRecordData(RecordData::COMPRESS_COMMIT_SIZE, compressCommitSize);
405             IncreaseRecordData(RecordData::COMPRESS_TOTAL_COMMIT, compressCommitSize);
406             break;
407         }
408         default:
409             break;
410     }
411 }
412 
RecordStatisticAfterGC()413 void GCStats::RecordStatisticAfterGC()
414 {
415     SetRecordData(RecordData::END_OBJ_SIZE, heap_->GetHeapObjectSize());
416     SetRecordData(RecordData::END_COMMIT_SIZE, heap_->GetCommittedSize());
417 
418     float duration = scopeDuration_[Scope::ScopeId::TotalGC];
419     switch (gcType_) {
420         case GCType::STW_YOUNG_GC: {
421             if (GetRecordData(RecordData::SEMI_COUNT) == 0) {
422                 SetRecordDuration(RecordDuration::SEMI_MIN_PAUSE, duration);
423                 SetRecordDuration(RecordDuration::SEMI_MAX_PAUSE, duration);
424             } else {
425                 SetRecordDuration(RecordDuration::SEMI_MIN_PAUSE,
426                     std::min(GetRecordDuration(RecordDuration::SEMI_MIN_PAUSE), duration));
427                 SetRecordDuration(RecordDuration::SEMI_MAX_PAUSE,
428                     std::max(GetRecordDuration(RecordDuration::SEMI_MAX_PAUSE), duration));
429             }
430             IncreaseRecordData(RecordData::SEMI_COUNT);
431             IncreaseRecordDuration(RecordDuration::SEMI_TOTAL_PAUSE, duration);
432             size_t semiAliveSize = heap_->GetNewSpace()->GetHeapObjectSize();
433             SetRecordData(RecordData::SEMI_ALIVE_SIZE, semiAliveSize);
434             IncreaseRecordData(RecordData::SEMI_TOTAL_ALIVE, semiAliveSize);
435             size_t promotedSize = heap_->GetPromotedSize();
436             SetRecordData(RecordData::SEMI_PROMOTE_SIZE, promotedSize);
437             IncreaseRecordData(RecordData::SEMI_TOTAL_PROMOTE, promotedSize);
438             break;
439         }
440         case GCType::PARTIAL_YOUNG_GC: {
441             if (GetRecordData(RecordData::YOUNG_COUNT) == 0) {
442                 SetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE, duration);
443                 SetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE, duration);
444             } else {
445                 SetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE,
446                     std::min(GetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE), duration));
447                 SetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE,
448                     std::max(GetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE), duration));
449             }
450             IncreaseRecordData(RecordData::YOUNG_COUNT);
451             float concurrentMarkDuration = scopeDuration_[Scope::ScopeId::ConcurrentMark];
452             IncreaseRecordDuration(RecordDuration::YOUNG_TOTAL_PAUSE, duration + concurrentMarkDuration);
453             size_t youngAliveSize = heap_->GetNewSpace()->GetHeapObjectSize();
454             SetRecordData(RecordData::YOUNG_ALIVE_SIZE, youngAliveSize);
455             IncreaseRecordData(RecordData::YOUNG_TOTAL_ALIVE, youngAliveSize);
456             size_t promotedSize = heap_->GetPromotedSize();
457             SetRecordData(RecordData::YOUNG_PROMOTE_SIZE, promotedSize);
458             IncreaseRecordData(RecordData::YOUNG_TOTAL_PROMOTE, promotedSize);
459             break;
460         }
461         case GCType::PARTIAL_OLD_GC: {
462             if (GetRecordData(RecordData::OLD_COUNT) == 0) {
463                 SetRecordDuration(RecordDuration::OLD_MIN_PAUSE, duration);
464                 SetRecordDuration(RecordDuration::OLD_MAX_PAUSE, duration);
465             } else {
466                 SetRecordDuration(RecordDuration::OLD_MIN_PAUSE,
467                     std::min(GetRecordDuration(RecordDuration::OLD_MIN_PAUSE), duration));
468                 SetRecordDuration(RecordDuration::OLD_MAX_PAUSE,
469                     std::max(GetRecordDuration(RecordDuration::OLD_MAX_PAUSE), duration));
470             }
471             IncreaseRecordData(RecordData::OLD_COUNT);
472             float concurrentMarkDuration = scopeDuration_[Scope::ScopeId::ConcurrentMark];
473             IncreaseRecordDuration(RecordDuration::OLD_TOTAL_PAUSE, duration + concurrentMarkDuration);
474             size_t oldAliveSize = heap_->GetHeapObjectSize();
475             SetRecordData(RecordData::OLD_ALIVE_SIZE, oldAliveSize);
476             IncreaseRecordData(RecordData::OLD_TOTAL_ALIVE, oldAliveSize);
477             break;
478         }
479         case GCType::COMPRESS_GC: {
480             if (GetRecordData(RecordData::COMPRESS_COUNT) == 0) {
481                 SetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE, duration);
482                 SetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE, duration);
483             } else {
484                 SetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE,
485                     std::min(GetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE), duration));
486                 SetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE,
487                     std::max(GetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE), duration));
488             }
489             IncreaseRecordData(RecordData::COMPRESS_COUNT);
490             IncreaseRecordDuration(RecordDuration::COMPRESS_TOTAL_PAUSE, duration);
491             size_t compressAliveSize = heap_->GetHeapObjectSize();
492             SetRecordData(RecordData::COMPRESS_ALIVE_SIZE, compressAliveSize);
493             IncreaseRecordData(RecordData::COMPRESS_TOTAL_ALIVE, compressAliveSize);
494             break;
495         }
496         default:
497             break;
498     }
499     RecordGCSpeed();
500 }
501 
RecordGCSpeed()502 void GCStats::RecordGCSpeed()
503 {
504     double survivalRate = GetAvgSurvivalRate();
505     size_t clearNativeSpeed = GetRecordData(RecordData::START_NATIVE_POINTER_NUM) /
506                               scopeDuration_[Scope::ScopeId::ClearNativeObject];
507 
508     if (gcType_ == GCType::PARTIAL_YOUNG_GC) {
509         gcSpeed_[(uint8_t)SpeedData::MARK_SPEED] =
510             GetRecordData(RecordData::START_YOUNG_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Mark];
511         size_t evacuateSpeed = survivalRate * GetRecordData(RecordData::START_YOUNG_OBJ_SIZE) /
512                                scopeDuration_[Scope::ScopeId::EvacuateSpace];
513         gcSpeed_[(uint8_t)SpeedData::YOUNG_EVACUATE_SPACE_SPEED] =
514             (evacuateSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_EVACUATE_SPACE_SPEED]) / 2;  // 2 means half
515         gcSpeed_[(uint8_t)SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED] =
516             (clearNativeSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED]) / 2;  // 2 means half
517         size_t updateReferenceSpeed = GetRecordData(RecordData::START_OBJ_SIZE) /
518                                       scopeDuration_[Scope::ScopeId::UpdateReference];
519         gcSpeed_[(uint8_t)SpeedData::YOUNG_UPDATE_REFERENCE_SPEED] =
520             (updateReferenceSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_UPDATE_REFERENCE_SPEED]) / 2;  // 2 means half
521     } else if (gcType_ == GCType::PARTIAL_OLD_GC) {
522         gcSpeed_[(uint8_t)SpeedData::MARK_SPEED] =
523             GetRecordData(RecordData::START_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Mark];
524         size_t sweepSpeed = GetRecordData(RecordData::START_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Sweep];
525         gcSpeed_[(uint8_t)SpeedData::SWEEP_SPEED] =
526             (sweepSpeed + gcSpeed_[(uint8_t)SpeedData::SWEEP_SPEED]) / 2;  // 2 means half
527         gcSpeed_[(uint8_t)SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED] =
528             (clearNativeSpeed + gcSpeed_[(uint8_t)SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED]) / 2;  // 2 means half
529 
530         size_t evacuateSpaceSpeed = (survivalRate * GetRecordData(RecordData::START_YOUNG_OBJ_SIZE) +
531             GetRecordData(RecordData::COLLECT_REGION_SET_SIZE)) / scopeDuration_[Scope::ScopeId::EvacuateSpace];
532         gcSpeed_[(uint8_t)SpeedData::OLD_EVACUATE_SPACE_SPEED] =
533             (evacuateSpaceSpeed + gcSpeed_[(uint8_t)SpeedData::OLD_EVACUATE_SPACE_SPEED]) / 2;  // 2 means half
534 
535         size_t updateReferenceSpeed = GetRecordData(RecordData::START_OBJ_SIZE) /
536                                     scopeDuration_[Scope::ScopeId::UpdateReference];
537         gcSpeed_[(uint8_t)SpeedData::UPDATE_REFERENCE_SPEED] =
538             (updateReferenceSpeed + gcSpeed_[(uint8_t)SpeedData::UPDATE_REFERENCE_SPEED]) / 2;  // 2 means half
539     }
540 }
541 
GetGCType(TriggerGCType gcType)542 GCType GCStats::GetGCType(TriggerGCType gcType)
543 {
544     if (!heap_->GetJSThread()->IsReadyToMark()) {
545         return heap_->IsFullMark() ? GCType::PARTIAL_OLD_GC : GCType::PARTIAL_YOUNG_GC;
546     }
547     switch (gcType) {
548         case TriggerGCType::YOUNG_GC:
549             return GCType::PARTIAL_YOUNG_GC;
550         case TriggerGCType::OLD_GC:
551             return GCType::PARTIAL_OLD_GC;
552         case TriggerGCType::FULL_GC:
553             return GCType::COMPRESS_GC;
554         default:
555             return GCType::OTHER;
556     }
557 }
558 
InitializeRecordList()559 void GCStats::InitializeRecordList()
560 {
561     for (float &duration : scopeDuration_) {
562         duration = 0.0f;
563     }
564     for (int idx = 0; idx <= GetRecordDataIndex(RecordData::END_RECORD_OVERWRITE); idx++) {
565         recordData_[idx] = 0;
566     }
567     concurrentMark_ = false;
568 }
569 
CheckIfLongTimePause()570 bool GCStats::CheckIfLongTimePause()
571 {
572     if (scopeDuration_[Scope::ScopeId::TotalGC] > longPauseTime_) {
573         LOG_GC(INFO) << "Has checked a long time gc";
574         return true;
575     }
576     return false;
577 }
578 }  // namespace panda::ecmascript
579