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 28namespace panda::ecmascript::pgo { 29class PGOProfilerManager { 30public: 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 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 48 void SetBundleName(const std::string &bundleName) 49 { 50 if (encoder_) { 51 encoder_->SetBundleName(bundleName); 52 } 53 } 54 55 const std::string GetBundleName() 56 { 57 if (encoder_) { 58 return encoder_->GetBundleName(); 59 } 60 return ""; 61 } 62 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 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 86 void Destroy() 87 { 88 if (encoder_) { 89 encoder_->Save(); 90 encoder_->Destroy(); 91 encoder_.reset(); 92 } 93 } 94 95 // Factory 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 110 bool IsEnable() const 111 { 112 return !disablePGO_ && encoder_ && encoder_->IsInitialized(); 113 } 114 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 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 139 void SamplePandaFileInfo(uint32_t checksum, const CString &abcName) 140 { 141 if (encoder_) { 142 encoder_->SamplePandaFileInfo(checksum, abcName); 143 } 144 } 145 146 void SetModuleName(const std::string &moduleName) 147 { 148 if (encoder_) { 149 encoder_->PostResetOutPathTask(moduleName); 150 } 151 } 152 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 161 bool GetPandaFileDesc(ApEntityId abcId, CString &desc) const 162 { 163 if (encoder_) { 164 return encoder_->GetPandaFileDesc(abcId, desc); 165 } 166 return false; 167 } 168 169 void SetApGenMode(ApGenMode mode) 170 { 171 if (encoder_) { 172 encoder_->SetApGenMode(mode); 173 } 174 } 175 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 186 void AsyncSave() 187 { 188 if (encoder_) { 189 encoder_->PostSaveTask(); 190 } 191 } 192 193 bool IsDisableAot() const 194 { 195 return disableAot_; 196 } 197 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 205 void SetDisablePGO(bool state) 206 { 207 disablePGO_ = state; 208 } 209 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 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 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 257 void SetIsApFileCompatible(bool isCompatible) 258 { 259 isApFileCompatible_ = isCompatible; 260 } 261 262 bool GetIsApFileCompatible() const 263 { 264 return isApFileCompatible_; 265 } 266 267 size_t GetMaxAotMethodSize() const 268 { 269 return maxAotMethodSize_; 270 } 271 272 void SetMaxAotMethodSize(uint32_t value) 273 { 274 maxAotMethodSize_ = value; 275 } 276 277 bool IsBigMethod(uint32_t methodSize) const 278 { 279 return maxAotMethodSize_ != 0 && methodSize > maxAotMethodSize_; 280 } 281 282 bool IsEnableForceIC() const 283 { 284 return isEnableForceIC_; 285 } 286 287 void SetEnableForceIC(bool isEnableForceIC) 288 { 289 isEnableForceIC_ = isEnableForceIC; 290 } 291 292private: 293 bool InitializeData() 294 { 295 if (!encoder_) { 296 return false; 297 } 298 bool initializedResult = encoder_->InitializeData(); 299 if (initializedResult && !enableSignalSaving_) { 300 RegisterSavingSignal(); 301 } 302 return initializedResult; 303 } 304 305 bool disableAot_ {false}; 306 bool disablePGO_ {false}; 307 std::unique_ptr<PGOProfilerEncoder> encoder_; 308 RequestAotCallback requestAotCallback_; 309 std::atomic_bool enableSignalSaving_ { false }; 310 os::memory::Mutex *mutex_ = new os::memory::Mutex(); 311 std::set<std::shared_ptr<PGOProfiler>> profilers_; 312 bool isApFileCompatible_ {true}; 313 bool isEnableForceIC_ {true}; 314 uint32_t maxAotMethodSize_ {0}; 315}; 316} // namespace panda::ecmascript::pgo 317#endif // ECMASCRIPT_PGO_PROFILER_MANAGER_H 318