• 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 "core/common/ace_application_info.h"
24 #include "render_service_client/core/transaction/rs_interfaces.h"
25 
26 namespace OHOS::Ace {
27 using namespace std;
28 PerfMonitor* PerfMonitor::pMonitor = nullptr;
29 constexpr int64_t SCENE_TIMEOUT = 10000000000;
30 constexpr float SINGLE_FRAME_TIME = 16600000;
31 
GetCurrentRealTimeNs()32 static int64_t GetCurrentRealTimeNs()
33 {
34     struct timespec ts = { 0, 0 };
35     if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
36         return 0;
37     }
38     return (ts.tv_sec * NS_TO_S + ts.tv_nsec);
39 }
40 
GetCurrentSystimeMs()41 static int64_t GetCurrentSystimeMs()
42 {
43     auto timeNow = std::chrono::system_clock::now();
44     auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(timeNow.time_since_epoch());
45     int64_t curSystime = tmp.count();
46     return curSystime;
47 }
48 
ConvertRealtimeToSystime(int64_t realTime,int64_t & sysTime)49 void ConvertRealtimeToSystime(int64_t realTime, int64_t& sysTime)
50 {
51     int64_t curRealTime = GetCurrentRealTimeNs();
52     if (curRealTime == 0) {
53         sysTime = 0;
54         return;
55     }
56     int64_t curSysTime = GetCurrentSystimeMs();
57     sysTime = curSysTime - (curRealTime - realTime) / NS_TO_MS;
58 }
59 
GetSourceTypeName(PerfSourceType sourceType)60 std::string GetSourceTypeName(PerfSourceType sourceType)
61 {
62     std::string type = "";
63     switch (sourceType) {
64         case PERF_TOUCH_EVENT:
65             type = "TOUCHSCREEN";
66             break;
67         case PERF_MOUSE_EVENT:
68             type = "MOUSE";
69             break;
70         case PERF_TOUCH_PAD:
71             type = "TOUCHPAD";
72             break;
73         case PERF_JOY_STICK:
74             type = "JOYSTICK";
75             break;
76         case PERF_KEY_EVENT:
77             type = "KEY_EVENT";
78             break;
79         default :
80             type = "UNKNOWN_SOURCE";
81             break;
82     }
83     return type;
84 }
85 
ConvertToRsData(OHOS::Rosen::DataBaseRs & dataRs,DataBase & data)86 void ConvertToRsData(OHOS::Rosen::DataBaseRs &dataRs, DataBase& data)
87 {
88     dataRs.eventType = static_cast<int32_t>(data.eventType);
89     dataRs.sceneId = data.sceneId;
90     dataRs.appPid = data.baseInfo.pid;
91     dataRs.uniqueId = data.inputTime / NS_TO_MS;
92     dataRs.inputTime = data.inputTime;
93     dataRs.beginVsyncTime = data.beginVsyncTime;
94     dataRs.endVsyncTime = data.endVsyncTime;
95     dataRs.versionCode = data.baseInfo.versionCode;
96     dataRs.versionName = data.baseInfo.versionName;
97     dataRs.bundleName = data.baseInfo.bundleName;
98     dataRs.processName = data.baseInfo.processName;
99     dataRs.abilityName = data.baseInfo.abilityName;
100     dataRs.pageUrl = data.baseInfo.pageUrl;
101     dataRs.sourceType = GetSourceTypeName(data.sourceType);
102     dataRs.note = data.baseInfo.note;
103 }
104 
ReportPerfEventToRS(DataBase & data)105 void ReportPerfEventToRS(DataBase& data)
106 {
107     OHOS::Rosen::DataBaseRs dataRs;
108     ConvertToRsData(dataRs, data);
109     switch (dataRs.eventType) {
110         case EVENT_RESPONSE:
111             Rosen::RSInterfaces::GetInstance().ReportEventResponse(dataRs);
112             break;
113         case EVENT_COMPLETE:
114             if (data.needReportToRS) {
115                 Rosen::RSInterfaces::GetInstance().ReportEventComplete(dataRs);
116             }
117             break;
118         case EVENT_JANK_FRAME:
119             Rosen::RSInterfaces::GetInstance().ReportEventJankFrame(dataRs);
120             break;
121         default :
122             break;
123     }
124 }
125 
ReportPerfEventToUI(DataBase data)126 void ReportPerfEventToUI(DataBase data)
127 {
128     switch (data.eventType) {
129         case EVENT_COMPLETE:
130             if (!data.needReportToRS) {
131                 EventReport::ReportEventComplete(data);
132             }
133             break;
134         case EVENT_JANK_FRAME:
135             if (data.totalMissed > 0) {
136                 EventReport::ReportEventJankFrame(data);
137             }
138             break;
139         default :
140             break;
141     }
142 }
143 
InitRecord(const std::string & sId,PerfActionType aType,PerfSourceType sType,const std::string & nt)144 void SceneRecord::InitRecord(const std::string& sId, PerfActionType aType, PerfSourceType sType, const std::string& nt)
145 {
146     sceneId = sId;
147     actionType = aType;
148     sourceType = sType;
149     note = nt;
150     beginVsyncTime = GetCurrentRealTimeNs();
151 }
152 
IsTimeOut(int64_t nowTime)153 bool SceneRecord::IsTimeOut(int64_t nowTime)
154 {
155     if (nowTime - beginVsyncTime > SCENE_TIMEOUT) {
156         return true;
157     }
158     return false;
159 }
160 
RecordFrame(int64_t vsyncTime,int64_t duration,int32_t skippedFrames)161 void SceneRecord::RecordFrame(int64_t vsyncTime, int64_t duration, int32_t skippedFrames)
162 {
163     if (totalFrames == 0) {
164         beginVsyncTime = GetCurrentRealTimeNs();
165         isFirstFrame = true;
166     } else {
167         isFirstFrame = false;
168     }
169     skippedFrames = static_cast<int32_t>(duration / SINGLE_FRAME_TIME);
170     if (!isFirstFrame && skippedFrames >= 1) {
171         if (duration > maxFrameTime) {
172             maxFrameTime = duration;
173         }
174         if (isSuccessive) {
175             seqMissFrames = seqMissFrames + skippedFrames;
176         } else {
177             seqMissFrames = skippedFrames;
178             isSuccessive = true;
179         }
180         if (maxSuccessiveFrames < seqMissFrames) {
181             maxSuccessiveFrames = seqMissFrames;
182         }
183         totalMissed += skippedFrames;
184     } else {
185         isSuccessive = false;
186         seqMissFrames = 0;
187     }
188     totalFrames++;
189 }
190 
Report(const std::string & sceneId,int64_t vsyncTime)191 void SceneRecord::Report(const std::string& sceneId, int64_t vsyncTime)
192 {
193     if (vsyncTime <= beginVsyncTime) {
194         endVsyncTime = GetCurrentRealTimeNs();
195     } else {
196         endVsyncTime = vsyncTime;
197     }
198 }
199 
IsFirstFrame()200 bool SceneRecord::IsFirstFrame()
201 {
202     return isFirstFrame;
203 }
204 
Reset()205 void SceneRecord::Reset()
206 {
207     beginVsyncTime = 0;
208     endVsyncTime = 0;
209     maxFrameTime = 0;
210     maxSuccessiveFrames = 0;
211     seqMissFrames = 0;
212     totalMissed = 0;
213     totalFrames = 0;
214     isSuccessive = false;
215     isFirstFrame = false;
216     sceneId = "";
217     actionType = UNKNOWN_ACTION;
218     sourceType = UNKNOWN_SOURCE;
219     note = "";
220 }
221 
GetPerfMonitor()222 PerfMonitor* PerfMonitor::GetPerfMonitor()
223 {
224     if (pMonitor == nullptr) {
225         pMonitor = new PerfMonitor();
226     }
227     return pMonitor;
228 }
229 
Start(const std::string & sceneId,PerfActionType type,const std::string & note)230 void PerfMonitor::Start(const std::string& sceneId, PerfActionType type, const std::string& note)
231 {
232     AceAsyncTraceBegin(0, sceneId.c_str());
233     std::lock_guard<std::mutex> Lock(mMutex);
234     SceneRecord* record = GetRecord(sceneId);
235     if (record != nullptr) {
236         record->Reset();
237         record->InitRecord(sceneId, type, mSourceType, note);
238     } else {
239         record = new SceneRecord();
240         record->InitRecord(sceneId, type, mSourceType, note);
241         mRecords.insert(std::pair<std::string, SceneRecord*> (sceneId, record));
242     }
243     RecordBaseInfo(record);
244 }
245 
End(const std::string & sceneId,bool isJsApi)246 void PerfMonitor::End(const std::string& sceneId, bool isJsApi)
247 {
248     std::lock_guard<std::mutex> Lock(mMutex);
249     SceneRecord* record = GetRecord(sceneId);
250     if (record != nullptr) {
251         RecordBaseInfo(record);
252         record->Report(sceneId, mVsyncTime);
253         ReportAnimateEnd(sceneId, record, !isJsApi);
254         RemoveRecord(sceneId);
255         AceAsyncTraceEnd(0, sceneId.c_str());
256     }
257 }
258 
RecordInputEvent(PerfActionType type,PerfSourceType sourceType,int64_t time)259 void PerfMonitor::RecordInputEvent(PerfActionType type, PerfSourceType sourceType, int64_t time)
260 {
261     mSourceType = sourceType;
262     if (time <= 0) {
263         time = GetCurrentRealTimeNs();
264     }
265     switch (type) {
266         case LAST_DOWN:
267             mInputTime[LAST_DOWN] = time;
268             break;
269         case LAST_UP:
270             mInputTime[LAST_UP] = time;
271             break;
272         case FIRST_MOVE:
273             mInputTime[FIRST_MOVE] = time;
274             break;
275         default:
276             break;
277     }
278 }
279 
SetFrameTime(int64_t vsyncTime,int64_t duration,double jank)280 void PerfMonitor::SetFrameTime(int64_t vsyncTime, int64_t duration, double jank)
281 {
282     std::lock_guard<std::mutex> Lock(mMutex);
283     mVsyncTime = vsyncTime;
284     int32_t skippedFrames = static_cast<int32_t> (jank);
285     for (auto it = mRecords.begin(); it != mRecords.end();) {
286         if (it->second != nullptr) {
287             (it->second)->RecordFrame(vsyncTime, duration, skippedFrames);
288             if ((it->second)->IsTimeOut(vsyncTime + duration)) {
289                 delete it->second;
290                 mRecords.erase(it++);
291                 continue;
292             }
293             if ((it->second)->IsFirstFrame()) {
294                 ReportAnimateStart(it->first, it->second);
295             }
296         }
297         it++;
298     }
299 }
300 
SetPageUrl(const std::string & pageUrl)301 void PerfMonitor::SetPageUrl(const std::string& pageUrl)
302 {
303     baseInfo.pageUrl = pageUrl;
304 }
305 
GetPageUrl()306 std::string PerfMonitor::GetPageUrl()
307 {
308     return baseInfo.pageUrl;
309 }
310 
RecordBaseInfo(SceneRecord * record)311 void PerfMonitor::RecordBaseInfo(SceneRecord* record)
312 {
313     baseInfo.pid = AceApplicationInfo::GetInstance().GetPid();
314     baseInfo.bundleName = AceApplicationInfo::GetInstance().GetPackageName();
315     baseInfo.versionCode = AceApplicationInfo::GetInstance().GetAppVersionCode();
316     baseInfo.versionName = AceApplicationInfo::GetInstance().GetAppVersionName();
317     baseInfo.processName = AceApplicationInfo::GetInstance().GetProcessName();
318     baseInfo.abilityName = AceApplicationInfo::GetInstance().GetAbilityName();
319     if (record != nullptr) {
320         baseInfo.note = record->note;
321     }
322 }
323 
GetRecord(const std::string & sceneId)324 SceneRecord* PerfMonitor::GetRecord(const std::string& sceneId)
325 {
326     if (mRecords.find(sceneId) != mRecords.end()) {
327         return mRecords[sceneId];
328     }
329     return nullptr;
330 }
331 
RemoveRecord(const std::string & sceneId)332 void PerfMonitor::RemoveRecord(const std::string& sceneId)
333 {
334     std::map <std::string, SceneRecord*>::iterator iter = mRecords.find(sceneId);
335     if (iter != mRecords.end()) {
336         if (iter->second != nullptr) {
337             delete iter->second;
338         }
339         mRecords.erase(iter);
340     }
341 }
342 
GetInputTime(PerfActionType type)343 int64_t PerfMonitor::GetInputTime(PerfActionType type)
344 {
345     int64_t inputTime = 0;
346     switch (type) {
347         case LAST_DOWN:
348             inputTime = mInputTime[LAST_DOWN];
349             break;
350         case LAST_UP:
351             inputTime = mInputTime[LAST_UP];
352             break;
353         case FIRST_MOVE:
354             inputTime = mInputTime[FIRST_MOVE];
355             break;
356         default:
357             inputTime = GetCurrentRealTimeNs();
358             break;
359     }
360     return inputTime;
361 }
362 
ReportAnimateStart(const std::string & sceneId,SceneRecord * record)363 void PerfMonitor::ReportAnimateStart(const std::string& sceneId, SceneRecord* record)
364 {
365     if (record == nullptr) {
366         return;
367     }
368     DataBase data;
369     FlushDataBase(record, data, true);
370     ReportPerfEvent(EVENT_RESPONSE, data);
371 }
372 
ReportAnimateEnd(const std::string & sceneId,SceneRecord * record,bool needCompleteTime)373 void PerfMonitor::ReportAnimateEnd(const std::string& sceneId, SceneRecord* record, bool needCompleteTime)
374 {
375     if (record == nullptr) {
376         return;
377     }
378     DataBase data;
379     FlushDataBase(record, data, needCompleteTime);
380     ReportPerfEvent(EVENT_JANK_FRAME, data);
381     ReportPerfEvent(EVENT_COMPLETE, data);
382 }
383 
FlushDataBase(SceneRecord * record,DataBase & data,bool needCompleteTime)384 void PerfMonitor::FlushDataBase(SceneRecord* record, DataBase& data, bool needCompleteTime)
385 {
386     if (record == nullptr) {
387         return;
388     }
389     data.sceneId = record->sceneId;
390     data.inputTime = GetInputTime(record->actionType);
391     data.beginVsyncTime = record->beginVsyncTime;
392     if (data.beginVsyncTime < data.inputTime) {
393         data.beginVsyncTime = data.inputTime;
394     }
395     data.endVsyncTime = record->endVsyncTime;
396     if (data.beginVsyncTime > data.endVsyncTime) {
397         data.endVsyncTime = data.beginVsyncTime;
398     }
399     data.maxFrameTime = record->maxFrameTime;
400     data.maxSuccessiveFrames = record->maxSuccessiveFrames;
401     data.totalMissed = record->totalMissed;
402     data.totalFrames = record->totalFrames;
403     data.needReportToRS = needCompleteTime;
404     data.sourceType = record->sourceType;
405     data.actionType = record->actionType;
406     data.baseInfo = baseInfo;
407 }
408 
ReportPerfEvent(PerfEventType type,DataBase & data)409 void PerfMonitor::ReportPerfEvent(PerfEventType type, DataBase& data)
410 {
411     switch (type) {
412         case EVENT_RESPONSE:
413             data.eventType = EVENT_RESPONSE;
414             break;
415         case EVENT_COMPLETE:
416             data.eventType = EVENT_COMPLETE;
417             break;
418         case EVENT_JANK_FRAME:
419             data.eventType = EVENT_JANK_FRAME;
420             break;
421         default :
422             break;
423     }
424     ReportPerfEventToRS(data);
425     ReportPerfEventToUI(data);
426 }
427 } // namespace OHOS::Ace
428