* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/mem/gc_stats.h"
#include "ecmascript/mem/gc_key_stats.h"
#include "common_components/base/time_utils.h"
#include "ecmascript/mem/heap-inl.h"
constexpr int DESCRIPTION_LENGTH = 25;
constexpr int DATA_LENGTH = 8;
#define STATS_DESCRIPTION_FORMAT(description) \
std::left << std::setw(DESCRIPTION_LENGTH) << (description)
#define STATS_DATA_FORMAT(data) \
std::setw(DATA_LENGTH) << (data)
namespace panda::ecmascript {
namespace {
struct PauseRecord {
RecordData count;
RecordDuration minPause;
RecordDuration maxPause;
RecordDuration totalPause;
};
constexpr PauseRecord GC_STATISTIC_RECORDS[] = {
{RecordData::YOUNG_COUNT, RecordDuration::YOUNG_MIN_PAUSE, RecordDuration::YOUNG_MAX_PAUSE,
RecordDuration::YOUNG_TOTAL_PAUSE},
{RecordData::OLD_COUNT, RecordDuration::OLD_MIN_PAUSE, RecordDuration::OLD_MAX_PAUSE,
RecordDuration::OLD_TOTAL_PAUSE},
{RecordData::COMPRESS_COUNT, RecordDuration::COMPRESS_MIN_PAUSE, RecordDuration::COMPRESS_MAX_PAUSE,
RecordDuration::COMPRESS_TOTAL_PAUSE},
{RecordData::LOCAL_CC_COUNT, RecordDuration::LOCAL_CC_MIN_PAUSE, RecordDuration::LOCAL_CC_MAX_PAUSE,
RecordDuration::LOCAL_CC_TOTAL_PAUSE},
{RecordData::SHARED_COUNT, RecordDuration::SHARED_MIN_PAUSE, RecordDuration::SHARED_MAX_PAUSE,
RecordDuration::SHARED_TOTAL_PAUSE},
{RecordData::SWEEP_COUNT, RecordDuration::SWEEP_MIN_PAUSE, RecordDuration::SWEEP_MAX_PAUSE,
RecordDuration::SWEEP_TOTAL_PAUSE},
};
}
const char *GCStats::GetGCStatisticType(GCType type)
{
switch (type) {
case GCType::SHARED_GC:
case GCType::SHARED_PARTIAL_GC:
case GCType::SHARED_FULL_GC:
case GCType::GLOBAL_GC:
return "Shared GC";
case GCType::PARTIAL_YOUNG_GC:
case GCType::PARTIAL_OLD_GC:
case GCType::LOCAL_CC:
case GCType::COMPRESS_GC:
case GCType::CMS_GC:
case GCType::STICKY_CMS_GC:
return "Local GC";
default:
return "UnknownType";
}
}
void GCStats::RecordGCStatisticStart()
{
lastGCStartTime_ = common::TimeUtil::CurrentTimeInMs();
lastGCType_ = GetGCStatisticType(gcType_);
}
void GCStats::RecordGCStatisticEnd()
{
lastGCEndTime_ = common::TimeUtil::CurrentTimeInMs();
}
GCStatisticData GCStats::GetGCStatistic()
{
GCStatisticData stats;
for (const auto &record : GC_STATISTIC_RECORDS) {
size_t count = GetRecordData(record.count);
if (count == 0) {
continue;
}
stats.count += count;
stats.maxPause = std::max(stats.maxPause, GetRecordDuration(record.maxPause));
stats.totalPause += GetRecordDuration(record.totalPause);
float minPause = GetRecordDuration(record.minPause);
if (stats.minPause == 0.0f || minPause < stats.minPause) {
stats.minPause = minPause;
}
}
stats.lastStartTime = lastGCStartTime_;
stats.lastEndTime = lastGCEndTime_;
stats.lastType = lastGCType_;
return stats;
}
GCStatisticData GCStats::MergeGCStatistic(const GCStatisticData &localStats,
const GCStatisticData &sharedStats)
{
GCStatisticData merged;
merged.count = localStats.count + sharedStats.count;
merged.maxPause = std::max(localStats.maxPause, sharedStats.maxPause);
if (localStats.count == 0) {
merged.minPause = sharedStats.minPause;
} else if (sharedStats.count == 0) {
merged.minPause = localStats.minPause;
} else {
merged.minPause = std::min(localStats.minPause, sharedStats.minPause);
}
merged.totalPause = localStats.totalPause + sharedStats.totalPause;
if (localStats.lastStartTime >= sharedStats.lastStartTime) {
merged.lastStartTime = localStats.lastStartTime;
merged.lastType = localStats.lastType;
} else {
merged.lastStartTime = sharedStats.lastStartTime;
merged.lastType = sharedStats.lastType;
}
merged.lastEndTime = std::max(localStats.lastEndTime, sharedStats.lastEndTime);
return merged;
}
void GCStats::PrintStatisticResult()
{
LOG_GC(INFO) << "/******************* GCStats statistic: *******************/";
PrintGCSummaryStatistic(GCType::PARTIAL_YOUNG_GC);
PrintGCSummaryStatistic(GCType::PARTIAL_OLD_GC);
PrintGCSummaryStatistic(GCType::COMPRESS_GC);
PrintGCSummaryStatistic(GCType::LOCAL_CC);
PrintGCMemoryStatistic();
}
void GCStats::PrintGCStatistic()
{
ASSERT(heap_ != nullptr);
ASSERT(heap_->GetEcmaVM() != nullptr);
if (heap_->GetEcmaVM()->GetJSOptions().EnableGCTracer() || CheckIfLongTimePause()) {
LOG_GC(INFO) << " [ " << GetGCTypeName() << " ] "
<< sizeToMB(recordData_[(uint8_t)RecordData::START_OBJ_SIZE]) << " ("
<< sizeToMB(recordData_[(uint8_t)RecordData::START_COMMIT_SIZE]) << ") -> "
<< sizeToMB(recordData_[(uint8_t)RecordData::END_OBJ_SIZE]) << " ("
<< sizeToMB(recordData_[(uint8_t)RecordData::END_COMMIT_SIZE]) << ") MB, "
<< scopeDuration_[Scope::ScopeId::TotalGC] << "(+"
<< GetConcurrrentMarkDuration()
<< ")ms, GCReason: " << GCReasonToString()
<< ", MarkReason: " << MarkReasonToString();
if constexpr (G_USE_CMS_GC) {
LOG_GC(INFO) << "IsInBackground: " << Runtime::GetInstance()->IsInBackground() << "; "
<< "SensitiveStatus: " << static_cast<int>(heap_->GetSensitiveStatus()) << "; "
<< "StartupStatus: " << std::to_string(static_cast<int>(heap_->GetStartupStatus())) << "; "
<< "BundleName: " << heap_->GetEcmaVM()->GetBundleName()
<< "; SlotSpace: " << std::to_string(heap_->GetSlotSpace()->GetCommittedSize())
<< "; TotalCommit" << std::to_string(heap_->GetCommittedSize());
} else {
LOG_GC(INFO) << "IsInBackground: " << Runtime::GetInstance()->IsInBackground() << "; "
<< "SensitiveStatus: " << static_cast<int>(heap_->GetSensitiveStatus()) << "; "
<< "StartupStatus: " << std::to_string(static_cast<int>(heap_->GetStartupStatus())) << "; "
<< "BundleName: " << heap_->GetEcmaVM()->GetBundleName()
<< "; Young: " << std::to_string(heap_->GetNewSpace()->GetCommittedSize())
<< "; Old: " << std::to_string(heap_->GetOldSpace()->GetCommittedSize())
<< "; TotalCommit" << std::to_string(heap_->GetCommittedSize());
}
PrintVerboseGCStatistic();
}
GCFinishTrace();
InitializeRecordList();
}
const char *GCStats::GCReasonToString()
{
return GCReasonToString(gcReason_);
}
const char *GCStats::GCReasonToString(GCReason reason)
{
switch (reason) {
case GCReason::ALLOCATION_LIMIT:
return "Memory reach limit";
case GCReason::ALLOCATION_FAILED:
return "Allocate object failed";
case GCReason::IDLE:
return "Idle time task";
case GCReason::SWITCH_BACKGROUND:
return "Switch to background";
case GCReason::EXTERNAL_TRIGGER:
return "Externally triggered";
case GCReason::WORKER_DESTRUCTION:
return "Worker Destruction";
case GCReason::TRIGGER_BY_JS:
return "Trigger by JS";
case GCReason::HINT_GC:
return "Trigger by hint";
case GCReason::NATIVE_LIMIT:
return "Native reach limit";
case GCReason::SHARED_LIMIT:
return "Shared reach limit";
case GCReason::IDLE_NATIVE:
return "Idle time task by native";
case GCReason::HANDLE_MARKING_FINISHED:
return "ConcurrentMark finished";
case GCReason::TRIGGER_BY_ARKUI:
return "Trigger by ArkUI";
case GCReason::TRIGGER_BY_ABILITY:
return "Trigger by AbilityRuntime";
case GCReason::TRIGGER_BY_MEM_TOOLS:
return "Trigger by Mem tools";
case GCReason::TRIGGER_BY_TASKPOOL:
return "Trigger by taskPool";
default:
return "Other";
}
}
const char *GCStats::MarkReasonToString()
{
return concurrentMark_ ? MarkReasonToString(markReason_) : "Not ConcurrentMark";
}
const char *GCStats::MarkReasonToString(MarkReason reason)
{
switch (reason) {
case MarkReason::ALLOCATION_LIMIT:
return "Memory reach limit";
case MarkReason::OLD_GC_WITHOUT_FULLMARK:
return "OldGC without concurrent full mark";
case MarkReason::IDLE:
return "Idle time task";
case MarkReason::EXIT_HIGH_SENSITIVE:
return "Exit high sensitive";
case MarkReason::EXTERNAL_TRIGGER:
return "Externally triggered";
case MarkReason::WORKER_DESTRUCTION:
return "Worker Destruction";
case MarkReason::TRIGGER_BY_JS:
return "Trigger by JS";
case MarkReason::HINT_GC:
return "Trigger by hint";
case MarkReason::NATIVE_LIMIT:
return "Native reach limit";
case MarkReason::SHARED_LIMIT:
return "Shared reach limit";
case MarkReason::EXIT_SERIALIZE:
return "Exit serialize";
default:
return "Other";
}
}
float GCStats::GetConcurrrentMarkDuration()
{
return concurrentMark_ ? scopeDuration_[Scope::ScopeId::ConcurrentMark] : 0;
}
void GCStats::PrintVerboseGCStatistic()
{
PrintGCDurationStatistic();
PrintGCMemoryStatistic();
PrintGCSummaryStatistic();
}
void GCStats::GCFinishTrace()
{
ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK,
("PartialGC::Finish" + std::to_string(heap_->IsConcurrentFullMark())
+ ";Reason" + std::to_string(static_cast<int>(gcReason_))
+ ";Sensitive" + std::to_string(static_cast<int>(heap_->GetSensitiveStatus()))
+ ";IsInBackground" + std::to_string(Runtime::GetInstance()->IsInBackground())
+ ";Startup" + std::to_string(heap_->OnStartupEvent())
+ ";ConMark" + std::to_string(static_cast<int>(heap_->GetJSThread()->GetMarkStatus()))
#if USE_CMS_GC
+ ";Slot" + std::to_string(heap_->GetSlotSpace()->GetCommittedSize())
#else
+ ";Young" + std::to_string(heap_->GetNewSpace()->GetCommittedSize())
+ ";Old" + std::to_string(heap_->GetOldSpace()->GetCommittedSize())
#endif
+ ";TotalCommit" + std::to_string(heap_->GetCommittedSize())
+ ";NativeBindingSize" + std::to_string(heap_->GetNativeBindingSize())
+ ";NativeLimitSize" + std::to_string(heap_->GetGlobalSpaceNativeLimit())).c_str(), "");
}
void GCStats::PrintGCMemoryStatistic()
{
NativeAreaAllocator *nativeAreaAllocator = heap_->GetNativeAreaAllocator();
HeapRegionAllocator *heapRegionAllocator = heap_->GetHeapRegionAllocator();
LOG_GC(INFO) << "/****************** GC Memory statistic: *****************/";
LOG_GC(INFO) << "AllSpaces used:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetCommittedSize())) << "KB\n"
#if USE_CMS_GC
<< "SlotSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetSlotSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetSlotSpace()->GetCommittedSize())) << "KB\n"
#else
<< "ActiveSemiSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetNewSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetNewSpace()->GetCommittedSize())) << "KB\n"
<< "OldSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetOldSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetOldSpace()->GetCommittedSize())) << "KB\n"
#endif
<< "HugeObjectSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeObjectSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n"
<< "NonMovableSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetNonMovableSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetNonMovableSpace()->GetCommittedSize())) << "KB\n"
<< "AppSpawnSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetAppSpawnSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetAppSpawnSpace()->GetCommittedSize())) << "KB";
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Anno memory usage size:")
<< STATS_DATA_FORMAT(sizeToMB(heapRegionAllocator->GetAnnoMemoryUsage())) << "MB\n"
<< STATS_DESCRIPTION_FORMAT("Native memory usage size:")
<< STATS_DATA_FORMAT(sizeToMB(nativeAreaAllocator->GetNativeMemoryUsage())) << "MB\n"
<< STATS_DESCRIPTION_FORMAT("NativeBindingSize:")
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeBindingSize())) << "KB\n"
<< STATS_DESCRIPTION_FORMAT("NativeLimitSize:")
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetGlobalSpaceNativeLimit())) << "KB\n"
<< STATS_DESCRIPTION_FORMAT("ArrayBufferNativeSize:")
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeAreaAllocator()->GetArrayBufferNativeSize()))
<< "KB\n"
<< STATS_DESCRIPTION_FORMAT("ChunkNativeSize:")
<< STATS_DATA_FORMAT(sizeToKB(heap_->GetNativeAreaAllocator()->GetChunkNativeSize())) << "KB";
switch (gcType_) {
case GCType::PARTIAL_YOUNG_GC: {
double copiedRate = double(GetRecordData(RecordData::YOUNG_ALIVE_SIZE)) /
GetRecordData(RecordData::YOUNG_COMMIT_SIZE);
double premotedRate = double(GetRecordData(RecordData::YOUNG_PROMOTE_SIZE)) /
GetRecordData(RecordData::YOUNG_COMMIT_SIZE);
double survivalRate = std::min(copiedRate + premotedRate, 1.0);
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Young copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
<< STATS_DESCRIPTION_FORMAT("Young promoted rate:") << STATS_DATA_FORMAT(premotedRate) << "\n"
<< STATS_DESCRIPTION_FORMAT("Young survival rate:") << STATS_DATA_FORMAT(survivalRate);
break;
}
case GCType::PARTIAL_OLD_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::OLD_ALIVE_SIZE)) /
GetRecordData(RecordData::OLD_COMMIT_SIZE));
break;
}
case GCType::COMPRESS_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::COMPRESS_ALIVE_SIZE)) /
GetRecordData(RecordData::COMPRESS_COMMIT_SIZE));
break;
}
case GCType::STICKY_CMS_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::SWEEP_ALIVE_SIZE)) /
GetRecordData(RecordData::SWEEP_COMMIT_SIZE));
break;
}
case GCType::CMS_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::SWEEP_ALIVE_SIZE)) /
GetRecordData(RecordData::SWEEP_COMMIT_SIZE));
break;
}
default:
break;
}
}
void GCStats::PrintGCDurationStatistic()
{
LOG_GC(INFO) << "/***************** GC Duration statistic: ****************/";
switch (gcType_) {
case GCType::PARTIAL_YOUNG_GC:
case GCType::PARTIAL_OLD_GC:
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Initialize:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Mark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("MarkRoots:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ConcurrentMark pause:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ConcurrentMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("WaitConcurrentMarkFinish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitConcurrentMarkFinished]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ReMark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ReMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ProcessSharedGCRSetWorkList:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessSharedGCRSetWorkList]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Sweep:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ClearNativeObject:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ClearNativeObject]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Evacuate:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Evacuate]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("UpdateReference:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateReference]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("UpdateWeekRef:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateWeekRef]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("UpdateRoot:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateRoot]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ProceeWorkload:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProceeWorkload]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("EvacuateSpace:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::EvacuateSpace]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("EvacuateRegion:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::EvacuateRegion]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("WaitFinish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitFinish]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Finish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
break;
case GCType::COMPRESS_GC:
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ProcessSharedGCRSetWorkList:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessSharedGCRSetWorkList]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Initialize:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Mark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("MarkRoots:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Sweep:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Finish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
break;
case GCType::STICKY_CMS_GC:
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Initialize:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Mark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("MarkRoots:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ConcurrentMark pause:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ConcurrentMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("WaitConcurrentMarkFinish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitConcurrentMarkFinished]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ReMark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ReMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ProcessSharedGCRSetWorkList:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessSharedGCRSetWorkList]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Sweep:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ClearNativeObject:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ClearNativeObject]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ClearDeadReferences:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ClearDeadReferences]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("WaitFinish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitFinish]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Finish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
case GCType::CMS_GC:
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Initialize:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Mark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("MarkRoots:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ConcurrentMark pause:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ConcurrentMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("WaitConcurrentMarkFinish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitConcurrentMarkFinished]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ReMark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ReMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ProcessSharedGCRSetWorkList:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessSharedGCRSetWorkList]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Sweep:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ClearNativeObject:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ClearNativeObject]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ClearDeadReferences:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ClearDeadReferences]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("WaitFinish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitFinish]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Finish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms";
break;
case GCType::LOCAL_CC:
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ConcurrentMark pause:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ConcurrentMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("WaitConcurrentMarkFinish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::WaitConcurrentMarkFinished]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ReMark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ReMark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("MarkRoots:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::MarkRoots]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ProcessSharedGCRSetWorkList:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ProcessSharedGCRSetWorkList]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("UpdateWeakRef:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateWeekRef]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("UpdateRoot:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateRoot]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Sweep:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms";
break;
default:
break;
}
}
bool GCStats::CheckIfNeedPrint(GCType type)
{
uint32_t gcCount = 0;
switch (type) {
case GCType::PARTIAL_YOUNG_GC:
gcCount = GetRecordData(RecordData::YOUNG_COUNT);
break;
case GCType::PARTIAL_OLD_GC:
gcCount = GetRecordData(RecordData::OLD_COUNT);
break;
case GCType::COMPRESS_GC:
gcCount = GetRecordData(RecordData::COMPRESS_COUNT);
break;
case GCType::LOCAL_CC:
gcCount = GetRecordData(RecordData::LOCAL_CC_COUNT);
break;
default:
break;
}
if (gcCount > 0) {
return true;
}
return false;
}
void GCStats::PrintGCSummaryStatistic(GCType type)
{
if (type != GCType::START && !CheckIfNeedPrint(type)) {
return;
} else {
type = type == GCType::START ? gcType_ : type;
}
LOG_GC(INFO) << "/***************** GC summary statistic: *****************/";
switch (type) {
case GCType::PARTIAL_YOUNG_GC: {
double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) /
GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) /
GetRecordData(RecordData::YOUNG_TOTAL_COMMIT);
double survivalRate = std::min(copiedRate + promotedRate, 1.0);
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("YoungGC occurs count")
<< STATS_DATA_FORMAT(GetRecordData(RecordData::YOUNG_COUNT)) << "\n"
<< STATS_DESCRIPTION_FORMAT("YoungGC max pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("YoungGC min pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("YoungGC average pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::YOUNG_TOTAL_PAUSE) /
GetRecordData(RecordData::YOUNG_COUNT)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Young average copied rate:") << STATS_DATA_FORMAT(copiedRate) << "\n"
<< STATS_DESCRIPTION_FORMAT("Young average promoted rate:") << STATS_DATA_FORMAT(promotedRate) << "\n"
<< STATS_DESCRIPTION_FORMAT("Young average survival rate:") << STATS_DATA_FORMAT(survivalRate);
break;
}
case GCType::PARTIAL_OLD_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("OldGC occurs count")
<< STATS_DATA_FORMAT(GetRecordData(RecordData::OLD_COUNT)) << "\n"
<< STATS_DESCRIPTION_FORMAT("OldGC max pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_MAX_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("OldGC min pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_MIN_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("OldGC average pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::OLD_TOTAL_PAUSE) /
GetRecordData(RecordData::OLD_COUNT)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::OLD_TOTAL_ALIVE)) /
GetRecordData(RecordData::OLD_TOTAL_COMMIT));
break;
}
case GCType::COMPRESS_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("CompressGC occurs count")
<< STATS_DATA_FORMAT(GetRecordData(RecordData::COMPRESS_COUNT)) << "\n"
<< STATS_DESCRIPTION_FORMAT("CompressGC max pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("CompressGC min pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("CompressGC average pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::COMPRESS_TOTAL_PAUSE) /
GetRecordData(RecordData::COMPRESS_COUNT)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::COMPRESS_TOTAL_ALIVE)) /
GetRecordData(RecordData::COMPRESS_TOTAL_COMMIT));
break;
}
case GCType::STICKY_CMS_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("StickySweepGC occurs count")
<< STATS_DATA_FORMAT(GetRecordData(RecordData::SWEEP_COUNT)) << "\n"
<< STATS_DESCRIPTION_FORMAT("StickySweepGC max pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("StickySweepGC min pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("StickySweepGC average pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SWEEP_TOTAL_PAUSE) /
GetRecordData(RecordData::SWEEP_COUNT)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::SWEEP_TOTAL_ALIVE)) /
GetRecordData(RecordData::SWEEP_TOTAL_COMMIT));
break;
}
case GCType::CMS_GC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("SweepGC occurs count")
<< STATS_DATA_FORMAT(GetRecordData(RecordData::SWEEP_COUNT)) << "\n"
<< STATS_DESCRIPTION_FORMAT("SweepGC max pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("SweepGC min pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("SweepGC average pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SWEEP_TOTAL_PAUSE) /
GetRecordData(RecordData::SWEEP_COUNT)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Heap average alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::SWEEP_TOTAL_ALIVE)) /
GetRecordData(RecordData::SWEEP_TOTAL_COMMIT));
break;
}
case GCType::LOCAL_CC: {
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("LOCALCC occurs count")
<< STATS_DATA_FORMAT(GetRecordData(RecordData::LOCAL_CC_COUNT)) << "\n"
<< STATS_DESCRIPTION_FORMAT("LOCALCC max pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::LOCAL_CC_MAX_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("LOCALCC min pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::LOCAL_CC_MIN_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("LOCALCC average pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::LOCAL_CC_TOTAL_PAUSE) /
GetRecordData(RecordData::LOCAL_CC_COUNT)) << "ms";
break;
}
default:
break;
}
}
size_t GCStats::GetAccumulatedAllocateSize()
{
return accumulatedFreeSize_ + heap_->GetHeapObjectSize();
}
void GCStats::RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason)
{
SetRecordData(RecordData::START_OBJ_SIZE, heap_->GetHeapObjectSize());
SetRecordData(RecordData::START_COMMIT_SIZE, heap_->GetCommittedSize());
if constexpr (!G_USE_CMS_GC) {
SetRecordData(RecordData::START_YOUNG_OBJ_SIZE, heap_->GetNewSpace()->GetHeapObjectSize());
}
SetRecordData(RecordData::START_NATIVE_POINTER_NUM, heap_->GetNativePointerListSize());
gcType_ = GetGCType(gcType);
gcReason_ = reason;
switch (gcType_) {
case GCType::PARTIAL_YOUNG_GC: {
size_t youngCommitSize = heap_->GetNewSpace()->GetCommittedSize();
SetRecordData(RecordData::YOUNG_COMMIT_SIZE, youngCommitSize);
IncreaseRecordData(RecordData::YOUNG_TOTAL_COMMIT, youngCommitSize);
break;
}
case GCType::PARTIAL_OLD_GC: {
size_t oldCommitSize = heap_->GetCommittedSize();
SetRecordData(RecordData::OLD_COMMIT_SIZE, oldCommitSize);
IncreaseRecordData(RecordData::OLD_TOTAL_COMMIT, oldCommitSize);
break;
}
case GCType::COMPRESS_GC: {
size_t compressCommitSize = heap_->GetCommittedSize();
SetRecordData(RecordData::COMPRESS_COMMIT_SIZE, compressCommitSize);
IncreaseRecordData(RecordData::COMPRESS_TOTAL_COMMIT, compressCommitSize);
break;
}
case GCType::STICKY_CMS_GC: {
size_t sweepCommitSize = heap_->GetCommittedSize();
SetRecordData(RecordData::SWEEP_COMMIT_SIZE, sweepCommitSize);
IncreaseRecordData(RecordData::SWEEP_TOTAL_COMMIT, sweepCommitSize);
break;
}
case GCType::CMS_GC: {
size_t sweepCommitSize = heap_->GetCommittedSize();
SetRecordData(RecordData::SWEEP_COMMIT_SIZE, sweepCommitSize);
IncreaseRecordData(RecordData::SWEEP_TOTAL_COMMIT, sweepCommitSize);
break;
}
default:
break;
}
ProcessBeforeLongGCStats();
RecordGCStatisticStart();
}
void GCStats::RecordStatisticAfterGC()
{
ASSERT(heap_ != nullptr);
SetRecordData(RecordData::END_OBJ_SIZE, heap_->GetHeapObjectSize());
SetRecordData(RecordData::END_COMMIT_SIZE, heap_->GetCommittedSize());
float duration = scopeDuration_[Scope::ScopeId::TotalGC];
switch (gcType_) {
case GCType::PARTIAL_YOUNG_GC: {
if (GetRecordData(RecordData::YOUNG_COUNT) == 0) {
SetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE, duration);
SetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE, duration);
} else {
SetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE,
std::min(GetRecordDuration(RecordDuration::YOUNG_MIN_PAUSE), duration));
SetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE,
std::max(GetRecordDuration(RecordDuration::YOUNG_MAX_PAUSE), duration));
}
IncreaseRecordData(RecordData::YOUNG_COUNT);
IncreaseRecordDuration(RecordDuration::YOUNG_TOTAL_PAUSE, duration);
size_t youngAliveSize = heap_->GetNewSpace()->GetHeapObjectSize();
SetRecordData(RecordData::YOUNG_ALIVE_SIZE, youngAliveSize);
IncreaseRecordData(RecordData::YOUNG_TOTAL_ALIVE, youngAliveSize);
size_t promotedSize = heap_->GetPromotedSize();
SetRecordData(RecordData::YOUNG_PROMOTE_SIZE, promotedSize);
IncreaseRecordData(RecordData::YOUNG_TOTAL_PROMOTE, promotedSize);
break;
}
case GCType::PARTIAL_OLD_GC: {
if (GetRecordData(RecordData::OLD_COUNT) == 0) {
SetRecordDuration(RecordDuration::OLD_MIN_PAUSE, duration);
SetRecordDuration(RecordDuration::OLD_MAX_PAUSE, duration);
} else {
SetRecordDuration(RecordDuration::OLD_MIN_PAUSE,
std::min(GetRecordDuration(RecordDuration::OLD_MIN_PAUSE), duration));
SetRecordDuration(RecordDuration::OLD_MAX_PAUSE,
std::max(GetRecordDuration(RecordDuration::OLD_MAX_PAUSE), duration));
}
IncreaseRecordData(RecordData::OLD_COUNT);
IncreaseRecordDuration(RecordDuration::OLD_TOTAL_PAUSE, duration);
size_t oldAliveSize = heap_->GetHeapObjectSize();
SetRecordData(RecordData::OLD_ALIVE_SIZE, oldAliveSize);
IncreaseRecordData(RecordData::OLD_TOTAL_ALIVE, oldAliveSize);
break;
}
case GCType::COMPRESS_GC: {
if (GetRecordData(RecordData::COMPRESS_COUNT) == 0) {
SetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE, duration);
SetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE, duration);
} else {
SetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE,
std::min(GetRecordDuration(RecordDuration::COMPRESS_MIN_PAUSE), duration));
SetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE,
std::max(GetRecordDuration(RecordDuration::COMPRESS_MAX_PAUSE), duration));
}
IncreaseRecordData(RecordData::COMPRESS_COUNT);
IncreaseRecordDuration(RecordDuration::COMPRESS_TOTAL_PAUSE, duration);
size_t compressAliveSize = heap_->GetHeapObjectSize();
SetRecordData(RecordData::COMPRESS_ALIVE_SIZE, compressAliveSize);
IncreaseRecordData(RecordData::COMPRESS_TOTAL_ALIVE, compressAliveSize);
break;
}
case GCType::STICKY_CMS_GC: {
if (GetRecordData(RecordData::SWEEP_COUNT) == 0) {
SetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE, duration);
SetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE, duration);
} else {
SetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE,
std::min(GetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE), duration));
SetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE,
std::max(GetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE), duration));
}
IncreaseRecordData(RecordData::SWEEP_COUNT);
IncreaseRecordDuration(RecordDuration::SWEEP_TOTAL_PAUSE, duration);
size_t sweepAliveSize = heap_->GetHeapObjectSize();
SetRecordData(RecordData::SWEEP_ALIVE_SIZE, sweepAliveSize);
IncreaseRecordData(RecordData::SWEEP_TOTAL_ALIVE, sweepAliveSize);
break;
}
case GCType::CMS_GC: {
if (GetRecordData(RecordData::SWEEP_COUNT) == 0) {
SetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE, duration);
SetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE, duration);
} else {
SetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE,
std::min(GetRecordDuration(RecordDuration::SWEEP_MIN_PAUSE), duration));
SetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE,
std::max(GetRecordDuration(RecordDuration::SWEEP_MAX_PAUSE), duration));
}
IncreaseRecordData(RecordData::SWEEP_COUNT);
IncreaseRecordDuration(RecordDuration::SWEEP_TOTAL_PAUSE, duration);
size_t sweepAliveSize = heap_->GetHeapObjectSize();
SetRecordData(RecordData::SWEEP_ALIVE_SIZE, sweepAliveSize);
IncreaseRecordData(RecordData::SWEEP_TOTAL_ALIVE, sweepAliveSize);
break;
}
case GCType::LOCAL_CC: {
if (GetRecordData(RecordData::LOCAL_CC_COUNT) == 0) {
SetRecordDuration(RecordDuration::LOCAL_CC_MIN_PAUSE, duration);
SetRecordDuration(RecordDuration::LOCAL_CC_MAX_PAUSE, duration);
} else {
SetRecordDuration(RecordDuration::LOCAL_CC_MIN_PAUSE,
std::min(GetRecordDuration(RecordDuration::LOCAL_CC_MIN_PAUSE), duration));
SetRecordDuration(RecordDuration::LOCAL_CC_MAX_PAUSE,
std::max(GetRecordDuration(RecordDuration::LOCAL_CC_MAX_PAUSE), duration));
}
IncreaseRecordData(RecordData::LOCAL_CC_COUNT);
IncreaseRecordDuration(RecordDuration::LOCAL_CC_TOTAL_PAUSE, duration);
break;
}
default:
break;
}
RecordGCSpeed();
if (gcType_ == GCType::COMPRESS_GC && scopeDuration_[Scope::ScopeId::TotalGC] > longPauseTime_) {
IncreaseFullGCLongTimeCount();
}
IncreaseTotalDuration(scopeDuration_[Scope::ScopeId::TotalGC]);
IncreaseAccumulatedFreeSize(GetRecordData(RecordData::START_OBJ_SIZE) -
GetRecordData(RecordData::END_OBJ_SIZE));
ProcessAfterLongGCStats();
RecordGCStatisticEnd();
}
void GCStats::ProcessAfterLongGCStats()
{
LongGCStats *longGCStats = GetLongGCStats();
float gcTotalTime = GetScopeDuration(GCStats::Scope::ScopeId::TotalGC);
if (IsLongGC(gcReason_, heap_->InSensitiveStatus(), Runtime::GetInstance()->IsInBackground(), gcTotalTime)) {
longGCStats->SetGCType(static_cast<int>(gcType_));
longGCStats->SetGCReason(static_cast<int>(gcReason_));
longGCStats->SetMarkReason(static_cast<int>(markReason_));
longGCStats->SetGCIsSensitive(heap_->InSensitiveStatus());
longGCStats->SetGCIsInBackground(Runtime::GetInstance()->IsInBackground());
longGCStats->SetGCTotalTime(gcTotalTime);
longGCStats->SetGCMarkTime(GetScopeDuration(GCStats::Scope::ScopeId::Mark));
longGCStats->SetGCEvacuateTime(GetScopeDuration(GCStats::Scope::ScopeId::Evacuate));
longGCStats->SetGCUpdateRootTime(GetScopeDuration(GCStats::Scope::ScopeId::UpdateRoot));
longGCStats->SetGCUpdateWeekRefTime(GetScopeDuration(GCStats::Scope::ScopeId::UpdateWeekRef));
longGCStats->SetGCUpdateReferenceTime(GetScopeDuration(GCStats::Scope::ScopeId::UpdateReference));
longGCStats->SetGCSweepNewToOldTime(GetScopeDuration(GCStats::Scope::ScopeId::SweepNewToOldRegions));
longGCStats->SetGCFinalizeTime(GetScopeDuration(GCStats::Scope::ScopeId::Finalize));
longGCStats->SetGCInvokeCallbackTime(GetScopeDuration(GCStats::Scope::ScopeId::InvokeNativeFinalizeCallbacks));
longGCStats->SetAfterGCTotalMemUsed(heap_->GetHeapObjectSize());
longGCStats->SetAfterGCTotalMemCommitted(heap_->GetCommittedSize());
if constexpr (G_USE_CMS_GC) {
longGCStats->SetAfterGCSlotSpaceMemUsed(heap_->GetSlotSpace()->GetHeapObjectSize());
longGCStats->SetAfterGCSlotSpaceMemCommitted(heap_->GetSlotSpace()->GetCommittedSize());
} else {
longGCStats->SetAfterGCActiveMemUsed(heap_->GetNewSpace()->GetHeapObjectSize());
longGCStats->SetAfterGCActiveMemCommitted(heap_->GetNewSpace()->GetCommittedSize());
longGCStats->SetAfterGCOldMemUsed(heap_->GetOldSpace()->GetHeapObjectSize());
longGCStats->SetAfterGCOldMemCommitted(heap_->GetOldSpace()->GetCommittedSize());
}
longGCStats->SetAfterGCHugeMemUsed(heap_->GetHugeObjectSpace()->GetHeapObjectSize());
longGCStats->SetAfterGCHugeMemCommitted(heap_->GetHugeObjectSpace()->GetCommittedSize());
longGCStats->SetAfterGCNativeBindingSize(heap_->GetNativeBindingSize());
longGCStats->SetAfterGCNativeLimit(heap_->GetGlobalSpaceNativeLimit());
}
}
void GCStats::ProcessBeforeLongGCStats()
{
LongGCStats *longGCStats = GetLongGCStats();
longGCStats->SetBeforeGCTotalMemUsed(heap_->GetHeapObjectSize());
longGCStats->SetBeforeGCTotalMemCommitted(heap_->GetCommittedSize());
if constexpr (G_USE_CMS_GC) {
longGCStats->SetBeforeGCSlotSpaceMemUsed(heap_->GetSlotSpace()->GetHeapObjectSize());
longGCStats->SetBeforeGCSlotSpaceMemCommitted(heap_->GetSlotSpace()->GetCommittedSize());
} else {
longGCStats->SetBeforeGCActiveMemUsed(heap_->GetNewSpace()->GetHeapObjectSize());
longGCStats->SetBeforeGCActiveMemCommitted(heap_->GetNewSpace()->GetCommittedSize());
longGCStats->SetBeforeGCOldMemUsed(heap_->GetOldSpace()->GetHeapObjectSize());
longGCStats->SetBeforeGCOldMemCommitted(heap_->GetOldSpace()->GetCommittedSize());
}
longGCStats->SetBeforeGCHugeMemUsed(heap_->GetHugeObjectSpace()->GetHeapObjectSize());
longGCStats->SetBeforeGCHugeMemCommitted(heap_->GetHugeObjectSpace()->GetCommittedSize());
longGCStats->SetBeforeGCNativeBindingSize(heap_->GetNativeBindingSize());
longGCStats->SetBeforeGCNativeLimit(heap_->GetGlobalSpaceNativeLimit());
}
| The Judgment criteria of Long GC
| IsInBackground | IsSensitive or Idle | GCTime |
| -----------------| ---------------------|---------|
| false | Sensitive | 33 |
| false | !Sensitive & !Idle | 33 |
| true | Idle | 200 |
| true | !Idle | 200 |
| true | Idle | 500 |
*/
bool GCStats::IsLongGC(GCReason gcReason, bool gcIsSensitive, bool gcIsInBackground, float gcTotalTime)
{
if (gcIsSensitive) {
if (gcTotalTime > GCKeyStats::GC_SENSITIVE_LONG_TIME) {
return true;
}
} else {
if (GCKeyStats::IsIdle(gcReason)) {
if (!gcIsInBackground && gcTotalTime > GCKeyStats::GC_IDLE_LONG_TIME) {
return true;
} else if (gcIsInBackground && gcTotalTime > GCKeyStats::GC_BACKGROUD_IDLE_LONG_TIME) {
return true;
}
} else {
if (!gcIsInBackground && gcTotalTime > GCKeyStats::GC_NOT_SENSITIVE_LONG_TIME) {
return true;
} else if (gcIsInBackground && gcTotalTime > GCKeyStats::GC_BACKGROUD_LONG_TIME) {
return true;
}
}
}
return false;
}
void GCStats::RecordGCSpeed()
{
double survivalRate = GetAvgSurvivalRate();
size_t clearNativeSpeed = GetRecordData(RecordData::START_NATIVE_POINTER_NUM) /
scopeDuration_[Scope::ScopeId::ClearNativeObject];
if (gcType_ == GCType::PARTIAL_YOUNG_GC) {
size_t objSize = GetRecordData(RecordData::START_YOUNG_OBJ_SIZE);
gcSpeed_[(uint8_t)SpeedData::MARK_SPEED] = objSize / scopeDuration_[Scope::ScopeId::Mark];
size_t evacuateSpeed = survivalRate * objSize / scopeDuration_[Scope::ScopeId::EvacuateSpace];
gcSpeed_[(uint8_t)SpeedData::YOUNG_EVACUATE_SPACE_SPEED] =
(evacuateSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_EVACUATE_SPACE_SPEED]) / 2;
gcSpeed_[(uint8_t)SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED] =
(clearNativeSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED]) / 2;
size_t updateReferenceSpeed = GetRecordData(RecordData::START_OBJ_SIZE) /
scopeDuration_[Scope::ScopeId::UpdateReference];
gcSpeed_[(uint8_t)SpeedData::YOUNG_UPDATE_REFERENCE_SPEED] =
(updateReferenceSpeed + gcSpeed_[(uint8_t)SpeedData::YOUNG_UPDATE_REFERENCE_SPEED]) / 2;
} else if (gcType_ == GCType::PARTIAL_OLD_GC) {
gcSpeed_[(uint8_t)SpeedData::MARK_SPEED] =
GetRecordData(RecordData::START_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Mark];
size_t sweepSpeed = GetRecordData(RecordData::START_OBJ_SIZE) / scopeDuration_[Scope::ScopeId::Sweep];
gcSpeed_[(uint8_t)SpeedData::SWEEP_SPEED] =
(sweepSpeed + gcSpeed_[(uint8_t)SpeedData::SWEEP_SPEED]) / 2;
gcSpeed_[(uint8_t)SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED] =
(clearNativeSpeed + gcSpeed_[(uint8_t)SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED]) / 2;
size_t evacuateSpaceSpeed = (survivalRate * GetRecordData(RecordData::START_YOUNG_OBJ_SIZE) +
GetRecordData(RecordData::COLLECT_REGION_SET_SIZE)) / scopeDuration_[Scope::ScopeId::EvacuateSpace];
gcSpeed_[(uint8_t)SpeedData::OLD_EVACUATE_SPACE_SPEED] =
(evacuateSpaceSpeed + gcSpeed_[(uint8_t)SpeedData::OLD_EVACUATE_SPACE_SPEED]) / 2;
size_t updateReferenceSpeed = GetRecordData(RecordData::START_OBJ_SIZE) /
scopeDuration_[Scope::ScopeId::UpdateReference];
gcSpeed_[(uint8_t)SpeedData::UPDATE_REFERENCE_SPEED] =
(updateReferenceSpeed + gcSpeed_[(uint8_t)SpeedData::UPDATE_REFERENCE_SPEED]) / 2;
}
}
GCType GCStats::GetGCType(TriggerGCType gcType)
{
switch (gcType) {
case TriggerGCType::YOUNG_GC:
return GCType::PARTIAL_YOUNG_GC;
case TriggerGCType::OLD_GC:
return GCType::PARTIAL_OLD_GC;
case TriggerGCType::FULL_GC:
return GCType::COMPRESS_GC;
case TriggerGCType::LOCAL_CC:
return GCType::LOCAL_CC;
case TriggerGCType::SHARED_GC:
return GCType::SHARED_GC;
case TriggerGCType::SHARED_PARTIAL_GC:
return GCType::SHARED_PARTIAL_GC;
case TriggerGCType::SHARED_FULL_GC:
return GCType::SHARED_FULL_GC;
case TriggerGCType::GLOBAL_GC:
return GCType::GLOBAL_GC;
case TriggerGCType::CMS_GC:
return GCType::CMS_GC;
case TriggerGCType::STICKY_CMS_GC:
return GCType::STICKY_CMS_GC;
default:
return GCType::OTHER;
}
}
void GCStats::InitializeRecordList()
{
for (float &duration : scopeDuration_) {
duration = 0.0f;
}
concurrentMark_ = false;
}
bool GCStats::CheckIfLongTimePause()
{
if (scopeDuration_[Scope::ScopeId::TotalGC] > longPauseTime_) {
LOG_GC(INFO) << "Has checked a long time gc";
return true;
}
return false;
}
void SharedGCStats::PrintStatisticResult()
{
LOG_GC(INFO) << "/******************* SharedGCStats statistic: *******************/";
PrintSharedGCSummaryStatistic();
PrintGCMemoryStatistic();
}
void SharedGCStats::PrintGCStatistic()
{
if (enableGCTracer_) {
PrintSharedGCOverview();
PrintSharedGCDuration();
PrintGCMemoryStatistic();
PrintSharedGCSummaryStatistic();
} else if (gcType_ == GCType::SHARED_PARTIAL_GC) {
PrintSharedGCOverview();
PrintGCMemoryStatistic();
}
SharedGCFinishTrace();
InitializeRecordList();
}
void SharedGCStats::SharedGCFinishTrace()
{
ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, ("SharedGC::Finish;Reason"
+ std::to_string(static_cast<int>(gcReason_))
+ ";Sensitive" + std::to_string(static_cast<int>(sHeap_->GetSensitiveStatus()))
+ ";IsInBackground" + std::to_string(Runtime::GetInstance()->IsInBackground())
+ ";Startup" + std::to_string(sHeap_->OnStartupEvent())
+ ";Old" + std::to_string(sHeap_->GetOldSpace()->GetCommittedSize())
+ ";huge" + std::to_string(sHeap_->GetHugeObjectSpace()->GetCommittedSize())
+ ";NonMov" + std::to_string(sHeap_->GetNonMovableSpace()->GetCommittedSize())
+ ";TotCommit" + std::to_string(sHeap_->GetCommittedSize())
+ ";NativeBindingSize" + std::to_string(sHeap_->GetNativeSizeAfterLastGC())
+ ";NativeLimitGC" + std::to_string(sHeap_->GetNativeSizeTriggerSharedGC())
+ ";NativeLimitCM" + std::to_string(sHeap_->GetNativeSizeTriggerSharedCM())).c_str(), "");
}
void SharedGCStats::PrintSharedGCOverview()
{
LOG_GC(INFO) << " [ " << GetGCTypeName() << " ] "
<< sizeToMB(recordData_[(uint8_t)RecordData::START_OBJ_SIZE]) << " ("
<< sizeToMB(recordData_[(uint8_t)RecordData::START_COMMIT_SIZE]) << ") -> "
<< sizeToMB(recordData_[(uint8_t)RecordData::END_OBJ_SIZE]) << " ("
<< sizeToMB(recordData_[(uint8_t)RecordData::END_COMMIT_SIZE]) << ") MB, "
<< scopeDuration_[Scope::ScopeId::TotalGC]
<< "ms, GCReason: " << GCReasonToString()
<< ", MarkReason: " << MarkReasonToString();
LOG_GC(INFO) << "IsInBackground: " << Runtime::GetInstance()->IsInBackground() << "; "
<< "SensitiveStatus: " << static_cast<int>(sHeap_->GetSensitiveStatus()) << "; "
<< "StartupStatus: " << std::to_string(static_cast<int>(sHeap_->GetStartupStatus())) << "; "
<< "Old: " << std::to_string(sHeap_->GetOldSpace()->GetCommittedSize()) << "; "
<< "Huge:" << std::to_string(sHeap_->GetHugeObjectSpace()->GetCommittedSize()) << "; "
<< "NonMov:" << std::to_string(sHeap_->GetNonMovableSpace()->GetCommittedSize()) << "; "
<< "TotCommit:" << std::to_string(sHeap_->GetCommittedSize());
}
void SharedGCStats::PrintSharedGCSummaryStatistic()
{
LOG_GC(INFO) << "/***************** GC summary statistic: *****************/";
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("SharedGC occurs count")
<< STATS_DATA_FORMAT(GetRecordData(RecordData::SHARED_COUNT)) << "\n"
<< STATS_DESCRIPTION_FORMAT("SharedGC max pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_MAX_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("SharedGC min pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_MIN_PAUSE)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("SharedGC average pause:")
<< STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_TOTAL_PAUSE) /
GetRecordData(RecordData::SHARED_COUNT)) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("SharedHeap average alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::SHARED_TOTAL_ALIVE)) /
GetRecordData(RecordData::SHARED_TOTAL_COMMIT));
}
void SharedGCStats::PrintGCMemoryStatistic()
{
NativeAreaAllocator *nativeAreaAllocator = sHeap_->GetNativeAreaAllocator();
HeapRegionAllocator *heapRegionAllocator = sHeap_->GetHeapRegionAllocator();
LOG_GC(INFO) << "/****************** GC Memory statistic: *****************/";
LOG_GC(INFO) << "AllSpaces used:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetCommittedSize())) << "KB\n"
<< "SharedOldSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetOldSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetOldSpace()->GetCommittedSize())) << "KB\n"
<< "SharedNonMovableSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNonMovableSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNonMovableSpace()->GetCommittedSize())) << "KB\n"
<< "SharedHugeObjectSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n"
<< "SharedAppSpawnSpace used:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetAppSpawnSpace()->GetHeapObjectSize())) << "KB"
<< " committed:"
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetAppSpawnSpace()->GetCommittedSize())) << "KB";
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Anno memory usage size:")
<< STATS_DATA_FORMAT(sizeToMB(heapRegionAllocator->GetAnnoMemoryUsage())) << "MB\n"
<< STATS_DESCRIPTION_FORMAT("Native memory usage size:")
<< STATS_DATA_FORMAT(sizeToMB(nativeAreaAllocator->GetNativeMemoryUsage())) << "MB\n"
<< STATS_DESCRIPTION_FORMAT("NativeBindingSize:")
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNativeSizeAfterLastGC())) << "KB\n"
<< STATS_DESCRIPTION_FORMAT("NativeLimitGC:")
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNativeSizeTriggerSharedGC())) << "KB\n"
<< STATS_DESCRIPTION_FORMAT("NativeLimitCM:")
<< STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNativeSizeTriggerSharedCM())) << "KB\n";
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:")
<< STATS_DATA_FORMAT(double(GetRecordData(RecordData::SHARED_ALIVE_SIZE)) /
GetRecordData(RecordData::SHARED_COMMIT_SIZE));
}
void SharedGCStats::PrintSharedGCDuration()
{
LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Initialize:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Mark:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Evacuate:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Evacuate]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("UpdateReference:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::UpdateReference]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Sweep:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("Finish:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("SuspendAll:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::SuspendAll]) << "ms\n"
<< STATS_DESCRIPTION_FORMAT("ResumeAll:")
<< STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::ResumeAll]) << "ms";
}
size_t SharedGCStats::GetAccumulatedAllocateSize()
{
return accumulatedFreeSize_ + sHeap_->GetHeapObjectSize();
}
void SharedGCStats::RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason)
{
size_t commitSize = sHeap_->GetCommittedSize();
SetRecordData(RecordData::START_OBJ_SIZE, sHeap_->GetHeapObjectSize());
SetRecordData(RecordData::START_COMMIT_SIZE, commitSize);
SetRecordData(RecordData::SHARED_COMMIT_SIZE, commitSize);
IncreaseRecordData(RecordData::SHARED_TOTAL_COMMIT, commitSize);
gcType_ = GetGCType(gcType);
gcReason_ = reason;
ProcessBeforeLongGCStats();
RecordGCStatisticStart();
}
void SharedGCStats::RecordStatisticAfterGC()
{
SetRecordData(RecordData::END_OBJ_SIZE, sHeap_->GetHeapObjectSize());
SetRecordData(RecordData::END_COMMIT_SIZE, sHeap_->GetCommittedSize());
float duration = scopeDuration_[Scope::ScopeId::TotalGC];
if (GetRecordData(RecordData::SHARED_COUNT) == 0) {
SetRecordDuration(RecordDuration::SHARED_MIN_PAUSE, duration);
SetRecordDuration(RecordDuration::SHARED_MAX_PAUSE, duration);
} else {
SetRecordDuration(RecordDuration::SHARED_MIN_PAUSE,
std::min(GetRecordDuration(RecordDuration::SHARED_MIN_PAUSE), duration));
SetRecordDuration(RecordDuration::SHARED_MAX_PAUSE,
std::max(GetRecordDuration(RecordDuration::SHARED_MAX_PAUSE), duration));
}
IncreaseRecordData(RecordData::SHARED_COUNT);
IncreaseRecordDuration(RecordDuration::SHARED_TOTAL_PAUSE, duration);
size_t heapAliveSize = sHeap_->GetHeapObjectSize();
SetRecordData(RecordData::SHARED_ALIVE_SIZE, heapAliveSize);
IncreaseRecordData(RecordData::SHARED_TOTAL_ALIVE, heapAliveSize);
IncreaseTotalDuration(scopeDuration_[Scope::ScopeId::TotalGC]);
IncreaseAccumulatedFreeSize(GetRecordData(RecordData::START_OBJ_SIZE) -
GetRecordData(RecordData::END_OBJ_SIZE));
ProcessAfterLongGCStats();
RecordGCStatisticEnd();
}
void SharedGCStats::ProcessAfterLongGCStats()
{
LongGCStats *longGCStats = GetLongGCStats();
float gcTotalTime = GetScopeDuration(GCStats::Scope::ScopeId::TotalGC);
if (IsLongGC(gcReason_, sHeap_->InSensitiveStatus(), Runtime::GetInstance()->IsInBackground(), gcTotalTime)) {
longGCStats->SetGCType(static_cast<int>(gcType_));
longGCStats->SetGCReason(static_cast<int>(gcReason_));
longGCStats->SetMarkReason(static_cast<int>(markReason_));
longGCStats->SetGCIsSensitive(sHeap_->InSensitiveStatus());
longGCStats->SetGCIsInBackground(Runtime::GetInstance()->IsInBackground());
longGCStats->SetGCTotalTime(gcTotalTime);
longGCStats->SetGCMarkTime(GetScopeDuration(GCStats::Scope::ScopeId::Mark));
longGCStats->SetAfterGCTotalMemUsed(sHeap_->GetHeapObjectSize());
longGCStats->SetAfterGCTotalMemCommitted(sHeap_->GetCommittedSize());
longGCStats->SetAfterGCOldMemUsed(sHeap_->GetOldSpace()->GetHeapObjectSize());
longGCStats->SetAfterGCOldMemCommitted(sHeap_->GetOldSpace()->GetCommittedSize());
longGCStats->SetAfterGCHugeMemUsed(sHeap_->GetHugeObjectSpace()->GetHeapObjectSize());
longGCStats->SetAfterGCHugeMemCommitted(sHeap_->GetHugeObjectSpace()->GetCommittedSize());
longGCStats->SetAfterGCNativeBindingSize(sHeap_->GetNativeSizeAfterLastGC());
longGCStats->SetAfterGCNativeLimit(sHeap_->GetNativeSizeTriggerSharedGC());
}
}
void SharedGCStats::ProcessBeforeLongGCStats()
{
LongGCStats *longGCStats = GetLongGCStats();
longGCStats->SetBeforeGCTotalMemUsed(sHeap_->GetHeapObjectSize());
longGCStats->SetBeforeGCTotalMemCommitted(sHeap_->GetCommittedSize());
longGCStats->SetBeforeGCOldMemUsed(sHeap_->GetOldSpace()->GetHeapObjectSize());
longGCStats->SetBeforeGCOldMemCommitted(sHeap_->GetOldSpace()->GetCommittedSize());
longGCStats->SetBeforeGCHugeMemUsed(sHeap_->GetHugeObjectSpace()->GetHeapObjectSize());
longGCStats->SetBeforeGCHugeMemCommitted(sHeap_->GetHugeObjectSpace()->GetCommittedSize());
longGCStats->SetBeforeGCNativeBindingSize(sHeap_->GetNativeSizeAfterLastGC());
longGCStats->SetBeforeGCNativeLimit(sHeap_->GetNativeSizeTriggerSharedGC());
}
}