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