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