1 /*
2 * Copyright (c) 2025 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 "appfreeze_cpu_freq_manager.h"
17
18 #include <fcntl.h>
19 #include <string>
20 #include <iostream>
21 #include <iomanip>
22 #include <sstream>
23 #include <cstdint>
24 #include <dlfcn.h>
25 #include <cstdio>
26
27 #include "file_ex.h"
28 #include "directory_ex.h"
29 #include "string_ex.h"
30 #include "hilog_tag_wrapper.h"
31 #include "time_util.h"
32 #include "appfreeze_util.h"
33 #include "dfx_define.h"
34 #include "fault_data.h"
35
36 namespace OHOS {
37 namespace AppExecFwk {
38 namespace {
39 constexpr int64_t HZ_TO_MHZ = 1000;
40 constexpr size_t CPU_FREQ_AND_TIME_NUM = 5;
41 constexpr int CPU_FREQ_DECIMAL_BASE = 10;
42 constexpr float CPU_PERCENTAGE = 100.0f;
43 constexpr float CPU_MIN_FREQ_USAGE_VALUE = 1.0f;
44 constexpr uint32_t TIME_IN_STATE_FIRST_INDEX = 0;
45 constexpr uint32_t TIME_IN_STATE_SECOND_INDEX = 1;
46 constexpr uint32_t START_TIME_FIRST_INDEX = 13;
47 constexpr uint32_t START_TIME_SECOND_INDEX = 14;
48 constexpr const char* const LOG_FILE_HEAD = "Generated by HiviewDFX @OpenHarmony";
49 constexpr const char* const LOG_FILE_SEP = "===============================================================";
50 constexpr int START_PATH_LEN = 128;
51 constexpr const char* const LIB_THREAD_CPU_LOAD_PATH = "libucollection_utility.z.so";
52 constexpr int TIME_LIMIT = 6000; // 6s
53 constexpr size_t MAX_CPU_MAP_SIZE = 10;
54 constexpr uint32_t DEFAULT_CPU_SIZE = 1;
55 constexpr const char* const CPU_INFO_PREFIX = "cpu-info-";
56
57 }
58 std::shared_ptr<AppfreezeCpuFreqManager> AppfreezeCpuFreqManager::instance_ = nullptr;
59 ffrt::mutex AppfreezeCpuFreqManager::freezeInfoMutex_;
60 int AppfreezeCpuFreqManager::cpuCount_ = 0;
61 std::map<std::string, CpuDataProcessor> AppfreezeCpuFreqManager::cpuInfoMap_;
62
63 typedef double (*GetThreadCpuload)(int);
64
AppfreezeCpuFreqManager()65 AppfreezeCpuFreqManager::AppfreezeCpuFreqManager()
66 {
67 cpuCount_ = AppfreezeUtil::GetCpuCount();
68 }
69
~AppfreezeCpuFreqManager()70 AppfreezeCpuFreqManager::~AppfreezeCpuFreqManager()
71 {
72 }
73
GetInstance()74 AppfreezeCpuFreqManager &AppfreezeCpuFreqManager::GetInstance()
75 {
76 static AppfreezeCpuFreqManager instance;
77 return instance;
78 }
79
ClearOldCpuData(uint64_t curTime)80 void AppfreezeCpuFreqManager::ClearOldCpuData(uint64_t curTime)
81 {
82 std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
83 if (cpuInfoMap_.size() < MAX_CPU_MAP_SIZE) {
84 return ;
85 }
86 for (auto it = cpuInfoMap_.begin(); it != cpuInfoMap_.end();) {
87 auto diff = curTime - it->second.GetCpuStartTime().halfStartTime;
88 if (diff > TIME_LIMIT || diff < 0) {
89 it = cpuInfoMap_.erase(it);
90 } else {
91 ++it;
92 }
93 }
94 }
95
IsSkipTask(uint64_t curTime,const std::string & key,int32_t pid)96 bool AppfreezeCpuFreqManager::IsSkipTask(uint64_t curTime, const std::string &key, int32_t pid)
97 {
98 std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
99 auto it = cpuInfoMap_.find(key);
100 if (it != cpuInfoMap_.end()) {
101 auto diff = curTime - it->second.GetCpuStartTime().halfStartTime;
102 if (diff > TIME_LIMIT || diff < 0) {
103 it = cpuInfoMap_.erase(it);
104 } else {
105 TAG_LOGW(AAFwkTag::APPDFR, "Skip this task. "
106 "The task of the current process is already being executed, pid:%{public}d", pid);
107 return true;
108 }
109 }
110 if (cpuInfoMap_.size() >= MAX_CPU_MAP_SIZE) {
111 TAG_LOGW(AAFwkTag::APPDFR, "Skip this task. "
112 "The current queue can only execute up to %{public}zu tasks", MAX_CPU_MAP_SIZE);
113 return true;
114 }
115 return false;
116 }
117
InitCpuDataProcessor(const std::string & eventType,int32_t pid,int32_t uid,const std::string & stackPath)118 bool AppfreezeCpuFreqManager::InitCpuDataProcessor(const std::string &eventType,
119 int32_t pid, int32_t uid, const std::string &stackPath)
120 {
121 uint64_t curTime = AppfreezeUtil::GetMilliseconds();
122 ClearOldCpuData(curTime);
123 std::string key = eventType + std::to_string(uid);
124 if (IsSkipTask(curTime, key, pid)) {
125 return false;
126 }
127 CpuStartTime cpuStartTime = {
128 .halfStartTime = curTime,
129 .optimalCpuStartTime = GetOptimalCpuTime(pid),
130 };
131 std::vector<std::vector<CpuFreqData>> cpuData;
132 std::vector<TotalTime> totalTimeList;
133 ParseCpuData(cpuData, totalTimeList);
134 CpuDataProcessor data(cpuData, totalTimeList, cpuStartTime, stackPath, pid);
135 {
136 std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
137 cpuInfoMap_[key] = data;
138 }
139 TAG_LOGD(AAFwkTag::APPDFR, "init success. eventType: %{public}s path: %{public}s "
140 "halfStartTime: %{public}" PRIu64", optimalCpuStartTime: %{public}" PRIu64".",
141 eventType.c_str(), stackPath.c_str(), cpuStartTime.halfStartTime,
142 cpuStartTime.optimalCpuStartTime);
143 return true;
144 }
145
ParseCpuData(std::vector<std::vector<CpuFreqData>> & datas,std::vector<TotalTime> & totalTimeLists)146 void AppfreezeCpuFreqManager::ParseCpuData(std::vector<std::vector<CpuFreqData>>& datas,
147 std::vector<TotalTime>& totalTimeLists)
148 {
149 TAG_LOGD(AAFwkTag::APPDFR, "ParseCpuData start time: %{public}s",
150 AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
151 std::string tmp = "start time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr();
152 TAG_LOGW(AAFwkTag::APPDFR, "ParseCpuData called, %{public}s", tmp.c_str());
153 for (int32_t i = 0; i < cpuCount_; ++i) {
154 std::vector<CpuFreqData> parseDatas;
155 TotalTime totalTime{};
156 if (ReadCpuDataByNum(i, parseDatas, totalTime)) {
157 datas.push_back(parseDatas);
158 totalTimeLists.push_back(totalTime);
159 }
160 }
161 TAG_LOGD(AAFwkTag::APPDFR, "ParseCpuData end time: %{public}s",
162 AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
163 }
164
ReadCpuDataByNum(int32_t num,std::vector<CpuFreqData> & parseDatas,TotalTime & totalTime)165 bool AppfreezeCpuFreqManager::ReadCpuDataByNum(int32_t num, std::vector<CpuFreqData>& parseDatas,
166 TotalTime& totalTime)
167 {
168 TAG_LOGD(AAFwkTag::APPDFR, "ReadCpuDataByNum start time: %{public}s",
169 AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
170 if (num > cpuCount_) {
171 TAG_LOGE(AAFwkTag::APPDFR, "Read cpu info failed, num:%{public}d, cpuCount:%{public}d",
172 num, cpuCount_);
173 return false;
174 }
175 std::string cpuFreqPath = "/sys/devices/system/cpu/cpu" + std::to_string(num) + "/power/time_in_state";
176 std::string data;
177 if (!LoadStringFromFile(cpuFreqPath, data)) {
178 TAG_LOGE(AAFwkTag::APPDFR, "Read cpu time failed, cpuFreqPath:%{public}s", cpuFreqPath.c_str());
179 return false;
180 }
181 std::istringstream iss(data);
182 std::string line;
183 while (std::getline(iss, line)) {
184 if (line.empty()) {
185 continue;
186 }
187 std::vector<std::string> tokens;
188 SplitStr(line, " ", tokens);
189 if (tokens.size() != CPU_FREQ_AND_TIME_NUM) {
190 continue;
191 }
192 CpuFreqData cpuFreqData{};
193 cpuFreqData.frequency = static_cast<uint64_t>(strtoull(tokens[TIME_IN_STATE_FIRST_INDEX].c_str(),
194 nullptr, CPU_FREQ_DECIMAL_BASE));
195 cpuFreqData.runningTime = static_cast<uint64_t>(strtoull(tokens[TIME_IN_STATE_SECOND_INDEX].c_str(),
196 nullptr, CPU_FREQ_DECIMAL_BASE));
197 totalTime.totalRunningTime += cpuFreqData.runningTime;
198 for (size_t i = 1; i < tokens.size(); ++i) {
199 totalTime.totalCpuTime += static_cast<uint64_t>(strtoull(tokens[i].c_str(), nullptr,
200 CPU_FREQ_DECIMAL_BASE));
201 }
202 parseDatas.push_back(cpuFreqData);
203 }
204 return true;
205 }
206
GetCpuStr(int code,std::vector<FrequencyPair> & freqPairs,float percentage)207 std::string AppfreezeCpuFreqManager::GetCpuStr(int code, std::vector<FrequencyPair>& freqPairs,
208 float percentage)
209 {
210 std::sort(freqPairs.begin(), freqPairs.end(),
211 [] (const auto& pairOne, const auto& pairTwo) { return pairOne.percentage > pairTwo.percentage; });
212
213 std::stringstream ss;
214 ss << "cpu" << std::to_string(code) << " Usage " << AppfreezeUtil::RoundToTwoDecimals(percentage) << "%, ";
215 bool isEnd = true;
216 for (const auto& pair : freqPairs) {
217 if (!isEnd) {
218 ss << ", ";
219 }
220 isEnd = false;
221 ss << pair.frequency << "MHZ " << AppfreezeUtil::RoundToTwoDecimals(pair.percentage) << "%";
222 }
223 ss << std::endl;
224 return ss.str();
225 }
226
GetCpuTotalValue(size_t i,std::vector<TotalTime> totalTimeList,std::vector<TotalTime> blockTotalTimeList,TotalTime & totalTime)227 bool AppfreezeCpuFreqManager::GetCpuTotalValue(size_t i, std::vector<TotalTime> totalTimeList,
228 std::vector<TotalTime> blockTotalTimeList, TotalTime& totalTime)
229 {
230 if (totalTimeList.size() <= i || totalTimeList.size() != blockTotalTimeList.size()) {
231 TAG_LOGE(AAFwkTag::APPDFR, "index:%{public}zu, halfTotal size:%{public}zu, "
232 "blockTotal size:%{public}zu.", i, totalTimeList.size(), blockTotalTimeList.size());
233 return false;
234 }
235 totalTime.totalCpuTime = totalTimeList[i].totalCpuTime > blockTotalTimeList[i].totalCpuTime ?
236 (totalTimeList[i].totalCpuTime - blockTotalTimeList[i].totalCpuTime) :
237 (blockTotalTimeList[i].totalCpuTime - totalTimeList[i].totalCpuTime);
238 if (totalTime.totalCpuTime <= 0) {
239 TAG_LOGE(AAFwkTag::APPDFR, "totalCpuTime:%{public}" PRIu64"less than zero.", totalTime.totalCpuTime);
240 return false;
241 }
242 totalTime.totalRunningTime = totalTimeList[i].totalRunningTime > blockTotalTimeList[i].totalRunningTime ?
243 (totalTimeList[i].totalRunningTime - blockTotalTimeList[i].totalRunningTime) :
244 (blockTotalTimeList[i].totalRunningTime - totalTimeList[i].totalRunningTime);
245 return true;
246 }
247
GetCpuInfoContent(const std::vector<std::vector<CpuFreqData>> & handlingHalfCpuData,const std::vector<TotalTime> & totalTimeList)248 std::string AppfreezeCpuFreqManager::GetCpuInfoContent(
249 const std::vector<std::vector<CpuFreqData>> &handlingHalfCpuData, const std::vector<TotalTime> &totalTimeList)
250 {
251 if (handlingHalfCpuData.size() == 0 || totalTimeList.size() == 0) {
252 return "";
253 }
254 std::stringstream ss;
255 ss << "start time:" << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
256 std::vector<std::vector<CpuFreqData>> blockCpuData;
257 std::vector<TotalTime> blockTotalTimeList;
258 ParseCpuData(blockCpuData, blockTotalTimeList);
259 if (handlingHalfCpuData.size() != blockCpuData.size()) {
260 TAG_LOGE(AAFwkTag::APPDFR, "Half and block have different sizes, halfData:%{public}zu, "
261 "blockData:%{public}zu", handlingHalfCpuData.size(), blockCpuData.size());
262 return "";
263 }
264 for (size_t i = 0; i < handlingHalfCpuData.size(); ++i) {
265 auto halfData = handlingHalfCpuData[i];
266 auto blockData = blockCpuData[i];
267 if (halfData.size() != blockData.size()) {
268 TAG_LOGE(AAFwkTag::APPDFR, "Half and block have different sizes, halfData:%{public}zu, "
269 "blockData:%{public}zu", halfData.size(), blockData.size());
270 return "";
271 }
272 TotalTime totalTime{};
273 if (!GetCpuTotalValue(i, totalTimeList, blockTotalTimeList, totalTime)) {
274 return "";
275 }
276 float percentage = (static_cast<float>(totalTime.totalRunningTime) /
277 static_cast<float>(totalTime.totalCpuTime)) * CPU_PERCENTAGE;;
278 std::vector<FrequencyPair> freqPairs;
279 for (size_t j = 0; j < halfData.size(); ++j) {
280 FrequencyPair pair{};
281 uint64_t runningTime = halfData[j].runningTime > blockData[j].runningTime ?
282 (halfData[j].runningTime - blockData[j].runningTime) :
283 (blockData[j].runningTime - halfData[j].runningTime);
284 pair.percentage = (static_cast<float>(runningTime) /
285 static_cast<float>(totalTime.totalCpuTime)) * CPU_PERCENTAGE;
286 if (pair.percentage < 1 || halfData[j].frequency != blockData[j].frequency) {
287 continue;
288 }
289 pair.frequency = halfData[j].frequency / HZ_TO_MHZ;
290 freqPairs.push_back(pair);
291 }
292 ss << GetCpuStr(i, freqPairs, percentage);
293 }
294 ss << "end time:" << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
295 return ss.str();
296 }
297
GetAppCpuTime(int32_t pid)298 uint64_t AppfreezeCpuFreqManager::GetAppCpuTime(int32_t pid)
299 {
300 if (pid < 0) {
301 return 0;
302 }
303 uint64_t cpuTime = 0;
304 std::string filePath = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(pid) + "/stat";
305 std::string content;
306 if (!LoadStringFromFile(filePath, content)) {
307 TAG_LOGE(AAFwkTag::APPDFR, "Read cpu task stat failed, path:%{public}s", filePath.c_str());
308 return cpuTime;
309 }
310 if (!content.empty()) {
311 std::vector<std::string> tokens;
312 SplitStr(content, " ", tokens);
313 if (tokens.size() <= START_TIME_SECOND_INDEX) {
314 TAG_LOGE(AAFwkTag::APPDFR, "GetAppCpuTime failed, content size: %{public}zu.", tokens.size());
315 return cpuTime;
316 }
317 cpuTime = static_cast<uint64_t>(strtoull(tokens[START_TIME_FIRST_INDEX].c_str(),
318 nullptr, CPU_FREQ_DECIMAL_BASE));
319 cpuTime += static_cast<uint64_t>(strtoull(tokens[START_TIME_SECOND_INDEX].c_str(),
320 nullptr, CPU_FREQ_DECIMAL_BASE));
321 }
322 return cpuTime;
323 }
324
GetProcessCpuTime(int32_t pid)325 uint64_t AppfreezeCpuFreqManager::GetProcessCpuTime(int32_t pid)
326 {
327 if (pid < 0) {
328 return 0;
329 }
330 std::string statPath = "/proc/" + std::to_string(pid) + "/stat";
331 std::string content;
332 if (!LoadStringFromFile(statPath, content)) {
333 TAG_LOGE(AAFwkTag::APPDFR, "Read cpu stat failed, path:%{public}s", statPath.c_str());
334 return 0;
335 }
336 uint64_t processCpuTime = 0;
337 if (!content.empty()) {
338 std::vector<std::string> tokens;
339 SplitStr(content, " ", tokens);
340 if (tokens.size() <= START_TIME_SECOND_INDEX) {
341 TAG_LOGE(AAFwkTag::APPDFR, "GetAppCpuTime failed, content size: %{public}zu.", tokens.size());
342 return processCpuTime;
343 }
344 processCpuTime = static_cast<uint64_t>(strtoull(tokens[START_TIME_FIRST_INDEX].c_str(),
345 nullptr, CPU_FREQ_DECIMAL_BASE));
346 processCpuTime += static_cast<uint64_t>(strtoull(tokens[START_TIME_SECOND_INDEX].c_str(),
347 nullptr, CPU_FREQ_DECIMAL_BASE));
348 }
349 return processCpuTime;
350 }
351
GetDeviceRuntime()352 uint64_t AppfreezeCpuFreqManager::GetDeviceRuntime()
353 {
354 std::string statPath = AppfreezeUtil::PROC_STAT_PATH;
355 std::string content;
356 if (!LoadStringFromFile(statPath, content)) {
357 TAG_LOGE(AAFwkTag::APPDFR, "Read device run time failed, path:%{public}s", statPath.c_str());
358 return 0;
359 }
360 uint64_t deviceRuntime = 0;
361 std::string line;
362 std::istringstream iss(content);
363 if (std::getline(iss, line) && !line.empty()) {
364 std::vector<std::string> strings;
365 SplitStr(line, " ", strings);
366 if (strings.size() <= DEFAULT_CPU_SIZE) {
367 TAG_LOGE(AAFwkTag::APPDFR, "GetDeviceRuntime failed, string size: %{public}zu.", strings.size());
368 return deviceRuntime;
369 }
370 for (size_t i = 1; i < strings.size(); ++i) {
371 deviceRuntime += static_cast<uint64_t>(strtoull(strings[i].c_str(), nullptr,
372 CPU_FREQ_DECIMAL_BASE));
373 }
374 }
375 return deviceRuntime;
376 }
377
GetOptimalCpuTime(int32_t pid)378 double AppfreezeCpuFreqManager::GetOptimalCpuTime(int32_t pid)
379 {
380 int maxCpuCount = cpuCount_ - AppfreezeUtil::CPU_COUNT_SUBTRACT;
381 if (maxCpuCount <= 0) {
382 TAG_LOGE(AAFwkTag::APPDFR, "GetOptimalCpuTime failed, maxCpuCount:%{public}d", maxCpuCount);
383 return -1;
384 }
385 std::string statPath = "/sys/devices/system/cpu/cpu" + std::to_string(maxCpuCount) + "/cpu_capacity";
386 std::string content;
387 int ret = -1;
388 if (!LoadStringFromFile(statPath, content)) {
389 TAG_LOGE(AAFwkTag::APPDFR, "GetOptimalCpuTime failed, path:%{public}s, errno:%{public}d",
390 statPath.c_str(), errno);
391 return ret;
392 }
393 if (content.empty()) {
394 TAG_LOGE(AAFwkTag::APPDFR, "Read info failed, path:%{public}s", statPath.c_str());
395 return ret;
396 }
397 int32_t dmips = static_cast<int32_t>(strtoull(content.c_str(), nullptr, CPU_FREQ_DECIMAL_BASE));
398 void* threadFuncHandler = dlopen(LIB_THREAD_CPU_LOAD_PATH, RTLD_LAZY);
399 if (threadFuncHandler == nullptr) {
400 TAG_LOGE(AAFwkTag::APPDFR, "dlopen failed, funcHandler is nullptr.");
401 return ret;
402 }
403 dlerror();
404 char* err = nullptr;
405 auto getThreadCpuload = reinterpret_cast<GetThreadCpuload>(dlsym(threadFuncHandler, "GetThreadCpuload"));
406 err = dlerror();
407 if (err != nullptr) {
408 TAG_LOGE(AAFwkTag::APPDFR, "dlsym GetThreadCpuload func failed. %{public}s", err);
409 return ret;
410 }
411 double optimalCpuTime = getThreadCpuload(pid);
412 threadFuncHandler = nullptr;
413 getThreadCpuload = nullptr;
414 dlclose(threadFuncHandler);
415 if (dmips <= 0 || optimalCpuTime < 0) {
416 return ret;
417 }
418 TAG_LOGW(AAFwkTag::APPDFR, "dmips %{public}d optimalCpuTime %{public}lf", dmips, optimalCpuTime);
419 return optimalCpuTime / dmips;
420 }
421
GetStartTime(uint64_t start)422 std::string AppfreezeCpuFreqManager::GetStartTime(uint64_t start)
423 {
424 const uint32_t placeholder = 3;
425 uint64_t startTime = start / AppfreezeUtil::SEC_TO_MILLISEC;
426 std::ostringstream startTimeStr;
427 startTimeStr << AppfreezeUtil::TimestampFormatToDate(startTime, "%Y-%m-%d %H:%M:%S");
428 startTimeStr << ":" << std::setw(placeholder) << std::setfill('0') <<
429 std::to_string(start % AppfreezeUtil::SEC_TO_MILLISEC);
430 return startTimeStr.str();
431 }
432
GetStaticInfoHead()433 std::string AppfreezeCpuFreqManager::GetStaticInfoHead()
434 {
435 std::ostringstream staticInfoStr;
436 staticInfoStr << "#Basic Concepts" << std::endl;
437 staticInfoStr << "T1: StaticsDuration, EndTime - StartTime." << std::endl;
438 staticInfoStr << "T2: CpuTime --Time that spend on CPU." << std::endl;
439 staticInfoStr << "T3: SyncWaitTime --SleepingTime + Runnable Time, etc." << std::endl;
440 staticInfoStr << "T4: OptimalCpuTime --run the thread at the max Core's max cpu capacity." << std::endl;
441 staticInfoStr << "T5: SupplyAvailableTime --T2 - T3. Time can be optimized by scheduling." << std::endl;
442 staticInfoStr << "Equation: T1 = T2 + T3. T2 = T4 = T5." << std::endl;
443 staticInfoStr <<
444 "|-----------------------------------StaticsDuration-----------------------------------|." << std::endl;
445 staticInfoStr <<
446 "|-------------------------CpuTime----------------------|--------SyncWaitTime----------|." << std::endl;
447 staticInfoStr <<
448 "|----OptimalCpuTime----|------SupplyAvailableTime------|--------SyncWaitTime----------|." << std::endl;
449 return staticInfoStr.str();
450 }
451
GetStaticInfo(int32_t pid,CpuStartTime cpuStartTime)452 std::string AppfreezeCpuFreqManager::GetStaticInfo(int32_t pid, CpuStartTime cpuStartTime)
453 {
454 std::ostringstream staticInfoStr;
455 staticInfoStr << GetStaticInfoHead() << std::endl;
456 staticInfoStr << "#Basic Statistical Infomation " << std::endl;
457 staticInfoStr << "ProcessCpuTime: " << GetProcessCpuTime(pid) << " ms" << std::endl;
458 staticInfoStr << "DeviceRuntime: " << GetDeviceRuntime() << " ms" << std::endl;
459 staticInfoStr << "Tid: " << pid << std::endl;
460 staticInfoStr << "StartTime: " << GetStartTime(cpuStartTime.halfStartTime) << std::endl;
461 staticInfoStr << "EndTime: " << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
462 uint64_t duration = AppfreezeUtil::GetMilliseconds() - cpuStartTime.halfStartTime;
463 staticInfoStr << "StaticsDuration: " << duration << " ms" << std::endl;
464 uint64_t cpuTime = GetAppCpuTime(pid);
465 uint64_t syncWaitTime = duration - cpuTime;
466 uint64_t optimalCpuTime = GetOptimalCpuTime(pid) - cpuStartTime.optimalCpuStartTime;
467 uint64_t supplyAvailableTime = duration - optimalCpuTime - syncWaitTime;
468 staticInfoStr << "CpuTime: " << cpuTime << " ms" << std::endl;
469 staticInfoStr << "SyncWaitTime: " << syncWaitTime << " ms" << std::endl;
470 staticInfoStr << "OptimalCpuTime: " << optimalCpuTime << " ms" << std::endl;
471 staticInfoStr << "SupplyAvailableTime: " << supplyAvailableTime << " ms" << std::endl;
472 return staticInfoStr.str();
473 }
474
WriteDfxLogToFile(const std::string & filePath,const std::string & bundleName)475 void AppfreezeCpuFreqManager::WriteDfxLogToFile(const std::string &filePath, const std::string &bundleName)
476 {
477 std::stringstream ss;
478 ss << LOG_FILE_HEAD << std::endl;
479 ss << LOG_FILE_SEP << std::endl;
480 ss << "TimeStamp: " << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
481 ss << "Module name: " << bundleName << std::endl;
482 OHOS::SaveStringToFile(filePath, ss.str());
483 }
484
IsContainHalfData(const std::string & key,CpuDataProcessor & cpuData,int32_t pid)485 bool AppfreezeCpuFreqManager::IsContainHalfData(const std::string &key, CpuDataProcessor &cpuData, int32_t pid)
486 {
487 std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
488 auto it = cpuInfoMap_.find(key);
489 if (it == cpuInfoMap_.end()) {
490 TAG_LOGI(AAFwkTag::APPDFR, "Not find warning fault, pid: %{public}d", pid);
491 return false;
492 }
493 int warningPid = it->second.GetPid();
494 if (warningPid != pid) {
495 TAG_LOGI(AAFwkTag::APPDFR, "Not find current pid:%{public}d, warning pid:%{public}d", pid, warningPid);
496 return false;
497 }
498 auto diff = AppfreezeUtil::GetMilliseconds() - it->second.GetCpuStartTime().halfStartTime;
499 if (diff > TIME_LIMIT) {
500 it = cpuInfoMap_.erase(it);
501 TAG_LOGI(AAFwkTag::APPDFR, "The last fault occurred more than 6 seconds ago, "
502 "diff: %{public}" PRIu64", pid: %{public}d.", diff, pid);
503 return false;
504 }
505 cpuData = it->second;
506 return true;
507 }
508
WriteCpuInfoToFile(const std::string & eventType,const std::string & bundleName,int32_t uid,int32_t pid,const std::string & eventName)509 std::string AppfreezeCpuFreqManager::WriteCpuInfoToFile(const std::string &eventType,
510 const std::string &bundleName, int32_t uid, int32_t pid, const std::string &eventName)
511 {
512 std::string key = eventType + std::to_string(uid);
513 CpuDataProcessor cpuData;
514 if (!IsContainHalfData(key, cpuData, pid)) {
515 return "";
516 }
517
518 std::string cpuInfo = GetCpuInfoContent(cpuData.GetHandlingHalfCpuData(), cpuData.GetTotalTimeList());
519 if (cpuInfo.empty()) {
520 return "";
521 }
522 std::string fileName = CPU_INFO_PREFIX + std::to_string(uid) +
523 AbilityRuntime::TimeUtil::FormatTime("%Y%m%d%H%M%S");
524 std::string filePath = AppfreezeUtil::CreateFile(AppfreezeUtil::EVENTLOG_PATH, fileName);
525 WriteDfxLogToFile(filePath, bundleName);
526
527 std::ostringstream str;
528 str << std::endl << GetStaticInfo(pid, cpuData.GetCpuStartTime());
529 str << std::endl << "#CpuFreq Usage (usage >=1%)" << std::endl << cpuInfo << std::endl;
530 std::string path = filePath + "," + cpuData.GetStackPath();
531 OHOS::SaveStringToFile(filePath, str.str(), false);
532 {
533 std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
534 cpuInfoMap_.erase(key);
535 }
536 TAG_LOGW(AAFwkTag::APPDFR, "Write CpuInfo to file: %{public}s", path.c_str());
537 return path;
538 }
539 } // namespace AppExecFwk
540 } // namespace OHOS
541