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