14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_PGO_PROFILER_MANAGER_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_PGO_PROFILER_MANAGER_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <atomic>
204514f5e3Sopenharmony_ci#include <csignal>
214514f5e3Sopenharmony_ci#include <memory>
224514f5e3Sopenharmony_ci
234514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_profiler.h"
244514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
254514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
264514f5e3Sopenharmony_ci#include "os/mutex.h"
274514f5e3Sopenharmony_ci
284514f5e3Sopenharmony_cinamespace panda::ecmascript::pgo {
294514f5e3Sopenharmony_ciclass PGOProfilerManager {
304514f5e3Sopenharmony_cipublic:
314514f5e3Sopenharmony_ci    using ApGenMode = PGOProfilerEncoder::ApGenMode;
324514f5e3Sopenharmony_ci    static PGOProfilerManager *PUBLIC_API GetInstance();
334514f5e3Sopenharmony_ci
344514f5e3Sopenharmony_ci    static void SavingSignalHandler(int signo);
354514f5e3Sopenharmony_ci
364514f5e3Sopenharmony_ci    PGOProfilerManager() = default;
374514f5e3Sopenharmony_ci    ~PGOProfilerManager() = default;
384514f5e3Sopenharmony_ci
394514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(PGOProfilerManager);
404514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(PGOProfilerManager);
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_ci    void Initialize(const std::string &outDir, uint32_t hotnessThreshold)
434514f5e3Sopenharmony_ci    {
444514f5e3Sopenharmony_ci        // For FA jsvm, merge with existed output file
454514f5e3Sopenharmony_ci        encoder_ = std::make_unique<PGOProfilerEncoder>(outDir, hotnessThreshold, ApGenMode::MERGE);
464514f5e3Sopenharmony_ci    }
474514f5e3Sopenharmony_ci
484514f5e3Sopenharmony_ci    void SetBundleName(const std::string &bundleName)
494514f5e3Sopenharmony_ci    {
504514f5e3Sopenharmony_ci        if (encoder_) {
514514f5e3Sopenharmony_ci            encoder_->SetBundleName(bundleName);
524514f5e3Sopenharmony_ci        }
534514f5e3Sopenharmony_ci    }
544514f5e3Sopenharmony_ci
554514f5e3Sopenharmony_ci    const std::string GetBundleName()
564514f5e3Sopenharmony_ci    {
574514f5e3Sopenharmony_ci        if (encoder_) {
584514f5e3Sopenharmony_ci            return encoder_->GetBundleName();
594514f5e3Sopenharmony_ci        }
604514f5e3Sopenharmony_ci        return "";
614514f5e3Sopenharmony_ci    }
624514f5e3Sopenharmony_ci
634514f5e3Sopenharmony_ci    void SetRequestAotCallback(const RequestAotCallback &cb)
644514f5e3Sopenharmony_ci    {
654514f5e3Sopenharmony_ci        os::memory::LockHolder lock(*mutex_);
664514f5e3Sopenharmony_ci        if (requestAotCallback_ != nullptr) {
674514f5e3Sopenharmony_ci            return;
684514f5e3Sopenharmony_ci        }
694514f5e3Sopenharmony_ci        requestAotCallback_ = cb;
704514f5e3Sopenharmony_ci    }
714514f5e3Sopenharmony_ci
724514f5e3Sopenharmony_ci    bool RequestAot(const std::string &bundleName, const std::string &moduleName, RequestAotMode triggerMode)
734514f5e3Sopenharmony_ci    {
744514f5e3Sopenharmony_ci        RequestAotCallback cb;
754514f5e3Sopenharmony_ci        {
764514f5e3Sopenharmony_ci            os::memory::LockHolder lock(*mutex_);
774514f5e3Sopenharmony_ci            if (requestAotCallback_ == nullptr) {
784514f5e3Sopenharmony_ci                LOG_ECMA(ERROR) << "Trigger aot failed. callback is null.";
794514f5e3Sopenharmony_ci                return false;
804514f5e3Sopenharmony_ci            }
814514f5e3Sopenharmony_ci            cb = requestAotCallback_;
824514f5e3Sopenharmony_ci        }
834514f5e3Sopenharmony_ci        return (cb(bundleName, moduleName, static_cast<int32_t>(triggerMode)) == 0);
844514f5e3Sopenharmony_ci    }
854514f5e3Sopenharmony_ci
864514f5e3Sopenharmony_ci    void Destroy()
874514f5e3Sopenharmony_ci    {
884514f5e3Sopenharmony_ci        if (encoder_) {
894514f5e3Sopenharmony_ci            encoder_->Save();
904514f5e3Sopenharmony_ci            encoder_->Destroy();
914514f5e3Sopenharmony_ci            encoder_.reset();
924514f5e3Sopenharmony_ci        }
934514f5e3Sopenharmony_ci    }
944514f5e3Sopenharmony_ci
954514f5e3Sopenharmony_ci    // Factory
964514f5e3Sopenharmony_ci    std::shared_ptr<PGOProfiler> Build(EcmaVM *vm, bool isEnable)
974514f5e3Sopenharmony_ci    {
984514f5e3Sopenharmony_ci        if (isEnable) {
994514f5e3Sopenharmony_ci            isEnable = InitializeData();
1004514f5e3Sopenharmony_ci        }
1014514f5e3Sopenharmony_ci        auto profiler = std::make_shared<PGOProfiler>(vm, isEnable);
1024514f5e3Sopenharmony_ci        {
1034514f5e3Sopenharmony_ci            os::memory::LockHolder lock(*mutex_);
1044514f5e3Sopenharmony_ci            profilers_.insert(profiler);
1054514f5e3Sopenharmony_ci        }
1064514f5e3Sopenharmony_ci        return profiler;
1074514f5e3Sopenharmony_ci    }
1084514f5e3Sopenharmony_ci
1094514f5e3Sopenharmony_ci    // Return false if force disabled or never initialized
1104514f5e3Sopenharmony_ci    bool IsEnable() const
1114514f5e3Sopenharmony_ci    {
1124514f5e3Sopenharmony_ci        return !disablePGO_ && encoder_ && encoder_->IsInitialized();
1134514f5e3Sopenharmony_ci    }
1144514f5e3Sopenharmony_ci
1154514f5e3Sopenharmony_ci    void Destroy(std::shared_ptr<PGOProfiler> &profiler)
1164514f5e3Sopenharmony_ci    {
1174514f5e3Sopenharmony_ci        if (profiler != nullptr) {
1184514f5e3Sopenharmony_ci            profiler->WaitPGODumpFinish();
1194514f5e3Sopenharmony_ci            profiler->HandlePGOPreDump();
1204514f5e3Sopenharmony_ci            Merge(profiler.get());
1214514f5e3Sopenharmony_ci            {
1224514f5e3Sopenharmony_ci                os::memory::LockHolder lock(*mutex_);
1234514f5e3Sopenharmony_ci                profilers_.erase(profiler);
1244514f5e3Sopenharmony_ci            }
1254514f5e3Sopenharmony_ci            profiler.reset();
1264514f5e3Sopenharmony_ci        }
1274514f5e3Sopenharmony_ci    }
1284514f5e3Sopenharmony_ci
1294514f5e3Sopenharmony_ci    void Reset(const std::shared_ptr<PGOProfiler>& profiler, bool isEnable)
1304514f5e3Sopenharmony_ci    {
1314514f5e3Sopenharmony_ci        if (isEnable) {
1324514f5e3Sopenharmony_ci            isEnable = InitializeData();
1334514f5e3Sopenharmony_ci        }
1344514f5e3Sopenharmony_ci        if (profiler) {
1354514f5e3Sopenharmony_ci            profiler->Reset(isEnable);
1364514f5e3Sopenharmony_ci        }
1374514f5e3Sopenharmony_ci    }
1384514f5e3Sopenharmony_ci
1394514f5e3Sopenharmony_ci    void SamplePandaFileInfo(uint32_t checksum, const CString &abcName)
1404514f5e3Sopenharmony_ci    {
1414514f5e3Sopenharmony_ci        if (encoder_) {
1424514f5e3Sopenharmony_ci            encoder_->SamplePandaFileInfo(checksum, abcName);
1434514f5e3Sopenharmony_ci        }
1444514f5e3Sopenharmony_ci    }
1454514f5e3Sopenharmony_ci
1464514f5e3Sopenharmony_ci    void SetModuleName(const std::string &moduleName)
1474514f5e3Sopenharmony_ci    {
1484514f5e3Sopenharmony_ci        if (encoder_) {
1494514f5e3Sopenharmony_ci            encoder_->PostResetOutPathTask(moduleName);
1504514f5e3Sopenharmony_ci        }
1514514f5e3Sopenharmony_ci    }
1524514f5e3Sopenharmony_ci
1534514f5e3Sopenharmony_ci    bool GetPandaFileId(const CString &abcName, ApEntityId &entryId) const
1544514f5e3Sopenharmony_ci    {
1554514f5e3Sopenharmony_ci        if (encoder_) {
1564514f5e3Sopenharmony_ci            return encoder_->GetPandaFileId(abcName, entryId);
1574514f5e3Sopenharmony_ci        }
1584514f5e3Sopenharmony_ci        return false;
1594514f5e3Sopenharmony_ci    }
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_ci    bool GetPandaFileDesc(ApEntityId abcId, CString &desc) const
1624514f5e3Sopenharmony_ci    {
1634514f5e3Sopenharmony_ci        if (encoder_) {
1644514f5e3Sopenharmony_ci            return encoder_->GetPandaFileDesc(abcId, desc);
1654514f5e3Sopenharmony_ci        }
1664514f5e3Sopenharmony_ci        return false;
1674514f5e3Sopenharmony_ci    }
1684514f5e3Sopenharmony_ci
1694514f5e3Sopenharmony_ci    void SetApGenMode(ApGenMode mode)
1704514f5e3Sopenharmony_ci    {
1714514f5e3Sopenharmony_ci        if (encoder_) {
1724514f5e3Sopenharmony_ci            encoder_->SetApGenMode(mode);
1734514f5e3Sopenharmony_ci        }
1744514f5e3Sopenharmony_ci    }
1754514f5e3Sopenharmony_ci
1764514f5e3Sopenharmony_ci    void Merge(PGOProfiler *profiler)
1774514f5e3Sopenharmony_ci    {
1784514f5e3Sopenharmony_ci        if (encoder_ && profiler->isEnable_) {
1794514f5e3Sopenharmony_ci            encoder_->TerminateSaveTask();
1804514f5e3Sopenharmony_ci            encoder_->Merge(*profiler->recordInfos_);
1814514f5e3Sopenharmony_ci        }
1824514f5e3Sopenharmony_ci    }
1834514f5e3Sopenharmony_ci
1844514f5e3Sopenharmony_ci    void RegisterSavingSignal();
1854514f5e3Sopenharmony_ci
1864514f5e3Sopenharmony_ci    void AsyncSave()
1874514f5e3Sopenharmony_ci    {
1884514f5e3Sopenharmony_ci        if (encoder_) {
1894514f5e3Sopenharmony_ci            encoder_->PostSaveTask();
1904514f5e3Sopenharmony_ci        }
1914514f5e3Sopenharmony_ci    }
1924514f5e3Sopenharmony_ci
1934514f5e3Sopenharmony_ci    bool IsDisableAot() const
1944514f5e3Sopenharmony_ci    {
1954514f5e3Sopenharmony_ci        return disableAot_;
1964514f5e3Sopenharmony_ci    }
1974514f5e3Sopenharmony_ci
1984514f5e3Sopenharmony_ci    void SetDisableAot(bool state)
1994514f5e3Sopenharmony_ci    {
2004514f5e3Sopenharmony_ci        disableAot_ = state;
2014514f5e3Sopenharmony_ci    }
2024514f5e3Sopenharmony_ci
2034514f5e3Sopenharmony_ci    // Only set flag to ensure future actions will not trigger PGO path
2044514f5e3Sopenharmony_ci    // Caller should handle existing threads and PGO data properly
2054514f5e3Sopenharmony_ci    void SetDisablePGO(bool state)
2064514f5e3Sopenharmony_ci    {
2074514f5e3Sopenharmony_ci        disablePGO_ = state;
2084514f5e3Sopenharmony_ci    }
2094514f5e3Sopenharmony_ci
2104514f5e3Sopenharmony_ci    void ForceSave()
2114514f5e3Sopenharmony_ci    {
2124514f5e3Sopenharmony_ci        os::memory::LockHolder lock(*mutex_);
2134514f5e3Sopenharmony_ci        for (const auto &profiler : profilers_) {
2144514f5e3Sopenharmony_ci            profiler->DumpByForce();
2154514f5e3Sopenharmony_ci        }
2164514f5e3Sopenharmony_ci        GetInstance()->AsyncSave();
2174514f5e3Sopenharmony_ci    }
2184514f5e3Sopenharmony_ci
2194514f5e3Sopenharmony_ci    bool PUBLIC_API TextToBinary(const std::string &inPath, const std::string &outPath, uint32_t hotnessThreshold,
2204514f5e3Sopenharmony_ci                                 ApGenMode mode)
2214514f5e3Sopenharmony_ci    {
2224514f5e3Sopenharmony_ci        PGOProfilerEncoder encoder(outPath, hotnessThreshold, mode);
2234514f5e3Sopenharmony_ci        PGOProfilerEncoder decoder(outPath, hotnessThreshold, mode);
2244514f5e3Sopenharmony_ci        if (!encoder.InitializeData()) {
2254514f5e3Sopenharmony_ci            LOG_ECMA(ERROR) << "PGO Profiler encoder initialized failed";
2264514f5e3Sopenharmony_ci            return false;
2274514f5e3Sopenharmony_ci        }
2284514f5e3Sopenharmony_ci        if (!decoder.InitializeData()) {
2294514f5e3Sopenharmony_ci            LOG_ECMA(ERROR) << "PGO Profiler decoder initialized failed";
2304514f5e3Sopenharmony_ci            return false;
2314514f5e3Sopenharmony_ci        }
2324514f5e3Sopenharmony_ci        bool ret = decoder.LoadAPTextFile(inPath);
2334514f5e3Sopenharmony_ci        if (ret) {
2344514f5e3Sopenharmony_ci            encoder.Merge(decoder);
2354514f5e3Sopenharmony_ci            ret = encoder.Save();
2364514f5e3Sopenharmony_ci        }
2374514f5e3Sopenharmony_ci        encoder.Destroy();
2384514f5e3Sopenharmony_ci        decoder.Destroy();
2394514f5e3Sopenharmony_ci        return ret;
2404514f5e3Sopenharmony_ci    }
2414514f5e3Sopenharmony_ci
2424514f5e3Sopenharmony_ci    bool PUBLIC_API BinaryToText(const std::string &inPath, const std::string &outPath, uint32_t hotnessThreshold)
2434514f5e3Sopenharmony_ci    {
2444514f5e3Sopenharmony_ci        PGOProfilerDecoder decoder(inPath, hotnessThreshold);
2454514f5e3Sopenharmony_ci        if (!decoder.LoadFull()) {
2464514f5e3Sopenharmony_ci            return false;
2474514f5e3Sopenharmony_ci        }
2484514f5e3Sopenharmony_ci        bool ret = decoder.SaveAPTextFile(outPath);
2494514f5e3Sopenharmony_ci        decoder.Clear();
2504514f5e3Sopenharmony_ci        return ret;
2514514f5e3Sopenharmony_ci    }
2524514f5e3Sopenharmony_ci
2534514f5e3Sopenharmony_ci    static bool PUBLIC_API MergeApFiles(const std::string &inFiles, const std::string &outPath,
2544514f5e3Sopenharmony_ci                                        uint32_t hotnessThreshold, ApGenMode mode);
2554514f5e3Sopenharmony_ci    static bool PUBLIC_API MergeApFiles(uint32_t checksum, PGOProfilerDecoder &merger);
2564514f5e3Sopenharmony_ci
2574514f5e3Sopenharmony_ci    void SetIsApFileCompatible(bool isCompatible)
2584514f5e3Sopenharmony_ci    {
2594514f5e3Sopenharmony_ci        isApFileCompatible_ = isCompatible;
2604514f5e3Sopenharmony_ci    }
2614514f5e3Sopenharmony_ci
2624514f5e3Sopenharmony_ci    bool GetIsApFileCompatible() const
2634514f5e3Sopenharmony_ci    {
2644514f5e3Sopenharmony_ci        return isApFileCompatible_;
2654514f5e3Sopenharmony_ci    }
2664514f5e3Sopenharmony_ci
2674514f5e3Sopenharmony_ci    size_t GetMaxAotMethodSize() const
2684514f5e3Sopenharmony_ci    {
2694514f5e3Sopenharmony_ci        return maxAotMethodSize_;
2704514f5e3Sopenharmony_ci    }
2714514f5e3Sopenharmony_ci
2724514f5e3Sopenharmony_ci    void SetMaxAotMethodSize(uint32_t value)
2734514f5e3Sopenharmony_ci    {
2744514f5e3Sopenharmony_ci        maxAotMethodSize_ = value;
2754514f5e3Sopenharmony_ci    }
2764514f5e3Sopenharmony_ci
2774514f5e3Sopenharmony_ci    bool IsBigMethod(uint32_t methodSize) const
2784514f5e3Sopenharmony_ci    {
2794514f5e3Sopenharmony_ci        return maxAotMethodSize_ != 0 && methodSize > maxAotMethodSize_;
2804514f5e3Sopenharmony_ci    }
2814514f5e3Sopenharmony_ci
2824514f5e3Sopenharmony_ci    bool IsEnableForceIC() const
2834514f5e3Sopenharmony_ci    {
2844514f5e3Sopenharmony_ci        return isEnableForceIC_;
2854514f5e3Sopenharmony_ci    }
2864514f5e3Sopenharmony_ci
2874514f5e3Sopenharmony_ci    void SetEnableForceIC(bool isEnableForceIC)
2884514f5e3Sopenharmony_ci    {
2894514f5e3Sopenharmony_ci        isEnableForceIC_ = isEnableForceIC;
2904514f5e3Sopenharmony_ci    }
2914514f5e3Sopenharmony_ci
2924514f5e3Sopenharmony_ciprivate:
2934514f5e3Sopenharmony_ci    bool InitializeData()
2944514f5e3Sopenharmony_ci    {
2954514f5e3Sopenharmony_ci        if (!encoder_) {
2964514f5e3Sopenharmony_ci            return false;
2974514f5e3Sopenharmony_ci        }
2984514f5e3Sopenharmony_ci        bool initializedResult = encoder_->InitializeData();
2994514f5e3Sopenharmony_ci        if (initializedResult && !enableSignalSaving_) {
3004514f5e3Sopenharmony_ci            RegisterSavingSignal();
3014514f5e3Sopenharmony_ci        }
3024514f5e3Sopenharmony_ci        return initializedResult;
3034514f5e3Sopenharmony_ci    }
3044514f5e3Sopenharmony_ci
3054514f5e3Sopenharmony_ci    bool disableAot_ {false};
3064514f5e3Sopenharmony_ci    bool disablePGO_ {false};
3074514f5e3Sopenharmony_ci    std::unique_ptr<PGOProfilerEncoder> encoder_;
3084514f5e3Sopenharmony_ci    RequestAotCallback requestAotCallback_;
3094514f5e3Sopenharmony_ci    std::atomic_bool enableSignalSaving_ { false };
3104514f5e3Sopenharmony_ci    os::memory::Mutex *mutex_ = new os::memory::Mutex();
3114514f5e3Sopenharmony_ci    std::set<std::shared_ptr<PGOProfiler>> profilers_;
3124514f5e3Sopenharmony_ci    bool isApFileCompatible_ {true};
3134514f5e3Sopenharmony_ci    bool isEnableForceIC_ {true};
3144514f5e3Sopenharmony_ci    uint32_t maxAotMethodSize_ {0};
3154514f5e3Sopenharmony_ci};
3164514f5e3Sopenharmony_ci} // namespace panda::ecmascript::pgo
3174514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_PGO_PROFILER_MANAGER_H
318