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 22namespace panda::ecmascript::pgo { 23bool 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 51bool 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 60bool 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 74bool 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 104void 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 123bool 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 149bool 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 170void PGOProfilerDecoder::UnLoadAPBinaryFile() 171{ 172 if (fileMapAddr_.GetOriginAddr() != nullptr && fileMapAddr_.GetSize() > 0) { 173 FileUnMap(fileMapAddr_); 174 fileMapAddr_.Reset(); 175 } 176} 177 178void 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 199bool 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 210bool PGOProfilerDecoder::GetHClassTreeDesc(PGOSampleType profileType, PGOHClassTreeDesc **desc) const 211{ 212 if (!isLoaded_ || !isVerifySuccess_) { 213 return false; 214 } 215 return recordSimpleInfos_->GetHClassTreeDesc(profileType, desc); 216} 217 218void 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 229CString PGOProfilerDecoder::GetNormalizedFileDesc(const JSPandaFile *jsPandaFile) const 230{ 231 ASSERT(jsPandaFile != nullptr); 232 if (header_->SupportProfileTypeWithAbcId()) { 233 return jsPandaFile->GetNormalizedFileDesc(); 234 } 235 return ""; 236} 237 238bool 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 259void 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