• 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 
16 #include "task_manager.h"
17 #include "common.h"
18 #include <chrono>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include "securec.h"
22 
23 #include "include/heartbeat.h"
24 #include "include/sp_utils.h"
25 #include "include/sp_csv_util.h"
26 #include "include/sp_profiler_factory.h"
27 #include "include/sp_thread_socket.h"
28 #include "include/startup_delay.h"
29 #include "include/ByTrace.h"
30 #include "include/smartperf_command.h"
31 #include "include/sp_log.h"
32 #include "include/RAM.h"
33 #include "include/common.h"
34 #include "include/FPS.h"
35 #include "include/sp_task.h"
36 #include "include/CPU.h"
37 #include "include/navigation.h"
38 #include "include/AI_schedule.h"
39 #include "include/Threads.h"
40 #include "include/FileDescriptor.h"
41 #include "include/GpuCounter.h"
42 #include "include/hiperf.h"
43 #include "Capture.h"
44 #include <sys/syscall.h>
45 #include <filesystem>
46 #include "include/sdk_data_recv.h"
47 
48 namespace {
49 OHOS::SmartPerf::TaskManager* g_mgr = nullptr;
50 thread_local OHOS::SmartPerf::ThreadLocal g_datas;
51 constexpr int32_t SAVE_DATA_INTERVAL_MINUTE = 5;
52 }
53 
54 namespace OHOS::SmartPerf {
ThreadLocal()55 ThreadLocal::ThreadLocal()
56 {
57     if (g_mgr == nullptr) {
58         return;
59     }
60     g_mgr->RegisterThreadLocal(this);
61 }
62 
~ThreadLocal()63 ThreadLocal::~ThreadLocal()
64 {
65     if (g_mgr == nullptr || (datasA_.empty() && datasB_.empty())) {
66         return;
67     }
68     g_mgr->CollectData(datasA_);
69     g_mgr->CollectData(datasB_);
70 }
71 
TaskManager(bool isIPC)72 TaskManager::TaskManager(bool isIPC)
73 {
74     g_mgr = this;
75     if (isIPC) {
76         Capture::GetInstance().SocketMessage();
77     }
78 }
79 
GpuCounterProcess(const ArgumentParser::ArgValue & value)80 void TaskManager::GpuCounterProcess(const ArgumentParser::ArgValue& value)
81 {
82     const int defaultFreq = 50;
83     const int minFreq = 50;
84     const int maxFreq = 1000;
85     if (std::holds_alternative<bool>(value)) {
86         // 如果val是bool类型,代表参数为-gc,使用默认频率
87         GpuCounter::GetInstance().SetFrequency(defaultFreq);
88         return;
89     }
90 
91     // -GPU_COUNTER为int类型
92     // 参数拓展时,如果有其他类型,需要增加if判断,否则会variant识别异常导致crash
93     int frequency = std::get<int>(value);
94     // GPU_COUNTER频率最大支持10000,但daemon采集间隔是1000。频率设置应小于采集间隔。
95     if (frequency <= maxFreq && frequency >= minFreq && frequency % minFreq == 0) {
96         GpuCounter::GetInstance().SetFrequency(frequency);
97     } else {
98         LOGW("GPU_COUNTER frequency must be a factor of 50 and in range [50,1000], " +
99              "this frequency is %d, set to 50", frequency);
100         GpuCounter::GetInstance().SetFrequency(defaultFreq);
101     }
102 }
103 
SpecialKeyProcess(const std::string specKey)104 void TaskManager::SpecialKeyProcess(const std::string specKey)
105 {
106     if (specKey == "-LOW_POWER") {
107         FPS::GetInstance().hapLowFpsFlag = true;
108     }
109     if (specKey == "-fc") {
110         FPS::GetInstance().hapNeedCatonInfo = true;
111     }
112 }
113 
AddTask(const std::unordered_map<std::string,ArgumentParser::ArgValue> & argv)114 void TaskManager::AddTask(const std::unordered_map<std::string, ArgumentParser::ArgValue>& argv)
115 {
116     for (auto& [key, val] : argv) {
117         auto iter = COMMAND_MAP.find(key);
118         if (iter == COMMAND_MAP.end()) {
119             continue;
120         }
121         SpecialKeyProcess(key);
122         switch (iter->second) {
123             case CommandType::CT_N: {
124                 collectCount_ = std::get<int>(val);
125                 continue;
126             }
127             case CommandType::CT_PKG:
128             case CommandType::CT_PID: {
129                 GetProcessInfo(iter->second, val);
130                 continue;
131             }
132             case CommandType::CT_PRINT: {
133                 printDataInfo_ = true;
134                 continue;
135             }
136             case CommandType::CT_VIEW: {
137                 FPS::GetInstance().SetLayerName(std::get<std::string>(val));
138                 continue;
139             }
140             case CommandType::CT_OUT: {
141                 SetFilePath(std::get<std::string>(val));
142                 continue;
143             }
144             case CommandType::CT_GC: {
145                 GpuCounterProcess(val);
146                 break;
147             }
148             default:
149                 break;
150         }
151 
152         SpProfiler* pro = SpProfilerFactory::GetCmdProfilerItem(iter->second, true);
153         if (pro == nullptr) {
154             continue;
155         }
156         pro->ipcCallback_ = ipcCallback_;
157         if (iter->second == CommandType::CT_C || iter->second == CommandType::CT_P) {
158             priorityTask_.insert(pro);
159         } else {
160             normalTask_.insert(pro);
161         }
162     }
163 }
164 
AddTask(const std::string & argv)165 void TaskManager::AddTask(const std::string& argv)
166 {
167     LOGD("AddTask argv (%s)", argv.c_str());
168     parameter_.Parse(argv);
169     AddTask(parameter_.Values());
170 }
171 
AddTask(SpProfiler * task,bool priority)172 void TaskManager::AddTask(SpProfiler* task, bool priority)
173 {
174     if (task == nullptr) {
175         return;
176     }
177     LOGD("Start the collection in the start/stop mode");
178     priority ? priorityTask_.insert(task) : normalTask_.insert(task);
179 }
180 
AddTask(std::vector<std::string> & argv)181 void TaskManager::AddTask(std::vector<std::string>& argv)
182 {
183     std::string argvStr;
184     for (auto& item : argv) {
185         argvStr += item + " ";
186     }
187     AddTask(argvStr);
188 }
189 
SetFilePath(const std::string & fileName,bool removeCurrentFile)190 void TaskManager::SetFilePath(const std::string& fileName, bool removeCurrentFile)
191 {
192     fileName_ = fileName;
193     saveFlag_ = true;
194     if (removeCurrentFile) {
195         std::remove(fileName_.c_str());
196     }
197     std::filesystem::path fullPath = fileName;
198     std::string dir = fullPath.parent_path().string();
199     GpuCounter::GetInstance().SetSavePathDirectory(dir);
200     SdkDataRecv::GetInstance().SetFilePath(dir);
201 }
202 
TaskFun(SpProfiler * pro,uint32_t batch,bool record)203 std::map<std::string, std::string> TaskManager::TaskFun(SpProfiler* pro, uint32_t batch, bool record)
204 {
205     auto mapRes = pro->ItemData();
206     if (record) {
207         if (g_datas.switch_) {
208             g_datas.datasA_[batch].insert(mapRes.begin(), mapRes.end());
209         } else {
210             g_datas.datasB_[batch].insert(mapRes.begin(), mapRes.end());
211         }
212     }
213     return mapRes;
214 }
215 
CollectThreadsData()216 void TaskManager::CollectThreadsData()
217 {
218     for (auto& item : threadLocals_) {
219         if (item == nullptr) {
220             continue;
221         }
222 
223         std::map<uint32_t, std::map<std::string, std::string>>& datas =
224             (running_ ^ item->switch_) ? item->datasA_ : item->datasB_;
225 
226         CollectData(datas);
227         std::map<uint32_t, std::map<std::string, std::string>>().swap(datas);
228     }
229 }
230 
StartSaveFileThread()231 void TaskManager::StartSaveFileThread()
232 {
233     if (scheduleSaveDataTh_.joinable()) {
234         LOGD("The thread save data is working");
235         return;
236     }
237     scheduleSaveDataTh_ = std::thread([this]() {
238         LOGD("running: %d, recordData: %d", running_.load(), recordData_.load());
239         while (running_ && recordData_) {
240             std::unique_lock<std::mutex> lock(scheduleSaveDataMtx_);
241             scheduleSaveDataCond_.wait(lock);
242             CollectThreadsData();
243             WriteToCSV();
244             std::map<uint32_t, std::map<std::string, std::string>>().swap(datas_);
245             savingFile_ = false;
246         }
247         LOGD("The data saving thread exits");
248     });
249 }
250 
SaveRegularly(std::chrono::steady_clock::time_point & loopEnd)251 void TaskManager::SaveRegularly(std::chrono::steady_clock::time_point& loopEnd)
252 {
253     if (!recordData_) {
254         return;
255     }
256 
257     if ((loopEnd - currentTimePoint_) >= std::chrono::minutes(SAVE_DATA_INTERVAL_MINUTE) &&
258         !(SpProfilerFactory::editorFlag)) {
259         std::unique_lock<std::mutex> lock(mtx_);
260         if (savingFile_) {
261             LOGD("Saving file");
262             return;
263         }
264         savingFile_ = true;
265         for (auto& item : threadLocals_) {
266             if (item == nullptr) {
267                 continue;
268             }
269             item->switch_ = !item->switch_;
270         }
271         LOGD("Start saving data automatically");
272         scheduleSaveDataCond_.notify_all();
273         currentTimePoint_ = loopEnd;
274     }
275 }
276 
Start(bool record)277 void TaskManager::Start(bool record)
278 {
279     if (priorityTask_.empty() && normalTask_.empty()) {
280         return;
281     }
282     ProcessOnceTask(true);
283     running_ = true;
284     if (record) {
285         saveFlag_ = true;
286         SetRecordState(true);
287     }
288     mainLoop_ = std::thread([this]() {
289         MainLoop();
290     });
291 }
292 
MainLoop()293 void TaskManager::MainLoop()
294 {
295     while (running_) {
296         auto loopStart = std::chrono::steady_clock::now();
297         bool recordData = recordData_.load();
298         if (dataIndex_++ == collectCount_) {
299             break;
300         }
301         LOGD("data index: %u", dataIndex_);
302         std::map<std::string, std::string> currDatas;
303         currDatas.emplace("timestamp", std::to_string(SPUtils::GetCurTime()));
304         if (recordData) {
305             datas_.emplace(dataIndex_,
306                 std::map<std::string, std::string>{{"timestamp", std::to_string(SPUtils::GetCurTime())}});
307         }
308         for (auto& item : priorityTask_) {
309             currDatas.merge(threadPool_.PushTask(&TaskManager::TaskFun, this, item, dataIndex_, recordData).get());
310         }
311         std::vector<std::future<std::map<std::string, std::string>>> result;
312         for (auto& item : normalTask_) {
313             result.emplace_back(threadPool_.PushTask(&TaskManager::TaskFun, this, item, dataIndex_, recordData));
314         }
315         for (auto& item : result) {
316             currDatas.merge(item.get());
317         }
318         for (auto& item : OHOS::SmartPerf::GpuCounter::GetInstance().GetGpuRealtimeData()) {
319             currDatas.insert(item);
320         }
321         if (nextTime_ != nullptr) {
322             *nextTime_ = SPUtils::GetCurTime();
323         }
324         ProcessCurrentBatch(currDatas);
325         auto loopEnd = std::chrono::steady_clock::now();
326         SaveRegularly(loopEnd);
327         auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(loopEnd - loopStart);
328         if (elapsed < std::chrono::seconds(1)) {
329             std::this_thread::sleep_for(std::chrono::seconds(1) - elapsed);
330         }
331     }
332     LOGD("main loop exit");
333     ProcessOnceTask(false);
334     running_ = false;
335     finishCond_.notify_all();
336     scheduleSaveDataCond_.notify_all();
337 }
338 
WriteToCSV()339 void TaskManager::WriteToCSV()
340 {
341     std::unique_lock<std::mutex> lock(mtx_);
342     if (datas_.empty() || !saveFlag_) {
343         LOGD("datas is empty or saveFlag: %d", saveFlag_);
344         return;
345     }
346     if (!dataFile_.is_open()) {
347         char filePath[PATH_MAX] = {0};
348         if (realpath(fileName_.c_str(), filePath) == nullptr) {
349             if (strncpy_s(filePath, PATH_MAX, fileName_.c_str(), fileName_.size()) != 0) {
350                 LOGE("strncpy_s failed");
351                 return;
352             }
353             LOGE("The file %s does not exist, will create", fileName_.c_str());
354         }
355         dataFile_.open(filePath, std::ios::out | std::ios::app);
356         if (!dataFile_.is_open()) {
357             LOGE("The file open fail");
358             return;
359         }
360         LOGD("The file will write data size = (%u)", datas_.size());
361         SetFileTitle();
362     }
363     for (auto& [_, v] : datas_) {
364         for (auto& item : titles_) {
365             auto it = v.find(item);
366             if (it != v.end()) {
367                 dataFile_ << it->second;
368             }
369             dataFile_ << ",";
370         }
371         dataFile_ << "\n";
372     }
373     dataFile_.close();
374 
375     if (!running_) {
376         std::map<uint32_t, std::map<std::string, std::string>>().swap(datas_);
377     }
378 }
379 
SetFileTitle()380 void TaskManager::SetFileTitle()
381 {
382     if (firstSetTitle_) {
383         for (const auto& [id, m] : datas_) {
384             for (const auto& [k, _] : m) {
385                 titles_.insert(k);
386             }
387         }
388         for (const auto& field : titles_) {
389             dataFile_ << field << ",";
390         }
391         dataFile_ << "\n";
392     }
393     firstSetTitle_ = false;
394 }
395 
Stop(bool pause)396 void TaskManager::Stop(bool pause)
397 {
398     isPause_ = pause;
399     running_ = false;
400     if (mainLoop_.joinable()) {
401         {
402             std::lock_guard<std::mutex> lock(mtx_);
403             running_ = false;
404         }
405         mainLoop_.join();
406     }
407     if (scheduleSaveDataTh_.joinable()) {
408         {
409             std::lock_guard<std::mutex> lock(mtx_);
410             running_ = false;
411         }
412         scheduleSaveDataCond_.notify_all();
413         scheduleSaveDataTh_.join();
414     }
415     if (!pause) {
416         LOGD("Start/Stop Collection End");
417         threadPool_.Stop();
418     }
419 }
420 
Wait()421 void TaskManager::Wait()
422 {
423     std::unique_lock<std::mutex> lock(finishMtx_);
424     finishCond_.wait(lock, [this] { return !running_.load(); });
425 }
426 
CollectData(std::map<uint32_t,std::map<std::string,std::string>> & datas)427 void TaskManager::CollectData(std::map<uint32_t, std::map<std::string, std::string>>& datas)
428 {
429     std::unique_lock<std::mutex> lock(mtx_);
430     for (auto& [k, v] : datas) {
431         if (v.empty()) {
432             continue;
433         }
434         datas_[k].merge(v);
435     }
436 }
437 
GetProcessInfo(CommandType type,const ArgumentParser::ArgValue & value)438 void TaskManager::GetProcessInfo(CommandType type, const ArgumentParser::ArgValue& value)
439 {
440     if (type == CommandType::CT_PKG) {
441         processName_ = std::get<std::string>(value);
442         OHOS::SmartPerf::StartUpDelay sp;
443         sp.GetPidByPkg(processName_, &processIds_);
444     }
445 
446     if (type == CommandType::CT_PID) {
447         processIds_ = std::to_string(std::get<int32_t>(value));
448         const std::string getProcPkg = "cat /proc/" + processIds_ + "/cmdline";
449         FILE *fd = popen(getProcPkg.c_str(), "r");
450         if (fd == nullptr) {
451             return;
452         }
453         char buf[1024] = {'\0'};
454         while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
455             processName_ = buf;
456         }
457         if (pclose(fd) == -1) {
458             LOGE("Error: Failed to close file");
459             return;
460         }
461     }
462 
463     FPS::GetInstance().SetProcessId(processIds_);
464     FPS::GetInstance().SetPackageName(processName_);
465     RAM::GetInstance().SetProcessId(processIds_);
466     RAM::GetInstance().SetPackageName(processName_);
467     CPU::GetInstance().SetProcessId(processIds_);
468     CPU::GetInstance().SetPackageName(processName_);
469     Navigation::GetInstance().SetProcessId(processIds_);
470     AISchedule::GetInstance().SetProcessId(processIds_);
471     Threads::GetInstance().SetProcessId(processIds_);
472     Threads::GetInstance().SetPackageName(processName_);
473     FileDescriptor::GetInstance().SetProcessId(processIds_);
474     FileDescriptor::GetInstance().SetPackageName(processName_);
475     Hiperf::GetInstance().SetProcessId(processIds_);
476 }
477 
RegisterThreadLocal(ThreadLocal * local)478 void TaskManager::RegisterThreadLocal(ThreadLocal* local)
479 {
480     std::unique_lock<std::mutex> lock(mtx_);
481     threadLocals_.emplace_back(local);
482 }
483 
MapToString(std::map<std::string,std::string> & myMap)484 std::string TaskManager::MapToString(std::map<std::string, std::string>& myMap)
485 {
486     if (hapCollect_) {
487         std::string appCollectMap = "t_index_info$$";
488         std::vector<std::string> keysToFind = {"fps", "refreshrate", "currentNow", "ddrFrequency", "cpu0Frequency",
489             "cpu1Frequency", "cpu2Frequency", "cpu3Frequency", "cpu4Frequency", "cpu5Frequency", "cpu6Frequency",
490             "cpu7Frequency", "cpu8Frequency", "cpu9Frequency", "cpu10Frequency", "cpu11Frequency", "gpuFrequency",
491             "pss", "shell_frame", "shell_back", "soc_thermal", "cpu0Usage", "cpu1Usage", "cpu2Usage", "cpu3Usage",
492             "cpu4Usage", "cpu5Usage", "cpu6Usage", "cpu7Usage", "cpu8Usage", "cpu9Usage", "cpu10Usage", "cpu11Usage",
493             "gpuLoad"};
494         for (const auto& key : keysToFind) {
495             if (auto iter = myMap.find(key); iter != myMap.end()) {
496                 appCollectMap += iter->first + ":" + iter->second + ",";
497             }
498         }
499         return appCollectMap;
500     } else {
501         std::string str = "{ ";
502         for (auto it = myMap.begin(); it != myMap.end(); ++it) {
503             str += "\"" + it->first + "\": " + it->second + ", ";
504         }
505         const int subLen = 2;
506         str.erase(str.end() - subLen, str.end());
507         str += " }";
508         return str;
509     }
510 }
511 
ProcessCurrentBatch(std::map<std::string,std::string> & data)512 void TaskManager::ProcessCurrentBatch(std::map<std::string, std::string>& data)
513 {
514     if (printDataInfo_) {
515         std::cerr << std::endl;
516         uint32_t index = 0;
517         for (auto& [k, v] : data) {
518             std::cerr << "order:" << index++ << " ";
519             std::cerr << k << "=" << v << std::endl;
520         }
521     }
522 
523     if (ipcDataRecv_) {
524         ipcCallback_(MapToString(data));
525     }
526 }
527 
EnableIPCCallback()528 void TaskManager::EnableIPCCallback()
529 {
530     ipcDataRecv_ = true;
531 }
532 
SetIPCCallback(std::function<void (const std::string &)> callback)533 void TaskManager::SetIPCCallback(std::function<void(const std::string&)> callback)
534 {
535     ipcCallback_ = callback;
536 }
537 
DisableIPCCallback()538 void TaskManager::DisableIPCCallback()
539 {
540     ipcDataRecv_ = false;
541 }
542 
SetHapFlag(bool flag)543 void TaskManager::SetHapFlag(bool flag)
544 {
545     hapCollect_ = flag;
546 }
547 
SetNextTime(long long & nextTime)548 void TaskManager::SetNextTime(long long& nextTime)
549 {
550     nextTime_ = &nextTime;
551 }
552 
ProcessOnceTask(bool start)553 void TaskManager::ProcessOnceTask(bool start)
554 {
555     for (auto& item : priorityTask_) {
556         if (item == nullptr) {
557             continue;
558         }
559         start ? item->StartExecutionOnce(isPause_.load()) : item->FinishtExecutionOnce(isPause_.load());
560     }
561 
562     for (auto& item : normalTask_) {
563         if (item == nullptr) {
564             continue;
565         }
566         start ? item->StartExecutionOnce(isPause_.load()) : item->FinishtExecutionOnce(isPause_.load());
567     }
568 }
569 
SetRecordState(bool record)570 void TaskManager::SetRecordState(bool record)
571 {
572     if (record) {
573         LOGD("Start saving data regularly");
574         currentTimePoint_ = std::chrono::steady_clock::now();
575         recordData_ = true;
576         StartSaveFileThread();
577     } else {
578         LOGD("Turn off timing to save data");
579         auto time = currentTimePoint_ + std::chrono::minutes(SAVE_DATA_INTERVAL_MINUTE + 1);
580         SaveRegularly(time);
581         recordData_ = false;
582 
583         if (scheduleSaveDataTh_.joinable()) {
584             scheduleSaveDataTh_.join();
585         }
586     }
587 }
588 
DeleteTask(SpProfiler * task)589 void TaskManager::DeleteTask(SpProfiler* task)
590 {
591     if (task == nullptr) {
592         return;
593     }
594 
595     for (auto iter = normalTask_.begin(); iter != normalTask_.end(); ++iter) {
596         if (task == *iter) {
597             normalTask_.erase(iter);
598             return;
599         }
600     }
601     for (auto iter = priorityTask_.begin(); iter != priorityTask_.end(); ++iter) {
602         if (task == *iter) {
603             priorityTask_.erase(iter);
604             return;
605         }
606     }
607 }
608 
InitDataCsv()609 void TaskManager::InitDataCsv()
610 {
611     if (!SPUtils::FileAccess(fileName_)) {
612         std::ofstream file(fileName_);
613         if (file) {
614             std::string chmodCmd = "chmod 777 " + fileName_;
615             std::string cmdResult;
616             SPUtils::LoadCmd(chmodCmd, cmdResult);
617             file.close();
618         } else {
619             LOGE("Failed to creat file");
620             return;
621         }
622     } else {
623         std::ofstream file(fileName_, std::ios::trunc);
624         if (!file) {
625             LOGE("Unable to open file");
626             return;
627         }
628         file.close();
629         LOGD("CreatPath already exists: %s", fileName_.c_str());
630     }
631 }
632 
GetArgumentParser()633 ArgumentParser& TaskManager::GetArgumentParser()
634 {
635     return parameter_;
636 }
637 }