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 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
17 #include <fstream>
18 
19 #include "ecmascript/platform/file.h"
20 namespace panda::ecmascript::pgo {
21 namespace {
22     constexpr int32_t PGO_SAVING_SIGNAL = 50;
23 } // namespace
24 
GetInstance()25 PGOProfilerManager* PGOProfilerManager::GetInstance()
26 {
27     static PGOProfilerManager* instance = new PGOProfilerManager();
28     return instance;
29 }
30 
MergeApFiles(const std::string &inFiles, const std::string &outPath, uint32_t hotnessThreshold, ApGenMode mode)31 bool PGOProfilerManager::MergeApFiles(const std::string &inFiles, const std::string &outPath, uint32_t hotnessThreshold,
32                                       ApGenMode mode)
33 {
34     arg_list_t apFileNames = base::StringHelper::SplitString(inFiles, GetFileDelimiter());
35     PGOProfilerEncoder merger(outPath, hotnessThreshold, mode);
36     if (!merger.InitializeData()) {
37         LOG_ECMA(ERROR) << "PGO Profiler encoder initialized failed. outPath: " << outPath
38                         << " ,hotnessThreshold: " << hotnessThreshold;
39         return false;
40     }
41     bool hasMerged = false;
42     std::string firstApFileName;
43     for (const auto &fileName : apFileNames) {
44         if (!base::StringHelper::EndsWith(fileName, ".ap")) {
45             LOG_ECMA(ERROR) << "The file path (" << fileName << ") does not end with .ap";
46             continue;
47         }
48         PGOProfilerDecoder decoder(fileName, hotnessThreshold);
49         if (!decoder.LoadFull(merger.GetAbcFilePool())) {
50             LOG_ECMA(ERROR) << "Fail to load file path (" << fileName << "), skip it.";
51             continue;
52         }
53         if (!hasMerged) {
54             firstApFileName = fileName;
55         } else {
56             if (!merger.VerifyPandaFileMatched(decoder.GetPandaFileInfos(), firstApFileName, fileName)) {
57                 continue;
58             }
59         }
60         if (!decoder.IsCompatibleWithAOTFile()) {
61             LOG_ECMA(ERROR) << "The ap file (" << fileName << ") is not compatible with AOT version. skip it";
62             continue;
63         }
64         merger.Merge(decoder.GetRecordDetailInfos());
65         merger.Merge(decoder.GetPandaFileInfos());
66         hasMerged = true;
67     }
68     if (!hasMerged) {
69         LOG_ECMA(ERROR)
70             << "No ap file pass verify, no ap file compatible an version, no ap file processed. Input files: "
71             << inFiles;
72         GetInstance()->SetIsApFileCompatible(false);
73         return false;
74     }
75     GetInstance()->SetIsApFileCompatible(true);
76     merger.Save();
77     return true;
78 }
79 
MergeApFiles(uint32_t checksum, PGOProfilerDecoder &merger)80 bool PGOProfilerManager::MergeApFiles(uint32_t checksum, PGOProfilerDecoder &merger)
81 {
82     uint32_t hotnessThreshold = merger.GetHotnessThreshold();
83     std::string inFiles(merger.GetInPath());
84     arg_list_t pandaFileNames = base::StringHelper::SplitString(inFiles, GetFileDelimiter());
85     if (pandaFileNames.empty()) {
86         return true;
87     }
88     merger.InitMergeData();
89     bool hasMerged = false;
90     std::string firstApFileName;
91     for (const auto &fileName : pandaFileNames) {
92         PGOProfilerDecoder decoder(fileName, hotnessThreshold);
93         if (!decoder.LoadAndVerify(checksum, merger.GetAbcFilePool())) {
94             LOG_ECMA(ERROR) << "Load and verify file (" << fileName << ") failed, skip it.";
95             continue;
96         }
97         if (!hasMerged) {
98             firstApFileName = fileName;
99         } else {
100             if (!merger.GetPandaFileInfos().VerifyChecksum(decoder.GetPandaFileInfos(), firstApFileName, fileName)) {
101                 continue;
102             }
103         }
104         if (!decoder.IsCompatibleWithAOTFile()) {
105             LOG_ECMA(ERROR) << "The ap file (" << fileName << ") is not compatible with AOT version. skip it";
106             continue;
107         }
108         merger.Merge(decoder);
109         hasMerged = true;
110     }
111     if (!hasMerged) {
112         LOG_ECMA(ERROR)
113             << "No ap file pass verify, no ap file compatible an version, no ap file processed. Input files: "
114             << inFiles;
115         GetInstance()->SetIsApFileCompatible(false);
116         return false;
117     }
118     GetInstance()->SetIsApFileCompatible(true);
119     return true;
120 }
121 
RegisterSavingSignal()122 void PGOProfilerManager::RegisterSavingSignal()
123 {
124     LOG_ECMA(INFO) << "Register Pgo Saving Signal";
125     if (encoder_ == nullptr) {
126         LOG_ECMA(ERROR) << "Can not register pgo saving signal, because encoder is null.";
127         return;
128     }
129     if (!encoder_->IsInitialized()) {
130         LOG_ECMA(DEBUG) << "Can not register pgo saving signal, because encoder is initialized.";
131         return;
132     }
133     signal(PGO_SAVING_SIGNAL, SavingSignalHandler);
134     enableSignalSaving_ = true;
135 }
136 
SavingSignalHandler(int signo)137 void PGOProfilerManager::SavingSignalHandler(int signo)
138 {
139     if (signo != PGO_SAVING_SIGNAL) {
140         return;
141     }
142 
143     PGOProfilerManager::GetInstance()->ForceSave();
144 }
145 } // namespace panda::ecmascript::pgo
146