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#ifndef ECMASCRIPT_PGO_PROFILER_ENCODER_H
17#define ECMASCRIPT_PGO_PROFILER_ENCODER_H
18
19#include <atomic>
20#include <memory>
21#include <utility>
22
23#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
24#include "macros.h"
25
26namespace panda::ecmascript::pgo {
27class PGOProfilerDecoder;
28class PGOProfilerEncoder {
29public:
30    enum ApGenMode { OVERWRITE, MERGE };
31
32    PGOProfilerEncoder(const std::string &outDir, uint32_t hotnessThreshold, ApGenMode mode)
33        : outDir_(outDir), hotnessThreshold_(hotnessThreshold), mode_(mode)
34    {
35        pandaFileInfos_ = std::make_unique<PGOPandaFileInfos>();
36        abcFilePool_ = std::make_shared<PGOAbcFilePool>();
37    }
38
39    ~PGOProfilerEncoder()
40    {
41        Destroy();
42    }
43
44    NO_COPY_SEMANTIC(PGOProfilerEncoder);
45    NO_MOVE_SEMANTIC(PGOProfilerEncoder);
46
47    static void AddChecksum(std::fstream& fileStream);
48
49    bool PUBLIC_API InitializeData();
50
51    void PUBLIC_API Destroy();
52
53    void SetBundleName(const std::string &bundleName)
54    {
55        bundleName_ = bundleName;
56    }
57
58    const std::string GetBundleName()
59    {
60        return bundleName_;
61    }
62
63    bool IsInitialized() const
64    {
65        return isProfilingInitialized_;
66    }
67
68    void SamplePandaFileInfo(uint32_t checksum, const CString &abcName);
69    bool PUBLIC_API GetPandaFileId(const CString &abcName, ApEntityId &entryId);
70    bool GetPandaFileDesc(ApEntityId abcId, CString &desc);
71    void Merge(const PGORecordDetailInfos &recordInfos);
72    void Merge(const PGOPandaFileInfos &pandaFileInfos);
73    void Merge(const PGOProfilerEncoder &encoder);
74    bool VerifyPandaFileMatched(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
75                                const std::string &incoming) const;
76    std::shared_ptr<PGOAbcFilePool> GetAbcFilePool() const
77    {
78        return abcFilePool_;
79    }
80    void TerminateSaveTask();
81    void PostSaveTask();
82    void SetApGenMode(ApGenMode mode)
83    {
84        mode_ = mode;
85    }
86
87    bool PUBLIC_API Save();
88
89    bool PUBLIC_API LoadAPTextFile(const std::string &inPath);
90
91    void PostResetOutPathTask(const std::string &moduleName);
92
93    bool ResetOutPathByModuleName(const std::string &moduleName);
94
95protected:
96    PGOProfilerHeader *header_ {nullptr};
97
98private:
99    void StartSaveTask(const SaveTask *task);
100    bool InternalSave(const SaveTask *task = nullptr);
101    bool SaveAndRename(const SaveTask *task = nullptr);
102    void MergeWithExistProfile(PGOProfilerEncoder &runtimeEncoder, PGOProfilerDecoder &decoder,
103                               const SaveTask *task = nullptr);
104    void RequestAot();
105    bool ResetOutPath(const std::string& profileFileName);
106
107    bool isProfilingInitialized_ {false};
108    std::string outDir_;
109    uint32_t hotnessThreshold_ {2};
110    std::string realOutPath_;
111    std::unique_ptr<PGOPandaFileInfos> pandaFileInfos_;
112    std::shared_ptr<PGOAbcFilePool> abcFilePool_;
113    std::shared_ptr<PGORecordDetailInfos> globalRecordInfos_;
114    // rwLock_ is used to protect the pandaFileInfos_ and abcFilePool_
115    RWLock rwLock_;
116    // mutex_ is used to protect the others
117    Mutex mutex_;
118    std::atomic_bool hasPostModuleName_ {false};
119    std::string moduleName_;
120    std::string bundleName_;
121    ApGenMode mode_ {OVERWRITE};
122    friend SaveTask;
123};
124
125class SaveTask : public Task {
126public:
127    explicit SaveTask(PGOProfilerEncoder *encoder, int32_t id) : Task(id), encoder_(encoder) {};
128    virtual ~SaveTask() override = default;
129
130    bool Run([[maybe_unused]] uint32_t threadIndex) override
131    {
132        ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SaveTask::Run");
133        encoder_->StartSaveTask(this);
134        return true;
135    }
136
137    TaskType GetTaskType() const override
138    {
139        return TaskType::PGO_SAVE_TASK;
140    }
141
142    NO_COPY_SEMANTIC(SaveTask);
143    NO_MOVE_SEMANTIC(SaveTask);
144private:
145    PGOProfilerEncoder *encoder_;
146};
147
148class ResetOutPathTask : public Task {
149public:
150    ResetOutPathTask(PGOProfilerEncoder *encoder, std::string moduleName, int32_t id)
151        : Task(id), encoder_(encoder), moduleName_(std::move(moduleName)) {};
152    virtual ~ResetOutPathTask() override = default;
153
154    bool Run([[maybe_unused]] uint32_t threadIndex) override
155    {
156        ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "ResetOutPathTask::Run");
157        encoder_->ResetOutPathByModuleName(moduleName_);
158        return true;
159    }
160
161    TaskType GetTaskType() const override
162    {
163        return TaskType::PGO_RESET_OUT_PATH_TASK;
164    }
165
166    NO_COPY_SEMANTIC(ResetOutPathTask);
167    NO_MOVE_SEMANTIC(ResetOutPathTask);
168
169private:
170    PGOProfilerEncoder *encoder_;
171    std::string moduleName_;
172};
173} // namespace panda::ecmascript::pgo
174#endif  // ECMASCRIPT_PGO_PROFILER_ENCODER_H
175