1 /*
2 * Copyright (C) 2021 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 #include <iostream>
16 #include <thread>
17 #include <string>
18 #include <climits>
19 #include "include/sp_task.h"
20 #include "include/sp_profiler_factory.h"
21 #include "include/sp_utils.h"
22 #include "include/FPS.h"
23 #include "include/RAM.h"
24 #include "include/Capture.h"
25 #include "include/startup_delay.h"
26 #include "include/sp_log.h"
27 #include "ByTrace.h"
28 #include <cstdio>
29 #include <ios>
30 #include <vector>
31 #include <fstream>
32 #include <sstream>
33 #include <regex>
34 #include "unistd.h"
35 #include <future>
36
37 namespace OHOS {
38 namespace SmartPerf {
39 const long long RM_0 = 0;
40 const long long RM_5000 = 5000;
41 const long long RM_1000000 = 1000000;
42 // init::-SESSIONID 12345678 -INTERVAL 1000 -PKG ohos.samples.ecg -c -g -t -p -f -r -fl 30
ParseToTask(std::string command,TaskInfo & taskInfo)43 static ExceptionMsg ParseToTask(std::string command, TaskInfo &taskInfo)
44 {
45 std::vector<std::string> args;
46 size_t pos = 0;
47 while ((pos = command.find(" ")) != std::string::npos) {
48 args.push_back(command.substr(0, pos));
49 command.erase(0, pos + 1);
50 }
51 args.push_back(command);
52 StuckNotification snf;
53 snf.isEffective = false;
54 std::string sessionId;
55 long long interval = 1000;
56 std::string pkg;
57 bool isFPS = false;
58 std::vector<std::string> configs;
59 for (size_t i = 0; i < args.size(); i++) {
60 if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_SESSIONID)) {
61 sessionId = args[++i];
62 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_INTERVAL)) {
63 interval = std::stoll(args[++i]);
64 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_PKG)) {
65 pkg = args[++i];
66 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_FL)) { // 获取用户fps的值,并赋给snf. CT_FL
67 snf.fps = std::stoi(args[++i]);
68 snf.isEffective = true;
69 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_FTL)) { // 获取frameTime的值 CT_FTL
70 snf.frameTime = std::stoi(args[++i]);
71 snf.isEffective = true;
72 } else {
73 if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_F)) { // 判断用户设置是否有-f
74 isFPS = true;
75 }
76 if (COMMAND_MAP.end() != COMMAND_MAP.find(args[i])) {
77 configs.push_back(args[i]);
78 }
79 }
80 }
81 if (snf.isEffective && (!isFPS)) {
82 return ExceptionMsg::TASK_CONFIG_NULL;
83 }
84 if (sessionId.empty()) {
85 LOGE("ExceptionMsg ParseToTask sessoin id is null");
86 return ExceptionMsg::SESSION_ID_NULL;
87 } else if (configs.size() == 0) {
88 LOGE("ExceptionMsg ParseToTask configs size is 0");
89 return ExceptionMsg::TASK_CONFIG_NULL;
90 }
91 taskInfo = { sessionId, pkg, configs, interval, snf };
92 return ExceptionMsg::NO_ERR;
93 }
94
MapToString(std::map<std::string,std::string> myMap)95 static std::string MapToString(std::map<std::string, std::string> myMap)
96 {
97 // 将Map转换为字符串
98 std::string str = "{ ";
99 for (auto it = myMap.begin(); it != myMap.end(); ++it) {
100 str += "\"" + it->first + "\": " + it->second + ", ";
101 }
102 const int subLen = 2;
103 str.erase(str.end() - subLen, str.end());
104 str += " }";
105 return str;
106 }
107
InitTask(const std::string & recvStr)108 ErrCode SPTask::InitTask(const std::string &recvStr)
109 {
110 LOGI("SPTask::InitTask start param(%s)", recvStr.c_str());
111 std::string result = "";
112 SPUtils::LoadCmd("rm -f /data/local/tmp/hiprofiler_[0-9]*.htrace", result);
113 result.clear();
114 SPUtils::LoadCmd("rm -f /data/local/tmp/perf_[0-9]*.data", result);
115 std::cout << recvStr << std::endl;
116 ExceptionMsg exMsg = ParseToTask(recvStr, curTaskInfo);
117 if (exMsg == ExceptionMsg::NO_ERR) {
118 isInit = true;
119 LOGI("SPTask::InitTask Ok");
120 return ErrCode::OK;
121 }
122
123 std::string errInfo = EXCEPTION_MSG_MAP.at(exMsg);
124 LOGI("SPTask::InitTask error(%s)", errInfo.c_str());
125 std::cout << "ExceptionMsg:" << errInfo << std::endl;
126 return ErrCode::FAILED;
127 }
128
AsyncCollectRam()129 std::future<std::map<std::string, std::string>> SPTask::AsyncCollectRam()
130 {
131 std::future<std::map<std::string, std::string>> futureResult;
132 for (std::string ramConfig : curTaskInfo.taskConfig) {
133 if (ramConfig.find("-r") != std::string::npos) {
134 futureResult = std::async(std::launch::async, []() {
135 return RAM::GetInstance().ItemData();
136 });
137 }
138 }
139 return futureResult;
140 }
141
AsyncCollectFps()142 std::future<std::map<std::string, std::string>> SPTask::AsyncCollectFps()
143 {
144 std::future<std::map<std::string, std::string>> futureResult;
145 for (std::string fpsConfig : curTaskInfo.taskConfig) {
146 if (fpsConfig.find("-f") != std::string::npos) {
147 futureResult = std::async(std::launch::async, []() {
148 return FPS::GetInstance().ItemData();
149 });
150 }
151 }
152 return futureResult;
153 }
154
CheckFutureRam(std::future<std::map<std::string,std::string>> & ramResult,std::map<std::string,std::string> & dataMap)155 void SPTask::CheckFutureRam(std::future<std::map<std::string, std::string>> &ramResult,
156 std::map<std::string, std::string> &dataMap)
157 {
158 if (ramResult.valid()) {
159 std::map<std::string, std::string> result = ramResult.get();
160 dataMap.insert(result.begin(), result.end());
161 }
162 }
163
CheckFutureFps(std::future<std::map<std::string,std::string>> & fpsResult,std::map<std::string,std::string> & dataMap)164 void SPTask::CheckFutureFps(std::future<std::map<std::string, std::string>> &fpsResult,
165 std::map<std::string, std::string> &dataMap)
166 {
167 if (fpsResult.valid()) {
168 std::map<std::string, std::string> result = fpsResult.get();
169 dataMap.insert(result.begin(), result.end());
170 }
171 }
172
GetItemData(std::map<std::string,std::string> & dataMap)173 void SPTask::GetItemData(std::map<std::string, std::string> &dataMap)
174 {
175 for (std::string itConfig : curTaskInfo.taskConfig) {
176 if (itConfig.find("-snapshot") != std::string::npos) {
177 Capture::GetInstance().SocketMessage();
178 std::map<std::string, std::string> captureMap = Capture::GetInstance().ItemData();
179 dataMap.insert(captureMap.begin(), captureMap.end());
180 }
181 SpProfiler *profiler = SpProfilerFactory::GetCmdProfilerItem(COMMAND_MAP.at(itConfig), false);
182 if (profiler != nullptr) {
183 std::map<std::string, std::string> itemMap = profiler->ItemData();
184 dataMap.insert(itemMap.begin(), itemMap.end());
185 }
186 }
187 }
188
StartTask(std::function<void (std::string data)> msgTask)189 ErrCode SPTask::StartTask(std::function<void(std::string data)> msgTask)
190 {
191 LOGI("SPTask::StartTask start ");
192 if (!isInit) {
193 LOGW("SPTask::StartTask initialization failed");
194 return ErrCode::FAILED;
195 }
196 isRunning = true;
197 startTime = SPUtils::GetCurTime();
198 if (!curTaskInfo.packageName.empty()) {
199 SpProfilerFactory::SetProfilerPkg(curTaskInfo.packageName);
200 }
201 thread = std::thread([this, msgTask]() {
202 while (isRunning) {
203 long long lastTime = SPUtils::GetCurTime();
204 std::lock_guard<std::mutex> lock(mtx);
205 std::map<std::string, std::string> dataMap;
206 dataMap.insert(std::pair<std::string, std::string>(std::string("timestamp"), std::to_string(lastTime)));
207 std::future<std::map<std::string, std::string>> ramResult = AsyncCollectRam();
208 std::future<std::map<std::string, std::string>> fpsResult = AsyncCollectFps();
209 GetItemData(dataMap);
210 CheckFutureRam(ramResult, dataMap);
211 CheckFutureFps(fpsResult, dataMap);
212 if (curTaskInfo.stuckInfo.isEffective) {
213 std::map<std::string, std::string> timeUsedMap = DetectionAndGrab();
214 if (!timeUsedMap.empty()) {
215 dataMap.insert(timeUsedMap.begin(), timeUsedMap.end());
216 }
217 }
218 SPData spdata;
219 spdata.values.insert(dataMap.begin(), dataMap.end());
220 vmap.push_back(spdata);
221
222 msgTask(MapToString(dataMap));
223 long long nextTime = SPUtils::GetCurTime();
224 long long costTime = nextTime - lastTime;
225 if (costTime < curTaskInfo.freq) {
226 std::this_thread::sleep_for(std::chrono::milliseconds(curTaskInfo.freq - costTime));
227 }
228 }
229 });
230 LOGI("SPTask::StartTask complete");
231 return ErrCode::OK;
232 }
StopTask()233 void SPTask::StopTask()
234 {
235 LOGI("SPTask::StopTask start");
236 isRunning = false;
237 if (isInit) {
238 KillHiperfCmd();
239
240 std::string thisBasePath = baseOutPath + "/" + curTaskInfo.sessionId;
241 if (!SPUtils::FileAccess(thisBasePath)) {
242 std::string cmdResult;
243 SPUtils::LoadCmd("mkdir -p " + thisBasePath, cmdResult);
244 }
245 std::string outGeneralPath = thisBasePath + "/t_general_info.csv";
246 std::string outIndexpath = thisBasePath + "/t_index_info.csv";
247 long long endTime = SPUtils::GetCurTime();
248 long long testDuration = (endTime - startTime) / 1000;
249 std::string screenStr = SPUtils::GetScreen();
250 int pos3 = screenStr.find("=");
251 std::string refreshrate = screenStr.substr(pos3 + 1);
252 std::map<std::string, std::string> taskInfoMap = {
253 { "sessionId", curTaskInfo.sessionId },
254 { "taskId", curTaskInfo.sessionId },
255 { "appName", curTaskInfo.packageName },
256 { "packageName", curTaskInfo.packageName },
257 { "startTime", std::to_string(startTime) },
258 { "endTime", std::to_string(endTime) },
259 { "testDuration", std::to_string(testDuration) },
260 { "taskName", "testtask" },
261 { "board", "hw" },
262 { "target_fps", refreshrate },
263 };
264 std::map<std::string, std::string> deviceInfo = SPUtils::GetDeviceInfo();
265 std::map<std::string, std::string> cpuInfo = SPUtils::GetCpuInfo();
266 std::map<std::string, std::string> gpuInfo = SPUtils::GetGpuInfo();
267 std::map<std::string, std::string> destMap;
268 destMap.insert(taskInfoMap.begin(), taskInfoMap.end());
269 destMap.insert(deviceInfo.begin(), deviceInfo.end());
270 destMap.insert(cpuInfo.begin(), cpuInfo.end());
271 destMap.insert(gpuInfo.begin(), gpuInfo.end());
272 OHOS::SmartPerf::SpCsvUtil::WriteCsvH(outGeneralPath, destMap);
273 OHOS::SmartPerf::SpCsvUtil::WriteCsv(outIndexpath, vmap);
274 }
275
276 isInit = false;
277 vmap.clear();
278 if (thread.joinable()) {
279 thread.join();
280 }
281
282 LOGI("SPTask::StopTask complete");
283 }
284
DetectionAndGrab()285 std::map<std::string, std::string> SPTask::DetectionAndGrab()
286 {
287 std::map<std::string, std::string> templateMap;
288 if (!curTaskInfo.stuckInfo.isEffective) {
289 return templateMap;
290 }
291
292 FpsCurrentFpsTime fcf = FPS::GetInstance().GetFpsCurrentFpsTime();
293 long long curframeTime = fcf.currentFpsTime / RM_1000000; // Convert to milliseconds
294 std::cout << "start::" << startCaptuerTime << std::endl;
295 if (curTaskInfo.stuckInfo.fps > fcf.fps || curTaskInfo.stuckInfo.frameTime < curframeTime) {
296 if (!isCaptureTrace) {
297 isCaptureTrace = true;
298 startCaptuerTime = SPUtils::GetCurTime();
299 std::cout << "ThreadGetHiperf::" << startCaptuerTime << std::endl;
300 ThreadGetHiperf(startCaptuerTime);
301 } else {
302 long long nowTime = SPUtils::GetCurTime();
303 long long diff = startCaptuerTime > nowTime ? (LLONG_MAX - startCaptuerTime + nowTime) :
304 (nowTime - startCaptuerTime);
305 std::cout << "else::" << startCaptuerTime << std::endl;
306 if (diff > RM_5000 && (!CheckCounterId())) {
307 isCaptureTrace = false;
308 startCaptuerTime = RM_0;
309 }
310 std::cout << "end::" << startCaptuerTime << std::endl;
311 }
312 }
313 templateMap["fpsWarn"] = std::to_string(fcf.fps);
314 templateMap["FrameTimeWarn"] = std::to_string(fcf.currentFpsTime);
315 templateMap["TraceTime"] = std::to_string(startCaptuerTime);
316 return templateMap;
317 }
318
CheckCounterId()319 bool SPTask::CheckCounterId()
320 {
321 std::string result;
322
323 SPUtils::LoadCmd("ps -ef |grep hiprofiler_cmd |grep -v grep", result);
324 if (result.empty()) {
325 return false;
326 }
327
328 if (result.find("-k") != std::string::npos) {
329 return true;
330 }
331
332 return false;
333 }
ThreadGetHiperf(long long ts)334 std::thread SPTask::ThreadGetHiperf(long long ts)
335 {
336 std::thread thGetTrace(&SPTask::GetHiperf, this, std::to_string(ts));
337 thGetTrace.detach();
338 return thGetTrace;
339 }
340
GetHiperf(const std::string & traceName)341 void SPTask::GetHiperf(const std::string &traceName)
342 {
343 std::string result;
344 std::string tmp = SetHiperf(traceName);
345 std::cout << tmp << std::endl;
346 LOGI("hiprofiler exec (%s)", tmp.c_str());
347 SPUtils::LoadCmd(tmp, result);
348 LOGI("hiprofiler exec end (%s)", result.c_str());
349 }
350
351
CheckTcpParam(std::string str,std::string & errorInfo)352 bool SPTask::CheckTcpParam(std::string str, std::string &errorInfo)
353 {
354 std::set<std::string> keys;
355 for (auto a : COMMAND_MAP) {
356 keys.insert(a.first.substr(1)); // 不需要前面的'-'
357 }
358
359 return SPUtils::VeriyParameter(keys, str, errorInfo);
360 }
361
KillHiperfCmd()362 void SPTask::KillHiperfCmd()
363 {
364 std::string killCmd = "kill -9 ";
365 std::string result;
366 std::vector<std::string> out;
367
368 std::cout << "pidof hiprofiler_cmd=" << killCmd << std::endl;
369 SPUtils::LoadCmd("pidof hiprofiler_cmd", result);
370 SPUtils::StrSplit(result, " ", out);
371
372 for (auto it = out.begin(); out.end() != it; ++it) {
373 result.clear();
374 SPUtils::LoadCmd(killCmd + (*it), result);
375 }
376
377 return;
378 }
379
SetHiperf(const std::string & traceName)380 std::string SPTask::SetHiperf(const std::string &traceName)
381 {
382 std::string hiPrefix = "hiprofiler_";
383 std::string dataPrefix = "perf_";
384 requestId++;
385 std::string trtmp = strOne + hiPrefix + traceName + strTwo + "\n" + strThree + std::to_string(requestId) + "\n" +
386 strFour + "\n" + strFive + hiPrefix + traceName + strSix + "\n" + strNine + strEleven + "\n" + strSeven +
387 dataPrefix + traceName + strEight + strTen + "\n" + conFig;
388 return trtmp;
389 }
390 }
391 }
392