• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_profiler_factory.h"
20 #include "include/sp_utils.h"
21 #include "include/FPS.h"
22 #include "include/FileDescriptor.h"
23 #include "include/RAM.h"
24 #include "include/CPU.h"
25 #include "include/Capture.h"
26 #include "include/startup_delay.h"
27 #include "include/sp_log.h"
28 #include "ByTrace.h"
29 #include <cstdio>
30 #include <ios>
31 #include <vector>
32 #include <fstream>
33 #include <sstream>
34 #include <regex>
35 #include "unistd.h"
36 #include <future>
37 #include "include/common.h"
38 #include "include/sp_csv_util.h"
39 #include "include/sp_thread_socket.h"
40 #include "effective.h"
41 namespace OHOS {
42 namespace SmartPerf {
43 const long long RM_1000 = 1000;
44 const long long END_WAITING_TIME = 8; // End waiting time,unit seconds
ParseCommandArgs(std::string & command)45 std::vector<std::string> ParseCommandArgs(std::string &command)
46 {
47     std::vector<std::string> args;
48     size_t pos = 0;
49     while ((pos = command.find(" ")) != std::string::npos) {
50         args.push_back(command.substr(0, pos));
51         command.erase(0, pos + 1);
52     }
53     args.push_back(command);
54     return args;
55 }
56 
PushCommandArgs(std::vector<std::string> & configVec,std::vector<std::string> & commandArgs,size_t & index)57 void PushCommandArgs(std::vector<std::string>& configVec, std::vector<std::string>& commandArgs, size_t& index)
58 {
59     if (COMMAND_MAP.end() != COMMAND_MAP.find(commandArgs[index]) ||
60         COMMAND_SHELL_MAP.end() != COMMAND_SHELL_MAP.find(commandArgs[index])) {
61         configVec.push_back(commandArgs[index]);
62     }
63 }
64 
65 // init::-SESSIONID 12345678 -INTERVAL 1000 -PKG ohos.samples.ecg -c -g -t -p -f -r -fl 30
ParseToTask(std::string command,TaskInfo & taskInfo)66 static ExceptionMsg ParseToTask(std::string command, TaskInfo &taskInfo)
67 {
68     StuckNotification snf;
69     snf.isEffective = false;
70     std::string sessionId;
71     long long interval = 1000;
72     std::string pkg;
73     std::string pid;
74     bool isFPS = false;
75     bool isPrint = false;
76     std::vector<std::string> configs;
77     std::vector<std::string> args = ParseCommandArgs(command);
78     for (size_t i = 0; i < args.size(); i++) {
79         if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_SESSIONID)) {
80             sessionId = args[++i];
81         } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_INTERVAL)) {
82             interval = SPUtilesTye::StringToSometype<long long>(args[++i]);
83         } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_PKG)) {
84             pkg = args[++i];
85         } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_PID)) {
86             pid = args[++i];
87         } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_PRINT)) {
88             isPrint = true;
89         } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_FL)) { // 获取用户fps的值,并赋给snf.   CT_FL
90             snf.fps = SPUtilesTye::StringToSometype<int>(args[++i]);
91             snf.isEffective = true;
92         } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_FTL)) { // 获取frameTime的值      CT_FTL
93             snf.frameTime = SPUtilesTye::StringToSometype<int>(args[++i]);
94             snf.isEffective = true;
95         } else {
96             if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_F)) { // 判断用户设置是否有-f
97                 isFPS = true;
98             }
99             PushCommandArgs(configs, args, i);
100         }
101     }
102     if (snf.isEffective && (!isFPS)) {
103         return ExceptionMsg::TASK_CONFIG_NULL;
104     }
105     if (sessionId.empty()) {
106         LOGE("ExceptionMsg ParseToTask sessoin id is null");
107         return ExceptionMsg::SESSION_ID_NULL;
108     } else if (configs.size() == 0) {
109         LOGE("ExceptionMsg ParseToTask configs size is 0");
110         return ExceptionMsg::TASK_CONFIG_NULL;
111     }
112     taskInfo = { sessionId, pkg, pid, configs, interval, snf, isPrint };
113     return ExceptionMsg::NO_ERR;
114 }
115 
InitTask(const std::string & recvStr)116 ErrCode SPTask::InitTask(const std::string &recvStr)
117 {
118     std::string result = "";
119     const std::string hiprofiler = CMD_COMMAND_MAP.at(CmdCommand::HIPROFILER);
120     SPUtils::LoadCmd(hiprofiler, result);
121     result.clear();
122     const std::string perf = CMD_COMMAND_MAP.at(CmdCommand::PERF);
123     SPUtils::LoadCmd(perf, result);
124     std::cout << recvStr.substr(recvStr.find("-SESSIONID")) << std::endl;
125     WLOGI("Received init task string: %s", recvStr.substr(recvStr.find("-SESSIONID")).c_str());
126     ExceptionMsg exMsg = ParseToTask(recvStr, curTaskInfo);
127     if (exMsg == ExceptionMsg::NO_ERR) {
128         if (taskMgr_ != nullptr) {
129             taskMgr_->Stop();
130             taskMgr_->WriteToCSV();
131         }
132         taskMgr_ = std::make_shared<TaskManager>(true);
133         taskMgr_->AddTask(recvStr);
134         if (curTaskInfo.stuckInfo.isEffective) {
135             if (curTaskInfo.stuckInfo.fps != 0) {
136                 Effective::GetInstance().fps_ = curTaskInfo.stuckInfo.fps;
137             } else {
138                 Effective::GetInstance().frameTime_ = curTaskInfo.stuckInfo.frameTime;
139             }
140         }
141         SetAppInitFlag();
142         LOGD("InitTask success, task initialized.");
143         return ErrCode::OK;
144     }
145 
146     std::string errInfo = EXCEPTION_MSG_MAP.at(exMsg);
147     LOGE("InitTask error(%s)", errInfo.c_str());
148     return ErrCode::FAILED;
149 }
150 
InitDataFile()151 void SPTask::InitDataFile()
152 {
153     gpuCounter.GetGpuCounterSaveReportData().clear();
154     startTime = SPUtils::GetCurTime();
155     std::vector<std::string> files = {
156         "sdk_data.csv",
157         "gpu_counter.csv",
158         "t_general_info.csv",
159         "t_index_info.csv",
160     };
161     std::string fileDir = baseOutPath + "/" + curTaskInfo.sessionId;
162 
163     for (const auto &file: files) {
164         std::string filePath = fileDir + "/" + file;
165         char filePathChar[PATH_MAX] = {0x00};
166         if (realpath(filePath.c_str(), filePathChar) == nullptr) {
167             LOGE("%s is not exist, init finish.", filePath.c_str());
168             continue;
169         }
170         std::remove(filePathChar);
171     }
172 
173     LOGD("Data file initialization completed.");
174     return;
175 }
176 
SetProfilerPid()177 void SPTask::SetProfilerPid()
178 {
179     SpProfilerFactory::editorFlag = true;
180     std::string processId = "";
181     std::string processIds = "";
182     OHOS::SmartPerf::StartUpDelay sp;
183     processId = sp.GetPidByPkg(curTaskInfo.packageName, &processIds);
184     SpProfilerFactory::SetProfilerPidByPkg(processId, processIds);
185 }
186 
StartTask(std::function<void (const std::string &)> msgTask)187 ErrCode SPTask::StartTask(std::function<void(const std::string&)> msgTask)
188 {
189     LOGD("Task starting...");
190     RAM &ram = RAM::GetInstance();
191     ram.SetFirstFlag();
192     LOGD("RAM first flag set.");
193     if (!isInit) {
194         WLOGE("Initialization failed.");
195         return ErrCode::FAILED;
196     }
197     isRunning = true;
198     LOGD("Task initialized, realTimeStart = %lld", SPUtils::GetCurTime());
199     InitDataFile();
200     LOGD("Data files initialized.");
201     thread = std::thread([=]() {
202         if (taskMgr_ == nullptr) {
203             return;
204         }
205         WLOGI("Starting data collection thread.");
206         std::string thisBasePath = baseOutPath + "/" + curTaskInfo.sessionId;
207         CreatPath(thisBasePath);
208         std::string outIndexpath = thisBasePath + "/t_index_info.csv";
209         taskMgr_->SetFilePath(outIndexpath);
210         taskMgr_->SetIPCCallback(msgTask);
211         taskMgr_->EnableIPCCallback();
212         taskMgr_->SetNextTime(nextTime);
213         taskMgr_->Start(false);
214         taskMgr_->Wait();
215     });
216     EnablePrint();
217     return ErrCode::OK;
218 }
219 
CreatPath(const std::string & path)220 void SPTask::CreatPath(const std::string& path)
221 {
222     if (!SPUtils::FileAccess(path)) {
223         LOGD("CreatPath does not exist, attempting to create: %s", path.c_str());
224         std::string cmdResult;
225         std::string creatPath = CMD_COMMAND_MAP.at(CmdCommand::CREAT_DIR) + path;
226         bool cmdSuccess = SPUtils::LoadCmd(creatPath, cmdResult);
227         if (cmdSuccess) {
228             LOGD("CreatPath created successfully: %s", path.c_str());
229         } else {
230             LOGE("Failed to create path: %s. Command result: %s", path.c_str(), cmdResult.c_str());
231         }
232     } else {
233         std::ofstream file(path, std::ios::trunc);
234         if (!file) {
235             LOGE("Unable to open file");
236             return;
237         }
238         file.close();
239         LOGD("CreatPath already exists: %s", path.c_str());
240     }
241 }
242 
SetTaskInfo()243 std::map<std::string, std::string> SPTask::SetTaskInfo()
244 {
245     long long endTime = SPUtils::GetCurTime();
246     long long testDuration = (endTime - startTime) / 1000;
247     std::string refreshrate;
248     LOGD("Test duration: %lld seconds", testDuration);
249     const std::string gpuDataVersion = "1.1";
250     std::string screenStr = SPUtils::GetScreen();
251     size_t pos3 = screenStr.find("=");
252     if (pos3 != std::string::npos) {
253         refreshrate = screenStr.substr(pos3 + 1);
254         LOGD("Screen refresh rate: %s", refreshrate.c_str());
255     } else {
256         LOGW("Failed to extract refresh rate from screen string: %s", screenStr.c_str());
257     }
258 
259     std::map<std::string, std::string> taskInfoMap = {
260         { "sessionId", curTaskInfo.sessionId },
261         { "taskId", curTaskInfo.sessionId },
262         { "appName", curTaskInfo.packageName },
263         { "packageName", curTaskInfo.packageName },
264         { "pid", curTaskInfo.pid },
265         { "startTime", std::to_string(startTime) },
266         { "endTime", std::to_string(endTime) },
267         { "testDuration", std::to_string(testDuration) },
268         { "taskName", "testtask" },
269         { "board", SPUtils::GetProductName() },
270         { "target_fps", refreshrate },
271         { "gpuDataVersion", gpuDataVersion },
272         { "battery_change", std::to_string(battaryEnd - battaryStart) },
273     };
274     return taskInfoMap;
275 }
276 
StopGetInfo()277 void SPTask::StopGetInfo()
278 {
279     bool isTcpMessage = true;
280 
281     std::map<std::string, std::string> taskInfoMap = SetTaskInfo();
282     std::map<std::string, std::string> deviceInfo = SPUtils::GetDeviceInfo();
283     if (deviceInfo.empty()) {
284         LOGW("Failed to get device info when stop.");
285     }
286     std::map<std::string, std::string> cpuInfo = SPUtils::GetCpuInfo(isTcpMessage);
287     if (cpuInfo.empty()) {
288         LOGW("Failed to get CPU info when stop.");
289     }
290     std::map<std::string, std::string> gpuInfo = SPUtils::GetGpuInfo(isTcpMessage);
291     if (gpuInfo.empty()) {
292         LOGW("Failed to get GPU info when stop.");
293     }
294     std::map<std::string, std::string> destMap;
295     destMap.merge(taskInfoMap);
296     destMap.merge(deviceInfo);
297     destMap.merge(cpuInfo);
298     destMap.merge(gpuInfo);
299     OHOS::SmartPerf::SpCsvUtil::WriteCsvH(destMap);
300     WLOGI("Write CSV header done.");
301 }
302 
StopTask()303 ErrCode SPTask::StopTask()
304 {
305     if (taskMgr_ != nullptr) {
306         taskMgr_->Stop();
307         taskMgr_->WriteToCSV();
308     }
309     if (GetRecordState()) {
310         WLOGI("Record state is valid. Stopping task and cleaning up.");
311         StopGetInfo();
312         recordState = false;
313     } else {
314         WLOGW("Record state is invalid. Skipping task stop operations.");
315     }
316 
317     WLOGI("Stopping task. isRunning: %d, isInit: %d", isRunning, isInit);
318     isRunning = false;
319     isInit = false;
320     if (stdOutLog >= 0) {
321         close(stdOutLog);
322         stdOutLog = -1;
323     }
324     if (thread.joinable()) {
325         LOGD("Joining thread.");
326         thread.join();
327     }
328     LOGD("Killing Hiperf command.");
329     WLOGI("Task successfully stopped.");
330     return ErrCode::OK;
331 }
332 
CheckTcpParam(const std::string & str,std::string & errorInfo)333 bool SPTask::CheckTcpParam(const std::string& str, std::string &errorInfo)
334 {
335     std::set<std::string> keys;
336     std::string params;
337     if (str.find("-SESSIONID") != std::string::npos) {
338         params = str.substr(str.find("-SESSIONID"));
339     } else {
340         LOGE("Init parameter error not contain '-SESSIONID'");
341         return false;
342     }
343     LOGD("Start validating Init parameter: %s", params.c_str());
344 
345     for (auto& a : COMMAND_MAP) {
346         keys.insert(a.first.substr(1)); // 不需要前面的'-'
347     }
348     for (auto& a : COMMAND_SHELL_MAP) {
349         keys.insert(a.first.substr(1));
350     }
351     bool isValid = SPUtils::VeriyParameter(keys, params, errorInfo);
352     if (isValid) {
353         LOGD("Init parameter validation successful");
354     } else {
355         LOGE("Init parameter validation failed, Error: %s", errorInfo.c_str());
356     }
357     return isValid;
358 }
359 
KillHiperfCmd()360 void SPTask::KillHiperfCmd()
361 {
362     long long now = 0;
363     long long runTime = 0;
364     const std::string killCmd = CMD_COMMAND_MAP.at(CmdCommand::KILL_CMD) + "-9 ";
365     std::string result;
366     std::vector<std::string> out;
367 
368     if (startCaptuerTime <= 0) {
369         return;
370     }
371 
372     now = SPUtils::GetCurTime();
373     runTime = now > startCaptuerTime ? now - startCaptuerTime : LLONG_MAX - startCaptuerTime + now;
374     runTime = runTime / RM_1000; // Convert to seconds
375 
376     LOGD("Preparing to exit run time(%lld)", runTime);
377     do {
378         out.clear();
379         const std::string hiprofilerPid = CMD_COMMAND_MAP.at(CmdCommand::HIPROFILER_PID);
380         SPUtils::LoadCmd(hiprofilerPid, result);
381         SPUtils::StrSplit(result, " ", out);
382         if (out.empty()) {
383             break;
384         }
385 
386         sleep(1);
387     } while (END_WAITING_TIME - runTime++ > 0);
388 
389     out.clear();
390     const std::string hiprofilerPid = CMD_COMMAND_MAP.at(CmdCommand::HIPROFILER_PID);
391     SPUtils::LoadCmd(hiprofilerPid, result);
392     SPUtils::StrSplit(result, " ", out);
393     LOGD("pidof hiprofiler_cmd size(%d)", out.size());
394     for (auto it = out.begin(); out.end() != it; ++it) {
395         result.clear();
396         SPUtils::LoadCmd(killCmd + (*it), result);
397     }
398 
399     return;
400 }
401 
GetRecordState()402 bool SPTask::GetRecordState()
403 {
404     return recordState;
405 }
GetCurrentBattary()406 int SPTask::GetCurrentBattary()
407 {
408     std::string content;
409     const std::string cmd = "hidumper -s 3302 -a -i | grep capacity";
410     SPUtils::LoadCmd(cmd, content);
411     content = content.substr(content.find(':') + 1);
412     if (content == "") {
413         WLOGE("Battery capacity is empty.");
414         return 0;
415     }
416     return SPUtilesTye::StringToSometype<int>(content);
417 }
418 
StartRecord()419 ErrCode SPTask::StartRecord()
420 {
421     battaryStart = GetCurrentBattary();
422     startTime = SPUtils::GetCurTime();
423     WLOGI("StartRecord initiated: Battery %d, Start time %lld.", battaryStart, startTime);
424     while (startTime > nextTime) {
425         std::this_thread::sleep_for(std::chrono::milliseconds(1));
426     }
427     SetStartFlag();
428     if (taskMgr_ != nullptr) {
429         taskMgr_->SetRecordState(true);
430     }
431     return ErrCode::OK;
432 }
433 
SetStartFlag()434 void SPTask::SetStartFlag()
435 {
436     InitDataFile();
437     recordState = true;
438 }
439 
StopRecord()440 ErrCode SPTask::StopRecord()
441 {
442     battaryEnd = GetCurrentBattary();
443     long long stopRecordTime = SPUtils::GetCurTime();
444     WLOGI("StopRecord initiated: Battery %d, Stop time %lld.", battaryEnd, stopRecordTime);
445     while (stopRecordTime > nextTime) {
446         std::this_thread::sleep_for(std::chrono::milliseconds(1));
447     }
448     ClearStopFlag();
449     if (taskMgr_ != nullptr) {
450         taskMgr_->SetRecordState(false);
451     }
452     return ErrCode::OK;
453 }
454 
ClearStopFlag()455 void SPTask::ClearStopFlag()
456 {
457     recordState = false;
458     std::string outGpuCounterDataPath = baseOutPath + "/" + curTaskInfo.sessionId;
459 
460     if (isInit) {
461         StopGetInfo();
462         gpuCounter.GetInstance().SaveData(outGpuCounterDataPath);
463     }
464 
465     Capture::GetInstance().SetCollectionNum();
466     KillHiperfCmd();
467 }
468 
GetCsvTitle()469 std::string SPTask::GetCsvTitle()
470 {
471     return csvTitle;
472 }
SetRecordState(bool status)473 void SPTask::SetRecordState(bool status)
474 {
475     recordState = status;
476 }
EnablePrint()477 void SPTask::EnablePrint()
478 {
479     if (curTaskInfo.isPrint) {
480         stdOutLog = SPUtils::GetTtyDeviceFd();
481         if (dup2(stdOutLog, STDERR_FILENO) < 0) {
482             LOGE("Dup2 fail");
483         } else {
484             close(stdOutLog);
485             stdOutLog = -1;
486         }
487     } else {
488         int &fd = SPUtils::GetTtyDeviceFd();
489         if (fd >= 0) {
490             close(fd);
491             fd = -1;
492         }
493     }
494 }
495 
SetAppCmd(const std::string & recvBuf)496 void SPTask::SetAppCmd(const std::string &recvBuf)
497 {
498     std::stringstream ssLine(recvBuf);
499     std::string word = "";
500     int count = 0;
501     int counter = 3;
502     while (ssLine >> word) {
503         count++;
504         if (count == counter) {
505             curTaskInfo.packageName = word;
506         } else if (count > counter) {
507             if  (word.find(":::") != std::string::npos) {
508                 size_t pos = word.find(":::");
509                 word = word.substr(0, pos);
510             }
511             curTaskInfo.taskConfig.push_back(word);
512         }
513     }
514 }
515 
GetCurTaskInfo()516 TaskInfo SPTask::GetCurTaskInfo()
517 {
518     return curTaskInfo;
519 }
520 
SetAppInitFlag()521 void SPTask::SetAppInitFlag()
522 {
523     isInit = true;
524     if (!GetCurTaskInfo().packageName.empty()) {
525         SetProfilerPid();
526         SpProfilerFactory::SetProfilerPkg(curTaskInfo.packageName);
527     }
528 }
529 }
530 }
531