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