1 /*
2 * Copyright (c) 2023-2024 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_info.h"
17 #include "ecmascript/ohos/framework_helper.h"
18 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
19 #include "libpandafile/bytecode_instruction-inl.h"
20
21 namespace panda::ecmascript::pgo {
22 using StringHelper = base::StringHelper;
ParseFromBinary(void * buffer,SectionInfo * const info)23 void PGOPandaFileInfos::ParseFromBinary(void *buffer, SectionInfo *const info)
24 {
25 void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
26 for (uint32_t i = 0; i < info->number_; i++) {
27 fileInfos_.emplace(*base::ReadBufferInSize<FileInfo>(&addr));
28 }
29 LOG_ECMA(DEBUG) << "Profiler panda file count:" << info->number_;
30 }
31
ProcessToBinary(std::fstream & fileStream,SectionInfo * info) const32 void PGOPandaFileInfos::ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const
33 {
34 fileStream.seekp(info->offset_);
35 info->number_ = fileInfos_.size();
36 for (auto localInfo : fileInfos_) {
37 fileStream.write(reinterpret_cast<char *>(&localInfo), FileInfo::Size());
38 }
39 info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
40 }
41
Merge(const PGOPandaFileInfos & pandaFileInfos)42 void PGOPandaFileInfos::Merge(const PGOPandaFileInfos &pandaFileInfos)
43 {
44 for (const auto &info : pandaFileInfos.fileInfos_) {
45 fileInfos_.emplace(info.GetChecksum(), info.GetAbcId());
46 }
47 }
48
MergeSafe(const PGOPandaFileInfos & pandaFileInfos)49 void PGOPandaFileInfos::MergeSafe(const PGOPandaFileInfos& pandaFileInfos)
50 {
51 WriteLockHolder lock(fileInfosLock_);
52 Merge(pandaFileInfos);
53 }
54
VerifyChecksum(const PGOPandaFileInfos & pandaFileInfos,const std::string & base,const std::string & incoming) const55 bool PGOPandaFileInfos::VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
56 const std::string &incoming) const
57 {
58 std::set<FileInfo> unionChecksum;
59 set_union(fileInfos_.begin(), fileInfos_.end(), pandaFileInfos.fileInfos_.begin(), pandaFileInfos.fileInfos_.end(),
60 inserter(unionChecksum, unionChecksum.begin()));
61 if (!fileInfos_.empty() && unionChecksum.empty()) {
62 LOG_ECMA(ERROR) << "First AP file(" << base << ") and the incoming file(" << incoming
63 << ") do not come from the same abc file, skip merge the incoming file.";
64 return false;
65 }
66 return true;
67 }
68
ProcessToText(std::ofstream & stream) const69 void PGOPandaFileInfos::ProcessToText(std::ofstream &stream) const
70 {
71 std::string pandaFileInfo = DumpUtils::NEW_LINE + DumpUtils::PANDA_FILE_INFO_HEADER;
72 bool isFirst = true;
73 for (auto &info : fileInfos_) {
74 if (!isFirst) {
75 pandaFileInfo += DumpUtils::BLOCK_SEPARATOR + DumpUtils::SPACE;
76 } else {
77 isFirst = false;
78 }
79 pandaFileInfo += (std::to_string(info.GetAbcId()) + DumpUtils::BLOCK_START);
80 pandaFileInfo += std::to_string(info.GetChecksum());
81 }
82
83 pandaFileInfo += (DumpUtils::SPACE + DumpUtils::ARRAY_END + DumpUtils::NEW_LINE);
84 stream << pandaFileInfo;
85 }
86
Checksum(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap,const std::shared_ptr<PGOAbcFilePool> & abcFilePool) const87 bool PGOPandaFileInfos::Checksum(const std::unordered_map<CString, uint32_t>& fileNameToChecksumMap,
88 const std::shared_ptr<PGOAbcFilePool>& abcFilePool) const
89 {
90 for (const auto& fileNameToChecksumPair: fileNameToChecksumMap) {
91 ApEntityId abcId(0);
92 abcFilePool->GetEntryIdByNormalizedName(fileNameToChecksumPair.first, abcId);
93 FileInfo tempInfo = FileInfo(fileNameToChecksumPair.second, abcId);
94 auto it = fileInfos_.find(tempInfo);
95 if (it != fileInfos_.end()) {
96 if (it->GetChecksum() != tempInfo.GetChecksum()) {
97 LOG_ECMA(ERROR)
98 << "Checksum verification failed. Please ensure that the "
99 ".abc and .ap match. Fail file: "
100 << fileNameToChecksumPair.first << "\n"
101 << " compile file checksum: "
102 << fileNameToChecksumPair.second
103 << " recorded checksum in ap file: " << it->GetChecksum();
104 return false;
105 }
106 }
107 }
108 return true;
109 }
110
Checksum(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap) const111 bool PGOPandaFileInfos::Checksum(const std::unordered_map<CString, uint32_t>& fileNameToChecksumMap) const
112 {
113 for (const auto& fileNameToChecksumPair: fileNameToChecksumMap) {
114 for (const auto &fileInfo : fileInfos_) {
115 if (fileInfo.GetChecksum() == fileNameToChecksumPair.second) {
116 return true;
117 }
118 }
119 }
120 LOG_ECMA(ERROR) << "Checksum verification failed. Please ensure that the .abc and .ap match.";
121 return false;
122 }
123
UpdateFileInfosAbcID(const PGOContext & context)124 void PGOPandaFileInfos::UpdateFileInfosAbcID(const PGOContext &context)
125 {
126 std::set<FileInfo> newFileInfos;
127 auto oldToNewInfoMap = context.GetAbcIdRemap();
128 for (const auto &fileInfo : fileInfos_) {
129 auto changeInfo = oldToNewInfoMap.find(fileInfo.GetAbcId());
130 if (changeInfo != oldToNewInfoMap.end()) {
131 newFileInfos.emplace(fileInfo.GetChecksum(), changeInfo->second);
132 } else {
133 newFileInfos.emplace(fileInfo);
134 }
135 }
136 fileInfos_.swap(newFileInfos);
137 }
138
ProcessToText(std::string & text) const139 void PGOMethodInfo::ProcessToText(std::string &text) const
140 {
141 text += std::to_string(GetMethodId().GetOffset());
142 text += DumpUtils::ELEMENT_SEPARATOR;
143 text += std::to_string(GetCount());
144 text += DumpUtils::ELEMENT_SEPARATOR;
145 text += GetSampleModeToString();
146 text += DumpUtils::ELEMENT_SEPARATOR;
147 text += GetMethodName();
148 }
149
ProcessToJson(ProfileType::VariantMap & function) const150 void PGOMethodInfo::ProcessToJson(ProfileType::VariantMap &function) const
151 {
152 std::string methodName = GetMethodName();
153 std::string functionName = methodName + "(" + std::to_string(GetMethodId().GetOffset()) + ")";
154 function.insert(std::make_pair(DumpJsonUtils::FUNCTION_NAME, functionName));
155 }
156
ParseFromText(const std::string & infoString)157 std::vector<std::string> PGOMethodInfo::ParseFromText(const std::string &infoString)
158 {
159 std::vector<std::string> infoStrings = StringHelper::SplitString(infoString, DumpUtils::ELEMENT_SEPARATOR);
160 return infoStrings;
161 }
162
CalcChecksum(const char * name,const uint8_t * byteCodeArray,uint32_t byteCodeLength)163 uint32_t PGOMethodInfo::CalcChecksum(const char *name, const uint8_t *byteCodeArray, uint32_t byteCodeLength)
164 {
165 uint32_t checksum = 0;
166 if (byteCodeArray != nullptr) {
167 checksum = CalcOpCodeChecksum(byteCodeArray, byteCodeLength);
168 }
169
170 if (name != nullptr) {
171 checksum = adler32(checksum, reinterpret_cast<const Bytef *>(name), strlen(name));
172 }
173 return checksum;
174 }
175
CalcOpCodeChecksum(const uint8_t * byteCodeArray,uint32_t byteCodeLength)176 uint32_t PGOMethodInfo::CalcOpCodeChecksum(const uint8_t *byteCodeArray, uint32_t byteCodeLength)
177 {
178 uint32_t checksum = 0;
179 BytecodeInstruction bcIns(byteCodeArray);
180 auto bcInsLast = bcIns.JumpTo(byteCodeLength);
181 while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
182 auto opCode = bcIns.GetOpcode();
183 checksum = adler32(checksum, reinterpret_cast<const Bytef *>(&opCode), sizeof(decltype(opCode)));
184 bcIns = bcIns.GetNext();
185 }
186 return checksum;
187 }
188
AddMethod(Chunk * chunk,Method * jsMethod,SampleMode mode)189 bool PGOMethodInfoMap::AddMethod(Chunk *chunk, Method *jsMethod, SampleMode mode)
190 {
191 PGOMethodId methodId(jsMethod->GetMethodId());
192 auto result = methodInfos_.find(methodId);
193 if (result != methodInfos_.end()) {
194 auto info = result->second;
195 info->IncreaseCount();
196 info->SetSampleMode(mode);
197 return false;
198 } else {
199 CString methodName = jsMethod->GetMethodName();
200 size_t strlen = methodName.size();
201 size_t size = static_cast<size_t>(PGOMethodInfo::Size(strlen));
202 void *infoAddr = chunk->Allocate(size);
203 if (infoAddr == nullptr) {
204 LOG_ECMA(ERROR) << "infoAddr is null!";
205 return false;
206 }
207 auto info = new (infoAddr) PGOMethodInfo(methodId, 0, mode, methodName.c_str());
208 info->IncreaseCount();
209 methodInfos_.emplace(methodId, info);
210 auto checksum = PGOMethodInfo::CalcChecksum(jsMethod->GetMethodName(), jsMethod->GetBytecodeArray(),
211 jsMethod->GetCodeSize());
212 methodsChecksum_.emplace(methodId, checksum);
213 return true;
214 }
215 }
216
GetOrInsertMethodTypeSet(Chunk * chunk,PGOMethodId methodId)217 PGOMethodTypeSet *PGOMethodInfoMap::GetOrInsertMethodTypeSet(Chunk *chunk, PGOMethodId methodId)
218 {
219 auto typeInfoSetIter = methodTypeInfos_.find(methodId);
220 if (typeInfoSetIter != methodTypeInfos_.end()) {
221 return typeInfoSetIter->second;
222 } else {
223 auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
224 methodTypeInfos_.emplace(methodId, typeInfoSet);
225 return typeInfoSet;
226 }
227 }
228
AddType(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGOSampleType type)229 bool PGOMethodInfoMap::AddType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type)
230 {
231 auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
232 ASSERT(typeInfoSet != nullptr);
233 typeInfoSet->AddType(offset, type);
234 return true;
235 }
236
AddCallTargetType(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGOSampleType type)237 bool PGOMethodInfoMap::AddCallTargetType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type)
238 {
239 auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
240 ASSERT(typeInfoSet != nullptr);
241 typeInfoSet->AddCallTargetType(offset, type);
242 return true;
243 }
244
AddObjectInfo(Chunk * chunk,PGOMethodId methodId,int32_t offset,const PGOObjectInfo & info)245 bool PGOMethodInfoMap::AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info)
246 {
247 auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
248 ASSERT(typeInfoSet != nullptr);
249 typeInfoSet->AddObjectInfo(offset, info);
250 return true;
251 }
252
AddDefine(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGODefineOpType type)253 bool PGOMethodInfoMap::AddDefine(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGODefineOpType type)
254 {
255 auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
256 ASSERT(typeInfoSet != nullptr);
257 typeInfoSet->AddDefine(offset, type);
258 return true;
259 }
260
Merge(Chunk * chunk,PGOMethodInfoMap * methodInfos)261 void PGOMethodInfoMap::Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos)
262 {
263 for (auto iter = methodInfos->methodInfos_.begin(); iter != methodInfos->methodInfos_.end(); iter++) {
264 auto methodId = iter->first;
265 auto fromMethodInfo = iter->second;
266
267 auto result = methodInfos_.find(methodId);
268 if (result != methodInfos_.end()) {
269 auto toMethodInfo = result->second;
270 toMethodInfo->Merge(fromMethodInfo);
271 } else {
272 size_t len = strlen(fromMethodInfo->GetMethodName());
273 size_t size = static_cast<size_t>(PGOMethodInfo::Size(len));
274 void *infoAddr = chunk->Allocate(size);
275 auto newMethodInfo = new (infoAddr) PGOMethodInfo(
276 methodId, fromMethodInfo->GetCount(), fromMethodInfo->GetSampleMode(), fromMethodInfo->GetMethodName());
277 methodInfos_.emplace(methodId, newMethodInfo);
278 }
279 fromMethodInfo->ClearCount();
280 }
281
282 for (auto iter = methodInfos->methodTypeInfos_.begin(); iter != methodInfos->methodTypeInfos_.end(); iter++) {
283 auto methodId = iter->first;
284 auto fromTypeInfo = iter->second;
285
286 auto result = methodTypeInfos_.find(methodId);
287 if (result != methodTypeInfos_.end()) {
288 auto toTypeInfo = result->second;
289 toTypeInfo->Merge(fromTypeInfo);
290 } else {
291 auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
292 typeInfoSet->Merge(fromTypeInfo);
293 methodTypeInfos_.emplace(methodId, typeInfoSet);
294 }
295 }
296
297 for (auto iter = methodInfos->methodsChecksum_.begin(); iter != methodInfos->methodsChecksum_.end(); iter++) {
298 auto methodId = iter->first;
299 auto result = methodsChecksum_.find(methodId);
300 if (result == methodsChecksum_.end()) {
301 methodsChecksum_.emplace(methodId, iter->second);
302 }
303 }
304 }
305
ParseFromBinary(Chunk * chunk,PGOContext & context,void ** buffer)306 bool PGOMethodInfoMap::ParseFromBinary(Chunk *chunk, PGOContext &context, void **buffer)
307 {
308 PGOProfilerHeader *const header = context.GetHeader();
309 ASSERT(header != nullptr);
310 SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
311 for (uint32_t j = 0; j < secInfo.number_; j++) {
312 PGOMethodInfo *info = base::ReadBufferInSize<PGOMethodInfo>(buffer);
313 if (info->IsFilter(context.GetHotnessThreshold())) {
314 if (header->SupportMethodChecksum()) {
315 base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
316 }
317 if (header->SupportType()) {
318 PGOMethodTypeSet::SkipFromBinary(buffer);
319 }
320 continue;
321 }
322 methodInfos_.emplace(info->GetMethodId(), info);
323 LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << DumpUtils::ELEMENT_SEPARATOR << info->GetCount()
324 << DumpUtils::ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
325 << DumpUtils::ELEMENT_SEPARATOR << info->GetMethodName();
326 if (header->SupportMethodChecksum()) {
327 auto checksum = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
328 methodsChecksum_.emplace(info->GetMethodId(), checksum);
329 }
330 if (header->SupportType()) {
331 auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
332 typeInfoSet->ParseFromBinary(context, buffer);
333 methodTypeInfos_.emplace(info->GetMethodId(), typeInfoSet);
334 }
335 }
336 return !methodInfos_.empty();
337 }
338
ProcessToBinary(PGOContext & context,ProfileTypeRef recordProfileRef,const SaveTask * task,std::fstream & stream,PGOProfilerHeader * const header) const339 bool PGOMethodInfoMap::ProcessToBinary(PGOContext &context, ProfileTypeRef recordProfileRef, const SaveTask *task,
340 std::fstream &stream, PGOProfilerHeader *const header) const
341 {
342 SectionInfo secInfo;
343 std::stringstream methodStream;
344 for (auto iter = methodInfos_.begin(); iter != methodInfos_.end(); iter++) {
345 LOG_ECMA(DEBUG) << "Method:" << iter->first << DumpUtils::ELEMENT_SEPARATOR << iter->second->GetCount()
346 << DumpUtils::ELEMENT_SEPARATOR
347 << std::to_string(static_cast<int>(iter->second->GetSampleMode()))
348 << DumpUtils::ELEMENT_SEPARATOR << iter->second->GetMethodName();
349 if (task && task->IsTerminate()) {
350 LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
351 return false;
352 }
353 auto curMethodInfo = iter->second;
354 if (curMethodInfo->IsFilter(context.GetHotnessThreshold())) {
355 continue;
356 }
357 methodStream.write(reinterpret_cast<char *>(curMethodInfo), curMethodInfo->Size());
358 if (header->SupportMethodChecksum()) {
359 auto checksumIter = methodsChecksum_.find(curMethodInfo->GetMethodId());
360 uint32_t checksum = 0;
361 if (checksumIter != methodsChecksum_.end()) {
362 checksum = checksumIter->second;
363 }
364 methodStream.write(reinterpret_cast<char *>(&checksum), sizeof(uint32_t));
365 }
366 if (header->SupportType()) {
367 auto typeInfoIter = methodTypeInfos_.find(curMethodInfo->GetMethodId());
368 if (typeInfoIter != methodTypeInfos_.end()) {
369 typeInfoIter->second->ProcessToBinary(context, methodStream);
370 } else {
371 uint32_t number = 0;
372 methodStream.write(reinterpret_cast<char *>(&number), sizeof(uint32_t));
373 }
374 }
375 secInfo.number_++;
376 }
377 if (secInfo.number_ > 0) {
378 secInfo.offset_ = sizeof(SectionInfo);
379 secInfo.size_ = static_cast<uint32_t>(methodStream.tellp());
380 stream.write(reinterpret_cast<char *>(&recordProfileRef), sizeof(uint32_t));
381 stream.write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo));
382 stream << methodStream.rdbuf();
383 return true;
384 }
385 return false;
386 }
387
ParseFromText(Chunk * chunk,uint32_t threshold,const std::vector<std::string> & content)388 bool PGOMethodInfoMap::ParseFromText(Chunk *chunk, uint32_t threshold, const std::vector<std::string> &content)
389 {
390 for (auto infoString : content) {
391 std::vector<std::string> infoStrings = PGOMethodInfo::ParseFromText(infoString);
392 if (infoStrings.size() < PGOMethodInfo::METHOD_INFO_COUNT) {
393 LOG_ECMA(ERROR) << "method info:" << infoString << " format error";
394 return false;
395 }
396 uint32_t count;
397 if (!StringHelper::StrToUInt32(infoStrings[PGOMethodInfo::METHOD_COUNT_INDEX].c_str(), &count)) {
398 LOG_ECMA(ERROR) << "count: " << infoStrings[PGOMethodInfo::METHOD_COUNT_INDEX] << " parse failed";
399 return false;
400 }
401 SampleMode mode;
402 if (!PGOMethodInfo::GetSampleMode(infoStrings[PGOMethodInfo::METHOD_MODE_INDEX], mode)) {
403 LOG_ECMA(ERROR) << "mode: " << infoStrings[PGOMethodInfo::METHOD_MODE_INDEX] << " parse failed";
404 return false;
405 }
406 if (count < threshold && mode == SampleMode::CALL_MODE) {
407 return true;
408 }
409 uint32_t methodId;
410 if (!StringHelper::StrToUInt32(infoStrings[PGOMethodInfo::METHOD_ID_INDEX].c_str(), &methodId)) {
411 LOG_ECMA(ERROR) << "method id: " << infoStrings[PGOMethodInfo::METHOD_ID_INDEX] << " parse failed";
412 return false;
413 }
414 std::string methodName = infoStrings[PGOMethodInfo::METHOD_NAME_INDEX];
415
416 void *infoAddr = chunk->Allocate(PGOMethodInfo::Size(methodName.size()));
417 auto info = new (infoAddr) PGOMethodInfo(PGOMethodId(methodId), count, mode, methodName.c_str());
418 methodInfos_.emplace(methodId, info);
419
420 // Parse Type Info
421 if (infoStrings.size() <= PGOMethodTypeSet::METHOD_TYPE_INFO_INDEX) {
422 continue;
423 }
424 std::string typeInfos = infoStrings[PGOMethodTypeSet::METHOD_TYPE_INFO_INDEX];
425 if (!typeInfos.empty()) {
426 size_t start = typeInfos.find_first_of(DumpUtils::ARRAY_START);
427 size_t end = typeInfos.find_last_of(DumpUtils::ARRAY_END);
428 if (start == std::string::npos || end == std::string::npos || start > end) {
429 LOG_ECMA(ERROR) << "Type info: " << typeInfos << " parse failed";
430 return false;
431 }
432 ASSERT(end > start + 1);
433 auto typeContent = typeInfos.substr(start + 1, end - (start + 1) - 1);
434 auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
435 if (!typeInfoSet->ParseFromText(typeContent)) {
436 // delete by chunk
437 LOG_ECMA(ERROR) << "Type info: " << typeInfos << " parse failed";
438 return false;
439 }
440 methodTypeInfos_.emplace(info->GetMethodId(), typeInfoSet);
441 }
442 }
443
444 return true;
445 }
446
ProcessToText(uint32_t threshold,const CString & recordName,std::ofstream & stream) const447 void PGOMethodInfoMap::ProcessToText(uint32_t threshold, const CString &recordName, std::ofstream &stream) const
448 {
449 std::string profilerString;
450 bool isFirst = true;
451 for (auto methodInfoIter : methodInfos_) {
452 auto methodInfo = methodInfoIter.second;
453 if (methodInfo->IsFilter(threshold)) {
454 continue;
455 }
456 if (isFirst) {
457 profilerString += DumpUtils::NEW_LINE;
458 profilerString += recordName;
459 profilerString += DumpUtils::BLOCK_START + DumpUtils::SPACE + DumpUtils::ARRAY_START;
460 profilerString += DumpUtils::NEW_LINE + DumpUtils::ALIGN;
461 isFirst = false;
462 } else {
463 profilerString += DumpUtils::BLOCK_SEPARATOR + DumpUtils::NEW_LINE + DumpUtils::ALIGN;
464 }
465 methodInfo->ProcessToText(profilerString);
466 profilerString += DumpUtils::ELEMENT_SEPARATOR;
467 auto checksumIter = methodsChecksum_.find(methodInfo->GetMethodId());
468 if (checksumIter != methodsChecksum_.end()) {
469 std::stringstream parseStream;
470 parseStream << std::internal << std::setfill('0') << std::showbase
471 << std::setw(DumpUtils::HEX_FORMAT_WIDTH_FOR_32BITS) << std::hex << checksumIter->second
472 << DumpUtils::ELEMENT_SEPARATOR;
473 profilerString += parseStream.str();
474 }
475 auto iter = methodTypeInfos_.find(methodInfo->GetMethodId());
476 if (iter != methodTypeInfos_.end()) {
477 iter->second->ProcessToText(profilerString);
478 }
479 }
480 if (!isFirst) {
481 profilerString += (DumpUtils::NEW_LINE + DumpUtils::ARRAY_END + DumpUtils::NEW_LINE);
482 stream << profilerString;
483 }
484 }
485
ProcessToJson(uint32_t threshold,ProfileType::jModuleType & jModule) const486 void PGOMethodInfoMap::ProcessToJson(uint32_t threshold, ProfileType::jModuleType &jModule) const
487 {
488 std::vector<ProfileType::VariantMap> functionArray;
489 for (auto methodInfoIter : methodInfos_) {
490 auto methodInfo = methodInfoIter.second;
491 if (methodInfo->IsFilter(threshold)) {
492 continue;
493 }
494 ProfileType::VariantMap function;
495 methodInfo->ProcessToJson(function);
496 auto iter = methodTypeInfos_.find(methodInfo->GetMethodId());
497 if (iter != methodTypeInfos_.end()) {
498 ProfileType::VariantVector typeArray;
499 iter->second->ProcessToJson(typeArray);
500 function.insert(std::make_pair(DumpJsonUtils::TYPE, typeArray));
501 }
502 functionArray.push_back(function);
503 }
504 jModule.insert(std::make_pair(DumpJsonUtils::FUNCTION, functionArray));
505 }
506
ParseFromBinary(PGOContext & context,void ** buffer)507 bool PGOMethodIdSet::ParseFromBinary(PGOContext &context, void **buffer)
508 {
509 PGOProfilerHeader *const header = context.GetHeader();
510 ASSERT(header != nullptr);
511 SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
512 for (uint32_t j = 0; j < secInfo.number_; j++) {
513 PGOMethodInfo *info = base::ReadBufferInSize<PGOMethodInfo>(buffer);
514 if (info->IsFilter(context.GetHotnessThreshold())) {
515 if (header->SupportMethodChecksum()) {
516 base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
517 }
518 if (header->SupportType()) {
519 PGOMethodTypeSet::SkipFromBinary(buffer);
520 }
521 continue;
522 }
523 uint32_t checksum = 0;
524 if (header->SupportMethodChecksum()) {
525 checksum = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
526 }
527 auto ret = methodInfoMap_.try_emplace(info->GetMethodName(), chunk_);
528 auto methodNameSetIter = ret.first;
529 auto &methodInfo = methodNameSetIter->second.GetOrCreateMethodInfo(checksum, info->GetMethodId());
530 LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << DumpUtils::ELEMENT_SEPARATOR << info->GetCount()
531 << DumpUtils::ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
532 << DumpUtils::ELEMENT_SEPARATOR << info->GetMethodName();
533 if (header->SupportType()) {
534 methodInfo.GetPGOMethodTypeSet().ParseFromBinary(context, buffer);
535 }
536 }
537
538 return !methodInfoMap_.empty();
539 }
540
GetMismatchResult(const CString & recordName,uint32_t & totalMethodCount,uint32_t & mismatchMethodCount,std::set<std::pair<std::string,CString>> & mismatchMethodSet) const541 void PGOMethodIdSet::GetMismatchResult(const CString &recordName, uint32_t &totalMethodCount,
542 uint32_t &mismatchMethodCount,
543 std::set<std::pair<std::string, CString>> &mismatchMethodSet) const
544 {
545 totalMethodCount += methodInfoMap_.size();
546 for (const auto &methodNameSet : methodInfoMap_) {
547 if (methodNameSet.second.IsMatch()) {
548 continue;
549 }
550 auto info = std::make_pair(methodNameSet.first, recordName);
551 mismatchMethodSet.emplace(info);
552 mismatchMethodCount++;
553 }
554 }
555
Merge(const PGOMethodIdSet & from)556 void PGOMethodIdSet::Merge(const PGOMethodIdSet &from)
557 {
558 for (const auto &methodNameSet : from.methodInfoMap_) {
559 auto iter = methodInfoMap_.find(methodNameSet.first);
560 if (iter == methodInfoMap_.end()) {
561 auto ret = methodInfoMap_.try_emplace(methodNameSet.first, chunk_);
562 iter = ret.first;
563 }
564 const_cast<PGOMethodNameSet &>(iter->second).Merge(methodNameSet.second);
565 }
566 }
567
Merge(const PGODecodeMethodInfo & from)568 void PGODecodeMethodInfo::Merge(const PGODecodeMethodInfo &from)
569 {
570 ASSERT(methodId_.IsValid() && from.methodId_.IsValid());
571 if (!(methodId_ == from.methodId_)) {
572 LOG_ECMA(ERROR) << "MethodId not match. " << methodId_ << " vs " << from.methodId_;
573 return;
574 }
575 pgoMethodTypeSet_.Merge(&from.pgoMethodTypeSet_);
576 }
577
PGORecordDetailInfos(uint32_t hotnessThreshold)578 PGORecordDetailInfos::PGORecordDetailInfos(uint32_t hotnessThreshold) : hotnessThreshold_(hotnessThreshold)
579 {
580 chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
581 InitSections();
582 };
583
~PGORecordDetailInfos()584 PGORecordDetailInfos::~PGORecordDetailInfos()
585 {
586 Clear();
587 }
588
GetMethodInfoMap(ProfileType recordProfileType)589 PGOMethodInfoMap *PGORecordDetailInfos::GetMethodInfoMap(ProfileType recordProfileType)
590 {
591 auto iter = recordInfos_.find(recordProfileType);
592 if (iter != recordInfos_.end()) {
593 return iter->second;
594 } else {
595 auto curMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
596 recordInfos_.emplace(recordProfileType, curMethodInfos);
597 return curMethodInfos;
598 }
599 }
600
AddMethod(ProfileType recordProfileType,Method * jsMethod,SampleMode mode)601 bool PGORecordDetailInfos::AddMethod(ProfileType recordProfileType, Method *jsMethod, SampleMode mode)
602 {
603 auto curMethodInfos = GetMethodInfoMap(recordProfileType);
604 ASSERT(curMethodInfos != nullptr);
605 ASSERT(jsMethod != nullptr);
606 return curMethodInfos->AddMethod(chunk_.get(), jsMethod, mode);
607 }
608
AddType(ProfileType recordProfileType,PGOMethodId methodId,int32_t offset,PGOSampleType type)609 bool PGORecordDetailInfos::AddType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset,
610 PGOSampleType type)
611 {
612 auto curMethodInfos = GetMethodInfoMap(recordProfileType);
613 ASSERT(curMethodInfos != nullptr);
614 return curMethodInfos->AddType(chunk_.get(), methodId, offset, type);
615 }
616
AddCallTargetType(ProfileType recordProfileType,PGOMethodId methodId,int32_t offset,PGOSampleType type)617 bool PGORecordDetailInfos::AddCallTargetType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset,
618 PGOSampleType type)
619 {
620 auto curMethodInfos = GetMethodInfoMap(recordProfileType);
621 ASSERT(curMethodInfos != nullptr);
622 return curMethodInfos->AddCallTargetType(chunk_.get(), methodId, offset, type);
623 }
624
AddObjectInfo(ProfileType recordProfileType,EntityId methodId,int32_t offset,const PGOObjectInfo & info)625 bool PGORecordDetailInfos::AddObjectInfo(
626 ProfileType recordProfileType, EntityId methodId, int32_t offset, const PGOObjectInfo &info)
627 {
628 auto curMethodInfos = GetMethodInfoMap(recordProfileType);
629 ASSERT(curMethodInfos != nullptr);
630 return curMethodInfos->AddObjectInfo(chunk_.get(), methodId, offset, info);
631 }
632
AddDefine(ProfileType recordProfileType,PGOMethodId methodId,int32_t offset,PGODefineOpType type)633 bool PGORecordDetailInfos::AddDefine(
634 ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGODefineOpType type)
635 {
636 auto curMethodInfos = GetMethodInfoMap(recordProfileType);
637 ASSERT(curMethodInfos != nullptr);
638 curMethodInfos->AddDefine(chunk_.get(), methodId, offset, type);
639
640 PGOHClassTreeDesc descInfo(type.GetProfileType());
641 auto iter = hclassTreeDescInfos_.find(descInfo);
642 if (iter == hclassTreeDescInfos_.end()) {
643 descInfo.SetProtoPt(type.GetPrototypePt());
644 hclassTreeDescInfos_.emplace(descInfo);
645 } else {
646 const_cast<PGOHClassTreeDesc &>(*iter).SetProtoPt(type.GetPrototypePt());
647 }
648 return true;
649 }
650
AddRootLayout(JSTaggedType hclass,ProfileType rootType)651 bool PGORecordDetailInfos::AddRootLayout(JSTaggedType hclass, ProfileType rootType)
652 {
653 PGOHClassTreeDesc descInfo(rootType);
654 auto iter = hclassTreeDescInfos_.find(descInfo);
655 if (iter != hclassTreeDescInfos_.end()) {
656 return const_cast<PGOHClassTreeDesc &>(*iter).DumpForRoot(hclass, rootType);
657 } else {
658 if (!descInfo.DumpForRoot(hclass, rootType)) {
659 return false;
660 }
661 hclassTreeDescInfos_.emplace(descInfo);
662 }
663 return true;
664 }
665
UpdateLayout(ProfileType rootType,JSTaggedType hclass,ProfileType curType)666 bool PGORecordDetailInfos::UpdateLayout(ProfileType rootType, JSTaggedType hclass, ProfileType curType)
667 {
668 PGOHClassTreeDesc descInfo(rootType);
669 auto iter = hclassTreeDescInfos_.find(descInfo);
670 if (iter != hclassTreeDescInfos_.end()) {
671 return const_cast<PGOHClassTreeDesc &>(*iter).UpdateLayout(hclass, curType);
672 } else {
673 if (!descInfo.UpdateLayout(hclass, curType)) {
674 return false;
675 }
676 hclassTreeDescInfos_.emplace(descInfo);
677 return false;
678 }
679 return true;
680 }
681
UpdateTransitionLayout(ProfileType rootType,JSTaggedType parent,ProfileType parentType,JSTaggedType child,ProfileType childType)682 bool PGORecordDetailInfos::UpdateTransitionLayout(
683 ProfileType rootType, JSTaggedType parent, ProfileType parentType, JSTaggedType child, ProfileType childType)
684 {
685 PGOHClassTreeDesc descInfo(rootType);
686 auto iter = hclassTreeDescInfos_.find(descInfo);
687 if (iter != hclassTreeDescInfos_.end()) {
688 return const_cast<PGOHClassTreeDesc &>(*iter).UpdateForTransition(parent, parentType, child, childType);
689 } else {
690 if (!descInfo.UpdateForTransition(parent, parentType, child, childType)) {
691 return false;
692 }
693 hclassTreeDescInfos_.emplace(descInfo);
694 }
695 return true;
696 }
697
AddRootPtType(ProfileType rootType,ProfileType ptType)698 void PGORecordDetailInfos::AddRootPtType(ProfileType rootType, ProfileType ptType)
699 {
700 PGOHClassTreeDesc descInfo(rootType);
701 auto iter = hclassTreeDescInfos_.find(descInfo);
702 if (iter != hclassTreeDescInfos_.end()) {
703 const_cast<PGOHClassTreeDesc &>(*iter).SetProtoPt(ptType);
704 } else {
705 descInfo.SetProtoPt(ptType);
706 hclassTreeDescInfos_.emplace(descInfo);
707 }
708 }
709
IsDumped(ProfileType rootType,ProfileType curType) const710 bool PGORecordDetailInfos::IsDumped(ProfileType rootType, ProfileType curType) const
711 {
712 PGOHClassTreeDesc descInfo(rootType);
713 auto iter = hclassTreeDescInfos_.find(descInfo);
714 if (iter != hclassTreeDescInfos_.end()) {
715 return const_cast<PGOHClassTreeDesc &>(*iter).IsDumped(curType);
716 }
717 return false;
718 }
719
Merge(const PGORecordDetailInfos & recordInfos)720 void PGORecordDetailInfos::Merge(const PGORecordDetailInfos &recordInfos)
721 {
722 const auto& methodInfos = recordInfos.recordInfos_;
723 for (auto& iter: methodInfos) {
724 auto recordType = iter.first;
725 auto fromMethodInfos = iter.second;
726
727 auto recordInfosIter = recordInfos_.find(recordType);
728 PGOMethodInfoMap *toMethodInfos = nullptr;
729 if (recordInfosIter == recordInfos_.end()) {
730 toMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
731 recordInfos_.emplace(recordType, toMethodInfos);
732 } else {
733 toMethodInfos = recordInfosIter->second;
734 }
735
736 ASSERT(toMethodInfos != nullptr);
737 toMethodInfos->Merge(chunk_.get(), fromMethodInfos);
738 }
739
740 recordPool_->Merge(*recordInfos.recordPool_);
741 protoTransitionPool_->Merge(*recordInfos.protoTransitionPool_);
742 // Merge global layout desc infos to global method info map
743 const auto& hclassTreeDescInfos = recordInfos.hclassTreeDescInfos_;
744 for (auto& fromInfo: hclassTreeDescInfos) {
745 auto result = hclassTreeDescInfos_.find(fromInfo);
746 if (result == hclassTreeDescInfos_.end()) {
747 PGOHClassTreeDesc descInfo(fromInfo.GetProfileType());
748 descInfo.SetProtoPt(fromInfo.GetProtoPt());
749 descInfo.Merge(fromInfo);
750 hclassTreeDescInfos_.emplace(descInfo);
751 } else {
752 const_cast<PGOHClassTreeDesc &>(*result).Merge(fromInfo);
753 }
754 }
755 }
756
MergeSafe(const PGORecordDetailInfos & recordInfos)757 void PGORecordDetailInfos::MergeSafe(const PGORecordDetailInfos& recordInfos)
758 {
759 LockHolder lock(mutex_);
760 Merge(recordInfos);
761 }
762
ParseFromBinary(void * buffer,PGOProfilerHeader * const header)763 bool PGORecordDetailInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header)
764 {
765 header_ = header;
766 // ProfileTypePool must be parsed at first
767 PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *profileTypePool_->GetPool());
768 if (!abcIdRemap_.empty()) {
769 // step2: [abc pool merge] remap decoder's profileType pool's abcId field.
770 LOG_ECMA(DEBUG) << "remap with abcRemapSize: " << abcIdRemap_.size();
771 profileTypePool_->Remap(*this);
772 }
773 PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *protoTransitionPool_);
774 PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *recordPool_);
775 SectionInfo *info = header->GetRecordInfoSection();
776 void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
777 for (uint32_t i = 0; i < info->number_; i++) {
778 ApEntityId recordId(0);
779 ProfileType recordType;
780 if (header->SupportProfileTypeWithAbcId()) {
781 auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
782 auto res = ProfileType::CreateFromProfileTypeRef(*this, recordTypeRef);
783 if (!res.has_value()) {
784 LOG_ECMA(ERROR) << "ParseFromBinary failed, current addr: " << addr << std::endl;
785 return false;
786 }
787 recordType = res.value();
788 recordId = recordType.GetId();
789 } else if (header->SupportRecordPool()) {
790 recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
791 } else {
792 auto *recordName = base::ReadBuffer(&addr);
793 recordPool_->Add(ProfileType(recordId), recordName);
794 }
795 recordType.UpdateId(recordId);
796 recordType.UpdateKind(ProfileType::Kind::RecordClassId);
797 PGOMethodInfoMap *methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
798 ASSERT(methodInfos != nullptr);
799 if (methodInfos->ParseFromBinary(chunk_.get(), *this, &addr)) {
800 recordInfos_.emplace(recordType, methodInfos);
801 } else {
802 nativeAreaAllocator_.Delete(methodInfos);
803 }
804 }
805
806 info = header->GetLayoutDescSection();
807 if (info == nullptr) {
808 return false;
809 }
810 if (header->SupportTrackField()) {
811 ParseFromBinaryForLayout(&addr);
812 }
813 return true;
814 }
815
ParseFromBinaryForLayout(void ** buffer)816 bool PGORecordDetailInfos::ParseFromBinaryForLayout(void **buffer)
817 {
818 SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
819 for (uint32_t i = 0; i < secInfo.number_; i++) {
820 auto *info = base::ReadBufferInSize<PGOHClassTreeDescInnerRef>(buffer);
821 if (info == nullptr) {
822 LOG_ECMA(INFO) << "Binary format error!";
823 continue;
824 }
825 hclassTreeDescInfos_.emplace(info->Convert(*this));
826 }
827 return true;
828 }
829
ProcessToBinary(const SaveTask * task,std::fstream & fileStream,PGOProfilerHeader * const header)830 void PGORecordDetailInfos::ProcessToBinary(
831 const SaveTask *task, std::fstream &fileStream, PGOProfilerHeader *const header)
832 {
833 header_ = header;
834 auto info = header->GetRecordInfoSection();
835 info->number_ = 0;
836 info->offset_ = static_cast<uint32_t>(fileStream.tellp());
837 for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
838 if (task && task->IsTerminate()) {
839 LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
840 break;
841 }
842 auto recordId = iter->first;
843 auto curMethodInfos = iter->second;
844 if (curMethodInfos->ProcessToBinary(*this, ProfileTypeRef(*this, recordId), task, fileStream, header)) {
845 info->number_++;
846 }
847 }
848 info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
849
850 info = header->GetLayoutDescSection();
851 if (info == nullptr) {
852 return;
853 }
854 info->number_ = 0;
855 info->offset_ = static_cast<uint32_t>(fileStream.tellp());
856 if (header->SupportType()) {
857 if (!ProcessToBinaryForLayout(const_cast<NativeAreaAllocator *>(&nativeAreaAllocator_), task, fileStream)) {
858 return;
859 }
860 info->number_++;
861 }
862 info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
863
864 PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *recordPool_);
865 PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *protoTransitionPool_);
866 // ProfileTypePool must be processed at last
867 PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *profileTypePool_->GetPool());
868 }
869
ProcessToBinaryForLayout(NativeAreaAllocator * allocator,const SaveTask * task,std::fstream & stream)870 bool PGORecordDetailInfos::ProcessToBinaryForLayout(
871 NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream)
872 {
873 SectionInfo secInfo;
874 auto layoutBeginPosition = stream.tellp();
875 stream.seekp(sizeof(SectionInfo), std::ofstream::cur);
876 for (const auto &typeInfo : hclassTreeDescInfos_) {
877 if (task && task->IsTerminate()) {
878 LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
879 return false;
880 }
881 auto profileType = PGOSampleType(typeInfo.GetProfileType());
882 size_t size = PGOHClassTreeDescInnerRef::CaculateSize(typeInfo);
883 if (size == 0) {
884 continue;
885 }
886
887 PGOSampleTypeRef classRef = PGOSampleTypeRef::ConvertFrom(*this, profileType);
888 auto protoSt = PGOSampleType(typeInfo.GetProtoPt());
889 PGOSampleTypeRef protoClassRef = PGOSampleTypeRef::ConvertFrom(*this, protoSt);
890 void *addr = allocator->Allocate(size);
891 auto descInfos = new (addr) PGOHClassTreeDescInnerRef(size, classRef, protoClassRef);
892 descInfos->Merge(typeInfo);
893 stream.write(reinterpret_cast<char *>(descInfos), size);
894 allocator->Delete(addr);
895 secInfo.number_++;
896 }
897
898 secInfo.offset_ = sizeof(SectionInfo);
899 secInfo.size_ = static_cast<uint32_t>(stream.tellp()) -
900 static_cast<uint32_t>(layoutBeginPosition) - sizeof(SectionInfo);
901 stream.seekp(layoutBeginPosition, std::ofstream::beg)
902 .write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo))
903 .seekp(0, std::ofstream::end);
904 return true;
905 }
906
ProcessToText(std::ofstream & stream) const907 void PGORecordDetailInfos::ProcessToText(std::ofstream &stream) const
908 {
909 std::string profilerString;
910 bool isFirst = true;
911 for (auto layoutInfoIter : hclassTreeDescInfos_) {
912 if (isFirst) {
913 profilerString += DumpUtils::NEW_LINE;
914 profilerString += DumpUtils::ARRAY_START + DumpUtils::NEW_LINE;
915 profilerString += DumpUtils::ALIGN;
916 isFirst = false;
917 } else {
918 profilerString += DumpUtils::BLOCK_SEPARATOR + DumpUtils::NEW_LINE;
919 profilerString += DumpUtils::ALIGN;
920 }
921 profilerString += PGOHClassTreeDescInner::GetTypeString(layoutInfoIter);
922 }
923 if (!isFirst) {
924 profilerString += (DumpUtils::NEW_LINE + DumpUtils::ARRAY_END + DumpUtils::NEW_LINE);
925 stream << profilerString;
926 }
927 for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
928 const CString recordName(recordPool_->GetName(iter->first));
929 if (recordName.empty()) {
930 LOG_ECMA(ERROR) << "record name is empty, " << iter->first.GetTypeString();
931 continue;
932 }
933 auto methodInfos = iter->second;
934 methodInfos->ProcessToText(hotnessThreshold_, recordName, stream);
935 }
936 recordPool_->ProcessToText(stream);
937 protoTransitionPool_->ProcessToText(stream);
938 // ProfileTypePool must be processed at last
939 profileTypePool_->GetPool()->ProcessToText(stream);
940 }
941
InitSections()942 void PGORecordDetailInfos::InitSections()
943 {
944 recordPool_ = std::make_unique<PGORecordPool>();
945 protoTransitionPool_ = std::make_unique<PGOProtoTransitionPool>();
946 profileTypePool_ = std::make_unique<PGOProfileTypePool>();
947 }
948
Clear()949 void PGORecordDetailInfos::Clear()
950 {
951 for (auto iter : recordInfos_) {
952 iter.second->Clear();
953 nativeAreaAllocator_.Delete(iter.second);
954 }
955 for (auto iter : hclassTreeDescInfos_) {
956 iter.Clear();
957 }
958 hclassTreeDescInfos_.clear();
959 recordInfos_.clear();
960 recordPool_->Clear();
961 protoTransitionPool_->Clear();
962 profileTypePool_->Clear();
963 hclassTreeDescInfos_.clear();
964 abcIdRemap_.clear();
965 chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
966 InitSections();
967 }
968
ClearSafe()969 void PGORecordDetailInfos::ClearSafe()
970 {
971 LockHolder lock(mutex_);
972 Clear();
973 }
974
Match(const CString & abcNormalizedDesc,const CString & recordName,EntityId methodId)975 bool PGORecordSimpleInfos::Match(const CString &abcNormalizedDesc, const CString &recordName, EntityId methodId)
976 {
977 auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
978 if (abcMethodIds == methodIds_.end()) {
979 LOG_COMPILER(DEBUG) << "AbcDesc not found. abcNormalizedDesc: " << abcNormalizedDesc
980 << ", methodIdsCount: " << methodIds_.size();
981 return false;
982 }
983 auto methodIdsIter = abcMethodIds->second.find(recordName);
984 if (methodIdsIter == abcMethodIds->second.end()) {
985 LOG_COMPILER(DEBUG) << "AbcDesc not found. recordName: " << recordName;
986 return false;
987 }
988 return methodIdsIter->second->Match(methodId);
989 }
990
ParseFromBinary(void * buffer,PGOProfilerHeader * const header,std::shared_ptr<PGOAbcFilePool> & abcFilePool)991 void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header,
992 std::shared_ptr<PGOAbcFilePool> &abcFilePool)
993 {
994 header_ = header;
995 // ProfileTypePool must be parsed at first
996 if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *profileTypePool_->GetPool())) {
997 LOG_ECMA(ERROR) << "Parse from binary failed for profile type pool.";
998 return;
999 }
1000 if (!abcIdRemap_.empty()) {
1001 // step2: [abc pool merge] remap decoder's profileType pool's abcId field.
1002 LOG_ECMA(DEBUG) << "remap with abcRemapSize: " << abcIdRemap_.size();
1003 profileTypePool_->Remap(*this);
1004 }
1005 if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *protoTransitionPool_)) {
1006 LOG_ECMA(ERROR) << "Parse from binary failed for proto transition pool.";
1007 return;
1008 }
1009 if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *recordPool_)) {
1010 LOG_ECMA(ERROR) << "Parse from binary failed for record pool.";
1011 return;
1012 }
1013 SectionInfo *info = header->GetRecordInfoSection();
1014 void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
1015 for (uint32_t i = 0; i < info->number_; i++) {
1016 CString recordName;
1017 const char *abcDesc = "";
1018 ProfileType recordType;
1019 if (header->SupportProfileTypeWithAbcId()) {
1020 auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
1021 recordType = ProfileType(*this, recordTypeRef);
1022 recordName = recordPool_->GetName(recordType);
1023 auto abcId = recordType.GetAbcId();
1024 const auto *entry = abcFilePool->GetPool()->GetEntry(abcId);
1025 if (entry != nullptr) {
1026 abcDesc = entry->GetData().c_str();
1027 }
1028 } else if (header->SupportRecordPool()) {
1029 auto recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
1030 recordName = recordPool_->GetName(ProfileType(recordId));
1031 } else {
1032 recordName = base::ReadBuffer(&addr);
1033 }
1034 PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1035 if (methodIds->ParseFromBinary(*this, &addr)) {
1036 auto methodIdsResult = methodIds_.try_emplace(JSPandaFile::GetNormalizedFileDesc(abcDesc));
1037 // check record name, the default record name of the framework abc does not enter the aot compilation
1038 FrameworkHelper::GetRealRecordName(recordName);
1039 (methodIdsResult.first->second).emplace(recordName, methodIds);
1040 } else {
1041 nativeAreaAllocator_.Delete(methodIds);
1042 }
1043 }
1044
1045 info = header->GetLayoutDescSection();
1046 if (info == nullptr) {
1047 return;
1048 }
1049 if (header->SupportTrackField()) {
1050 ParseFromBinaryForLayout(&addr);
1051 }
1052 }
1053
Merge(const PGORecordSimpleInfos & simpleInfos)1054 void PGORecordSimpleInfos::Merge(const PGORecordSimpleInfos &simpleInfos)
1055 {
1056 for (const auto &fromAbcMethodIds : simpleInfos.methodIds_) {
1057 auto toAbcMethodIds = methodIds_.try_emplace(fromAbcMethodIds.first);
1058 for (const auto &method : fromAbcMethodIds.second) {
1059 auto result = toAbcMethodIds.first->second.find(method.first);
1060 if (result == toAbcMethodIds.first->second.end()) {
1061 PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1062 auto ret = toAbcMethodIds.first->second.emplace(method.first, methodIds);
1063 ASSERT(ret.second);
1064 result = ret.first;
1065 }
1066 const_cast<PGOMethodIdSet &>(*result->second).Merge(*method.second);
1067 }
1068 }
1069 recordPool_->Merge(*simpleInfos.recordPool_);
1070 protoTransitionPool_->Merge(*simpleInfos.protoTransitionPool_);
1071 // Merge global layout desc infos to global method info map
1072 for (const auto &hclassTreeDescInfo : simpleInfos.hclassTreeDescInfos_) {
1073 auto result = hclassTreeDescInfos_.find(hclassTreeDescInfo);
1074 if (result == hclassTreeDescInfos_.end()) {
1075 PGOHClassTreeDesc descInfo(hclassTreeDescInfo.GetProfileType());
1076 descInfo.SetProtoPt(hclassTreeDescInfo.GetProtoPt());
1077 descInfo.Merge(hclassTreeDescInfo);
1078 hclassTreeDescInfos_.emplace(descInfo);
1079 } else {
1080 const_cast<PGOHClassTreeDesc &>(*result).Merge(hclassTreeDescInfo);
1081 }
1082 }
1083 }
1084
ParseFromBinaryForLayout(void ** buffer)1085 bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer)
1086 {
1087 SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
1088 for (uint32_t i = 0; i < secInfo.number_; i++) {
1089 auto *info = base::ReadBufferInSize<PGOHClassTreeDescInnerRef>(buffer);
1090 if (info == nullptr) {
1091 LOG_ECMA(INFO) << "Binary format error!";
1092 continue;
1093 }
1094 hclassTreeDescInfos_.emplace(info->Convert(*this));
1095 }
1096 return true;
1097 }
1098
InitSections()1099 void PGORecordSimpleInfos::InitSections()
1100 {
1101 recordPool_ = std::make_unique<PGORecordPool>();
1102 protoTransitionPool_ = std::make_unique<PGOProtoTransitionPool>();
1103 profileTypePool_ = std::make_unique<PGOProfileTypePool>();
1104 }
1105
Clear()1106 void PGORecordSimpleInfos::Clear()
1107 {
1108 for (const auto &abcMethodIds: methodIds_) {
1109 for (const auto &iter : abcMethodIds.second) {
1110 iter.second->Clear();
1111 nativeAreaAllocator_.Delete(iter.second);
1112 }
1113 }
1114 for (auto iter : hclassTreeDescInfos_) {
1115 iter.Clear();
1116 }
1117 hclassTreeDescInfos_.clear();
1118 methodIds_.clear();
1119 recordPool_->Clear();
1120 profileTypePool_->Clear();
1121 hclassTreeDescInfos_.clear();
1122 abcIdRemap_.clear();
1123 chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1124 InitSections();
1125 }
1126
PGORecordSimpleInfos(uint32_t threshold)1127 PGORecordSimpleInfos::PGORecordSimpleInfos(uint32_t threshold) : hotnessThreshold_(threshold)
1128 {
1129 chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1130 InitSections();
1131 }
1132
~PGORecordSimpleInfos()1133 PGORecordSimpleInfos::~PGORecordSimpleInfos()
1134 {
1135 Clear();
1136 }
1137 } // namespace panda::ecmascript::pgo
1138