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