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