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