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