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