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
27using Result = panda::ecmascript::tooling::Result;
28using Profile = panda::ecmascript::tooling::Profile;
29namespace OHOS::ArkCompiler::Toolchain {
30bool 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
50int 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
70int 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
90int 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
110int 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
130int 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
151void 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
198bool 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
222void ProfilerClient::SetSamplingInterval(int interval)
223{
224    this->interval_ = interval;
225}
226} // OHOS::ArkCompiler::Toolchain
227