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