1/* 2 * Copyright (c) 2023 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/incremental_marker.h" 17 18#include <ctime> 19#include <regex> 20#include <sys/time.h> 21 22#include "ecmascript/mem/concurrent_marker.h" 23#include "ecmascript/mem/parallel_marker-inl.h" 24#include "ecmascript/runtime_call_id.h" 25 26namespace panda::ecmascript { 27IncrementalMarker::IncrementalMarker(Heap *heap) 28 : heap_(heap), 29 vm_(heap->GetEcmaVM()), 30 workManager_(heap->GetWorkManager()) {} 31 32void IncrementalMarker::TriggerIncrementalMark(int64_t idleMicroSec) 33{ 34 ASSERT(!heap_->GetConcurrentMarker()->IsTriggeredConcurrentMark()); 35 double startTime = GetCurrentTimeInMs(); 36 switch (states_) { 37 case IncrementalGCStates::ROOT_SCAN: 38 Mark(); 39 ProcessIncrementalMark(idleMicroSec - (GetCurrentTimeInMs() - startTime)); 40 RecordIdleTime(idleMicroSec, startTime, true); 41 break; 42 case IncrementalGCStates::INCREMENTAL_MARK: 43 ProcessIncrementalMark(idleMicroSec); 44 RecordIdleTime(idleMicroSec, startTime); 45 break; 46 case IncrementalGCStates::REMARK: 47 UpdateIncrementalMarkingSpeed(GetCurrentTimeInMs() - startTime_); 48 heap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::IDLE); 49 RecordIdleTime(idleMicroSec, startTime); 50 PrintGCIdleUsageStatistic(); 51 break; 52 default: // LOCV_EXCL_BR_LINE 53 LOG_ECMA(FATAL) << "this branch is unreachable"; 54 UNREACHABLE(); 55 } 56} 57 58void IncrementalMarker::Mark() 59{ 60 LOG_GC(DEBUG) << "IncrementalMarker: Incremental Marking Begin"; 61 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "IncrementalMarker::Mark"); 62 MEM_ALLOCATE_AND_GC_TRACE(vm_, IncrementalMarking); 63 Initialize(); 64 heap_->GetNonMovableMarker()->MarkRoots(MAIN_THREAD_INDEX); 65 states_ = IncrementalGCStates::INCREMENTAL_MARK; 66} 67 68void IncrementalMarker::Initialize() 69{ 70 MEM_ALLOCATE_AND_GC_TRACE(vm_, IncrementalMarkingInitialize); 71 startTime_ = GetCurrentTimeInMs(); 72 startObjectSize_ = heap_->GetHeapObjectSize(); 73 isIncrementalMarking_ = true; 74 markingFinished_ = false; 75 heap_->SetMarkType(MarkType::MARK_FULL); 76 heap_->GetJSThread()->SetMarkStatus(MarkStatus::MARKING); 77 heap_->Prepare(); 78 heap_->GetOldSpace()->SelectCSet(); 79 heap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { 80 current->ClearMarkGCBitset(); 81 current->ClearCrossRegionRSet(); 82 }); 83 heap_->EnumerateNonNewSpaceRegions([](Region *current) { 84 current->ResetAliveObject(); 85 }); 86 87 workManager_->Initialize(TriggerGCType::OLD_GC, ParallelGCTaskPhase::OLD_HANDLE_GLOBAL_POOL_TASK); 88} 89 90void IncrementalMarker::ProcessIncrementalMark(int64_t idleMicroSec) 91{ 92 RecursionScope recurScope(this); 93 if (idleMicroSec <= 0) { 94 return; 95 } 96 LOG_GC(DEBUG) << "IncrementalMarker: Process Incremental Marking"; 97 uint32_t markStepSize = static_cast<uint32_t>(idleMicroSec) * markingSpeed_; 98 heap_->GetNonMovableMarker()->ProcessIncrementalMarkStack(MAIN_THREAD_INDEX, markStepSize); 99 if (markingFinished_) { 100 states_ = IncrementalGCStates::REMARK; 101 heap_->GetJSThread()->SetMarkStatus(MarkStatus::MARK_FINISHED); 102 return; 103 } 104} 105 106void IncrementalMarker::Finish() 107{ 108 states_ = IncrementalGCStates::ROOT_SCAN; 109 isIncrementalMarking_ = false; 110 heap_->GetJSThread()->SetMarkStatus(MarkStatus::READY_TO_MARK); 111 heap_->GetOldSpace()->RevertCSet(); 112 auto callback = [](Region *region) { 113 region->ClearMarkGCBitset(); 114 region->ClearCrossRegionRSet(); 115 region->ResetAliveObject(); 116 }; 117 heap_->EnumerateRegions(callback); 118} 119 120double IncrementalMarker::GetCurrentTimeInMs() 121{ 122 struct timeval tv; 123 gettimeofday(&tv, nullptr); 124 return static_cast<double>(tv.tv_sec) * MS_PER_SECOND + (tv.tv_usec / MS_PER_SECOND); 125} 126 127void IncrementalMarker::Reset() 128{ 129 isIncrementalMarking_ = false; 130 states_ = IncrementalGCStates::ROOT_SCAN; 131 heap_->GetJSThread()->SetMarkStatus(MarkStatus::READY_TO_MARK); 132 workManager_->Finish(); 133} 134 135void IncrementalMarker::RecordIdleTime(int64_t idleMicroSec, double startTime, bool needInitialize) 136{ 137 if (needInitialize) { 138 receiveIdleTime_ = 0; 139 totalUsedIdleTime_ = 0.0; 140 exceedIdleTime_ = 0.0; 141 } 142 double usedIdleTime = GetCurrentTimeInMs() - startTime; 143 receiveIdleTime_ += idleMicroSec; 144 totalUsedIdleTime_ += std::min((double)idleMicroSec, usedIdleTime); 145 exceedIdleTime_ += usedIdleTime > idleMicroSec ? usedIdleTime - idleMicroSec : 0; 146} 147 148void IncrementalMarker::PrintGCIdleUsageStatistic() 149{ 150 if (!vm_->IsOptionalLogEnabled()) { 151 return; 152 } 153 LOG_GC(INFO) << "/************* GCStats Idle usage statistic: *************/"; 154 LOG_GC(INFO) << "Receive idle time: " << receiveIdleTime_ << "ms\n" 155 << "GC in idle time: " << totalUsedIdleTime_ << "ms\n" 156 << "GC out of idle time: " << exceedIdleTime_ << "ms\n" 157 << "Total duration of gc:" << GetCurrentTimeInMs() - startTime_ << "ms"; 158} 159} // namespace panda::ecmascript 160