• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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