• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
17 #include <memory>
18 
19 #include "ecmascript/base/file_header.h"
20 #include "ecmascript/jspandafile/js_pandafile.h"
21 #include "ecmascript/jspandafile/method_literal.h"
22 #include "ecmascript/log_wrapper.h"
23 #include "ecmascript/pgo_profiler/pgo_profiler_info.h"
24 #include "ecmascript/platform/file.h"
25 
26 namespace panda::ecmascript::pgo {
Load(const std::shared_ptr<PGOAbcFilePool> & externalAbcFilePool)27 bool PGOProfilerDecoder::Load(const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool)
28 {
29     if (isLoaded_) {
30         Clear();
31     }
32     if (!LoadAPBinaryFile()) {
33         return false;
34     }
35     void *addr = fileMapAddr_.GetOriginAddr();
36 
37     if (!PGOProfilerHeader::ParseFromBinary(addr, fileMapAddr_.GetSize(), &header_)) {
38         UnLoadAPBinaryFile();
39         LOG_ECMA(ERROR) << "Parse profiler header failed";
40         return false;
41     }
42     pandaFileInfos_.ParseFromBinary(addr, header_->GetPandaInfoSection());
43 
44     if (!recordSimpleInfos_) {
45         recordSimpleInfos_ = std::make_unique<PGORecordSimpleInfos>(hotnessThreshold_);
46     }
47     LoadAbcIdPool(externalAbcFilePool, *recordSimpleInfos_, addr);
48     recordSimpleInfos_->ParseFromBinary(addr, header_, abcFilePool_);
49     UnLoadAPBinaryFile();
50 
51     isLoaded_ = true;
52     return true;
53 }
54 
Verify(uint32_t checksum)55 bool PGOProfilerDecoder::Verify(uint32_t checksum)
56 {
57     if (!isLoaded_) {
58         return false;
59     }
60     if (IsMethodMatchEnabled()) {
61         LOG_ECMA(INFO) << "Skip verify file checksum, use method checksum instead.";
62         isVerifySuccess_ = true;
63     } else {
64         isVerifySuccess_ = pandaFileInfos_.Checksum(checksum);
65     }
66     return isVerifySuccess_;
67 }
68 
LoadAndVerify(uint32_t checksum,const std::shared_ptr<PGOAbcFilePool> & externalAbcFilePool)69 bool PGOProfilerDecoder::LoadAndVerify(uint32_t checksum, const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool)
70 {
71     // The file does not exist. Enter full compiler mode.
72     if (inPath_.empty()) {
73         LOG_ECMA(INFO) << "When the file is empty. Enter full compiler mode.";
74         Clear();
75         return true;
76     }
77     if (Load(externalAbcFilePool) && Verify(checksum)) {
78         return true;
79     }
80     return false;
81 }
82 
LoadFull(const std::shared_ptr<PGOAbcFilePool> & externalAbcFilePool)83 bool PGOProfilerDecoder::LoadFull(const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool)
84 {
85     if (isLoaded_) {
86         Clear();
87     }
88     // profiler dump tools may write data to memory when merge ap files.
89     if (!LoadAPBinaryFile(PAGE_PROT_READWRITE)) {
90         return false;
91     }
92     void *addr = fileMapAddr_.GetOriginAddr();
93 
94     if (!PGOProfilerHeader::ParseFromBinary(addr, fileMapAddr_.GetSize(), &header_)) {
95         UnLoadAPBinaryFile();
96         LOG_ECMA(ERROR) << "Parse profiler header failed";
97         return false;
98     }
99     pandaFileInfos_.ParseFromBinary(addr, header_->GetPandaInfoSection());
100     if (!recordDetailInfos_) {
101         recordDetailInfos_ = std::make_shared<PGORecordDetailInfos>(hotnessThreshold_);
102     }
103 
104     LoadAbcIdPool(externalAbcFilePool, *recordDetailInfos_, addr);
105     recordDetailInfos_->ParseFromBinary(addr, header_);
106     recordDetailInfos_->ResetAbcIdRemap();
107     isLoaded_ = true;
108     return true;
109 }
110 
LoadAbcIdPool(const std::shared_ptr<PGOAbcFilePool> & externalAbcFilePool,PGOContext & context,void * addr)111 void PGOProfilerDecoder::LoadAbcIdPool(const std::shared_ptr<PGOAbcFilePool> &externalAbcFilePool,
112                                        PGOContext &context, void *addr)
113 {
114     if (externalAbcFilePool != nullptr) {
115         abcFilePool_ = externalAbcFilePool;
116         externalAbcFilePool_ = true;
117     } else {
118         abcFilePool_ = std::make_unique<PGOAbcFilePool>();
119         externalAbcFilePool_ = false;
120     }
121 
122     if (header_->SupportProfileTypeWithAbcId()) {
123         auto abcFilePoolTemp = std::make_shared<PGOAbcFilePool>();
124         PGOFileSectionInterface::ParseSectionFromBinary(context, addr, header_, *abcFilePoolTemp->GetPool());
125         // step1: [abc pool merge] merge abcFilePool from ap file to memory.
126         abcFilePool_->Merge(context, *abcFilePoolTemp);
127     }
128 }
129 
SaveAPTextFile(const std::string & outPath)130 bool PGOProfilerDecoder::SaveAPTextFile(const std::string &outPath)
131 {
132     if (!isLoaded_) {
133         return false;
134     }
135     std::string realOutPath;
136     if (!RealPath(outPath, realOutPath, false)) {
137         return false;
138     }
139     std::ofstream fileStream(realOutPath.c_str());
140     if (!fileStream.is_open()) {
141         LOG_ECMA(ERROR) << "The file path(" << realOutPath << ") open failure!";
142         return false;
143     }
144 
145     if (!header_->ProcessToText(fileStream)) {
146         return false;
147     }
148     pandaFileInfos_.ProcessToText(fileStream);
149     recordDetailInfos_->ProcessToText(fileStream);
150     abcFilePool_->GetPool()->ProcessToText(fileStream);
151     return true;
152 }
153 
LoadAPBinaryFile(int prot)154 bool PGOProfilerDecoder::LoadAPBinaryFile(int prot)
155 {
156     std::string realPath;
157     if (!RealPath(inPath_, realPath)) {
158         return false;
159     }
160 
161     static const std::string endString = ".ap";
162     if (realPath.compare(realPath.length() - endString.length(), endString.length(), endString)) {
163         LOG_ECMA(ERROR) << "The file path( " << realPath << ") does not end with .ap";
164         return false;
165     }
166     LOG_ECMA(INFO) << "Load profiler from file:" << realPath;
167     fileMapAddr_ = FileMap(realPath.c_str(), FILE_RDONLY, prot);
168     if (fileMapAddr_.GetOriginAddr() == nullptr) {
169         LOG_ECMA(ERROR) << "File mmap failed";
170         return false;
171     }
172     return true;
173 }
174 
UnLoadAPBinaryFile()175 void PGOProfilerDecoder::UnLoadAPBinaryFile()
176 {
177     if (fileMapAddr_.GetOriginAddr() != nullptr && fileMapAddr_.GetSize() > 0) {
178         FileUnMap(fileMapAddr_);
179         fileMapAddr_.Reset();
180     }
181 }
182 
Clear()183 void PGOProfilerDecoder::Clear()
184 {
185     if (isLoaded_) {
186         UnLoadAPBinaryFile();
187         isVerifySuccess_ = true;
188         hotnessThreshold_ = 0;
189         PGOProfilerHeader::Destroy(&header_);
190         pandaFileInfos_.Clear();
191         if (abcFilePool_ && !externalAbcFilePool_) {
192             abcFilePool_->Clear();
193         }
194         if (recordDetailInfos_) {
195             recordDetailInfos_->Clear();
196         }
197         if (recordSimpleInfos_) {
198             recordSimpleInfos_->Clear();
199         }
200         isLoaded_ = false;
201     }
202 }
203 
Match(const JSPandaFile * jsPandaFile,const CString & recordName,PGOMethodId methodId)204 bool PGOProfilerDecoder::Match(const JSPandaFile *jsPandaFile, const CString &recordName, PGOMethodId methodId)
205 {
206     if (!isLoaded_) {
207         return true;
208     }
209     if (!isVerifySuccess_) {
210         return false;
211     }
212     return recordSimpleInfos_->Match(GetNormalizedFileDesc(jsPandaFile), recordName, EntityId(methodId));
213 }
214 
GetHClassTreeDesc(PGOSampleType profileType,PGOHClassTreeDesc ** desc) const215 bool PGOProfilerDecoder::GetHClassTreeDesc(PGOSampleType profileType, PGOHClassTreeDesc **desc) const
216 {
217     if (!isLoaded_ || !isVerifySuccess_) {
218         return false;
219     }
220     return recordSimpleInfos_->GetHClassTreeDesc(profileType, desc);
221 }
222 
GetMismatchResult(const JSPandaFile * jsPandaFile,uint32_t & totalMethodCount,uint32_t & mismatchMethodCount,std::set<std::pair<std::string,CString>> & mismatchMethodSet) const223 void PGOProfilerDecoder::GetMismatchResult(const JSPandaFile *jsPandaFile, uint32_t &totalMethodCount,
224                                            uint32_t &mismatchMethodCount,
225                                            std::set<std::pair<std::string, CString>> &mismatchMethodSet) const
226 {
227     if (!isLoaded_ || !isVerifySuccess_) {
228         return;
229     }
230     return recordSimpleInfos_->GetMismatchResult(GetNormalizedFileDesc(jsPandaFile), totalMethodCount,
231                                                  mismatchMethodCount, mismatchMethodSet);
232 }
233 
GetNormalizedFileDesc(const JSPandaFile * jsPandaFile) const234 CString PGOProfilerDecoder::GetNormalizedFileDesc(const JSPandaFile *jsPandaFile) const
235 {
236     ASSERT(jsPandaFile != nullptr);
237     if (header_->SupportProfileTypeWithAbcId()) {
238         return jsPandaFile->GetNormalizedFileDesc();
239     }
240     return "";
241 }
242 
InitMergeData()243 bool PGOProfilerDecoder::InitMergeData()
244 {
245     ASSERT(!isLoaded_);
246     if (!recordSimpleInfos_) {
247         recordSimpleInfos_ = std::make_unique<PGORecordSimpleInfos>(hotnessThreshold_);
248     }
249     if (!header_) {
250         // For merge scene, we only care about the ap capability which is in the version field.
251         PGOProfilerHeader::Build(&header_, sizeof(PGOProfilerHeader));
252         memset_s(header_, sizeof(PGOProfilerHeader), 0, sizeof(PGOProfilerHeader));
253     }
254     if (!abcFilePool_) {
255         abcFilePool_ = std::make_shared<PGOAbcFilePool>();
256         externalAbcFilePool_ = false;
257     }
258     isLoaded_ = true;
259     isVerifySuccess_ = true;
260     return true;
261 }
262 
Merge(const PGOProfilerDecoder & decoder)263 void PGOProfilerDecoder::Merge(const PGOProfilerDecoder &decoder)
264 {
265     if (!isLoaded_ || !isVerifySuccess_) {
266         return;
267     }
268     // For merge scene, we chose the highest version from input ap files
269     if (!(header_->CompatibleVerify(decoder.header_->GetVersion()))) {
270         // For merge scene, we only care about the ap capability which is in the version field.
271         memcpy_s(header_, sizeof(base::FileHeaderBase), decoder.header_, sizeof(base::FileHeaderBase));
272     }
273     pandaFileInfos_.Merge(decoder.GetPandaFileInfos());
274     recordSimpleInfos_->Merge(decoder.GetRecordSimpleInfos());
275 }
276 } // namespace panda::ecmascript::pgo
277