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 namespace OHOS {
40 namespace SmartPerf {
41 const long long RM_0 = 0;
42 const long long RM_5000 = 5000;
43 const long long RM_1000 = 1000;
44 const long long RM_1000000 = 1000000;
45 const long long END_WAITING_TIME = 8; // End waiting time,unit seconds
ParseCommandArgs(std::string & command)46 std::vector<std::string> ParseCommandArgs(std::string &command)
47 {
48 std::vector<std::string> args;
49 size_t pos = 0;
50 while ((pos = command.find(" ")) != std::string::npos) {
51 args.push_back(command.substr(0, pos));
52 command.erase(0, pos + 1);
53 }
54 args.push_back(command);
55 return args;
56 }
57
58 // init::-SESSIONID 12345678 -INTERVAL 1000 -PKG ohos.samples.ecg -c -g -t -p -f -r -fl 30
ParseToTask(std::string command,TaskInfo & taskInfo)59 static ExceptionMsg ParseToTask(std::string command, TaskInfo &taskInfo)
60 {
61 StuckNotification snf;
62 snf.isEffective = false;
63 std::string sessionId;
64 long long interval = 1000;
65 std::string pkg;
66 std::string pid;
67 bool isFPS = false;
68 bool isPrint = false;
69 std::vector<std::string> configs;
70 std::vector<std::string> args = ParseCommandArgs(command);
71 for (size_t i = 0; i < args.size(); i++) {
72 if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_SESSIONID)) {
73 sessionId = args[++i];
74 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_INTERVAL)) {
75 interval = SPUtilesTye::StringToSometype<long long>(args[++i]);
76 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_PKG)) {
77 pkg = args[++i];
78 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_PID)) {
79 pid = args[++i];
80 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_PRINT)) {
81 isPrint = true;
82 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_FL)) { // 获取用户fps的值,并赋给snf. CT_FL
83 snf.fps = SPUtilesTye::StringToSometype<int>(args[++i]);
84 snf.isEffective = true;
85 } else if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_FTL)) { // 获取frameTime的值 CT_FTL
86 snf.frameTime = SPUtilesTye::StringToSometype<int>(args[++i]);
87 snf.isEffective = true;
88 } else {
89 if (args[i] == COMMAND_MAP_REVERSE.at(CommandType::CT_F)) { // 判断用户设置是否有-f
90 isFPS = true;
91 }
92 if (COMMAND_MAP.end() != COMMAND_MAP.find(args[i])) {
93 configs.push_back(args[i]);
94 }
95 }
96 }
97 if (snf.isEffective && (!isFPS)) {
98 return ExceptionMsg::TASK_CONFIG_NULL;
99 }
100 if (sessionId.empty()) {
101 LOGE("ExceptionMsg ParseToTask sessoin id is null");
102 return ExceptionMsg::SESSION_ID_NULL;
103 } else if (configs.size() == 0) {
104 LOGE("ExceptionMsg ParseToTask configs size is 0");
105 return ExceptionMsg::TASK_CONFIG_NULL;
106 }
107 taskInfo = { sessionId, pkg, pid, configs, interval, snf, isPrint };
108 return ExceptionMsg::NO_ERR;
109 }
110
MapToString(std::map<std::string,std::string> myMap)111 static std::string MapToString(std::map<std::string, std::string> myMap)
112 {
113 // 将Map转换为字符串
114 std::string str = "{ ";
115 for (auto it = myMap.begin(); it != myMap.end(); ++it) {
116 str += "\"" + it->first + "\": " + it->second + ", ";
117 }
118 const int subLen = 2;
119 str.erase(str.end() - subLen, str.end());
120 str += " }";
121 return str;
122 }
123
PrintMap(std::map<std::string,std::string> & dataMap)124 void SPTask::PrintMap(std::map<std::string, std::string> &dataMap)
125 {
126 if (curTaskInfo.isPrint) {
127 int i = 0;
128 for (auto iter = dataMap.cbegin() ; iter != dataMap.cend(); ++iter) {
129 fprintf(stderr, "\norder:%d %s=%s", i++, iter->first.c_str(), iter->second.c_str());
130 }
131 std::cerr << std::endl << std::flush;
132 }
133 }
134
InitTask(const std::string & recvStr)135 ErrCode SPTask::InitTask(const std::string &recvStr)
136 {
137 std::string result = "";
138 std::string hiprofiler = CMD_COMMAND_MAP.at(CmdCommand::HIPROFILER);
139 SPUtils::LoadCmd(hiprofiler, result);
140 result.clear();
141 std::string perf = CMD_COMMAND_MAP.at(CmdCommand::PERF);
142 SPUtils::LoadCmd(perf, result);
143 std::cout << recvStr.substr(recvStr.find("-SESSIONID")) << std::endl;
144 WLOGI("Received init task string: %s", recvStr.substr(recvStr.find("-SESSIONID")).c_str());
145 ExceptionMsg exMsg = ParseToTask(recvStr, curTaskInfo);
146 if (exMsg == ExceptionMsg::NO_ERR) {
147 FPS &fps = FPS::GetInstance();
148 fps.isGameApp = SPUtils::GetIsGameApp(curTaskInfo.packageName);
149 fps.firstDump = true;
150 isInit = true;
151 LOGD("InitTask success, task initialized.");
152 return ErrCode::OK;
153 }
154
155 std::string errInfo = EXCEPTION_MSG_MAP.at(exMsg);
156 LOGE("InitTask error(%s)", errInfo.c_str());
157 return ErrCode::FAILED;
158 }
159
AsyncCollectRam()160 std::future<std::map<std::string, std::string>> SPTask::AsyncCollectRam()
161 {
162 std::promise<std::map<std::string, std::string>> p;
163 std::future<std::map<std::string, std::string>> futureResult;
164 for (std::string ramConfig : curTaskInfo.taskConfig) {
165 if (ramConfig.find("-r") != std::string::npos) {
166 futureResult = p.get_future();
167 std::thread([p = std::move(p)]() mutable {
168 LOGD("Starting RAM collection in new thread");
169 p.set_value(RAM::GetInstance().ItemData());
170 }).detach();
171 }
172 }
173 return futureResult;
174 }
175
AsyncCollectCpu()176 std::future<std::map<std::string, std::string>> SPTask::AsyncCollectCpu()
177 {
178 std::promise<std::map<std::string, std::string>> p;
179 std::future<std::map<std::string, std::string>> futureResult;
180 for (std::string cpuConfig : curTaskInfo.taskConfig) {
181 if (cpuConfig.find("-c") != std::string::npos) {
182 futureResult = p.get_future();
183 std::thread([p = std::move(p)]() mutable {
184 LOGD("Starting CPU collection in new thread");
185 p.set_value(CPU::GetInstance().ItemData());
186 }).detach();
187 }
188 }
189 return futureResult;
190 }
191
AsyncCollectFps()192 std::future<std::map<std::string, std::string>> SPTask::AsyncCollectFps()
193 {
194 std::promise<std::map<std::string, std::string>> p;
195 std::future<std::map<std::string, std::string>> futureResult;
196 for (std::string fpsConfig : curTaskInfo.taskConfig) {
197 if (fpsConfig == "-f") {
198 futureResult = p.get_future();
199 std::thread([p = std::move(p)]() mutable {
200 LOGD("Starting FPS collection in new thread");
201 p.set_value(FPS::GetInstance().ItemData());
202 }).detach();
203 }
204 }
205 return futureResult;
206 }
207
AsyncCollectFds()208 std::future<std::map<std::string, std::string>> SPTask::AsyncCollectFds()
209 {
210 std::promise<std::map<std::string, std::string>> p;
211 std::future<std::map<std::string, std::string>> futureResult;
212 for (std::string fdsConfig : curTaskInfo.taskConfig) {
213 if (fdsConfig.find("-fds") != std::string::npos) {
214 futureResult = p.get_future();
215 std::thread([p = std::move(p)]() mutable {
216 p.set_value(FileDescriptor::GetInstance().ItemData());
217 }).detach();
218 }
219 }
220 return futureResult;
221 }
222
CheckFutureRam(std::future<std::map<std::string,std::string>> & ramResult,std::map<std::string,std::string> & dataMap)223 void SPTask::CheckFutureRam(std::future<std::map<std::string, std::string>> &ramResult,
224 std::map<std::string, std::string> &dataMap)
225 {
226 if (ramResult.valid()) {
227 std::map<std::string, std::string> result = ramResult.get();
228 dataMap.insert(result.begin(), result.end());
229 }
230 }
231
CheckFutureCpu(std::future<std::map<std::string,std::string>> & cpuResult,std::map<std::string,std::string> & dataMap)232 void SPTask::CheckFutureCpu(std::future<std::map<std::string, std::string>> &cpuResult,
233 std::map<std::string, std::string> &dataMap)
234 {
235 if (cpuResult.valid()) {
236 std::map<std::string, std::string> result = cpuResult.get();
237 dataMap.insert(result.begin(), result.end());
238 }
239 }
240
CheckFutureFps(std::future<std::map<std::string,std::string>> & fpsResult,std::map<std::string,std::string> & dataMap)241 void SPTask::CheckFutureFps(std::future<std::map<std::string, std::string>> &fpsResult,
242 std::map<std::string, std::string> &dataMap)
243 {
244 if (fpsResult.valid()) {
245 std::map<std::string, std::string> result = fpsResult.get();
246 dataMap.insert(result.begin(), result.end());
247 }
248 }
249
CheckFutureFds(std::future<std::map<std::string,std::string>> & fdsResult,std::map<std::string,std::string> & dataMap)250 void SPTask::CheckFutureFds(std::future<std::map<std::string, std::string>> &fdsResult,
251 std::map<std::string, std::string> &dataMap)
252 {
253 if (fdsResult.valid()) {
254 std::map<std::string, std::string> result = fdsResult.get();
255 dataMap.insert(result.begin(), result.end());
256 }
257 }
258
GetItemData(std::map<std::string,std::string> & dataMap)259 void SPTask::GetItemData(std::map<std::string, std::string> &dataMap)
260 {
261 for (std::string itConfig : curTaskInfo.taskConfig) {
262 if (itConfig.find("-snapshot") != std::string::npos && screenshotFlag) {
263 Capture::GetInstance().SocketMessage();
264 std::map<std::string, std::string> captureMap = Capture::GetInstance().ItemData();
265 dataMap.insert(captureMap.begin(), captureMap.end());
266 }
267
268 if (itConfig.find("-gc") != std::string::npos ||
269 itConfig.find("-o") != std::string::npos ||
270 itConfig.find("-lockfreq") != std::string::npos) {
271 continue;
272 }
273
274 SpProfiler *profiler = SpProfilerFactory::GetCmdProfilerItem(COMMAND_MAP.at(itConfig), false);
275 if (profiler != nullptr) {
276 std::map<std::string, std::string> itemMap = profiler->ItemData();
277 dataMap.insert(itemMap.begin(), itemMap.end());
278 }
279 }
280 }
281
ConfigDataThread()282 void SPTask::ConfigDataThread()
283 {
284 for (std::string itConfig : curTaskInfo.taskConfig) {
285 if (!sdkData) {
286 ConfigureSdkData(itConfig);
287 }
288
289 if (itConfig.find("-gc") != std::string::npos) {
290 WLOGI("Starting GpuCounter collection in new thread");
291 gpuCounter.StartCollect(GpuCounter::GC_START);
292 }
293
294 if (itConfig.find("-lockfreq") != std::string::npos) {
295 lockFreq.SetIsCollecting(true);
296 lockFreqThread = std::thread([this]() {
297 WLOGI("Starting lock frequency locking thread");
298 this->lockFreq.LockingThread();
299 });
300 }
301 }
302 }
303
ConfigureSdkData(std::string itConfig)304 void SPTask::ConfigureSdkData(std::string itConfig)
305 {
306 if (itConfig.find("-o") != std::string::npos) {
307 sdkData = true;
308 OHOS::system::SetParameter("debug.smartperf.sdkdataenable", "1");
309 SdkDataRecv &sdkDataRecv = SdkDataRecv::GetInstance();
310 sdkDataRecv.SetRunningState(true);
311 WLOGI("Starting sdkdata collection in new thread");
312 sdk = std::thread([&sdkDataRecv, this]() { this->RunSdkServer(sdkDataRecv); });
313 }
314 }
315
RunSdkServer(SdkDataRecv & sdkDataRecv)316 void SPTask::RunSdkServer(SdkDataRecv &sdkDataRecv)
317 {
318 sdkDataRecv.ServerThread(sdkvec);
319 }
320
ResetSdkParam()321 void SPTask::ResetSdkParam()
322 {
323 WLOGI("Disabling sdk data collection and resetting parameters");
324 OHOS::system::SetParameter("debug.smartperf.sdkdataenable", "0");
325 sdkData = false;
326 SdkDataRecv &sdkDataRecv = SdkDataRecv::GetInstance();
327 sdkDataRecv.SetRunningState(false);
328 int listenFd = sdkDataRecv.GetListenFd();
329 if (listenFd != -1) {
330 LOGD("Closing sdk data listenFd: %d", listenFd);
331 close(listenFd);
332 sdkDataRecv.SetListenFd(-1);
333 }
334 if (sdk.joinable()) {
335 LOGD("Joining sdk data server thread");
336 sdk.join();
337 }
338 }
339
StopSdkRecv()340 void SPTask::StopSdkRecv()
341 {
342 if (!sdkData || sdkvec.size() <= 0) {
343 WLOGI("SDK data is not enabled or sdkvec is empty");
344 return;
345 }
346 LOGD("SDK data stop");
347 std::string outSdkDataDir = baseOutPath + "/" + curTaskInfo.sessionId;
348 char outSdkDataDirChar[PATH_MAX] = {0x00};
349 if (realpath(outSdkDataDir.c_str(), outSdkDataDirChar) == nullptr) {
350 WLOGE("data dir %s is nullptr", outSdkDataDir.c_str());
351 return;
352 }
353 std::string outSdkDataPath = std::string(outSdkDataDirChar) + "/sdk_data.csv";
354 sdkDataMtx.lock();
355 std::ofstream outFile;
356 outFile.open(outSdkDataPath.c_str(), std::ios::out | std::ios::trunc);
357 if (!outFile.is_open()) {
358 WLOGE("data %s open failed", outSdkDataPath.c_str());
359 sdkDataMtx.unlock();
360 return;
361 }
362 std::string title = "source,timestamp,eventName,enable,value\r";
363 outFile << title << std::endl;
364 for (const auto &item : sdkvec) {
365 outFile << item << std::endl;
366 }
367 outFile.close();
368 sdkDataMtx.unlock();
369 WLOGI("SDK data written successfully to %s", outSdkDataPath.c_str());
370 return;
371 }
372
InitDataFile()373 void SPTask::InitDataFile()
374 {
375 vmap.clear();
376 sdkvec.clear();
377 gpuCounter.GetGpuCounterSaveReportData().clear();
378 SdkDataRecv::GetInstance().SetStartRecordTime();
379 startTime = SPUtils::GetCurTime();
380 std::vector<std::string> files = {
381 "sdk_data.csv",
382 "gpu_counter.csv",
383 "t_general_info.csv",
384 "t_index_info.csv",
385 };
386 std::string fileDir = baseOutPath + "/" + curTaskInfo.sessionId;
387
388 for (const auto &file: files) {
389 std::string filePath = fileDir + "/" + file;
390 char filePathChar[PATH_MAX] = {0x00};
391 if (realpath(filePath.c_str(), filePathChar) == nullptr) {
392 LOGE("%s is not exist, init finish.", filePath.c_str());
393 continue;
394 }
395 std::remove(filePathChar);
396 }
397
398 LOGD("Data file initialization completed.");
399 return;
400 }
401
SetProfilerPid()402 void SPTask::SetProfilerPid()
403 {
404 SpProfilerFactory::editorFlag = true;
405 std::string processId = "";
406 std::string processIds = "";
407 OHOS::SmartPerf::StartUpDelay sp;
408 processId = sp.GetPidByPkg(curTaskInfo.packageName, &processIds);
409 SpProfilerFactory::SetProfilerPidByPkg(processId, processIds);
410 }
411
AsyncGetDataMap(std::function<void (std::string data)> msgTask)412 void SPTask::AsyncGetDataMap(std::function<void(std::string data)> msgTask)
413 {
414 long long lastTime = SPUtils::GetCurTime();
415 asyncDataMtx.lock();
416 std::map<std::string, std::string> dataMap;
417 if (!curTaskInfo.packageName.empty()) {
418 SetProfilerPid();
419 }
420 dataMap.insert(std::pair<std::string, std::string>(std::string("timestamp"), std::to_string(lastTime)));
421 std::future<std::map<std::string, std::string>> fpsResult = AsyncCollectFps();
422 std::future<std::map<std::string, std::string>> cpuResult = AsyncCollectCpu();
423 std::future<std::map<std::string, std::string>> ramResult = AsyncCollectRam();
424 std::future<std::map<std::string, std::string>> fdsResult = AsyncCollectFds();
425 GetItemData(dataMap);
426 CheckFutureFps(fpsResult, dataMap);
427 CheckFutureCpu(cpuResult, dataMap);
428 CheckFutureRam(ramResult, dataMap);
429 CheckFutureFds(fdsResult, dataMap);
430 if (curTaskInfo.stuckInfo.isEffective && recordTrace) {
431 std::map<std::string, std::string> timeUsedMap = DetectionAndGrab();
432 if (!timeUsedMap.empty()) {
433 dataMap.insert(timeUsedMap.begin(), timeUsedMap.end());
434 }
435 }
436 SPData spdata;
437 spdata.values.insert(dataMap.begin(), dataMap.end());
438 if (GetRecordState()) {
439 ProcessErrorData(spdata);
440 }
441 gpuCounter.GetGpuRealtimeData(dataMap);
442 SdkDataRecv::GetInstance().GetSdkDataRealtimeData(dataMap);
443 if (GetRecordState()) {
444 PrintMap(dataMap);
445 }
446 msgTask(MapToString(dataMap));
447 nextTime = SPUtils::GetCurTime();
448 long long costTime = nextTime - lastTime;
449 long long pTime = 998;
450 if (costTime < curTaskInfo.freq) {
451 std::this_thread::sleep_for(std::chrono::milliseconds(pTime - costTime));
452 }
453 asyncDataMtx.unlock();
454 }
455
StartTask(std::function<void (std::string data)> msgTask)456 ErrCode SPTask::StartTask(std::function<void(std::string data)> msgTask)
457 {
458 LOGD("Task starting...");
459 RAM &ram = RAM::GetInstance();
460 ram.SetFirstFlag();
461 LOGD("RAM first flag set.");
462 if (!isInit) {
463 WLOGE("Initialization failed.");
464 return ErrCode::FAILED;
465 }
466 isRunning = true;
467 realTimeStart = SPUtils::GetCurTime();
468 LOGD("Task initialized, realTimeStart = %lld", realTimeStart);
469 if (!curTaskInfo.packageName.empty()) {
470 SpProfilerFactory::SetProfilerPkg(curTaskInfo.packageName);
471 LOGD("Profiler package name set to: %s", curTaskInfo.packageName.c_str());
472 } else {
473 LOGW("No package name provided for profiler.");
474 }
475 if (!curTaskInfo.pid.empty()) {
476 SpProfilerFactory::SetProfilerPidByPkg(curTaskInfo.pid);
477 }
478 InitDataFile();
479 LOGD("Data files initialized.");
480 ConfigDataThread();
481 LOGD("Data collection thread configuration completed.");
482 thread = std::thread([this, msgTask]() {
483 WLOGI("Starting data collection thread.");
484 while (isRunning) {
485 AsyncGetDataMap(msgTask);
486 }
487 WLOGI("Data collection thread exiting.");
488 if (curTaskInfo.isPrint) {
489 std::cerr << "End please press the enter key..." << std::endl << std::flush;
490 }
491 });
492 EnablePrint();
493 return ErrCode::OK;
494 }
495
CreatPath(std::string path)496 void SPTask::CreatPath(std::string path)
497 {
498 if (!SPUtils::FileAccess(path)) {
499 LOGD("CreatPath does not exist, attempting to create: %s", path.c_str());
500 std::string cmdResult;
501 std::string creatPath = CMD_COMMAND_MAP.at(CmdCommand::CREAT_DIR) + path;
502 bool cmdSuccess = SPUtils::LoadCmd(creatPath, cmdResult);
503 if (cmdSuccess) {
504 LOGD("CreatPath created successfully: %s", path.c_str());
505 } else {
506 LOGE("Failed to create path: %s. Command result: %s", path.c_str(), cmdResult.c_str());
507 }
508 } else {
509 LOGD("CreatPath already exists: %s", path.c_str());
510 }
511 }
512
SetTaskInfo()513 std::map<std::string, std::string> SPTask::SetTaskInfo()
514 {
515 long long endTime = SPUtils::GetCurTime();
516 long long testDuration = (endTime - startTime) / 1000;
517 std::string refreshrate;
518 LOGD("Test duration: %lld seconds", testDuration);
519 const std::string gpuDataVersion = "1.1";
520 std::string screenStr = SPUtils::GetScreen();
521 size_t pos3 = screenStr.find("=");
522 if (pos3 != std::string::npos) {
523 refreshrate = screenStr.substr(pos3 + 1);
524 LOGD("Screen refresh rate: %s", refreshrate.c_str());
525 } else {
526 LOGW("Failed to extract refresh rate from screen string: %s", screenStr.c_str());
527 }
528
529 std::map<std::string, std::string> taskInfoMap = {
530 { "sessionId", curTaskInfo.sessionId },
531 { "taskId", curTaskInfo.sessionId },
532 { "appName", curTaskInfo.packageName },
533 { "packageName", curTaskInfo.packageName },
534 { "pid", curTaskInfo.pid },
535 { "startTime", std::to_string(startTime) },
536 { "endTime", std::to_string(endTime) },
537 { "testDuration", std::to_string(testDuration) },
538 { "taskName", "testtask" },
539 { "board", "hw" },
540 { "target_fps", refreshrate },
541 { "gpuDataVersion", gpuDataVersion },
542 { "battery_change", std::to_string(battaryEnd - battaryStart) },
543 };
544 return taskInfoMap;
545 }
546
StopGetInfo()547 void SPTask::StopGetInfo()
548 {
549 bool isTcpMessage = true;
550 CreatPath(baseOutPath);
551 std::string thisBasePath = baseOutPath + "/" + curTaskInfo.sessionId;
552 CreatPath(thisBasePath);
553 std::string outIndexpath = thisBasePath + "/t_index_info.csv";
554
555 std::map<std::string, std::string> taskInfoMap = SetTaskInfo();
556 std::map<std::string, std::string> deviceInfo = SPUtils::GetDeviceInfo();
557 if (deviceInfo.empty()) {
558 LOGW("Failed to get device info when stop.");
559 }
560 std::map<std::string, std::string> cpuInfo = SPUtils::GetCpuInfo(isTcpMessage);
561 if (cpuInfo.empty()) {
562 LOGW("Failed to get CPU info when stop.");
563 }
564 std::map<std::string, std::string> gpuInfo = SPUtils::GetGpuInfo(isTcpMessage);
565 if (gpuInfo.empty()) {
566 LOGW("Failed to get GPU info when stop.");
567 }
568 std::map<std::string, std::string> destMap;
569 destMap.insert(taskInfoMap.begin(), taskInfoMap.end());
570 destMap.insert(deviceInfo.begin(), deviceInfo.end());
571 destMap.insert(cpuInfo.begin(), cpuInfo.end());
572 destMap.insert(gpuInfo.begin(), gpuInfo.end());
573 OHOS::SmartPerf::SpCsvUtil::WriteCsvH(destMap);
574 OHOS::SmartPerf::SpCsvUtil::WriteCsv(outIndexpath, vmap);
575 WLOGI("Write CSV header done.");
576 }
StopGpuCounterRecv()577 void SPTask::StopGpuCounterRecv()
578 {
579 std::string outGpuCounterDataPath = baseOutPath + "/" + curTaskInfo.sessionId;
580
581 if (GetRecordState()) {
582 WLOGI("Record state is valid. Saving GPU counter data.");
583 gpuCounter.GetInstance().SaveData(outGpuCounterDataPath);
584 } else {
585 WLOGW("Record state is invalid. GPU counter data will not be saved.");
586 }
587 }
StopTask()588 ErrCode SPTask::StopTask()
589 {
590 if (GetRecordState()) {
591 WLOGI("Record state is valid. Stopping task and cleaning up.");
592 StopGetInfo();
593 StopSdkRecv();
594 StopGpuCounterRecv();
595
596 vmap.clear();
597 sdkvec.clear();
598 gpuCounter.GetGpuCounterData().clear();
599 recordState = false;
600 screenshotFlag = false;
601 } else {
602 WLOGW("Record state is invalid. Skipping task stop operations.");
603 }
604
605 ResetSdkParam();
606 gpuCounter.StopCollect();
607 lockFreq.SetIsCollecting(false);
608 if (lockFreqThread.joinable()) {
609 LOGD("Joining lockFreqThread.");
610 lockFreqThread.join();
611 }
612
613 WLOGI("Stopping task. isRunning: %d, isInit: %d", isRunning, isInit);
614 isRunning = false;
615 isInit = false;
616 realTimeStart = 0;
617 if (stdOutLog >= 0) {
618 close(stdOutLog);
619 stdOutLog = -1;
620 }
621 if (thread.joinable()) {
622 LOGD("Joining thread.");
623 thread.join();
624 }
625 LOGD("Killing Hiperf command.");
626 SpProfilerFactory::editorFlag = false;
627 WLOGI("Task successfully stopped.");
628 return ErrCode::OK;
629 }
630
DetectionAndGrab()631 std::map<std::string, std::string> SPTask::DetectionAndGrab()
632 {
633 std::map<std::string, std::string> templateMap;
634 if (!curTaskInfo.stuckInfo.isEffective) {
635 LOGE("StuckInfo is not effective. Returning empty map.");
636 return templateMap;
637 }
638
639 FpsCurrentFpsTime fcf = FPS::GetInstance().GetFpsCurrentFpsTime();
640 long long nowTime = SPUtils::GetCurTime();
641 long long curframeTime = fcf.currentFpsTime / RM_1000000; // Convert to milliseconds
642 LOGD("Start capture time: %lld", startCaptuerTime);
643
644 if (startCaptuerTime > 0) {
645 long long diff =
646 startCaptuerTime > nowTime ? (LLONG_MAX - startCaptuerTime + nowTime) : (nowTime - startCaptuerTime);
647 LOGD("Time difference: %lld ms", diff);
648
649 if (diff > RM_5000 && (!CheckCounterId())) {
650 LOGW("Time difference exceeded threshold, resetting start capture time.");
651 startCaptuerTime = RM_0;
652 }
653 }
654
655 if (curTaskInfo.stuckInfo.fps > fcf.fps || curTaskInfo.stuckInfo.frameTime < curframeTime) {
656 if (startCaptuerTime == 0) {
657 startCaptuerTime = nowTime;
658 LOGD("ThreadGetHiperf::%ld", startCaptuerTime);
659 ThreadGetHiperf(startCaptuerTime);
660 }
661 }
662 templateMap["fpsWarn"] = std::to_string(fcf.fps);
663 templateMap["FrameTimeWarn"] = std::to_string(fcf.currentFpsTime);
664 templateMap["TraceTime"] = std::to_string(startCaptuerTime);
665
666 return templateMap;
667 }
668
CheckCounterId()669 bool SPTask::CheckCounterId()
670 {
671 std::string result;
672 std::string hiprofilerCmd = CMD_COMMAND_MAP.at(CmdCommand::HIPROFILER_CMD);
673 LOGD("Loading hiprofiler command");
674 SPUtils::LoadCmd(hiprofilerCmd, result);
675 if (result.empty()) {
676 LOGW("Failed to load hiprofiler command or received empty result.");
677 return false;
678 }
679
680 if (result.find("-k") != std::string::npos) {
681 LOGD("Command contains '-k'.");
682 return true;
683 }
684
685 LOGD("Command does not contain '-k'.");
686 return false;
687 }
ThreadGetHiperf(long long timeStamp)688 std::thread SPTask::ThreadGetHiperf(long long timeStamp)
689 {
690 auto thGetTrace = [this, timeStamp]() { this->GetHiperf(std::to_string(timeStamp)); };
691 std::thread spThread(thGetTrace);
692 spThread.detach();
693 return spThread;
694 }
695
GetHiperf(const std::string & traceName)696 void SPTask::GetHiperf(const std::string &traceName)
697 {
698 std::string result;
699 std::string tmp = SetHiperf(traceName);
700 std::cout << tmp << std::endl;
701 SPUtils::LoadCmd(tmp, result);
702 LOGD("hiprofiler exec (%s), hiprofiler exec trace name(%s), hiprofiler exec end (%s)",
703 tmp.c_str(), traceName.c_str(), result.c_str());
704 }
705
706
CheckTcpParam(std::string str,std::string & errorInfo)707 bool SPTask::CheckTcpParam(std::string str, std::string &errorInfo)
708 {
709 std::set<std::string> keys;
710 std::string params;
711 if (str.find("-SESSIONID") != std::string::npos) {
712 params = str.substr(str.find("-SESSIONID"));
713 } else {
714 LOGE("Init parameter error not contain '-SESSIONID'");
715 return false;
716 }
717 LOGD("Start validating Init parameter: %s", params.c_str());
718
719 for (auto a : COMMAND_MAP) {
720 keys.insert(a.first.substr(1)); // 不需要前面的'-'
721 }
722 bool isValid = SPUtils::VeriyParameter(keys, params, errorInfo);
723 if (isValid) {
724 LOGD("Init parameter validation successful");
725 } else {
726 LOGE("Init parameter validation failed, Error: %s", errorInfo.c_str());
727 }
728 return isValid;
729 }
730
KillHiperfCmd()731 void SPTask::KillHiperfCmd()
732 {
733 long long now = 0;
734 long long runTime = 0;
735 std::string killCmd = CMD_COMMAND_MAP.at(CmdCommand::KILL_CMD) + "-9 ";
736 std::string result;
737 std::vector<std::string> out;
738
739 if (startCaptuerTime <= 0) {
740 return;
741 }
742
743 now = SPUtils::GetCurTime();
744 runTime = now > startCaptuerTime ? now - startCaptuerTime : LLONG_MAX - startCaptuerTime + now;
745 runTime = runTime / RM_1000; // Convert to seconds
746
747 LOGD("Preparing to exit run time(%lld)", runTime);
748 do {
749 out.clear();
750 std::string hiprofilerPid = CMD_COMMAND_MAP.at(CmdCommand::HIPROFILER_PID);
751 SPUtils::LoadCmd(hiprofilerPid, result);
752 SPUtils::StrSplit(result, " ", out);
753 if (out.empty()) {
754 break;
755 }
756
757 sleep(1);
758 } while (END_WAITING_TIME - runTime++ > 0);
759
760 out.clear();
761 std::string hiprofilerPid = CMD_COMMAND_MAP.at(CmdCommand::HIPROFILER_PID);
762 SPUtils::LoadCmd(hiprofilerPid, result);
763 SPUtils::StrSplit(result, " ", out);
764 LOGD("pidof hiprofiker_cmd size(%d)", out.size());
765 for (auto it = out.begin(); out.end() != it; ++it) {
766 result.clear();
767 SPUtils::LoadCmd(killCmd + (*it), result);
768 }
769
770 return;
771 }
772
SetHiperf(const std::string & traceName)773 std::string SPTask::SetHiperf(const std::string &traceName)
774 {
775 std::string hiPrefix = "hiprofiler_";
776 std::string dataPrefix = "perf_";
777 requestId++;
778 std::string trtmp = strOne + hiPrefix + traceName + strTwo + "\n" + strThree + std::to_string(requestId) + "\n" +
779 strFour + "\n" + strFive + hiPrefix + traceName + strSix + "\n" + strNine + strEleven + "\n" + strSeven +
780 dataPrefix + traceName + strEight + strTen + "\n" + conFig;
781 return trtmp;
782 }
783
GetRecordState()784 bool SPTask::GetRecordState()
785 {
786 return recordState;
787 }
GetCurrentBattary()788 int SPTask::GetCurrentBattary()
789 {
790 std::string content;
791 const std::string cmd = "hidumper -s 3302 -a -i | grep capacity";
792 SPUtils::LoadCmd(cmd, content);
793 content = content.substr(content.find(':') + 1);
794 if (content == "") {
795 WLOGE("Battery capacity is empty.");
796 return 0;
797 }
798 return SPUtilesTye::StringToSometype<int>(content);
799 }
800
StartRecord()801 ErrCode SPTask::StartRecord()
802 {
803 battaryStart = GetCurrentBattary();
804 startTime = SPUtils::GetCurTime();
805 WLOGI("StartRecord initiated: Battery %d, Start time %lld.", battaryStart, startTime);
806 while (startTime > nextTime) {
807 std::this_thread::sleep_for(std::chrono::milliseconds(1));
808 }
809 InitDataFile();
810 screenshotFlag = true;
811 recordState = true;
812 recordTrace = true;
813 return ErrCode::OK;
814 }
815
StopRecord()816 ErrCode SPTask::StopRecord()
817 {
818 battaryEnd = GetCurrentBattary();
819 long long stopRecordTime = SPUtils::GetCurTime();
820 WLOGI("StopRecord initiated: Battery %d, Stop time %lld.", battaryEnd, stopRecordTime);
821 while (stopRecordTime > nextTime) {
822 std::this_thread::sleep_for(std::chrono::milliseconds(1));
823 }
824 screenshotFlag = false;
825 recordState = false;
826 recordTrace = false;
827 std::string outGpuCounterDataPath = baseOutPath + "/" + curTaskInfo.sessionId;
828
829 if (isInit) {
830 StopGetInfo();
831 if (sdkData) {
832 StopSdkRecv();
833 }
834 gpuCounter.GetInstance().SaveData(outGpuCounterDataPath);
835 }
836
837 vmap.clear();
838 sdkvec.clear();
839 gpuCounter.GetGpuCounterData().clear();
840 Capture::GetInstance().SetCollectionNum();
841 KillHiperfCmd();
842
843 return ErrCode::OK;
844 }
GetRealStartTime() const845 time_t SPTask::GetRealStartTime() const
846 {
847 return realTimeStart;
848 }
SetTcpToken(std::string token)849 void SPTask::SetTcpToken(std::string token)
850 {
851 tcpToken = token;
852 }
GetTcpToken()853 std::string SPTask::GetTcpToken()
854 {
855 return tcpToken;
856 }
ProcessErrorData(SPData & spdata)857 void SPTask::ProcessErrorData(SPData &spdata)
858 {
859 unsigned int newDataSize = spdata.values.size();
860 if (newDataSize > dataSize) {
861 for (auto iter = spdata.values.cbegin(); iter != spdata.values.cend(); ++iter) {
862 csvTitle += iter->first + ",";
863 }
864 if (!vmap.empty()) {
865 vmap.pop_back();
866 }
867 }
868 dataSize = newDataSize;
869 vmap.push_back(spdata);
870 }
GetCsvTitle()871 std::string SPTask::GetCsvTitle()
872 {
873 return csvTitle;
874 }
SetRecordState(bool status)875 void SPTask::SetRecordState(bool status)
876 {
877 recordState = status;
878 }
EnablePrint()879 void SPTask::EnablePrint()
880 {
881 if (curTaskInfo.isPrint) {
882 stdOutLog = SPUtils::GetTtyDeviceFd();
883 if (dup2(stdOutLog, STDERR_FILENO) < 0) {
884 LOGE("Dup2 fail");
885 } else {
886 close(stdOutLog);
887 stdOutLog = -1;
888 }
889 } else {
890 int &fd = SPUtils::GetTtyDeviceFd();
891 if (fd >= 0) {
892 close(fd);
893 fd = -1;
894 }
895 }
896 }
897 }
898 }
899