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