1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/dfx/pgo_profiler/pgo_profiler_loader.h"
17
18 #include <string>
19
20 #include "ecmascript/base/string_helper.h"
21 #include "ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h"
22 #include "ecmascript/js_tagged_value.h"
23 #include "ecmascript/log_wrapper.h"
24 #include "ecmascript/method.h"
25 #include "ecmascript/platform/file.h"
26
27 namespace panda::ecmascript {
Load(const std::string & inPath,uint32_t hotnessThreshold)28 bool PGOProfilerLoader::Load(const std::string &inPath, uint32_t hotnessThreshold)
29 {
30 hotnessThreshold_ = hotnessThreshold;
31 isLoaded_ = false;
32 hotnessMethods_.clear();
33 if (inPath.empty()) {
34 return false;
35 }
36 std::string realPath;
37 if (!RealPath(inPath, realPath)) {
38 return false;
39 }
40
41 static const std::string endString = ".ap";
42 if (realPath.compare(realPath.length() - endString.length(), endString.length(), endString)) {
43 LOG_ECMA(ERROR) << "The file path( " << realPath << ") does not end with .ap";
44 return false;
45 }
46 LOG_ECMA(INFO) << "Load profiler from file:" << realPath;
47
48 fd_t fd = Open(realPath.c_str(), FILE_RDONLY);
49 if (UNLIKELY(fd == INVALID_FD)) {
50 LOG_ECMA(ERROR) << "open file failed";
51 return false;
52 }
53 int64_t fileSize = GetFileSizeByFd(fd);
54 if (fileSize == -1) {
55 Close(fd);
56 LOG_ECMA(ERROR) << "GetFileSize failed";
57 return false;
58 }
59
60 fd_t extra = INVALID_FD;
61 void *addr = FileMmap(fd, fileSize, 0, &extra);
62 if (addr == nullptr) {
63 Close(fd);
64 LOG_ECMA(ERROR) << "file mmap failed";
65 return false;
66 }
67
68 if (!ParseProfilerHeader(&addr)) {
69 FileUnMap(addr, fileSize, &extra);
70 Close(fd);
71 LOG_ECMA(ERROR) << "Parse profiler header failure";
72 return false;
73 }
74 if (!ParsePandaFileInfo(&addr)) {
75 FileUnMap(addr, fileSize, &extra);
76 Close(fd);
77 LOG_ECMA(ERROR) << "Parse profiler panda file info failure";
78 return false;
79 }
80 ParseProfiler(&addr);
81 FileUnMap(addr, fileSize, &extra);
82 Close(fd);
83
84 isLoaded_ = true;
85 return true;
86 }
87
Verify(uint32_t checksum)88 bool PGOProfilerLoader::Verify(uint32_t checksum)
89 {
90 isVerifySuccess_ = false;
91 if (!isLoaded_) {
92 return false;
93 }
94 for (auto info : pandaFileProfilerInfos_) {
95 if (checksum == info.GetChecksum()) {
96 isVerifySuccess_ = true;
97 return true;
98 }
99 }
100 LOG_ECMA(ERROR) << "Verify profiler failure";
101 return false;
102 }
103
LoadAndVerify(const std::string & inPath,uint32_t hotnessThreshold,uint32_t checksum)104 bool PGOProfilerLoader::LoadAndVerify(const std::string &inPath, uint32_t hotnessThreshold, uint32_t checksum)
105 {
106 // When the file name is empty, Enter full compiler mode.
107 if (inPath.empty()) {
108 return true;
109 }
110
111 if (Load(inPath, hotnessThreshold) && Verify(checksum)) {
112 return true;
113 }
114 return false;
115 }
116
ParseProfilerHeader(void ** buffer)117 bool PGOProfilerLoader::ParseProfilerHeader(void **buffer)
118 {
119 if (memcpy_s(&header_, sizeof(PGOProfilerHeader), *buffer, sizeof(PGOProfilerHeader)) != EOK) {
120 LOG_FULL(FATAL) << "memcopy_s failed";
121 return false;
122 }
123 *buffer = ToVoidPtr(ToUintPtr(*buffer) + sizeof(PGOProfilerHeader));
124 return header_.Verify();
125 }
126
ParsePandaFileInfo(void ** buffer)127 bool PGOProfilerLoader::ParsePandaFileInfo(void **buffer)
128 {
129 uint32_t size = *(reinterpret_cast<uint32_t *>(*buffer));
130 *buffer = ToVoidPtr(ToUintPtr(*buffer) + sizeof(uint32_t));
131 pandaFileProfilerInfos_.resize(size);
132 for (uint32_t i = 0; i < size; i++) {
133 pandaFileProfilerInfos_.emplace_back(*(reinterpret_cast<PandaFileProfilerInfo *>(*buffer)));
134 *buffer = ToVoidPtr(ToUintPtr(*buffer) + sizeof(PandaFileProfilerInfo));
135 }
136 LOG_ECMA(DEBUG) << "Profiler panda file count:" << size;
137 return true;
138 }
139
ParseProfiler(void ** buffer)140 void PGOProfilerLoader::ParseProfiler(void **buffer)
141 {
142 uint32_t recordNameCount = *(reinterpret_cast<uint32_t *>(*buffer));
143 *buffer = ToVoidPtr(ToUintPtr(*buffer) + sizeof(uint32_t));
144 for (uint32_t i = 0; i < recordNameCount; i++) {
145 auto recordName = ConvertToString(reinterpret_cast<char *>(*buffer));
146 *buffer = ToVoidPtr(ToUintPtr(*buffer) + recordName.size() + 1);
147 std::unordered_set<EntityId> methodIds;
148
149 uint32_t methodCount = *(reinterpret_cast<uint32_t *>(*buffer));
150 *buffer = ToVoidPtr(ToUintPtr(*buffer) + sizeof(uint32_t));
151 for (uint32_t j = 0; j < methodCount; j++) {
152 MethodProfilerInfo *info = reinterpret_cast<MethodProfilerInfo *>(*buffer);
153 if (info->GetCount() >= hotnessThreshold_) {
154 methodIds.emplace(info->GetMethodId());
155 LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << "/" << info->GetCount()
156 << "/" << std::to_string(static_cast<int>(info->GetSampleMode()))
157 << "/" << info->GetMethodName() << "/" << info->GetMethodLength();
158 }
159 *buffer = ToVoidPtr(ToUintPtr(*buffer) + info->Size());
160 }
161 if (!methodIds.empty()) {
162 hotnessMethods_.emplace(recordName, methodIds);
163 }
164 }
165 }
166
Match(const CString & recordName,EntityId methodId)167 bool PGOProfilerLoader::Match(const CString &recordName, EntityId methodId)
168 {
169 if (!isLoaded_) {
170 return true;
171 }
172 if (!isVerifySuccess_) {
173 return false;
174 }
175 auto hotnessMethodSet = hotnessMethods_.find(recordName);
176 if (hotnessMethodSet == hotnessMethods_.end()) {
177 return false;
178 }
179 return hotnessMethodSet->second.find(methodId) != hotnessMethodSet->second.end();
180 }
181 } // namespace panda::ecmascript
182