14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/mem/incremental_marker.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include <ctime> 194514f5e3Sopenharmony_ci#include <regex> 204514f5e3Sopenharmony_ci#include <sys/time.h> 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_ci#include "ecmascript/mem/concurrent_marker.h" 234514f5e3Sopenharmony_ci#include "ecmascript/mem/parallel_marker-inl.h" 244514f5e3Sopenharmony_ci#include "ecmascript/runtime_call_id.h" 254514f5e3Sopenharmony_ci 264514f5e3Sopenharmony_cinamespace panda::ecmascript { 274514f5e3Sopenharmony_ciIncrementalMarker::IncrementalMarker(Heap *heap) 284514f5e3Sopenharmony_ci : heap_(heap), 294514f5e3Sopenharmony_ci vm_(heap->GetEcmaVM()), 304514f5e3Sopenharmony_ci workManager_(heap->GetWorkManager()) {} 314514f5e3Sopenharmony_ci 324514f5e3Sopenharmony_civoid IncrementalMarker::TriggerIncrementalMark(int64_t idleMicroSec) 334514f5e3Sopenharmony_ci{ 344514f5e3Sopenharmony_ci ASSERT(!heap_->GetConcurrentMarker()->IsTriggeredConcurrentMark()); 354514f5e3Sopenharmony_ci double startTime = GetCurrentTimeInMs(); 364514f5e3Sopenharmony_ci switch (states_) { 374514f5e3Sopenharmony_ci case IncrementalGCStates::ROOT_SCAN: 384514f5e3Sopenharmony_ci Mark(); 394514f5e3Sopenharmony_ci ProcessIncrementalMark(idleMicroSec - (GetCurrentTimeInMs() - startTime)); 404514f5e3Sopenharmony_ci RecordIdleTime(idleMicroSec, startTime, true); 414514f5e3Sopenharmony_ci break; 424514f5e3Sopenharmony_ci case IncrementalGCStates::INCREMENTAL_MARK: 434514f5e3Sopenharmony_ci ProcessIncrementalMark(idleMicroSec); 444514f5e3Sopenharmony_ci RecordIdleTime(idleMicroSec, startTime); 454514f5e3Sopenharmony_ci break; 464514f5e3Sopenharmony_ci case IncrementalGCStates::REMARK: 474514f5e3Sopenharmony_ci UpdateIncrementalMarkingSpeed(GetCurrentTimeInMs() - startTime_); 484514f5e3Sopenharmony_ci heap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::IDLE); 494514f5e3Sopenharmony_ci RecordIdleTime(idleMicroSec, startTime); 504514f5e3Sopenharmony_ci PrintGCIdleUsageStatistic(); 514514f5e3Sopenharmony_ci break; 524514f5e3Sopenharmony_ci default: // LOCV_EXCL_BR_LINE 534514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 544514f5e3Sopenharmony_ci UNREACHABLE(); 554514f5e3Sopenharmony_ci } 564514f5e3Sopenharmony_ci} 574514f5e3Sopenharmony_ci 584514f5e3Sopenharmony_civoid IncrementalMarker::Mark() 594514f5e3Sopenharmony_ci{ 604514f5e3Sopenharmony_ci LOG_GC(DEBUG) << "IncrementalMarker: Incremental Marking Begin"; 614514f5e3Sopenharmony_ci ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "IncrementalMarker::Mark"); 624514f5e3Sopenharmony_ci MEM_ALLOCATE_AND_GC_TRACE(vm_, IncrementalMarking); 634514f5e3Sopenharmony_ci Initialize(); 644514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->MarkRoots(MAIN_THREAD_INDEX); 654514f5e3Sopenharmony_ci states_ = IncrementalGCStates::INCREMENTAL_MARK; 664514f5e3Sopenharmony_ci} 674514f5e3Sopenharmony_ci 684514f5e3Sopenharmony_civoid IncrementalMarker::Initialize() 694514f5e3Sopenharmony_ci{ 704514f5e3Sopenharmony_ci MEM_ALLOCATE_AND_GC_TRACE(vm_, IncrementalMarkingInitialize); 714514f5e3Sopenharmony_ci startTime_ = GetCurrentTimeInMs(); 724514f5e3Sopenharmony_ci startObjectSize_ = heap_->GetHeapObjectSize(); 734514f5e3Sopenharmony_ci isIncrementalMarking_ = true; 744514f5e3Sopenharmony_ci markingFinished_ = false; 754514f5e3Sopenharmony_ci heap_->SetMarkType(MarkType::MARK_FULL); 764514f5e3Sopenharmony_ci heap_->GetJSThread()->SetMarkStatus(MarkStatus::MARKING); 774514f5e3Sopenharmony_ci heap_->Prepare(); 784514f5e3Sopenharmony_ci heap_->GetOldSpace()->SelectCSet(); 794514f5e3Sopenharmony_ci heap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { 804514f5e3Sopenharmony_ci current->ClearMarkGCBitset(); 814514f5e3Sopenharmony_ci current->ClearCrossRegionRSet(); 824514f5e3Sopenharmony_ci }); 834514f5e3Sopenharmony_ci heap_->EnumerateNonNewSpaceRegions([](Region *current) { 844514f5e3Sopenharmony_ci current->ResetAliveObject(); 854514f5e3Sopenharmony_ci }); 864514f5e3Sopenharmony_ci 874514f5e3Sopenharmony_ci workManager_->Initialize(TriggerGCType::OLD_GC, ParallelGCTaskPhase::OLD_HANDLE_GLOBAL_POOL_TASK); 884514f5e3Sopenharmony_ci} 894514f5e3Sopenharmony_ci 904514f5e3Sopenharmony_civoid IncrementalMarker::ProcessIncrementalMark(int64_t idleMicroSec) 914514f5e3Sopenharmony_ci{ 924514f5e3Sopenharmony_ci RecursionScope recurScope(this); 934514f5e3Sopenharmony_ci if (idleMicroSec <= 0) { 944514f5e3Sopenharmony_ci return; 954514f5e3Sopenharmony_ci } 964514f5e3Sopenharmony_ci LOG_GC(DEBUG) << "IncrementalMarker: Process Incremental Marking"; 974514f5e3Sopenharmony_ci uint32_t markStepSize = static_cast<uint32_t>(idleMicroSec) * markingSpeed_; 984514f5e3Sopenharmony_ci heap_->GetNonMovableMarker()->ProcessIncrementalMarkStack(MAIN_THREAD_INDEX, markStepSize); 994514f5e3Sopenharmony_ci if (markingFinished_) { 1004514f5e3Sopenharmony_ci states_ = IncrementalGCStates::REMARK; 1014514f5e3Sopenharmony_ci heap_->GetJSThread()->SetMarkStatus(MarkStatus::MARK_FINISHED); 1024514f5e3Sopenharmony_ci return; 1034514f5e3Sopenharmony_ci } 1044514f5e3Sopenharmony_ci} 1054514f5e3Sopenharmony_ci 1064514f5e3Sopenharmony_civoid IncrementalMarker::Finish() 1074514f5e3Sopenharmony_ci{ 1084514f5e3Sopenharmony_ci states_ = IncrementalGCStates::ROOT_SCAN; 1094514f5e3Sopenharmony_ci isIncrementalMarking_ = false; 1104514f5e3Sopenharmony_ci heap_->GetJSThread()->SetMarkStatus(MarkStatus::READY_TO_MARK); 1114514f5e3Sopenharmony_ci heap_->GetOldSpace()->RevertCSet(); 1124514f5e3Sopenharmony_ci auto callback = [](Region *region) { 1134514f5e3Sopenharmony_ci region->ClearMarkGCBitset(); 1144514f5e3Sopenharmony_ci region->ClearCrossRegionRSet(); 1154514f5e3Sopenharmony_ci region->ResetAliveObject(); 1164514f5e3Sopenharmony_ci }; 1174514f5e3Sopenharmony_ci heap_->EnumerateRegions(callback); 1184514f5e3Sopenharmony_ci} 1194514f5e3Sopenharmony_ci 1204514f5e3Sopenharmony_cidouble IncrementalMarker::GetCurrentTimeInMs() 1214514f5e3Sopenharmony_ci{ 1224514f5e3Sopenharmony_ci struct timeval tv; 1234514f5e3Sopenharmony_ci gettimeofday(&tv, nullptr); 1244514f5e3Sopenharmony_ci return static_cast<double>(tv.tv_sec) * MS_PER_SECOND + (tv.tv_usec / MS_PER_SECOND); 1254514f5e3Sopenharmony_ci} 1264514f5e3Sopenharmony_ci 1274514f5e3Sopenharmony_civoid IncrementalMarker::Reset() 1284514f5e3Sopenharmony_ci{ 1294514f5e3Sopenharmony_ci isIncrementalMarking_ = false; 1304514f5e3Sopenharmony_ci states_ = IncrementalGCStates::ROOT_SCAN; 1314514f5e3Sopenharmony_ci heap_->GetJSThread()->SetMarkStatus(MarkStatus::READY_TO_MARK); 1324514f5e3Sopenharmony_ci workManager_->Finish(); 1334514f5e3Sopenharmony_ci} 1344514f5e3Sopenharmony_ci 1354514f5e3Sopenharmony_civoid IncrementalMarker::RecordIdleTime(int64_t idleMicroSec, double startTime, bool needInitialize) 1364514f5e3Sopenharmony_ci{ 1374514f5e3Sopenharmony_ci if (needInitialize) { 1384514f5e3Sopenharmony_ci receiveIdleTime_ = 0; 1394514f5e3Sopenharmony_ci totalUsedIdleTime_ = 0.0; 1404514f5e3Sopenharmony_ci exceedIdleTime_ = 0.0; 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci double usedIdleTime = GetCurrentTimeInMs() - startTime; 1434514f5e3Sopenharmony_ci receiveIdleTime_ += idleMicroSec; 1444514f5e3Sopenharmony_ci totalUsedIdleTime_ += std::min((double)idleMicroSec, usedIdleTime); 1454514f5e3Sopenharmony_ci exceedIdleTime_ += usedIdleTime > idleMicroSec ? usedIdleTime - idleMicroSec : 0; 1464514f5e3Sopenharmony_ci} 1474514f5e3Sopenharmony_ci 1484514f5e3Sopenharmony_civoid IncrementalMarker::PrintGCIdleUsageStatistic() 1494514f5e3Sopenharmony_ci{ 1504514f5e3Sopenharmony_ci if (!vm_->IsOptionalLogEnabled()) { 1514514f5e3Sopenharmony_ci return; 1524514f5e3Sopenharmony_ci } 1534514f5e3Sopenharmony_ci LOG_GC(INFO) << "/************* GCStats Idle usage statistic: *************/"; 1544514f5e3Sopenharmony_ci LOG_GC(INFO) << "Receive idle time: " << receiveIdleTime_ << "ms\n" 1554514f5e3Sopenharmony_ci << "GC in idle time: " << totalUsedIdleTime_ << "ms\n" 1564514f5e3Sopenharmony_ci << "GC out of idle time: " << exceedIdleTime_ << "ms\n" 1574514f5e3Sopenharmony_ci << "Total duration of gc:" << GetCurrentTimeInMs() - startTime_ << "ms"; 1584514f5e3Sopenharmony_ci} 1594514f5e3Sopenharmony_ci} // namespace panda::ecmascript 160