• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 <sys/time.h>
16 
17 #include "base/perfmonitor/perf_monitor.h"
18 
19 #include "base/log/ace_trace.h"
20 #include "base/log/event_report.h"
21 #include "base/log/jank_frame_report.h"
22 #include "base/log/log.h"
23 #include "base/perfmonitor/perf_constants.h"
24 #include "base/utils/system_properties.h"
25 #include "core/common/ace_application_info.h"
26 #include "render_service_client/core/transaction/rs_interfaces.h"
27 
28 namespace OHOS::Ace {
29 using namespace std;
30 PerfMonitor* PerfMonitor::pMonitor = nullptr;
31 constexpr int64_t SCENE_TIMEOUT = 10000000000;
32 constexpr int64_t RESPONSE_TIMEOUT = 60000000;
33 constexpr int64_t STARTAPP_FRAME_TIMEOUT = 100000000;
34 constexpr float SINGLE_FRAME_TIME = 16600000;
35 const int32_t JANK_SKIPPED_THRESHOLD = SystemProperties::GetJankFrameThreshold();
36 const int32_t DEFAULT_JANK_REPORT_THRESHOLD = 3;
37 
GetCurrentRealTimeNs()38 static int64_t GetCurrentRealTimeNs()
39 {
40     struct timespec ts = { 0, 0 };
41     if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
42         return 0;
43     }
44     return (ts.tv_sec * NS_TO_S + ts.tv_nsec);
45 }
46 
GetCurrentSystimeMs()47 static int64_t GetCurrentSystimeMs()
48 {
49     auto timeNow = std::chrono::system_clock::now();
50     auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(timeNow.time_since_epoch());
51     int64_t curSystime = tmp.count();
52     return curSystime;
53 }
54 
ConvertRealtimeToSystime(int64_t realTime,int64_t & sysTime)55 void ConvertRealtimeToSystime(int64_t realTime, int64_t& sysTime)
56 {
57     int64_t curRealTime = GetCurrentRealTimeNs();
58     if (curRealTime == 0) {
59         sysTime = 0;
60         return;
61     }
62     int64_t curSysTime = GetCurrentSystimeMs();
63     sysTime = curSysTime - (curRealTime - realTime) / NS_TO_MS;
64 }
65 
GetSourceTypeName(PerfSourceType sourceType)66 std::string GetSourceTypeName(PerfSourceType sourceType)
67 {
68     std::string type = "";
69     switch (sourceType) {
70         case PERF_TOUCH_EVENT:
71             type = "TOUCHSCREEN";
72             break;
73         case PERF_MOUSE_EVENT:
74             type = "MOUSE";
75             break;
76         case PERF_TOUCH_PAD:
77             type = "TOUCHPAD";
78             break;
79         case PERF_JOY_STICK:
80             type = "JOYSTICK";
81             break;
82         case PERF_KEY_EVENT:
83             type = "KEY_EVENT";
84             break;
85         default :
86             type = "UNKNOWN_SOURCE";
87             break;
88     }
89     return type;
90 }
91 
ConvertToRsData(OHOS::Rosen::DataBaseRs & dataRs,DataBase & data)92 void ConvertToRsData(OHOS::Rosen::DataBaseRs &dataRs, DataBase& data)
93 {
94     dataRs.eventType = static_cast<int32_t>(data.eventType);
95     dataRs.sceneId = data.sceneId;
96     dataRs.appPid = data.baseInfo.pid;
97     dataRs.uniqueId = data.beginVsyncTime / NS_TO_MS;
98     dataRs.inputTime = data.inputTime;
99     dataRs.beginVsyncTime = data.beginVsyncTime;
100     dataRs.endVsyncTime = data.endVsyncTime;
101     dataRs.versionCode = data.baseInfo.versionCode;
102     dataRs.versionName = data.baseInfo.versionName;
103     dataRs.bundleName = data.baseInfo.bundleName;
104     dataRs.processName = data.baseInfo.processName;
105     dataRs.abilityName = data.baseInfo.abilityName;
106     dataRs.pageUrl = data.baseInfo.pageUrl;
107     dataRs.sourceType = GetSourceTypeName(data.sourceType);
108     dataRs.note = data.baseInfo.note;
109     dataRs.isDisplayAnimator = data.isDisplayAnimator;
110 }
111 
ReportPerfEventToRS(DataBase & data)112 void ReportPerfEventToRS(DataBase& data)
113 {
114     OHOS::Rosen::DataBaseRs dataRs;
115     ConvertToRsData(dataRs, data);
116     switch (dataRs.eventType) {
117         case EVENT_RESPONSE:
118             {
119                 ACE_SCOPED_TRACE("EVENT_REPORT_RESPONSE_RS sceneId = %s, uniqueId = %lld",
120                     dataRs.sceneId.c_str(), static_cast<long long> (dataRs.uniqueId));
121                 Rosen::RSInterfaces::GetInstance().ReportEventResponse(dataRs);
122                 break;
123             }
124         case EVENT_COMPLETE:
125             {
126                 if (data.isDisplayAnimator) {
127                     ACE_SCOPED_TRACE("EVENT_REPORT_COMPLETE_RS sceneId = %s, uniqueId = %lld",
128                         dataRs.sceneId.c_str(), static_cast<long long> (dataRs.uniqueId));
129                     Rosen::RSInterfaces::GetInstance().ReportEventComplete(dataRs);
130                 }
131                 break;
132             }
133         case EVENT_JANK_FRAME:
134             {
135                 ACE_SCOPED_TRACE("EVENT_REPORT_JANK_RS sceneId = %s, uniqueId = %lld",
136                     dataRs.sceneId.c_str(), static_cast<long long> (dataRs.uniqueId));
137                 Rosen::RSInterfaces::GetInstance().ReportEventJankFrame(dataRs);
138                 break;
139             }
140         default :
141             break;
142     }
143 }
144 
ReportPerfEventToUI(DataBase data)145 void ReportPerfEventToUI(DataBase data)
146 {
147     switch (data.eventType) {
148         case EVENT_COMPLETE:
149             if (!data.needReportRs) {
150                 EventReport::ReportEventComplete(data);
151             }
152             break;
153         case EVENT_JANK_FRAME:
154             if (data.totalFrames > 0) {
155                 EventReport::ReportEventJankFrame(data);
156             }
157             break;
158         default :
159             break;
160     }
161 }
162 
InitRecord(const std::string & sId,PerfActionType aType,PerfSourceType sType,const std::string & nt,int64_t time)163 void SceneRecord::InitRecord(const std::string& sId, PerfActionType aType, PerfSourceType sType, const std::string& nt,
164     int64_t time)
165 {
166     sceneId = sId;
167     actionType = aType;
168     sourceType = sType;
169     note = nt;
170     inputTime = time;
171     beginVsyncTime = GetCurrentRealTimeNs();
172     isDisplayAnimator = IsDisplayAnimator(sceneId);
173 }
174 
IsTimeOut(int64_t nowTime)175 bool SceneRecord::IsTimeOut(int64_t nowTime)
176 {
177     if (nowTime - beginVsyncTime > SCENE_TIMEOUT) {
178         return true;
179     }
180     return false;
181 }
182 
RecordFrame(int64_t vsyncTime,int64_t duration,int32_t skippedFrames)183 void SceneRecord::RecordFrame(int64_t vsyncTime, int64_t duration, int32_t skippedFrames)
184 {
185     if (totalFrames == 0) {
186         beginVsyncTime = GetCurrentRealTimeNs();
187         isFirstFrame = true;
188     } else {
189         isFirstFrame = false;
190     }
191     skippedFrames = static_cast<int32_t>(duration / SINGLE_FRAME_TIME);
192     if (!isFirstFrame && skippedFrames >= 1) {
193         if (isSuccessive) {
194             seqMissFrames = seqMissFrames + skippedFrames;
195         } else {
196             seqMissFrames = skippedFrames;
197             isSuccessive = true;
198         }
199         if (maxSuccessiveFrames < seqMissFrames) {
200             maxSuccessiveFrames = seqMissFrames;
201         }
202         totalMissed += skippedFrames;
203     } else {
204         isSuccessive = false;
205         seqMissFrames = 0;
206     }
207     if (!isFirstFrame && duration > maxFrameTime) {
208         maxFrameTime = duration;
209     }
210     totalFrames++;
211 }
212 
Report(const std::string & sceneId,int64_t vsyncTime,bool isRsRender)213 void SceneRecord::Report(const std::string& sceneId, int64_t vsyncTime, bool isRsRender)
214 {
215     if (isRsRender || vsyncTime <= beginVsyncTime) {
216         endVsyncTime = GetCurrentRealTimeNs();
217     } else {
218         endVsyncTime = vsyncTime;
219     }
220     needReportRs = !isRsRender;
221 }
222 
IsFirstFrame()223 bool SceneRecord::IsFirstFrame()
224 {
225     return isFirstFrame;
226 }
227 
IsDisplayAnimator(const std::string & sceneId)228 bool SceneRecord::IsDisplayAnimator(const std::string& sceneId)
229 {
230     if (sceneId == PerfConstants::APP_LIST_FLING || sceneId == PerfConstants::APP_SWIPER_SCROLL
231         || sceneId == PerfConstants::SNAP_RECENT_ANI) {
232         return true;
233     }
234     return false;
235 }
236 
Reset()237 void SceneRecord::Reset()
238 {
239     beginVsyncTime = 0;
240     endVsyncTime = 0;
241     maxFrameTime = 0;
242     maxSuccessiveFrames = 0;
243     seqMissFrames = 0;
244     totalMissed = 0;
245     totalFrames = 0;
246     isSuccessive = false;
247     isFirstFrame = false;
248     sceneId = "";
249     actionType = UNKNOWN_ACTION;
250     sourceType = UNKNOWN_SOURCE;
251     note = "";
252 }
253 
GetPerfMonitor()254 PerfMonitor* PerfMonitor::GetPerfMonitor()
255 {
256     if (pMonitor == nullptr) {
257         pMonitor = new PerfMonitor();
258     }
259     return pMonitor;
260 }
261 
Start(const std::string & sceneId,PerfActionType type,const std::string & note)262 void PerfMonitor::Start(const std::string& sceneId, PerfActionType type, const std::string& note)
263 {
264     std::lock_guard<std::mutex> Lock(mMutex);
265     int64_t inputTime = GetInputTime(sceneId, type, note);
266     SceneRecord* record = GetRecord(sceneId);
267     if (record == nullptr) {
268         record = new SceneRecord();
269         record->InitRecord(sceneId, type, mSourceType, note, inputTime);
270         mRecords.insert(std::pair<std::string, SceneRecord*> (sceneId, record));
271         RecordBaseInfo(record);
272         AceAsyncTraceBegin(0, sceneId.c_str());
273     }
274 }
275 
End(const std::string & sceneId,bool isRsRender)276 void PerfMonitor::End(const std::string& sceneId, bool isRsRender)
277 {
278     std::lock_guard<std::mutex> Lock(mMutex);
279     SceneRecord* record = GetRecord(sceneId);
280     if (record != nullptr) {
281         RecordBaseInfo(record);
282         record->Report(sceneId, mVsyncTime, isRsRender);
283         ReportAnimateEnd(sceneId, record);
284         RemoveRecord(sceneId);
285         AceAsyncTraceEnd(0, sceneId.c_str());
286     }
287 }
288 
RecordInputEvent(PerfActionType type,PerfSourceType sourceType,int64_t time)289 void PerfMonitor::RecordInputEvent(PerfActionType type, PerfSourceType sourceType, int64_t time)
290 {
291     mSourceType = sourceType;
292     if (time <= 0) {
293         time = GetCurrentRealTimeNs();
294     }
295     switch (type) {
296         case LAST_DOWN:
297             {
298                 ACE_SCOPED_TRACE("RecordInputEvent: last_down=%lld(ns)", static_cast<long long>(time));
299                 mInputTime[LAST_DOWN] = time;
300                 break;
301             }
302         case LAST_UP:
303             {
304                 ACE_SCOPED_TRACE("RecordInputEvent: last_up=%lld(ns)", static_cast<long long>(time));
305                 mInputTime[LAST_UP] = time;
306                 isResponseExclusion = true;
307                 break;
308             }
309         case FIRST_MOVE:
310             {
311                 ACE_SCOPED_TRACE("RecordInputEvent: first_move=%lld(ns)", static_cast<long long>(time));
312                 mInputTime[FIRST_MOVE] = time;
313                 break;
314             }
315         default:
316             break;
317     }
318 }
319 
SetFrameTime(int64_t vsyncTime,int64_t duration,double jank,const std::string & windowName)320 void PerfMonitor::SetFrameTime(int64_t vsyncTime, int64_t duration, double jank, const std::string& windowName)
321 {
322     std::lock_guard<std::mutex> Lock(mMutex);
323     mVsyncTime = vsyncTime;
324     int32_t skippedFrames = static_cast<int32_t> (jank);
325     for (auto it = mRecords.begin(); it != mRecords.end();) {
326         if (it->second != nullptr) {
327             (it->second)->RecordFrame(vsyncTime, duration, skippedFrames);
328             if ((it->second)->IsTimeOut(vsyncTime + duration)) {
329                 delete it->second;
330                 mRecords.erase(it++);
331                 continue;
332             }
333             if ((it->second)->IsFirstFrame()) {
334                 ReportAnimateStart(it->first, it->second);
335             }
336         }
337         it++;
338     }
339     ProcessJank(jank, windowName);
340 }
341 
ReportJankFrameApp(double jank)342 void PerfMonitor::ReportJankFrameApp(double jank)
343 {
344     if (jank >= static_cast<double>(JANK_SKIPPED_THRESHOLD)) {
345         JankInfo jankInfo;
346         jankInfo.skippedFrameTime = static_cast<int64_t>(jank * SINGLE_FRAME_TIME);
347         RecordBaseInfo(nullptr);
348         jankInfo.baseInfo = baseInfo;
349         EventReport::ReportJankFrameApp(jankInfo);
350     }
351 }
352 
SetPageUrl(const std::string & pageUrl)353 void PerfMonitor::SetPageUrl(const std::string& pageUrl)
354 {
355     baseInfo.pageUrl = pageUrl;
356 }
357 
GetPageUrl()358 std::string PerfMonitor::GetPageUrl()
359 {
360     return baseInfo.pageUrl;
361 }
362 
RecordBaseInfo(SceneRecord * record)363 void PerfMonitor::RecordBaseInfo(SceneRecord* record)
364 {
365     baseInfo.pid = AceApplicationInfo::GetInstance().GetPid();
366     baseInfo.bundleName = AceApplicationInfo::GetInstance().GetPackageName();
367     baseInfo.versionCode = AceApplicationInfo::GetInstance().GetAppVersionCode();
368     baseInfo.versionName = AceApplicationInfo::GetInstance().GetAppVersionName();
369     baseInfo.processName = AceApplicationInfo::GetInstance().GetProcessName();
370     baseInfo.abilityName = AceApplicationInfo::GetInstance().GetAbilityName();
371     if (record != nullptr) {
372         baseInfo.note = record->note;
373     }
374 }
375 
GetRecord(const std::string & sceneId)376 SceneRecord* PerfMonitor::GetRecord(const std::string& sceneId)
377 {
378     if (mRecords.find(sceneId) != mRecords.end()) {
379         return mRecords[sceneId];
380     }
381     return nullptr;
382 }
383 
RemoveRecord(const std::string & sceneId)384 void PerfMonitor::RemoveRecord(const std::string& sceneId)
385 {
386     std::map <std::string, SceneRecord*>::iterator iter = mRecords.find(sceneId);
387     if (iter != mRecords.end()) {
388         if (iter->second != nullptr) {
389             delete iter->second;
390         }
391         mRecords.erase(iter);
392     }
393 }
394 
GetInputTime(const std::string & sceneId,PerfActionType type,const std::string & note)395 int64_t PerfMonitor::GetInputTime(const std::string& sceneId, PerfActionType type, const std::string& note)
396 {
397     int64_t inputTime = 0;
398     switch (type) {
399         case LAST_DOWN:
400             inputTime = mInputTime[LAST_DOWN];
401             break;
402         case LAST_UP:
403             inputTime = mInputTime[LAST_UP];
404             break;
405         case FIRST_MOVE:
406             inputTime = mInputTime[FIRST_MOVE];
407             break;
408         default:
409             break;
410     }
411     if (inputTime <= 0 || IsExceptResponseTime(inputTime, sceneId)) {
412         ACE_SCOPED_TRACE("GetInputTime: now time");
413         inputTime = GetCurrentRealTimeNs();
414     }
415     return inputTime;
416 }
417 
ReportAnimateStart(const std::string & sceneId,SceneRecord * record)418 void PerfMonitor::ReportAnimateStart(const std::string& sceneId, SceneRecord* record)
419 {
420     if (record == nullptr) {
421         return;
422     }
423     DataBase data;
424     FlushDataBase(record, data);
425     ReportPerfEvent(EVENT_RESPONSE, data);
426 }
427 
ReportAnimateEnd(const std::string & sceneId,SceneRecord * record)428 void PerfMonitor::ReportAnimateEnd(const std::string& sceneId, SceneRecord* record)
429 {
430     if (record == nullptr) {
431         return;
432     }
433     DataBase data;
434     FlushDataBase(record, data);
435     ReportPerfEvent(EVENT_JANK_FRAME, data);
436     ReportPerfEvent(EVENT_COMPLETE, data);
437 }
438 
FlushDataBase(SceneRecord * record,DataBase & data)439 void PerfMonitor::FlushDataBase(SceneRecord* record, DataBase& data)
440 {
441     if (record == nullptr) {
442         return;
443     }
444     data.sceneId = record->sceneId;
445     data.inputTime = record->inputTime;
446     data.beginVsyncTime = record->beginVsyncTime;
447     if (data.beginVsyncTime < data.inputTime) {
448         data.inputTime = data.beginVsyncTime;
449     }
450     data.endVsyncTime = record->endVsyncTime;
451     if (data.beginVsyncTime > data.endVsyncTime) {
452         data.endVsyncTime = data.beginVsyncTime;
453     }
454     data.maxFrameTime = record->maxFrameTime;
455     data.maxSuccessiveFrames = record->maxSuccessiveFrames;
456     data.totalMissed = record->totalMissed;
457     data.totalFrames = record->totalFrames;
458     data.needReportRs = record->needReportRs;
459     data.isDisplayAnimator = record->isDisplayAnimator;
460     data.sourceType = record->sourceType;
461     data.actionType = record->actionType;
462     data.baseInfo = baseInfo;
463 }
464 
ReportPerfEvent(PerfEventType type,DataBase & data)465 void PerfMonitor::ReportPerfEvent(PerfEventType type, DataBase& data)
466 {
467     switch (type) {
468         case EVENT_RESPONSE:
469             data.eventType = EVENT_RESPONSE;
470             break;
471         case EVENT_COMPLETE:
472             data.eventType = EVENT_COMPLETE;
473             break;
474         case EVENT_JANK_FRAME:
475             data.eventType = EVENT_JANK_FRAME;
476             break;
477         default :
478             break;
479     }
480     ReportPerfEventToUI(data);
481     ReportPerfEventToRS(data);
482 }
483 
IsExceptResponseTime(int64_t time,const std::string & sceneId)484 bool PerfMonitor::IsExceptResponseTime(int64_t time, const std::string& sceneId)
485 {
486     if ((sceneId == PerfConstants::ABILITY_OR_PAGE_SWITCH
487         && GetCurrentRealTimeNs() - time > RESPONSE_TIMEOUT)
488         || sceneId == PerfConstants::VOLUME_BAR_SHOW
489         || sceneId == PerfConstants::APP_TRANSITION_TO_OTHER_APP
490         || sceneId == PerfConstants::APP_TRANSITION_FROM_OTHER_APP) {
491         return true;
492     }
493     if (sceneId == PerfConstants::PC_APP_CENTER_GESTURE_OPERATION ||
494         sceneId == PerfConstants::PC_GESTURE_TO_RECENT ||
495         sceneId == PerfConstants::PC_SHORTCUT_SHOW_DESKTOP ||
496         sceneId == PerfConstants::PC_SHORTCUT_RESTORE_DESKTOP ||
497         sceneId == PerfConstants::PC_SHOW_DESKTOP_GESTURE_OPERATION ||
498         sceneId == PerfConstants::PC_ALT_TAB_TO_RECENT ||
499         sceneId == PerfConstants::PC_SHORTCUT_TO_RECENT ||
500         sceneId == PerfConstants::PC_EXIT_RECENT ||
501         sceneId == PerfConstants::PC_SHORTCUT_TO_APP_CENTER ||
502         sceneId == PerfConstants::PC_SHORTCUT_TO_APP_CENTER_ON_RECENT ||
503         sceneId == PerfConstants::PC_SHORTCUT_EXIT_APP_CENTER) {
504         return true;
505     }
506     return false;
507 }
508 
509 // for jank frame app
IsExclusionFrame()510 bool PerfMonitor::IsExclusionFrame()
511 {
512     return isResponseExclusion || isStartAppFrame || isBackgroundApp;
513 }
514 
SetAppStartStatus()515 void PerfMonitor::SetAppStartStatus()
516 {
517     isStartAppFrame = true;
518     startAppTime = GetCurrentRealTimeNs();
519 }
520 
CheckInStartAppStatus()521 void PerfMonitor::CheckInStartAppStatus()
522 {
523     if (isStartAppFrame) {
524         int64_t curTime = GetCurrentRealTimeNs();
525         if (curTime - startAppTime >= STARTAPP_FRAME_TIMEOUT) {
526             isStartAppFrame = false;
527             startAppTime = curTime;
528         }
529     }
530 }
531 
SetAppForeground(bool isShow)532 void PerfMonitor::SetAppForeground(bool isShow)
533 {
534     isBackgroundApp = !isShow;
535 }
536 
CheckExclusionWindow(const std::string & windowName)537 void PerfMonitor::CheckExclusionWindow(const std::string& windowName)
538 {
539     isExclusionWindow = false;
540     if (windowName == "softKeyboard1" ||
541         windowName == "SCBWallpaper1" ||
542         windowName == "SCBStatusBar15") {
543         isExclusionWindow = true;
544     }
545 }
546 
CheckResponseStatus()547 void PerfMonitor::CheckResponseStatus()
548 {
549     if (isResponseExclusion) {
550         isResponseExclusion = false;
551     }
552 }
553 
ProcessJank(double jank,const std::string & windowName)554 void PerfMonitor::ProcessJank(double jank, const std::string& windowName)
555 {
556     // single frame behavior report
557     CheckExclusionWindow(windowName);
558     ReportJankFrame(jank, windowName);
559     CheckInStartAppStatus();
560     CheckResponseStatus();
561 }
562 
ReportJankFrame(double jank,const std::string & windowName)563 void PerfMonitor::ReportJankFrame(double jank, const std::string& windowName)
564 {
565     if (jank >= static_cast<double>(DEFAULT_JANK_REPORT_THRESHOLD) && !IsExclusionFrame()) {
566         JankInfo jankInfo;
567         jankInfo.skippedFrameTime = static_cast<int64_t>(jank * SINGLE_FRAME_TIME);
568         jankInfo.windowName = windowName;
569         RecordBaseInfo(nullptr);
570         jankInfo.baseInfo = baseInfo;
571         EventReport::ReportJankFrameFiltered(jankInfo);
572     }
573 }
574 } // namespace OHOS::Ace
575