1 /*
2 * Copyright (c) 2024 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/pgo_profiler/pgo_state.h"
17
18 #include "ecmascript/checkpoint/thread_state_transition.h"
19 #include "ecmascript/js_thread.h"
20 #include "ecmascript/pgo_profiler/pgo_profiler.h"
21 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
22
23 namespace panda::ecmascript::pgo {
24 using State = PGOState::State;
25 using GCState = PGOState::GCState;
PGOState()26 PGOState::PGOState()
27 {
28 manager_ = PGOProfilerManager::GetInstance();
29 }
30
ToString(State state)31 std::string PGOState::ToString(State state)
32 {
33 switch (state) {
34 case State::STOP:
35 return "STOP";
36 case State::SAVE:
37 return "SAVE";
38 case State::START:
39 return "START";
40 default:
41 return "UNKNOWN";
42 }
43 }
44
ToString(GCState state)45 std::string PGOState::ToString(GCState state)
46 {
47 switch (state) {
48 case GCState::STOP:
49 return "STOP";
50 case GCState::WAITING:
51 return "WAITING";
52 case GCState::RUNNING:
53 return "RUNNING";
54 default:
55 return "UNKNOWN";
56 }
57 }
58
GetState() const59 State PGOState::GetState() const
60 {
61 return state_.load(std::memory_order_acquire);
62 }
63
SetState(State state)64 void PGOState::SetState(State state)
65 {
66 #if PRINT_STATE_CHANGE
67 PrintStateChange(GetState(), state);
68 #endif
69 state_.store(state, std::memory_order_release);
70 }
71
GCIsWaiting() const72 bool PGOState::GCIsWaiting() const
73 {
74 GCState gcState = GetGCState();
75 return gcState == GCState::WAITING;
76 }
77
GCIsRunning() const78 bool PGOState::GCIsRunning() const
79 {
80 GCState gcState = GetGCState();
81 return gcState == GCState::RUNNING;
82 }
83
GCIsStop() const84 bool PGOState::GCIsStop() const
85 {
86 GCState gcState = GetGCState();
87 return gcState == GCState::STOP;
88 }
89
StateIsStop() const90 bool PGOState::StateIsStop() const
91 {
92 State state = GetState();
93 return state == State::STOP;
94 }
95
StateIsStart() const96 bool PGOState::StateIsStart() const
97 {
98 State state = GetState();
99 return state == State::START;
100 }
101
StateIsSave() const102 bool PGOState::StateIsSave() const
103 {
104 State state = GetState();
105 return state == State::SAVE;
106 }
107
108 #if PRINT_STATE_CHANGE
TryChangeState(State expected,State desired)109 bool PGOState::TryChangeState(State expected, State desired)
110 {
111 auto original = expected;
112 if (state_.compare_exchange_strong(expected, desired, std::memory_order_acq_rel)) {
113 PrintStateChange(expected, desired);
114 return true;
115 }
116 PrintStateChange(original, expected, desired);
117 return false;
118 }
119 #endif
120
121 #if !PRINT_STATE_CHANGE
TryChangeState(State expected,State desired)122 bool PGOState::TryChangeState(State expected, State desired)
123 {
124 if (state_.compare_exchange_strong(expected, desired, std::memory_order_acq_rel)) {
125 return true;
126 }
127 return false;
128 }
129 #endif
130
SetGCState(GCState state)131 void PGOState::SetGCState(GCState state)
132 {
133 gcState_.store(state, std::memory_order_release);
134 }
135
GetGCState() const136 GCState PGOState::GetGCState() const
137 {
138 return gcState_.load(std::memory_order_acquire);
139 }
140
SuspendByGC()141 void PGOState::SuspendByGC()
142 {
143 LockHolder lock(stateMutex_);
144 // possible state: START, SAVE, STOP
145 if (StateIsStart()) {
146 // possible gc state: STOP
147 SetGCState(GCState::WAITING);
148 needRedump_ = true;
149 WaitDump();
150 }
151 // possible gc state: STOP, WAITING
152 SetGCState(GCState::RUNNING);
153 }
154
ResumeByGC(PGOProfiler * profiler)155 void PGOState::ResumeByGC(PGOProfiler* profiler)
156 {
157 LockHolder lock(stateMutex_);
158 // possible state: START, SAVE, STOP
159 SetGCState(GCState::STOP);
160 if (needRedump_) {
161 manager_->TryDispatchDumpTask(profiler);
162 needRedump_ = false;
163 }
164 NotifyAllGCWaiters();
165 }
166
SetStartIfStop()167 bool PGOState::SetStartIfStop()
168 {
169 LockHolder lock(stateMutex_);
170 // possible state: STOP, SAVE
171 // possible gc state: STOP, WAITING, RUNNING
172 if (GCIsStop() && TryChangeState(State::STOP, State::START)) {
173 return true;
174 }
175 return false;
176 }
177
SetStopAndNotify()178 void PGOState::SetStopAndNotify()
179 {
180 LockHolder lock(stateMutex_);
181 // possible state: START, SAVE
182 SetState(State::STOP);
183 NotifyAllDumpWaiters();
184 }
185
SetSaveAndNotify()186 void PGOState::SetSaveAndNotify()
187 {
188 LockHolder lock(stateMutex_);
189 // possible state: START
190 SetState(State::SAVE);
191 NotifyAllDumpWaiters();
192 }
193
StartDumpBeforeDestroy(JSThread * thread)194 void PGOState::StartDumpBeforeDestroy([[maybe_unused]] JSThread *thread)
195 {
196 LockHolder lock(stateMutex_);
197 // possible state: STOP, SAVE, START
198 // may notify after change to STOP and SAVE, we need to make sure state is STOP
199 while (!StateIsStop()) {
200 WaitDump();
201 }
202 // possible gc state: STOP, WAITING, RUNNING
203 if (!GCIsStop()) {
204 WaitGC();
205 }
206 SetState(State::START);
207 }
208
WaitDump()209 void PGOState::WaitDump()
210 {
211 stateCondition_.Wait(&stateMutex_);
212 }
213
NotifyAllDumpWaiters()214 void PGOState::NotifyAllDumpWaiters()
215 {
216 stateCondition_.SignalAll();
217 }
218
WaitGC()219 void PGOState::WaitGC()
220 {
221 gcCondition_.Wait(&stateMutex_);
222 }
223
NotifyAllGCWaiters()224 void PGOState::NotifyAllGCWaiters()
225 {
226 gcCondition_.SignalAll();
227 }
228 } // namespace panda::ecmascript::pgo
229