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 "tooling/client/domain/profiler_client.h"
17 #include "tooling/base/pt_types.h"
18 #include "common/log_wrapper.h"
19 #include "tooling/utils/utils.h"
20 #include "tooling/client/session/session.h"
21 
22 #include <map>
23 #include <functional>
24 #include <cstring>
25 #include <fstream>
26 
27 using Result = panda::ecmascript::tooling::Result;
28 using Profile = panda::ecmascript::tooling::Profile;
29 namespace OHOS::ArkCompiler::Toolchain {
DispatcherCmd(const std::string &cmd)30 bool ProfilerClient::DispatcherCmd(const std::string &cmd)
31 {
32     std::map<std::string, std::function<int()>> dispatcherTable {
33         { "cpuprofile", std::bind(&ProfilerClient::CpuprofileCommand, this)},
34         { "cpuprofile-stop", std::bind(&ProfilerClient::CpuprofileStopCommand, this)},
35         { "cpuprofile-setSamplingInterval", std::bind(&ProfilerClient::SetSamplingIntervalCommand, this)},
36         { "cpuprofile-enable", std::bind(&ProfilerClient::CpuprofileEnableCommand, this)},
37         { "cpuprofile-disable", std::bind(&ProfilerClient::CpuprofileDisableCommand, this)},
38     };
39 
40     auto entry = dispatcherTable.find(cmd);
41     if (entry == dispatcherTable.end()) {
42         LOGI("Unknown commond: %{public}s", cmd.c_str());
43         return false;
44     }
45     entry->second();
46     LOGI("DispatcherCmd cmd: %{public}s", cmd.c_str());
47     return true;
48 }
49 
CpuprofileEnableCommand()50 int ProfilerClient::CpuprofileEnableCommand()
51 {
52     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
53     uint32_t id = session->GetMessageId();
54 
55     idEventMap_.emplace(id, "cpuprofileenable");
56     std::unique_ptr<PtJson> request = PtJson::CreateObject();
57     request->Add("id", id);
58     request->Add("method", "Profiler.enable");
59 
60     std::unique_ptr<PtJson> params = PtJson::CreateObject();
61     request->Add("params", params);
62 
63     std::string message = request->Stringify();
64     if (session->ClientSendReq(message)) {
65         session->GetDomainManager().SetDomainById(id, "Profiler");
66     }
67     return 0;
68 }
69 
CpuprofileDisableCommand()70 int ProfilerClient::CpuprofileDisableCommand()
71 {
72     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
73     uint32_t id = session->GetMessageId();
74 
75     idEventMap_.emplace(id, "cpuprofiledisable");
76     std::unique_ptr<PtJson> request = PtJson::CreateObject();
77     request->Add("id", id);
78     request->Add("method", "Profiler.disable");
79 
80     std::unique_ptr<PtJson> params = PtJson::CreateObject();
81     request->Add("params", params);
82 
83     std::string message = request->Stringify();
84     if (session->ClientSendReq(message)) {
85         session->GetDomainManager().SetDomainById(id, "Profiler");
86     }
87     return 0;
88 }
89 
CpuprofileCommand()90 int ProfilerClient::CpuprofileCommand()
91 {
92     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
93     uint32_t id = session->GetMessageId();
94 
95     idEventMap_.emplace(id, "cpuprofile");
96     std::unique_ptr<PtJson> request = PtJson::CreateObject();
97     request->Add("id", id);
98     request->Add("method", "Profiler.start");
99 
100     std::unique_ptr<PtJson> params = PtJson::CreateObject();
101     request->Add("params", params);
102 
103     std::string message = request->Stringify();
104     if (session->ClientSendReq(message)) {
105         session->GetDomainManager().SetDomainById(id, "Profiler");
106     }
107     return 0;
108 }
109 
CpuprofileStopCommand()110 int ProfilerClient::CpuprofileStopCommand()
111 {
112     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
113     uint32_t id = session->GetMessageId();
114 
115     idEventMap_.emplace(id, "cpuprofilestop");
116     std::unique_ptr<PtJson> request = PtJson::CreateObject();
117     request->Add("id", id);
118     request->Add("method", "Profiler.stop");
119 
120     std::unique_ptr<PtJson> params = PtJson::CreateObject();
121     request->Add("params", params);
122 
123     std::string message = request->Stringify();
124     if (session->ClientSendReq(message)) {
125         session->GetDomainManager().SetDomainById(id, "Profiler");
126     }
127     return 0;
128 }
129 
SetSamplingIntervalCommand()130 int ProfilerClient::SetSamplingIntervalCommand()
131 {
132     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
133     uint32_t id = session->GetMessageId();
134 
135     idEventMap_.emplace(id, "setsamplinginterval");
136     std::unique_ptr<PtJson> request = PtJson::CreateObject();
137     request->Add("id", id);
138     request->Add("method", "Profiler.setSamplingInterval");
139 
140     std::unique_ptr<PtJson> params = PtJson::CreateObject();
141     params->Add("interval", interval_);
142     request->Add("params", params);
143 
144     std::string message = request->Stringify();
145     if (session->ClientSendReq(message)) {
146         session->GetDomainManager().SetDomainById(id, "Profiler");
147     }
148     return 0;
149 }
150 
RecvProfilerResult(std::unique_ptr<PtJson> json)151 void ProfilerClient::RecvProfilerResult(std::unique_ptr<PtJson> json)
152 {
153     if (json == nullptr) {
154         LOGE("arkdb: json parse error");
155         return;
156     }
157 
158     if (!json->IsObject()) {
159         LOGE("arkdb: json parse format error");
160         json->ReleaseRoot();
161         return;
162     }
163 
164     std::unique_ptr<PtJson> result;
165     Result ret = json->GetObject("result", &result);
166     if (ret != Result::SUCCESS) {
167         LOGE("arkdb: find result error");
168         return;
169     }
170 
171     std::unique_ptr<PtJson> profile;
172     ret = result->GetObject("profile", &profile);
173     if (ret != Result::SUCCESS) {
174         LOGE("arkdb: the cmd is not cp-stop!");
175         return;
176     }
177 
178     char date[16];
179     char time[16];
180     bool res = Utils::GetCurrentTime(date, time, sizeof(date));
181     if (!res) {
182         LOGE("arkdb: get time failed");
183         return;
184     }
185 
186     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
187     ProfilerSingleton &pro = session->GetProfilerSingleton();
188     std::string fileName = "CPU-" + std::to_string(sessionId_) + "-" + std::string(date) + "T" +
189                            std::string(time) + ".cpuprofile";
190     std::string cpufile = pro.GetAddress() + fileName;
191     std::cout << "session " << sessionId_ << " cpuprofile file name is " << cpufile << std::endl;
192     std::cout << ">>> ";
193     fflush(stdout);
194     WriteCpuProfileForFile(cpufile, profile->Stringify());
195     pro.AddCpuName(fileName);
196 }
197 
WriteCpuProfileForFile(const std::string &fileName, const std::string &data)198 bool ProfilerClient::WriteCpuProfileForFile(const std::string &fileName, const std::string &data)
199 {
200     std::ofstream ofs;
201     std::string realPath;
202     bool res = Utils::RealPath(fileName, realPath, false);
203     if (!res) {
204         LOGE("arkdb: path is not realpath!");
205         return false;
206     }
207     ofs.open(fileName.c_str(), std::ios::out);
208     if (!ofs.is_open()) {
209         LOGE("arkdb: file open error!");
210         return false;
211     }
212     size_t strSize = data.size();
213     ofs.write(data.c_str(), strSize);
214     ofs.close();
215     ofs.clear();
216     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
217     ProfilerSingleton &pro = session->GetProfilerSingleton();
218     pro.SetAddress("/data/");
219     return true;
220 }
221 
SetSamplingInterval(int interval)222 void ProfilerClient::SetSamplingInterval(int interval)
223 {
224     this->interval_ = interval;
225 }
226 } // OHOS::ArkCompiler::Toolchain
227