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 *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 IsEnable()109 bool IsEnable() const 110 { 111 return encoder_ && encoder_->IsInitialized(); 112 } 113 Destroy(std::shared_ptr<PGOProfiler> & profiler)114 void Destroy(std::shared_ptr<PGOProfiler> &profiler) 115 { 116 if (profiler != nullptr) { 117 profiler->HandlePGOPreDump(); 118 profiler->WaitPGODumpFinish(); 119 Merge(profiler.get()); 120 { 121 os::memory::LockHolder lock(*mutex_); 122 profilers_.erase(profiler); 123 } 124 profiler.reset(); 125 } 126 } 127 Reset(const std::shared_ptr<PGOProfiler> & profiler,bool isEnable)128 void Reset(const std::shared_ptr<PGOProfiler>& profiler, bool isEnable) 129 { 130 if (isEnable) { 131 isEnable = InitializeData(); 132 } 133 if (profiler) { 134 profiler->Reset(isEnable); 135 } 136 } 137 SamplePandaFileInfo(uint32_t checksum,const CString & abcName)138 void SamplePandaFileInfo(uint32_t checksum, const CString &abcName) 139 { 140 if (encoder_) { 141 encoder_->SamplePandaFileInfo(checksum, abcName); 142 } 143 } 144 SetModuleName(const std::string & moduleName)145 void SetModuleName(const std::string &moduleName) 146 { 147 if (encoder_) { 148 encoder_->PostResetOutPathTask(moduleName); 149 } 150 } 151 GetPandaFileId(const CString & abcName,ApEntityId & entryId)152 bool GetPandaFileId(const CString &abcName, ApEntityId &entryId) const 153 { 154 if (encoder_) { 155 return encoder_->GetPandaFileId(abcName, entryId); 156 } 157 return false; 158 } 159 GetPandaFileDesc(ApEntityId abcId,CString & desc)160 bool GetPandaFileDesc(ApEntityId abcId, CString &desc) const 161 { 162 if (encoder_) { 163 return encoder_->GetPandaFileDesc(abcId, desc); 164 } 165 return false; 166 } 167 SetApGenMode(ApGenMode mode)168 void SetApGenMode(ApGenMode mode) 169 { 170 if (encoder_) { 171 encoder_->SetApGenMode(mode); 172 } 173 } 174 Merge(PGOProfiler * profiler)175 void Merge(PGOProfiler *profiler) 176 { 177 if (encoder_ && profiler->isEnable_) { 178 encoder_->TerminateSaveTask(); 179 encoder_->Merge(*profiler->recordInfos_); 180 } 181 } 182 183 void RegisterSavingSignal(); 184 AsynSave()185 void AsynSave() 186 { 187 if (encoder_) { 188 encoder_->PostSaveTask(); 189 } 190 } 191 IsDisableAot()192 bool IsDisableAot() const 193 { 194 return disableAot_; 195 } 196 SetDisableAot(bool state)197 void SetDisableAot(bool state) 198 { 199 disableAot_ = state; 200 } 201 ForceSave()202 void ForceSave() 203 { 204 os::memory::LockHolder lock(*mutex_); 205 for (const auto &profiler : profilers_) { 206 profiler->DumpByForce(); 207 } 208 GetInstance()->AsynSave(); 209 } 210 TextToBinary(const std::string & inPath,const std::string & outPath,uint32_t hotnessThreshold,ApGenMode mode)211 bool PUBLIC_API TextToBinary(const std::string &inPath, const std::string &outPath, uint32_t hotnessThreshold, 212 ApGenMode mode) 213 { 214 PGOProfilerEncoder encoder(outPath, hotnessThreshold, mode); 215 PGOProfilerEncoder decoder(outPath, hotnessThreshold, mode); 216 if (!encoder.InitializeData()) { 217 LOG_ECMA(ERROR) << "PGO Profiler encoder initialized failed"; 218 return false; 219 } 220 if (!decoder.InitializeData()) { 221 LOG_ECMA(ERROR) << "PGO Profiler decoder initialized failed"; 222 return false; 223 } 224 bool ret = decoder.LoadAPTextFile(inPath); 225 if (ret) { 226 encoder.Merge(decoder); 227 ret = encoder.Save(); 228 } 229 encoder.Destroy(); 230 decoder.Destroy(); 231 return ret; 232 } 233 BinaryToText(const std::string & inPath,const std::string & outPath,uint32_t hotnessThreshold)234 bool PUBLIC_API BinaryToText(const std::string &inPath, const std::string &outPath, uint32_t hotnessThreshold) 235 { 236 PGOProfilerDecoder decoder(inPath, hotnessThreshold); 237 if (!decoder.LoadFull()) { 238 return false; 239 } 240 bool ret = decoder.SaveAPTextFile(outPath); 241 decoder.Clear(); 242 return ret; 243 } 244 245 static bool MergeApFiles(const std::string &inFiles, const std::string &outPath, uint32_t hotnessThreshold, 246 ApGenMode mode); 247 static bool MergeApFiles(uint32_t checksum, PGOProfilerDecoder &merger); 248 249 private: InitializeData()250 bool InitializeData() 251 { 252 if (!encoder_) { 253 return false; 254 } 255 bool initializedResult = encoder_->InitializeData(); 256 if (initializedResult && !enableSignalSaving_) { 257 RegisterSavingSignal(); 258 } 259 return initializedResult; 260 } 261 262 bool disableAot_ {false}; 263 std::unique_ptr<PGOProfilerEncoder> encoder_; 264 RequestAotCallback requestAotCallback_; 265 std::atomic_bool enableSignalSaving_ { false }; 266 os::memory::Mutex *mutex_ = new os::memory::Mutex(); 267 std::set<std::shared_ptr<PGOProfiler>> profilers_; 268 }; 269 } // namespace panda::ecmascript::pgo 270 #endif // ECMASCRIPT_PGO_PROFILER_MANAGER_H 271