/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/pgo_profiler/pgo_state.h" #include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/js_thread.h" #include "ecmascript/pgo_profiler/pgo_profiler.h" #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" namespace panda::ecmascript::pgo { using State = PGOState::State; using GCState = PGOState::GCState; PGOState::PGOState() { manager_ = PGOProfilerManager::GetInstance(); } std::string PGOState::ToString(State state) { switch (state) { case State::STOP: return "STOP"; case State::SAVE: return "SAVE"; case State::START: return "START"; default: return "UNKNOWN"; } } std::string PGOState::ToString(GCState state) { switch (state) { case GCState::STOP: return "STOP"; case GCState::WAITING: return "WAITING"; case GCState::RUNNING: return "RUNNING"; default: return "UNKNOWN"; } } State PGOState::GetState() const { return state_.load(std::memory_order_acquire); } void PGOState::SetState(State state) { #if PRINT_STATE_CHANGE PrintStateChange(GetState(), state); #endif state_.store(state, std::memory_order_release); } bool PGOState::GCIsWaiting() const { GCState gcState = GetGCState(); return gcState == GCState::WAITING; } bool PGOState::GCIsRunning() const { GCState gcState = GetGCState(); return gcState == GCState::RUNNING; } bool PGOState::GCIsStop() const { GCState gcState = GetGCState(); return gcState == GCState::STOP; } bool PGOState::StateIsStop() const { State state = GetState(); return state == State::STOP; } bool PGOState::StateIsStart() const { State state = GetState(); return state == State::START; } bool PGOState::StateIsSave() const { State state = GetState(); return state == State::SAVE; } #if PRINT_STATE_CHANGE bool PGOState::TryChangeState(State expected, State desired) { auto original = expected; if (state_.compare_exchange_strong(expected, desired, std::memory_order_acq_rel)) { PrintStateChange(expected, desired); return true; } PrintStateChange(original, expected, desired); return false; } #endif #if !PRINT_STATE_CHANGE bool PGOState::TryChangeState(State expected, State desired) { if (state_.compare_exchange_strong(expected, desired, std::memory_order_acq_rel)) { return true; } return false; } #endif void PGOState::SetGCState(GCState state) { gcState_.store(state, std::memory_order_release); } GCState PGOState::GetGCState() const { return gcState_.load(std::memory_order_acquire); } void PGOState::SuspendByGC() { LockHolder lock(stateMutex_); // possible state: START, SAVE, STOP if (StateIsStart()) { // possible gc state: STOP SetGCState(GCState::WAITING); needRedump_ = true; WaitDump(); } // possible gc state: STOP, WAITING SetGCState(GCState::RUNNING); } void PGOState::ResumeByGC(PGOProfiler* profiler) { LockHolder lock(stateMutex_); // possible state: START, SAVE, STOP SetGCState(GCState::STOP); if (needRedump_) { manager_->TryDispatchDumpTask(profiler); needRedump_ = false; } NotifyAllGCWaiters(); } bool PGOState::SetStartIfStop() { LockHolder lock(stateMutex_); // possible state: STOP, SAVE // possible gc state: STOP, WAITING, RUNNING if (GCIsStop() && TryChangeState(State::STOP, State::START)) { return true; } return false; } void PGOState::SetStopAndNotify() { LockHolder lock(stateMutex_); // possible state: START, SAVE SetState(State::STOP); NotifyAllDumpWaiters(); } void PGOState::SetSaveAndNotify() { LockHolder lock(stateMutex_); // possible state: START SetState(State::SAVE); NotifyAllDumpWaiters(); } void PGOState::StartDumpBeforeDestroy([[maybe_unused]] JSThread *thread) { LockHolder lock(stateMutex_); // possible state: STOP, SAVE, START // may notify after change to STOP and SAVE, we need to make sure state is STOP while (!StateIsStop()) { WaitDump(); } // possible gc state: STOP, WAITING, RUNNING if (!GCIsStop()) { WaitGC(); } SetState(State::START); } void PGOState::WaitDump() { stateCondition_.Wait(&stateMutex_); } void PGOState::NotifyAllDumpWaiters() { stateCondition_.SignalAll(); } void PGOState::WaitGC() { gcCondition_.Wait(&stateMutex_); } void PGOState::NotifyAllGCWaiters() { gcCondition_.SignalAll(); } } // namespace panda::ecmascript::pgo