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 "profile.h"
17 #include <cassert>
18 #include <cstring>
19 #include <fstream>
20 #include <istream>
21 #include <iostream>
22 #include <string>
23 #include <unordered_map>
24 #include <vector>
25 #include <sys/types.h>
26 #include <cerrno>
27 #include <algorithm>
28 #include "namemangler.h"
29 #include "file_layout.h"
30 #include "types_def.h"
31
32 namespace maple {
33 constexpr uint8 Profile::stringEnd = 0x00;
34 uint32 Profile::hotFuncCountThreshold = 0;
35 bool Profile::debug = false;
36 bool Profile::initialized = false;
37 constexpr uint32 kPrecision = 1000000;
38
Profile()39 Profile::Profile() {}
40
CheckProfileHeader(const Header & header) const41 bool Profile::CheckProfileHeader(const Header &header) const
42 {
43 return (memcmp(header.magic, kProfileMagic, sizeof(kProfileMagic)) == 0);
44 }
45
GetProfileNameByType(uint8 type) const46 std::string Profile::GetProfileNameByType(uint8 type) const
47 {
48 switch (type) {
49 case kFunction:
50 return "FUNCTION";
51 case kClassMeta:
52 return "CLASSMETA";
53 case kFieldMeta:
54 return "FIELDMETA";
55 case kMethodMeta:
56 return "METHODMETA";
57 case kReflectionStr:
58 return "ReflectionStr";
59 case kLiteral:
60 return "Literal";
61 case kBBInfo:
62 return "IRProfDescption";
63 case kIRCounter:
64 return "IRProfCounter";
65 case kFileDesc:
66 return "FileDescription";
67 default:
68 CHECK_FATAL(false, "type not found");
69 }
70 }
71
CheckDexValid(uint32 idx) const72 bool Profile::CheckDexValid(uint32 idx) const
73 {
74 if (isAppProfile) {
75 return true; // for app dont't check dexName
76 }
77 return (dexName.empty() || dexName.find(strMap.at(idx)) != std::string::npos);
78 }
79
ParseLiteral(const char * data,const char * end)80 void Profile::ParseLiteral(const char *data, const char *end)
81 {
82 if (data > end) {
83 LogInfo::MapleLogger() << "parse Literal error" << '\n';
84 }
85 const std::string str(data, end - data);
86 std::stringstream ss;
87 ss.str(str);
88 std::string item;
89 while (std::getline(ss, item)) {
90 literal.insert(item);
91 }
92 if (debug) {
93 LogInfo::MapleLogger() << "parse Literal succ literal size " << literal.size() << "\n";
94 }
95 }
96
GetFunctionName(uint32 classIdx,uint32 methodIdx,uint32 sigIdx) const97 std::string Profile::GetFunctionName(uint32 classIdx, uint32 methodIdx, uint32 sigIdx) const
98 {
99 const std::string className = namemangler::EncodeName(strMap.at(classIdx));
100 const std::string methodName = namemangler::EncodeName(strMap.at(methodIdx));
101 const std::string sigName = namemangler::EncodeName(strMap.at(sigIdx));
102 const std::string funcName = className + "_7C" + methodName + "_7C" + sigName;
103 return funcName;
104 }
105
GetMethodSigStr(uint32 methodIdx,uint32 sigIdx) const106 std::string Profile::GetMethodSigStr(uint32 methodIdx, uint32 sigIdx) const
107 {
108 const std::string methodName = namemangler::EncodeName(strMap.at(methodIdx));
109 const std::string sigName = namemangler::EncodeName(strMap.at(sigIdx));
110 const std::string methodSigStr = methodName + "_7C" + sigName;
111 return methodSigStr;
112 }
113
ParseFunc(const char * data,int32 fileNum)114 void Profile::ParseFunc(const char *data, int32 fileNum)
115 {
116 const MapleFileProf *funcProf = nullptr;
117 const FunctionItem *funcItem = nullptr;
118 size_t offset = 0;
119 for (int32 mapleFileIdx = 0; mapleFileIdx < fileNum; ++mapleFileIdx) {
120 funcProf = reinterpret_cast<const MapleFileProf *>(data + offset);
121 if (CheckDexValid(funcProf->idx)) {
122 if (debug) {
123 LogInfo::MapleLogger() << "FuncProfile"
124 << ":" << strMap.at(funcProf->idx) << ":" << funcProf->num << "\n";
125 }
126 funcItem = reinterpret_cast<const FunctionItem *>(data + offset + sizeof(MapleFileProf));
127 for (uint32 item = 0; item < funcProf->num; ++item, ++funcItem) {
128 if (funcItem->type >= kLayoutTypeCount) {
129 if (debug) {
130 LogInfo::MapleLogger() << "ParseFunc Error usupport type " << funcItem->type << "\n";
131 }
132 continue;
133 }
134 std::string funcName = GetFunctionName(funcItem->classIdx, funcItem->methodIdx, funcItem->sigIdx);
135 funcProfData.insert(
136 std::make_pair(funcName, (FuncItem) {.callTimes = funcItem->callTimes, .type = funcItem->type}));
137 }
138 }
139 // new maple file's profile
140 offset += sizeof(MapleFileProf) + funcProf->size;
141 }
142 }
143
ParseMethodSignature(const char * data,int fileNum,std::unordered_set<std::string> & metaData) const144 void Profile::ParseMethodSignature(const char *data, int fileNum, std::unordered_set<std::string> &metaData) const
145 {
146 const MapleFileProf *methodSigProf = nullptr;
147 const MethodSignatureItem *methodSigItem = nullptr;
148 uint32_t offset = 0;
149 for (int32 mapleFileIdx = 0; mapleFileIdx < fileNum; ++mapleFileIdx) {
150 methodSigProf = reinterpret_cast<const MapleFileProf *>(data + offset);
151 if (CheckDexValid(methodSigProf->idx)) {
152 if (debug) {
153 LogInfo::MapleLogger() << "MethodSignatureProfile"
154 << ":" << strMap.at(methodSigProf->idx) << ":" << methodSigProf->num << "\n";
155 }
156 methodSigItem = reinterpret_cast<const MethodSignatureItem *>(data + offset + sizeof(MapleFileProf));
157 for (uint32 item = 0; item < methodSigProf->num; ++item, ++methodSigItem) {
158 std::string methodSigStr = GetMethodSigStr(methodSigItem->methodIdx, methodSigItem->sigIdx);
159 metaData.insert(methodSigStr);
160 }
161 // new maple file's profile
162 }
163 offset += sizeof(MapleFileProf) + methodSigProf->size;
164 }
165 }
166
ParseIRFuncDesc(const char * data,int32 fileNum)167 void Profile::ParseIRFuncDesc(const char *data, int32 fileNum)
168 {
169 const MapleFileProf *funcProf = nullptr;
170 const FunctionIRProfItem *funcItem = nullptr;
171 size_t offset = 0;
172 for (int32 mapleFileIdx = 0; mapleFileIdx < fileNum; ++mapleFileIdx) {
173 funcProf = reinterpret_cast<const MapleFileProf *>(data + offset);
174 if (CheckDexValid(funcProf->idx)) {
175 if (debug) {
176 LogInfo::MapleLogger() << "IRFuncProfile"
177 << ":" << strMap.at(funcProf->idx) << ":" << funcProf->num << "\n";
178 }
179 funcItem = reinterpret_cast<const FunctionIRProfItem *>(data + offset + sizeof(MapleFileProf));
180 for (uint32 item = 0; item < funcProf->num; ++item, ++funcItem) {
181 if ((funcItem->counterStart <= counterTab.size()) && (funcItem->counterEnd <= counterTab.size())) {
182 auto begin = counterTab.begin() + funcItem->counterStart;
183 auto end = counterTab.begin() + funcItem->counterEnd + 1;
184 std::vector<uint32> tempCounter(begin, end);
185 BBInfo bbInfo(funcItem->hash, tempCounter.size(), std::move(tempCounter));
186 std::string funcName = GetFunctionName(funcItem->classIdx, funcItem->methodIdx, funcItem->sigIdx);
187 funcBBProfData.emplace(std::make_pair(funcName, bbInfo));
188 }
189 }
190 }
191 // new maple file's profile
192 offset += sizeof(MapleFileProf) + funcProf->size;
193 }
194 }
195
ParseCounterTab(const char * data,int32 fileNum)196 void Profile::ParseCounterTab(const char *data, int32 fileNum)
197 {
198 const MapleFileProf *counterProf = nullptr;
199 size_t offset = 0;
200 for (int32 mapleFileIdx = 0; mapleFileIdx < fileNum; ++mapleFileIdx) {
201 counterProf = reinterpret_cast<const MapleFileProf *>(data + offset);
202 if (CheckDexValid(counterProf->idx)) {
203 if (debug) {
204 LogInfo::MapleLogger() << "module name " << strMap.at(counterProf->idx) << std::endl;
205 }
206 const FuncCounterItem *item =
207 reinterpret_cast<const FuncCounterItem *>(data + offset + sizeof(MapleFileProf));
208 for (uint32 i = 0; i < counterProf->num; ++i, ++item) {
209 counterTab.emplace_back(item->callTimes);
210 }
211 }
212 offset += sizeof(MapleFileProf) + counterProf->size;
213 }
214 }
215
ParseMeta(const char * data,int32 fileNum,std::unordered_set<std::string> & metaData) const216 void Profile::ParseMeta(const char *data, int32 fileNum, std::unordered_set<std::string> &metaData) const
217 {
218 const MapleFileProf *metaProf = nullptr;
219 size_t offset = 0;
220 for (int32 mapleFileIdx = 0; mapleFileIdx < fileNum; ++mapleFileIdx) {
221 metaProf = reinterpret_cast<const MapleFileProf *>(data + offset);
222 if (CheckDexValid(metaProf->idx)) {
223 if (debug) {
224 LogInfo::MapleLogger() << "module name " << strMap.at(metaProf->idx) << '\n';
225 }
226 const MetaItem *metaItem = reinterpret_cast<const MetaItem *>(data + offset + sizeof(MapleFileProf));
227 for (uint32 item = 0; item < metaProf->num; ++item, ++metaItem) {
228 metaData.insert(strMap.at(metaItem->idx));
229 }
230 }
231 offset += sizeof(MapleFileProf) + metaProf->size;
232 }
233 }
234
ParseReflectionStr(const char * data,int32 fileNum)235 void Profile::ParseReflectionStr(const char *data, int32 fileNum)
236 {
237 const MapleFileProf *metaProf = nullptr;
238 size_t offset = 0;
239 for (int32 mapleFileIdx = 0; mapleFileIdx < fileNum; ++mapleFileIdx) {
240 metaProf = reinterpret_cast<const MapleFileProf *>(data + offset);
241 if (CheckDexValid(metaProf->idx)) {
242 if (debug) {
243 LogInfo::MapleLogger() << "module name " << strMap.at(metaProf->idx) << '\n';
244 }
245
246 const ReflectionStrItem *strItem =
247 reinterpret_cast<const ReflectionStrItem *>(data + offset + sizeof(MapleFileProf));
248 for (uint32 item = 0; item < metaProf->num; ++item, ++strItem) {
249 reflectionStrData.insert(std::make_pair(strMap.at(strItem->idx), strItem->type));
250 }
251 }
252 offset += sizeof(MapleFileProf) + metaProf->size;
253 }
254 }
255
DeCompress(const std::string & path,const std::string & dexNameInner,ProfileType type)256 bool Profile::DeCompress(const std::string &path, const std::string &dexNameInner, ProfileType type)
257 {
258 if (initialized) {
259 LogInfo::MapleLogger() << "System server Profile has been decompressed before" << '\n';
260 return valid;
261 }
262 initialized = true;
263
264 this->dexName = dexNameInner;
265 bool res = true;
266 std::ifstream in(path, std::ios::binary);
267 if (!in.is_open()) {
268 if (errno != ENOENT && errno != EACCES) {
269 LogInfo::MapleLogger() << "WARN: DeCompress("
270 << "), failed to open " << path << '\n';
271 ;
272 }
273 res = false;
274 return res;
275 }
276 in.seekg(0, std::ios::end);
277 size_t byteCount = static_cast<size_t>(in.tellg());
278 in.seekg(0, std::ios::beg);
279 std::vector<char> bufVector;
280 bufVector.resize(byteCount);
281 char *buf = reinterpret_cast<char *>(bufVector.data());
282 if (!in.read(buf, byteCount)) {
283 LogInfo::MapleLogger() << "WARN: DeCompress("
284 << "), failed to read all data for " << path << '\n';
285 res = false;
286 in.close();
287 return res;
288 }
289 if (byteCount < sizeof(Header)) {
290 LogInfo::MapleLogger() << "WARN: DeCompress("
291 << "), failed, read no data for " << path << '\n';
292 res = false;
293 in.close();
294 return res;
295 }
296 Header *header = reinterpret_cast<Header *>(buf);
297 if (!CheckProfileHeader(*header)) {
298 if (debug) {
299 LogInfo::MapleLogger() << "invalid maigc number " << header->magic << '\n';
300 ;
301 }
302 res = false;
303 in.close();
304 return res;
305 }
306 this->isAppProfile = (header->profileFileType == kApp) ? true : false;
307 size_t stringTabSize = byteCount - header->stringTabOff;
308 if (debug) {
309 LogInfo::MapleLogger() << "Header summary "
310 << "profile num " << static_cast<uint32>(header->profileNum) << "string table size"
311 << stringTabSize << '\n';
312 }
313 const char *strBuf = buf + header->stringTabOff;
314 const char *cursor = strBuf;
315 const char *sentinel = strBuf + stringTabSize;
316 while (cursor < sentinel) {
317 size_t len = std::strlen(cursor);
318 const char *next = cursor + len + 1;
319 strMap.emplace_back(cursor);
320 cursor = next;
321 }
322 DEBUG_ASSERT(strMap.size() == header->stringCount, "string count doesn't match");
323 if (debug) {
324 LogInfo::MapleLogger() << "str size " << strMap.size() << '\n';
325 for (const auto &item : strMap) {
326 LogInfo::MapleLogger() << item << '\n';
327 }
328 LogInfo::MapleLogger() << "str size print end " << '\n';
329 }
330 uint8_t idx = 0;
331 for (idx = 0; idx < header->profileNum; ++idx) {
332 ProfileDataInfo *profileDataInfo = &(header->data[idx]);
333 if (debug) {
334 LogInfo::MapleLogger() << "profile file num for type "
335 << GetProfileNameByType(profileDataInfo->profileType) << " "
336 << static_cast<uint32>(profileDataInfo->mapleFileNum) << '\n';
337 }
338 if (debug) {
339 LogInfo::MapleLogger() << GetProfileNameByType(profileDataInfo->profileType) << " Start" << '\n';
340 }
341 char *proFileData = buf + profileDataInfo->profileDataOff;
342 if (type != kAll && type != profileDataInfo->profileType) {
343 continue; // only parse the indicated type
344 }
345 switch (profileDataInfo->profileType) {
346 case kFunction:
347 ParseFunc(proFileData, profileDataInfo->mapleFileNum);
348 break;
349 case kClassMeta:
350 ParseMeta(proFileData, profileDataInfo->mapleFileNum, classMeta);
351 break;
352 case kFieldMeta:
353 ParseMeta(proFileData, profileDataInfo->mapleFileNum, fieldMeta);
354 break;
355 case kMethodMeta:
356 ParseMeta(proFileData, profileDataInfo->mapleFileNum, methodMeta);
357 break;
358 case kReflectionStr:
359 ParseReflectionStr(proFileData, profileDataInfo->mapleFileNum);
360 break;
361 case kLiteral:
362 ParseLiteral(proFileData, strBuf);
363 break;
364 case kBBInfo:
365 ParseIRFuncDesc(proFileData, profileDataInfo->mapleFileNum);
366 break;
367 case kIRCounter:
368 ParseCounterTab(proFileData, profileDataInfo->mapleFileNum);
369 break;
370 case kMethodSig:
371 ParseMethodSignature(proFileData, profileDataInfo->mapleFileNum, methodSigMeta);
372 break;
373 case kFileDesc: {
374 uint32_t appPackageNameIdx = *reinterpret_cast<uint32_t *>(proFileData);
375 this->appPackageName = strMap.at(appPackageNameIdx);
376 if (!appPackageName.empty() && this->appPackageName != appPackageName) {
377 LogInfo::MapleLogger() << "app profile doesnt match expect " << this->appPackageName << " but got "
378 << appPackageName << '\n';
379 return false;
380 }
381 break;
382 }
383 default:
384 LogInfo::MapleLogger() << "unsupported tag " << profileDataInfo->profileType << '\n';
385 break;
386 }
387 }
388 LogInfo::MapleLogger() << "SUCC parse " << path << '\n';
389 valid = true;
390 in.close();
391 return res;
392 }
393
SetProfileMode()394 void Profile::SetProfileMode()
395 {
396 profileMode = true;
397 }
398
CheckFuncHot(const std::string & funcName) const399 bool Profile::CheckFuncHot(const std::string &funcName) const
400 {
401 if (funcProfData.empty()) {
402 return false;
403 }
404 if (valid) {
405 auto iter = funcProfData.find(funcName);
406 if (iter == funcProfData.end()) {
407 return false;
408 }
409 if (hotFuncCountThreshold == 0) {
410 if (Options::profileHotCountSeted) {
411 hotFuncCountThreshold = Options::profileHotCount;
412 } else {
413 std::vector<uint32> times;
414 for (auto &item : funcProfData) {
415 times.push_back((item.second).callTimes);
416 }
417 std::sort(times.begin(), times.end(), std::greater<uint32>());
418 size_t index =
419 static_cast<size_t>(static_cast<double>(times.size()) / kPrecision * (Options::profileHotRate));
420 hotFuncCountThreshold = times.at(index);
421 }
422 }
423 return (iter->second).callTimes >= hotFuncCountThreshold;
424 }
425 return false;
426 }
427
CheckMethodHot(const std::string & className) const428 bool Profile::CheckMethodHot(const std::string &className) const
429 {
430 if (methodMeta.empty()) {
431 return true;
432 }
433 if (valid) {
434 if (methodMeta.find(className) == methodMeta.end()) {
435 return false;
436 }
437 return true;
438 }
439 return false;
440 }
441
CheckMethodSigHot(const std::string & methodSigStr) const442 bool Profile::CheckMethodSigHot(const std::string &methodSigStr) const
443 {
444 if (methodSigMeta.empty()) {
445 return false;
446 }
447 if (valid) {
448 if (methodSigMeta.find(methodSigStr) == methodSigMeta.end()) {
449 return false;
450 }
451 return true;
452 }
453 return false;
454 }
455
CheckFieldHot(const std::string & className) const456 bool Profile::CheckFieldHot(const std::string &className) const
457 {
458 if (fieldMeta.empty()) {
459 return true;
460 }
461 if (valid) {
462 if (fieldMeta.find(className) == fieldMeta.end()) {
463 return false;
464 }
465 return true;
466 }
467 return false;
468 }
469
CheckClassHot(const std::string & className) const470 bool Profile::CheckClassHot(const std::string &className) const
471 {
472 // If in mode sample all class set to cold, except for core-all so,core-all have
473 // some hot class pre defined
474 if (profileMode && !isCoreSo) {
475 return false;
476 }
477 if (classMeta.empty()) {
478 return true;
479 }
480 if (valid || isCoreSo) {
481 return classMeta.find(className) != classMeta.end();
482 }
483 return false;
484 }
485
CheckLiteralHot(const std::string & literalInner) const486 bool Profile::CheckLiteralHot(const std::string &literalInner) const
487 {
488 if (valid) {
489 if ((this->literal).find(literalInner) == (this->literal).end()) {
490 return false;
491 }
492 return true;
493 }
494 return false;
495 }
496
GetLiteralProfileSize() const497 size_t Profile::GetLiteralProfileSize() const
498 {
499 if (valid) {
500 return literal.size();
501 }
502 return 0;
503 }
504
CheckReflectionStrHot(const std::string & str,uint8 & layoutType) const505 bool Profile::CheckReflectionStrHot(const std::string &str, uint8 &layoutType) const
506 {
507 if (valid) {
508 auto item = reflectionStrData.find(str);
509 if (item == reflectionStrData.end()) {
510 return false;
511 }
512 layoutType = item->second;
513 return true;
514 }
515 return false;
516 }
517
GetFunctionProf() const518 const std::unordered_map<std::string, Profile::FuncItem> &Profile::GetFunctionProf() const
519 {
520 return funcProfData;
521 }
522
GetFunctionBBProf(const std::string & funcName,Profile::BBInfo & result)523 bool Profile::GetFunctionBBProf(const std::string &funcName, Profile::BBInfo &result)
524 {
525 auto item = funcBBProfData.find(funcName);
526 if (item == funcBBProfData.end()) {
527 return false;
528 }
529 result = item->second;
530 return true;
531 }
532
GetMeta(uint8 type)533 std::unordered_set<std::string> &Profile::GetMeta(uint8 type)
534 {
535 switch (type) {
536 case kClassMeta:
537 return classMeta;
538 case kFieldMeta:
539 return fieldMeta;
540 case kMethodMeta:
541 return methodMeta;
542 default:
543 CHECK_FATAL(false, "type not found");
544 }
545 }
546
SetFuncStatus(const std::string & funcName,bool succ)547 void Profile::SetFuncStatus(const std::string &funcName, bool succ)
548 {
549 if (succ) {
550 funcBBProfUseInfo[funcName] = true;
551 }
552 }
553
DumpFuncIRProfUseInfo() const554 void Profile::DumpFuncIRProfUseInfo() const
555 {
556 if (funcBBProfData.empty()) {
557 return;
558 }
559 LogInfo::MapleLogger() << "ir profile succ " << funcBBProfUseInfo.size() << " total func " << funcBBProfData.size()
560 << '\n';
561 }
562
Dump() const563 void Profile::Dump() const
564 {
565 std::ofstream outFile;
566 outFile.open("prof.dump");
567 CHECK_FATAL(!outFile.is_open(), "open file failed");
568 outFile << "classMeta profile start " << '\n';
569 for (const auto &item : classMeta) {
570 outFile << item << '\n';
571 }
572
573 outFile << "fieldMeta profile start " << '\n';
574 for (const auto &item : fieldMeta) {
575 outFile << item << '\n';
576 }
577
578 outFile << "methodMeta profile start " << '\n';
579 for (const auto &item : methodMeta) {
580 outFile << item << '\n';
581 }
582
583 outFile << "literal profile start " << '\n';
584 for (const auto &item : literal) {
585 outFile << item << '\n';
586 }
587
588 outFile << "func profile start " << '\n';
589 for (const auto &item : funcProfData) {
590 outFile << item.first << " " << static_cast<uint32>((item.second).type) << " " << (item.second).callTimes
591 << '\n';
592 }
593
594 outFile << "reflectStr profile start " << '\n';
595 for (const auto &item : reflectionStrData) {
596 outFile << item.first << " " << static_cast<uint32>(item.second) << '\n';
597 }
598 outFile.close();
599 }
600 } // namespace maple
601