• 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 #ifndef ECMASCRIPT_PGO_PROFILER_MANAGER_H
17 #define ECMASCRIPT_PGO_PROFILER_MANAGER_H
18 
19 #include <atomic>
20 #include <csignal>
21 #include <memory>
22 
23 #include "ecmascript/pgo_profiler/pgo_profiler.h"
24 #include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
25 #include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
26 #include "os/mutex.h"
27 
28 namespace panda::ecmascript::pgo {
29 class PGOProfilerManager {
30 public:
31     using ApGenMode = PGOProfilerEncoder::ApGenMode;
32     static PGOProfilerManager *PUBLIC_API GetInstance();
33 
34     static void SavingSignalHandler(int signo);
35 
36     PGOProfilerManager() = default;
37     ~PGOProfilerManager() = default;
38 
39     NO_COPY_SEMANTIC(PGOProfilerManager);
40     NO_MOVE_SEMANTIC(PGOProfilerManager);
41 
Initialize(const std::string & outDir,uint32_t hotnessThreshold)42     void Initialize(const std::string &outDir, uint32_t hotnessThreshold)
43     {
44         // For FA jsvm, merge with existed output file
45         encoder_ = std::make_unique<PGOProfilerEncoder>(outDir, hotnessThreshold, ApGenMode::MERGE);
46     }
47 
SetBundleName(const std::string & bundleName)48     void SetBundleName(const std::string &bundleName)
49     {
50         if (encoder_) {
51             encoder_->SetBundleName(bundleName);
52         }
53     }
54 
GetBundleName()55     const std::string GetBundleName()
56     {
57         if (encoder_) {
58             return encoder_->GetBundleName();
59         }
60         return "";
61     }
62 
SetRequestAotCallback(const RequestAotCallback & cb)63     void SetRequestAotCallback(const RequestAotCallback &cb)
64     {
65         os::memory::LockHolder lock(*mutex_);
66         if (requestAotCallback_ != nullptr) {
67             return;
68         }
69         requestAotCallback_ = cb;
70     }
71 
RequestAot(const std::string & bundleName,const std::string & moduleName,RequestAotMode triggerMode)72     bool RequestAot(const std::string &bundleName, const std::string &moduleName, RequestAotMode triggerMode)
73     {
74         RequestAotCallback cb;
75         {
76             os::memory::LockHolder lock(*mutex_);
77             if (requestAotCallback_ == nullptr) {
78                 LOG_ECMA(ERROR) << "Trigger aot failed. callback is null.";
79                 return false;
80             }
81             cb = requestAotCallback_;
82         }
83         return (cb(bundleName, moduleName, static_cast<int32_t>(triggerMode)) == 0);
84     }
85 
Destroy()86     void Destroy()
87     {
88         if (encoder_) {
89             encoder_->Save();
90             encoder_->Destroy();
91             encoder_.reset();
92         }
93     }
94 
95     // Factory
Build(EcmaVM * vm,bool isEnable)96     std::shared_ptr<PGOProfiler> Build(EcmaVM *vm, bool isEnable)
97     {
98         if (isEnable) {
99             isEnable = InitializeData();
100         }
101         auto profiler = std::make_shared<PGOProfiler>(vm, isEnable);
102         {
103             os::memory::LockHolder lock(*mutex_);
104             profilers_.insert(profiler);
105         }
106         return profiler;
107     }
108 
109     // Return false if force disabled or never initialized
IsEnable()110     bool IsEnable() const
111     {
112         return !disablePGO_ && encoder_ && encoder_->IsInitialized();
113     }
114 
Destroy(std::shared_ptr<PGOProfiler> & profiler)115     void Destroy(std::shared_ptr<PGOProfiler> &profiler)
116     {
117         if (profiler != nullptr) {
118             profiler->WaitPGODumpFinish();
119             profiler->HandlePGOPreDump();
120             Merge(profiler.get());
121             {
122                 os::memory::LockHolder lock(*mutex_);
123                 profilers_.erase(profiler);
124             }
125             profiler.reset();
126         }
127     }
128 
Reset(const std::shared_ptr<PGOProfiler> & profiler,bool isEnable)129     void Reset(const std::shared_ptr<PGOProfiler>& profiler, bool isEnable)
130     {
131         if (isEnable) {
132             isEnable = InitializeData();
133         }
134         if (profiler) {
135             profiler->Reset(isEnable);
136         }
137     }
138 
SamplePandaFileInfo(uint32_t checksum,const CString & abcName)139     void SamplePandaFileInfo(uint32_t checksum, const CString &abcName)
140     {
141         if (encoder_) {
142             encoder_->SamplePandaFileInfo(checksum, abcName);
143         }
144     }
145 
SetModuleName(const std::string & moduleName)146     void SetModuleName(const std::string &moduleName)
147     {
148         if (encoder_) {
149             encoder_->PostResetOutPathTask(moduleName);
150         }
151     }
152 
GetPandaFileId(const CString & abcName,ApEntityId & entryId)153     bool GetPandaFileId(const CString &abcName, ApEntityId &entryId) const
154     {
155         if (encoder_) {
156             return encoder_->GetPandaFileId(abcName, entryId);
157         }
158         return false;
159     }
160 
GetPandaFileDesc(ApEntityId abcId,CString & desc)161     bool GetPandaFileDesc(ApEntityId abcId, CString &desc) const
162     {
163         if (encoder_) {
164             return encoder_->GetPandaFileDesc(abcId, desc);
165         }
166         return false;
167     }
168 
SetApGenMode(ApGenMode mode)169     void SetApGenMode(ApGenMode mode)
170     {
171         if (encoder_) {
172             encoder_->SetApGenMode(mode);
173         }
174     }
175 
Merge(PGOProfiler * profiler)176     void Merge(PGOProfiler *profiler)
177     {
178         if (encoder_ && profiler->isEnable_) {
179             encoder_->TerminateSaveTask();
180             encoder_->Merge(*profiler->recordInfos_);
181         }
182     }
183 
184     void RegisterSavingSignal();
185 
AsyncSave()186     void AsyncSave()
187     {
188         if (encoder_) {
189             encoder_->PostSaveTask();
190         }
191     }
192 
IsDisableAot()193     bool IsDisableAot() const
194     {
195         return disableAot_;
196     }
197 
SetDisableAot(bool state)198     void SetDisableAot(bool state)
199     {
200         disableAot_ = state;
201     }
202 
203     // Only set flag to ensure future actions will not trigger PGO path
204     // Caller should handle existing threads and PGO data properly
SetDisablePGO(bool state)205     void SetDisablePGO(bool state)
206     {
207         disablePGO_ = state;
208     }
209 
ForceSave()210     void ForceSave()
211     {
212         os::memory::LockHolder lock(*mutex_);
213         for (const auto &profiler : profilers_) {
214             profiler->DumpByForce();
215         }
216         GetInstance()->AsyncSave();
217     }
218 
TextToBinary(const std::string & inPath,const std::string & outPath,uint32_t hotnessThreshold,ApGenMode mode)219     bool PUBLIC_API TextToBinary(const std::string &inPath, const std::string &outPath, uint32_t hotnessThreshold,
220                                  ApGenMode mode)
221     {
222         PGOProfilerEncoder encoder(outPath, hotnessThreshold, mode);
223         PGOProfilerEncoder decoder(outPath, hotnessThreshold, mode);
224         if (!encoder.InitializeData()) {
225             LOG_ECMA(ERROR) << "PGO Profiler encoder initialized failed";
226             return false;
227         }
228         if (!decoder.InitializeData()) {
229             LOG_ECMA(ERROR) << "PGO Profiler decoder initialized failed";
230             return false;
231         }
232         bool ret = decoder.LoadAPTextFile(inPath);
233         if (ret) {
234             encoder.Merge(decoder);
235             ret = encoder.Save();
236         }
237         encoder.Destroy();
238         decoder.Destroy();
239         return ret;
240     }
241 
BinaryToText(const std::string & inPath,const std::string & outPath,uint32_t hotnessThreshold)242     bool PUBLIC_API BinaryToText(const std::string &inPath, const std::string &outPath, uint32_t hotnessThreshold)
243     {
244         PGOProfilerDecoder decoder(inPath, hotnessThreshold);
245         if (!decoder.LoadFull()) {
246             return false;
247         }
248         bool ret = decoder.SaveAPTextFile(outPath);
249         decoder.Clear();
250         return ret;
251     }
252 
253     static bool PUBLIC_API MergeApFiles(const std::string &inFiles, const std::string &outPath,
254                                         uint32_t hotnessThreshold, ApGenMode mode);
255     static bool PUBLIC_API MergeApFiles(uint32_t checksum, PGOProfilerDecoder &merger);
256 
SetIsApFileCompatible(bool isCompatible)257     void SetIsApFileCompatible(bool isCompatible)
258     {
259         isApFileCompatible_ = isCompatible;
260     }
261 
GetIsApFileCompatible()262     bool GetIsApFileCompatible() const
263     {
264         return isApFileCompatible_;
265     }
266 
GetMaxAotMethodSize()267     size_t GetMaxAotMethodSize() const
268     {
269         return maxAotMethodSize_;
270     }
271 
SetMaxAotMethodSize(uint32_t value)272     void SetMaxAotMethodSize(uint32_t value)
273     {
274         maxAotMethodSize_ = value;
275     }
276 
IsBigMethod(uint32_t methodSize)277     bool IsBigMethod(uint32_t methodSize) const
278     {
279         return maxAotMethodSize_ != 0 && methodSize > maxAotMethodSize_;
280     }
281 
282 private:
InitializeData()283     bool InitializeData()
284     {
285         if (!encoder_) {
286             return false;
287         }
288         bool initializedResult = encoder_->InitializeData();
289         if (initializedResult && !enableSignalSaving_) {
290             RegisterSavingSignal();
291         }
292         return initializedResult;
293     }
294 
295     bool disableAot_ {false};
296     bool disablePGO_ {false};
297     std::unique_ptr<PGOProfilerEncoder> encoder_;
298     RequestAotCallback requestAotCallback_;
299     std::atomic_bool enableSignalSaving_ { false };
300     os::memory::Mutex *mutex_ = new os::memory::Mutex();
301     std::set<std::shared_ptr<PGOProfiler>> profilers_;
302     bool isApFileCompatible_ {true};
303     uint32_t maxAotMethodSize_ {0};
304 };
305 } // namespace panda::ecmascript::pgo
306 #endif  // ECMASCRIPT_PGO_PROFILER_MANAGER_H
307