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