1 /*
2  * Copyright (c) 2022 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_PROFILE_DECODER_H
17 #define ECMASCRIPT_PGO_PROFILE_DECODER_H
18 
19 #include "ecmascript/jspandafile/method_literal.h"
20 #include "ecmascript/log.h"
21 #include "ecmascript/log_wrapper.h"
22 #include "ecmascript/pgo_profiler/pgo_profiler_info.h"
23 #include "ecmascript/pgo_profiler/pgo_utils.h"
24 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
25 #include "ecmascript/platform/map.h"
26 
27 namespace panda::ecmascript::pgo {
28 class PGOProfilerDecoder {
29 public:
30     PGOProfilerDecoder() = default;
PGOProfilerDecoder(const std::string &inPath, uint32_t hotnessThreshold)31     PGOProfilerDecoder(const std::string &inPath, uint32_t hotnessThreshold)
32         : inPath_(inPath), hotnessThreshold_(hotnessThreshold) {}
33 
~PGOProfilerDecoder()34     virtual ~PGOProfilerDecoder()
35     {
36         Clear();
37     };
38 
39     NO_COPY_SEMANTIC(PGOProfilerDecoder);
40     NO_MOVE_SEMANTIC(PGOProfilerDecoder);
41 
42     bool PUBLIC_API Match(const JSPandaFile *jsPandaFile, const CString &recordName, PGOMethodId methodId);
43 
44     bool PUBLIC_API LoadAndVerify(uint32_t checksum,
45                                   const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool = nullptr);
46     bool PUBLIC_API LoadFull(const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool = nullptr);
47     void PUBLIC_API Clear();
48 
49     bool PUBLIC_API SaveAPTextFile(const std::string &outPath);
50 
51     void Merge(const PGOProfilerDecoder &decoder);
52 
GetAbcFilePool() const53     std::shared_ptr<PGOAbcFilePool> GetAbcFilePool() const
54     {
55         return abcFilePool_;
56     }
57 
58     bool InitMergeData();
59 
SetInPath(const std::string &inPath)60     void SetInPath(const std::string &inPath)
61     {
62         LOG_COMPILER(INFO) << "Set Profiler paths: " << inPath;
63         inPath_ = inPath;
64     }
65 
GetInPath() const66     const std::string& GetInPath() const
67     {
68         return inPath_;
69     }
70 
SetHotnessThreshold(uint32_t hotnessThreshold)71     void SetHotnessThreshold(uint32_t hotnessThreshold)
72     {
73         hotnessThreshold_ = hotnessThreshold;
74     }
75 
GetHotnessThreshold() const76     uint32_t GetHotnessThreshold() const
77     {
78         return hotnessThreshold_;
79     }
80 
81     template <typename Callback>
Update(const JSPandaFile *jsPandaFile, Callback callback)82     void Update(const JSPandaFile *jsPandaFile, Callback callback)
83     {
84         if (!isLoaded_ || !isVerifySuccess_) {
85             return;
86         }
87         recordSimpleInfos_->Update(GetNormalizedFileDesc(jsPandaFile), callback);
88     }
89 
90     template <typename Callback>
Update(const JSPandaFile *jsPandaFile, const CString &recordName, Callback callback)91     void Update(const JSPandaFile *jsPandaFile, const CString &recordName, Callback callback)
92     {
93         if (!isLoaded_ || !isVerifySuccess_) {
94             return;
95         }
96         recordSimpleInfos_->Update(GetNormalizedFileDesc(jsPandaFile), recordName, callback);
97     }
98 
99     template <typename Callback>
GetTypeInfo(const JSPandaFile *jsPandaFile, const CString &recordName, const MethodLiteral *methodLiteral, Callback callback) const100     void GetTypeInfo(const JSPandaFile *jsPandaFile, const CString &recordName, const MethodLiteral *methodLiteral,
101                      Callback callback) const
102     {
103         if (!isLoaded_ || !isVerifySuccess_ || methodLiteral == nullptr) {
104             return;
105         }
106         const auto *methodName = MethodLiteral::GetMethodName(jsPandaFile, methodLiteral->GetMethodId());
107         if (IsMethodMatchEnabled()) {
108             auto checksum =
109                 PGOMethodInfo::CalcChecksum(methodName, methodLiteral->GetBytecodeArray(),
110                                             MethodLiteral::GetCodeSize(jsPandaFile, methodLiteral->GetMethodId()));
111 
112             return recordSimpleInfos_->GetTypeInfo(GetNormalizedFileDesc(jsPandaFile), recordName, methodName, checksum,
113                                                    callback);
114         }
115         recordSimpleInfos_->GetTypeInfo(GetNormalizedFileDesc(jsPandaFile), recordName, methodName, callback);
116     }
117 
MatchAndMarkMethod(const JSPandaFile *jsPandaFile, const CString &recordName, const char *methodName, EntityId methodId)118     void MatchAndMarkMethod(const JSPandaFile *jsPandaFile, const CString &recordName, const char *methodName,
119                             EntityId methodId)
120     {
121         if (!isLoaded_ || !isVerifySuccess_) {
122             return;
123         }
124         recordSimpleInfos_->MatchAndMarkMethod(GetNormalizedFileDesc(jsPandaFile), recordName, methodName, methodId);
125     }
126 
127     void PUBLIC_API GetMismatchResult(const JSPandaFile *jsPandaFile, uint32_t &totalMethodCount,
128         uint32_t &mismatchMethodCount, std::set<std::pair<std::string, CString>> &mismatchMethodSet) const;
129 
IsMethodMatchEnabled() const130     bool IsMethodMatchEnabled() const
131     {
132         return header_->SupportMethodChecksum();
133     }
134 
135     bool PUBLIC_API GetHClassTreeDesc(PGOSampleType profileType, PGOHClassTreeDesc **desc) const;
136 
137     template <typename Callback>
IterateHClassTreeDesc(Callback callback) const138     bool IterateHClassTreeDesc(Callback callback) const
139     {
140         if (!isLoaded_ || !isVerifySuccess_) {
141             return false;
142         }
143         return recordSimpleInfos_->IterateHClassTreeDesc(callback);
144     }
145 
146     template <typename Callback>
IterateProtoTransitionPool(Callback callback) const147     bool IterateProtoTransitionPool(Callback callback) const
148     {
149         if (!isLoaded_ || !isVerifySuccess_) {
150             return false;
151         }
152         return recordSimpleInfos_->IterateProtoTransitionPool(callback);
153     }
154 
IsLoaded() const155     bool IsLoaded() const
156     {
157         return isLoaded_;
158     }
159 
GetRecordDetailInfos() const160     PGORecordDetailInfos &GetRecordDetailInfos() const
161     {
162         return *recordDetailInfos_;
163     }
164 
GetRecordDetailInfosPtr() const165     std::shared_ptr<PGORecordDetailInfos> GetRecordDetailInfosPtr() const
166     {
167         return recordDetailInfos_;
168     }
169 
GetRecordSimpleInfos() const170     PGORecordSimpleInfos &GetRecordSimpleInfos() const
171     {
172         return *recordSimpleInfos_;
173     }
174 
GetPandaFileInfos() const175     const PGOPandaFileInfos &GetPandaFileInfos() const
176     {
177         return pandaFileInfos_;
178     }
179 
GetAbcNameById(ApEntityId abcId, CString &abcName) const180     bool GetAbcNameById(ApEntityId abcId, CString &abcName) const
181     {
182         ASSERT(header_ != nullptr);
183         if (!header_->SupportProfileTypeWithAbcId()) {
184             return false;
185         }
186         ASSERT(abcFilePool_ != nullptr);
187         ASSERT(abcFilePool_->GetPool() != nullptr);
188         const auto *entry = abcFilePool_->GetPool()->GetEntry(abcId);
189         if (entry == nullptr) {
190             LOG_COMPILER(ERROR) << "Can not find abcId in pgo file. abcId: " << abcId;
191             return false;
192         }
193         abcName = entry->GetData();
194         return true;
195     }
196 
GetABCIdByJSPandaFile(const JSPandaFile *jsPandaFile, ApEntityId &entryId) const197     bool GetABCIdByJSPandaFile(const JSPandaFile *jsPandaFile, ApEntityId &entryId) const
198     {
199         if (abcFilePool_ == nullptr) {
200             return false;
201         }
202         CString name = jsPandaFile->GetNormalizedFileDesc();
203         return abcFilePool_->GetEntryIdByNormalizedName(name, entryId);
204     }
205 
IsCompatibleWithAOTFile()206     bool IsCompatibleWithAOTFile()
207     {
208         // Can be null when AP file path is empty
209         if (header_ == nullptr) {
210             return false;
211         }
212         return header_->IsCompatibleWithAOTFile();
213     }
214 
215 private:
216     bool Load(const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool);
217     bool Verify(uint32_t checksum);
218 
219     bool LoadAPBinaryFile(int prot = PAGE_PROT_READ);
220     void UnLoadAPBinaryFile();
221     CString PUBLIC_API GetNormalizedFileDesc(const JSPandaFile *jsPandaFile) const;
222     void LoadAbcIdPool(const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool, PGOContext &context,
223                        void *addr);
224 
225     bool isLoaded_ {false};
226     bool isVerifySuccess_ {false};
227     std::string inPath_;
228     uint32_t hotnessThreshold_ {0};
229     PGOProfilerHeader *header_ {nullptr};
230     PGOPandaFileInfos pandaFileInfos_;
231     std::shared_ptr<PGOAbcFilePool> abcFilePool_;
232     bool externalAbcFilePool_ {false};
233     std::shared_ptr<PGORecordDetailInfos> recordDetailInfos_;
234     std::unique_ptr<PGORecordSimpleInfos> recordSimpleInfos_;
235     MemMap fileMapAddr_;
236 };
237 } // namespace panda::ecmascript::pgo
238 #endif  // ECMASCRIPT_PGO_PROFILE_DECODER_H
239