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