• 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             iter = COMMAND_SHELL_MAP.find(key);
120         }
121         if (iter == COMMAND_MAP.end() || iter == COMMAND_SHELL_MAP.end()) {
122             continue;
123         }
124         SpecialKeyProcess(key);
125         HandleCommandType(iter->second, val);
126 
127         SpProfiler* pro = SpProfilerFactory::GetCmdProfilerItem(iter->second, true);
128         if (pro == nullptr) {
129             continue;
130         }
131         pro->ipcCallback_ = ipcCallback_;
132         if (iter->second == CommandType::CT_C || iter->second == CommandType::CT_P) {
133             priorityTask_.insert(pro);
134         } else {
135             normalTask_.insert(pro);
136         }
137     }
138 }
139 
HandleCommandType(CommandType cmdType,const ArgumentParser::ArgValue & val)140 void TaskManager::HandleCommandType(CommandType cmdType, const ArgumentParser::ArgValue& val)
141 {
142     switch (cmdType) {
143         case CommandType::CT_N: {
144             collectCount_ = std::get<int>(val);
145             break;
146         }
147         case CommandType::CT_PKG:
148         case CommandType::CT_PID: {
149             GetProcessInfo(cmdType, val);
150             break;
151         }
152         case CommandType::CT_PRINT: {
153             printDataInfo_ = true;
154             break;
155         }
156         case CommandType::CT_VIEW: {
157             FPS::GetInstance().SetLayerName(std::get<std::string>(val));
158             break;
159         }
160         case CommandType::CT_OUT: {
161             SetFilePath(std::get<std::string>(val));
162             break;
163         }
164         case CommandType::CT_GC: {
165             GpuCounterProcess(val);
166             break;
167         }
168         default:
169             break;
170     }
171 }
172 
AddTask(const std::string & argv)173 void TaskManager::AddTask(const std::string& argv)
174 {
175     LOGD("AddTask argv (%s)", argv.c_str());
176     parameter_.Parse(argv);
177     AddTask(parameter_.Values());
178 }
179 
AddTask(SpProfiler * task,bool priority)180 void TaskManager::AddTask(SpProfiler* task, bool priority)
181 {
182     if (task == nullptr) {
183         return;
184     }
185     LOGD("Start the collection in the start/stop mode");
186     priority ? priorityTask_.insert(task) : normalTask_.insert(task);
187 }
188 
AddTask(std::vector<std::string> & argv)189 void TaskManager::AddTask(std::vector<std::string>& argv)
190 {
191     std::string argvStr;
192     for (auto& item : argv) {
193         argvStr += item + " ";
194     }
195     AddTask(argvStr);
196 }
197 
SetFilePath(const std::string & fileName,bool removeCurrentFile)198 void TaskManager::SetFilePath(const std::string& fileName, bool removeCurrentFile)
199 {
200     fileName_ = fileName;
201     saveFlag_ = true;
202     if (removeCurrentFile) {
203         std::remove(fileName_.c_str());
204     }
205     std::filesystem::path fullPath = fileName;
206     std::string dir = fullPath.parent_path().string();
207     GpuCounter::GetInstance().SetSavePathDirectory(dir);
208     SdkDataRecv::GetInstance().SetFilePath(dir);
209 }
210 
TaskFun(SpProfiler * pro,uint32_t batch,bool record)211 std::map<std::string, std::string> TaskManager::TaskFun(SpProfiler* pro, uint32_t batch, bool record)
212 {
213     auto mapRes = pro->ItemData();
214     if (record) {
215         if (g_datas.switch_) {
216             g_datas.datasA_[batch].insert(mapRes.begin(), mapRes.end());
217         } else {
218             g_datas.datasB_[batch].insert(mapRes.begin(), mapRes.end());
219         }
220     }
221     return mapRes;
222 }
223 
CollectThreadsData()224 void TaskManager::CollectThreadsData()
225 {
226     for (auto& item : threadLocals_) {
227         if (item == nullptr) {
228             continue;
229         }
230 
231         std::map<uint32_t, std::map<std::string, std::string>>& datas =
232             (running_ ^ item->switch_) ? item->datasA_ : item->datasB_;
233 
234         CollectData(datas);
235         std::map<uint32_t, std::map<std::string, std::string>>().swap(datas);
236     }
237 }
238 
StartSaveFileThread()239 void TaskManager::StartSaveFileThread()
240 {
241     if (scheduleSaveDataTh_.joinable()) {
242         LOGD("The thread save data is working");
243         return;
244     }
245     scheduleSaveDataTh_ = std::thread([this]() {
246         LOGD("running: %d, recordData: %d", running_.load(), recordData_.load());
247         while (running_ && recordData_) {
248             std::unique_lock<std::mutex> lock(scheduleSaveDataMtx_);
249             scheduleSaveDataCond_.wait(lock);
250             CollectThreadsData();
251             WriteToCSV();
252             std::map<uint32_t, std::map<std::string, std::string>>().swap(datas_);
253             savingFile_ = false;
254         }
255         LOGD("The data saving thread exits");
256     });
257 }
258 
SaveRegularly(std::chrono::steady_clock::time_point & loopEnd)259 void TaskManager::SaveRegularly(std::chrono::steady_clock::time_point& loopEnd)
260 {
261     if (!recordData_) {
262         return;
263     }
264 
265     if ((loopEnd - currentTimePoint_) >= std::chrono::minutes(SAVE_DATA_INTERVAL_MINUTE) &&
266         !(SpProfilerFactory::editorFlag)) {
267         std::unique_lock<std::mutex> lock(mtx_);
268         if (savingFile_) {
269             LOGD("Saving file");
270             return;
271         }
272         savingFile_ = true;
273         for (auto& item : threadLocals_) {
274             if (item == nullptr) {
275                 continue;
276             }
277             item->switch_ = !item->switch_;
278         }
279         LOGD("Start saving data automatically");
280         scheduleSaveDataCond_.notify_all();
281         currentTimePoint_ = loopEnd;
282     }
283 }
284 
Start(bool record)285 void TaskManager::Start(bool record)
286 {
287     if (priorityTask_.empty() && normalTask_.empty()) {
288         return;
289     }
290     ProcessOnceTask(true);
291     running_ = true;
292     if (record) {
293         saveFlag_ = true;
294         SetRecordState(true);
295     }
296     mainLoop_ = std::thread([this]() {
297         MainLoop();
298     });
299 }
300 
MainLoop()301 void TaskManager::MainLoop()
302 {
303     while (running_) {
304         auto loopStart = std::chrono::steady_clock::now();
305         bool recordData = recordData_.load();
306         if (dataIndex_++ == collectCount_) {
307             break;
308         }
309         LOGD("data index: %u", dataIndex_);
310         std::map<std::string, std::string> currDatas;
311         currDatas.emplace("timestamp", std::to_string(SPUtils::GetCurTime()));
312         if (recordData) {
313             datas_.emplace(dataIndex_,
314                 std::map<std::string, std::string>{{"timestamp", std::to_string(SPUtils::GetCurTime())}});
315         }
316         for (auto& item : priorityTask_) {
317             currDatas.merge(threadPool_.PushTask(&TaskManager::TaskFun, this, item, dataIndex_, recordData).get());
318         }
319         std::vector<std::future<std::map<std::string, std::string>>> result;
320         for (auto& item : normalTask_) {
321             result.emplace_back(threadPool_.PushTask(&TaskManager::TaskFun, this, item, dataIndex_, recordData));
322         }
323         for (auto& item : result) {
324             currDatas.merge(item.get());
325         }
326         for (auto& item : OHOS::SmartPerf::GpuCounter::GetInstance().GetGpuRealtimeData()) {
327             currDatas.insert(item);
328         }
329         if (nextTime_ != nullptr) {
330             *nextTime_ = SPUtils::GetCurTime();
331         }
332         ProcessCurrentBatch(currDatas);
333         auto loopEnd = std::chrono::steady_clock::now();
334         SaveRegularly(loopEnd);
335         auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(loopEnd - loopStart);
336         if (elapsed < std::chrono::seconds(1)) {
337             std::this_thread::sleep_for(std::chrono::seconds(1) - elapsed);
338         }
339     }
340     LOGD("main loop exit");
341     ProcessOnceTask(false);
342     running_ = false;
343     finishCond_.notify_all();
344     scheduleSaveDataCond_.notify_all();
345 }
346 
WriteToCSV()347 void TaskManager::WriteToCSV()
348 {
349     std::unique_lock<std::mutex> lock(mtx_);
350     if (datas_.empty() || !saveFlag_) {
351         LOGD("datas is empty or saveFlag: %d", saveFlag_);
352         return;
353     }
354     if (!dataFile_.is_open()) {
355         char filePath[PATH_MAX] = {0};
356         if (realpath(fileName_.c_str(), filePath) == nullptr) {
357             if (strncpy_s(filePath, PATH_MAX, fileName_.c_str(), fileName_.size()) != 0) {
358                 LOGE("strncpy_s failed");
359                 return;
360             }
361             LOGE("The file %s does not exist, will create", fileName_.c_str());
362         }
363         dataFile_.open(filePath, std::ios::out | std::ios::app);
364         if (!dataFile_.is_open()) {
365             LOGE("The file open fail");
366             return;
367         }
368         LOGD("The file will write data size = (%u)", datas_.size());
369         SetFileTitle();
370     }
371     for (auto& [_, v] : datas_) {
372         for (auto& item : titles_) {
373             auto it = v.find(item);
374             if (it != v.end()) {
375                 dataFile_ << it->second;
376             }
377             dataFile_ << ",";
378         }
379         dataFile_ << "\n";
380     }
381     dataFile_.close();
382 
383     if (!running_) {
384         std::map<uint32_t, std::map<std::string, std::string>>().swap(datas_);
385     }
386 }
387 
SetFileTitle()388 void TaskManager::SetFileTitle()
389 {
390     if (firstSetTitle_) {
391         for (const auto& [id, m] : datas_) {
392             for (const auto& [k, _] : m) {
393                 titles_.insert(k);
394             }
395         }
396         for (const auto& field : titles_) {
397             dataFile_ << field << ",";
398         }
399         dataFile_ << "\n";
400     }
401     firstSetTitle_ = false;
402 }
403 
Stop(bool pause)404 void TaskManager::Stop(bool pause)
405 {
406     isPause_ = pause;
407     running_ = false;
408     if (mainLoop_.joinable()) {
409         {
410             std::lock_guard<std::mutex> lock(mtx_);
411             running_ = false;
412         }
413         mainLoop_.join();
414     }
415     if (scheduleSaveDataTh_.joinable()) {
416         {
417             std::lock_guard<std::mutex> lock(mtx_);
418             running_ = false;
419         }
420         scheduleSaveDataCond_.notify_all();
421         scheduleSaveDataTh_.join();
422     }
423     if (!pause) {
424         LOGD("Start/Stop Collection End");
425         threadPool_.Stop();
426     }
427 }
428 
Wait()429 void TaskManager::Wait()
430 {
431     std::unique_lock<std::mutex> lock(finishMtx_);
432     finishCond_.wait(lock, [this] { return !running_.load(); });
433 }
434 
CollectData(std::map<uint32_t,std::map<std::string,std::string>> & datas)435 void TaskManager::CollectData(std::map<uint32_t, std::map<std::string, std::string>>& datas)
436 {
437     std::unique_lock<std::mutex> lock(mtx_);
438     for (auto& [k, v] : datas) {
439         if (v.empty()) {
440             continue;
441         }
442         datas_[k].merge(v);
443     }
444 }
445 
GetProcessInfo(CommandType type,const ArgumentParser::ArgValue & value)446 void TaskManager::GetProcessInfo(CommandType type, const ArgumentParser::ArgValue& value)
447 {
448     if (type == CommandType::CT_PKG) {
449         processName_ = std::get<std::string>(value);
450         OHOS::SmartPerf::StartUpDelay sp;
451         sp.GetPidByPkg(processName_, &processIds_);
452     }
453 
454     if (type == CommandType::CT_PID) {
455         processIds_ = std::to_string(std::get<int32_t>(value));
456         const std::string getProcPkg = "cat /proc/" + processIds_ + "/cmdline";
457         FILE *fd = popen(getProcPkg.c_str(), "r");
458         if (fd == nullptr) {
459             return;
460         }
461         char buf[1024] = {'\0'};
462         while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
463             processName_ = buf;
464         }
465         if (pclose(fd) == -1) {
466             LOGE("Error: Failed to close file");
467             return;
468         }
469     }
470 
471     FPS::GetInstance().SetProcessId(processIds_);
472     FPS::GetInstance().SetPackageName(processName_);
473     RAM::GetInstance().SetProcessId(processIds_);
474     RAM::GetInstance().SetPackageName(processName_);
475     CPU::GetInstance().SetProcessId(processIds_);
476     CPU::GetInstance().SetPackageName(processName_);
477     Navigation::GetInstance().SetProcessId(processIds_);
478     AISchedule::GetInstance().SetProcessId(processIds_);
479     Threads::GetInstance().SetProcessId(processIds_);
480     Threads::GetInstance().SetPackageName(processName_);
481     FileDescriptor::GetInstance().SetProcessId(processIds_);
482     FileDescriptor::GetInstance().SetPackageName(processName_);
483     Hiperf::GetInstance().SetProcessId(processIds_);
484 }
485 
RegisterThreadLocal(ThreadLocal * local)486 void TaskManager::RegisterThreadLocal(ThreadLocal* local)
487 {
488     std::unique_lock<std::mutex> lock(mtx_);
489     threadLocals_.emplace_back(local);
490 }
491 
MapToString(std::map<std::string,std::string> & myMap)492 std::string TaskManager::MapToString(std::map<std::string, std::string>& myMap)
493 {
494     if (hapCollect_) {
495         std::string appCollectMap = "t_index_info$$";
496         std::vector<std::string> keysToFind = {"fps", "refreshrate", "currentNow", "ddrFrequency", "cpu0Frequency",
497             "cpu1Frequency", "cpu2Frequency", "cpu3Frequency", "cpu4Frequency", "cpu5Frequency", "cpu6Frequency",
498             "cpu7Frequency", "cpu8Frequency", "cpu9Frequency", "cpu10Frequency", "cpu11Frequency", "gpuFrequency",
499             "pss", "shell_frame", "shell_back", "soc_thermal", "cpu0Usage", "cpu1Usage", "cpu2Usage", "cpu3Usage",
500             "cpu4Usage", "cpu5Usage", "cpu6Usage", "cpu7Usage", "cpu8Usage", "cpu9Usage", "cpu10Usage", "cpu11Usage",
501             "gpuLoad"};
502         for (const auto& key : keysToFind) {
503             if (auto iter = myMap.find(key); iter != myMap.end()) {
504                 appCollectMap += iter->first + ":" + iter->second + ",";
505             }
506         }
507         return appCollectMap;
508     } else {
509         std::string str = "{ ";
510         for (auto it = myMap.begin(); it != myMap.end(); ++it) {
511             str += "\"" + it->first + "\": " + it->second + ", ";
512         }
513         const int subLen = 2;
514         str.erase(str.end() - subLen, str.end());
515         str += " }";
516         return str;
517     }
518 }
519 
ProcessCurrentBatch(std::map<std::string,std::string> & data)520 void TaskManager::ProcessCurrentBatch(std::map<std::string, std::string>& data)
521 {
522     if (printDataInfo_) {
523         std::cerr << std::endl;
524         uint32_t index = 0;
525         for (auto& [k, v] : data) {
526             std::cerr << "order:" << index++ << " ";
527             std::cerr << k << "=" << v << std::endl;
528         }
529     }
530 
531     if (ipcDataRecv_) {
532         ipcCallback_(MapToString(data));
533     }
534 }
535 
EnableIPCCallback()536 void TaskManager::EnableIPCCallback()
537 {
538     ipcDataRecv_ = true;
539 }
540 
SetIPCCallback(std::function<void (const std::string &)> callback)541 void TaskManager::SetIPCCallback(std::function<void(const std::string&)> callback)
542 {
543     ipcCallback_ = callback;
544 }
545 
DisableIPCCallback()546 void TaskManager::DisableIPCCallback()
547 {
548     ipcDataRecv_ = false;
549 }
550 
SetHapFlag(bool flag)551 void TaskManager::SetHapFlag(bool flag)
552 {
553     hapCollect_ = flag;
554 }
555 
SetNextTime(long long & nextTime)556 void TaskManager::SetNextTime(long long& nextTime)
557 {
558     nextTime_ = &nextTime;
559 }
560 
ProcessOnceTask(bool start)561 void TaskManager::ProcessOnceTask(bool start)
562 {
563     for (auto& item : priorityTask_) {
564         if (item == nullptr) {
565             continue;
566         }
567         start ? item->StartExecutionOnce(isPause_.load()) : item->FinishtExecutionOnce(isPause_.load());
568     }
569 
570     for (auto& item : normalTask_) {
571         if (item == nullptr) {
572             continue;
573         }
574         start ? item->StartExecutionOnce(isPause_.load()) : item->FinishtExecutionOnce(isPause_.load());
575     }
576 }
577 
SetRecordState(bool record)578 void TaskManager::SetRecordState(bool record)
579 {
580     if (record) {
581         LOGD("Start saving data regularly");
582         currentTimePoint_ = std::chrono::steady_clock::now();
583         recordData_ = true;
584         StartSaveFileThread();
585     } else {
586         LOGD("Turn off timing to save data");
587         auto time = currentTimePoint_ + std::chrono::minutes(SAVE_DATA_INTERVAL_MINUTE + 1);
588         SaveRegularly(time);
589         recordData_ = false;
590 
591         if (scheduleSaveDataTh_.joinable()) {
592             scheduleSaveDataTh_.join();
593         }
594     }
595 }
596 
DeleteTask(SpProfiler * task)597 void TaskManager::DeleteTask(SpProfiler* task)
598 {
599     if (task == nullptr) {
600         return;
601     }
602 
603     for (auto iter = normalTask_.begin(); iter != normalTask_.end(); ++iter) {
604         if (task == *iter) {
605             normalTask_.erase(iter);
606             return;
607         }
608     }
609     for (auto iter = priorityTask_.begin(); iter != priorityTask_.end(); ++iter) {
610         if (task == *iter) {
611             priorityTask_.erase(iter);
612             return;
613         }
614     }
615 }
616 
InitDataCsv()617 void TaskManager::InitDataCsv()
618 {
619     if (!SPUtils::FileAccess(fileName_)) {
620         std::ofstream file(fileName_);
621         if (file) {
622             std::string chmodCmd = "chmod 777 " + fileName_;
623             std::string cmdResult;
624             SPUtils::LoadCmd(chmodCmd, cmdResult);
625             file.close();
626         } else {
627             LOGE("Failed to creat file");
628             return;
629         }
630     } else {
631         std::ofstream file(fileName_, std::ios::trunc);
632         if (!file) {
633             LOGE("Unable to open file");
634             return;
635         }
636         file.close();
637         LOGD("CreatPath already exists: %s", fileName_.c_str());
638     }
639 }
640 
GetArgumentParser()641 ArgumentParser& TaskManager::GetArgumentParser()
642 {
643     return parameter_;
644 }
645 }