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 "animator_monitor.h"
17 #include "input_monitor.h"
18 #include "jank_frame_monitor.h"
19 #include "perf_reporter.h"
20 #include "perf_trace.h"
21 #include "perf_utils.h"
22 #include "res_sched_client.h"
23 #include "hiview_logger.h"
24 #include "white_block_monitor.h"
25
26 namespace OHOS {
27 namespace HiviewDFX {
28
29 DEFINE_LOG_LABEL(0xD002D66, "Hiview-PerfMonitor");
30
GetInstance()31 AnimatorMonitor& AnimatorMonitor::GetInstance()
32 {
33 static AnimatorMonitor instance;
34 return instance;
35 }
36
AnimatorMonitor()37 AnimatorMonitor::AnimatorMonitor()
38 {
39 RegisterAnimatorCallback(this);
40 }
41
~AnimatorMonitor()42 AnimatorMonitor::~AnimatorMonitor()
43 {
44 UnregisterAnimatorCallback(this);
45 }
46
RegisterAnimatorCallback(IAnimatorCallback * cb)47 void AnimatorMonitor::RegisterAnimatorCallback(IAnimatorCallback* cb)
48 {
49 std::lock_guard<std::mutex> Lock(mMutex);
50 if (std::find(animatorCallbacks.begin(), animatorCallbacks.end(), cb) == animatorCallbacks.end()) {
51 animatorCallbacks.push_back(cb);
52 }
53 }
54
UnregisterAnimatorCallback(IAnimatorCallback * cb)55 void AnimatorMonitor::UnregisterAnimatorCallback(IAnimatorCallback* cb)
56 {
57 std::lock_guard<std::mutex> Lock(mMutex);
58 auto it = std::find(animatorCallbacks.begin(), animatorCallbacks.end(), cb);
59 if (it != animatorCallbacks.end()) {
60 animatorCallbacks.erase(it);
61 }
62 }
63
Start(const std::string & sceneId,PerfActionType type,const std::string & note)64 void AnimatorMonitor::Start(const std::string& sceneId, PerfActionType type, const std::string& note)
65 {
66 std::lock_guard<std::mutex> Lock(mMutex);
67 for (auto* cb: animatorCallbacks) {
68 cb->OnAnimatorStart(sceneId, type, note);
69 }
70 }
71
End(const std::string & sceneId,bool isRsRender)72 void AnimatorMonitor::End(const std::string& sceneId, bool isRsRender)
73 {
74 std::lock_guard<std::mutex> Lock(mMutex);
75 for (auto* cb: animatorCallbacks) {
76 cb->OnAnimatorStop(sceneId, isRsRender);
77 }
78 }
79
OnAnimatorStart(const std::string & sceneId,PerfActionType type,const std::string & note)80 void AnimatorMonitor::OnAnimatorStart(const std::string& sceneId, PerfActionType type, const std::string& note)
81 {
82 if (!isValidSceneId(sceneId)) {
83 HIVIEW_LOGW("invalid sceneId: %{public}s", sceneId.c_str());
84 return;
85 }
86 AnimatorRecord* record = GetRecord(sceneId);
87 XPERF_TRACE_SCOPED("Animation start and current sceneId=%s", sceneId.c_str());
88 HIVIEW_LOGD("Animation start and current sceneId: %{public}s", sceneId.c_str());
89 if (record == nullptr) {
90 record = new AnimatorRecord();
91 int64_t inputTime = InputMonitor::GetInstance().GetInputTime(sceneId, type, note);
92 PerfSourceType sourceType = InputMonitor::GetInstance().GetSourceType();
93 record->InitRecord(sceneId, type, sourceType, note, inputTime);
94 mRecords.insert(std::pair<std::string, AnimatorRecord*> (sceneId, record));
95 XperfAsyncTraceBegin(0, sceneId.c_str());
96 } else {
97 HIVIEW_LOGW("Animation has already started, sceneId: %{public}s", sceneId.c_str());
98 }
99 }
100
OnAnimatorStop(const std::string & sceneId,bool isRsRender)101 void AnimatorMonitor::OnAnimatorStop(const std::string& sceneId, bool isRsRender)
102 {
103 AnimatorRecord* record = GetRecord(sceneId);
104 XPERF_TRACE_SCOPED("Animation end and current sceneId=%s", sceneId.c_str());
105 HIVIEW_LOGD("Animation stop and current sceneId: %{public}s", sceneId.c_str());
106 if (record != nullptr) {
107 SceneMonitor::GetInstance().FlushSubHealthInfo();
108 int64_t mVsyncTime = InputMonitor::GetInstance().GetVsyncTime();
109 record->Report(sceneId, mVsyncTime, isRsRender);
110 ReportAnimateEnd(sceneId, record);
111 RemoveRecord(sceneId);
112 XperfAsyncTraceEnd(0, sceneId.c_str());
113 } else {
114 HIVIEW_LOGW("Animation has not started, sceneId: %{public}s", sceneId.c_str());
115 }
116 }
117
OnVsyncEvent(int64_t vsyncTime,int64_t duration,double jank,const std::string & windowName)118 void AnimatorMonitor::OnVsyncEvent(int64_t vsyncTime, int64_t duration, double jank, const std::string& windowName)
119 {
120 std::lock_guard<std::mutex> Lock(mMutex);
121 InputMonitor::GetInstance().SetVsyncTime(vsyncTime);
122 int32_t skippedFrames = static_cast<int32_t> (jank);
123 for (auto it = mRecords.begin(); it != mRecords.end();) {
124 if (it->second != nullptr) {
125 (it->second)->RecordFrame(vsyncTime, duration, skippedFrames);
126 if ((it->second)->IsTimeOut(vsyncTime + duration)) {
127 SceneMonitor::GetInstance().OnSceneChanged(SceneType::NON_EXPERIENCE_ANIMATOR,
128 false, it->second->sceneId);
129 delete it->second;
130 it = mRecords.erase(it);
131 continue;
132 }
133 if ((it->second)->IsFirstFrame()) {
134 ReportAnimateStart(it->first, it->second);
135 }
136 }
137 it++;
138 }
139 }
140
RecordsIsEmpty()141 bool AnimatorMonitor::RecordsIsEmpty()
142 {
143 std::lock_guard<std::mutex> Lock(mMutex);
144 return mRecords.empty();
145 }
146
GetRecord(const std::string & sceneId)147 AnimatorRecord* AnimatorMonitor::GetRecord(const std::string& sceneId)
148 {
149 auto iter = mRecords.find(sceneId);
150 if (iter != mRecords.end()) {
151 return iter->second;
152 }
153 return nullptr;
154 }
155
SetSubHealthInfo(const SubHealthInfo & info)156 void AnimatorMonitor::SetSubHealthInfo(const SubHealthInfo& info)
157 {
158 subHealthRecordTime = GetCurrentSystimeMs();
159 SceneMonitor::GetInstance().SetSubHealthInfo(info);
160 }
161
IsSubHealthScene()162 bool AnimatorMonitor::IsSubHealthScene()
163 {
164 return (GetCurrentSystimeMs() - subHealthRecordTime < VAILD_JANK_SUB_HEALTH_INTERVAL);
165 }
166
RemoveRecord(const std::string & sceneId)167 void AnimatorMonitor::RemoveRecord(const std::string& sceneId)
168 {
169 std::map <std::string, AnimatorRecord*>::iterator iter = mRecords.find(sceneId);
170 if (iter != mRecords.end()) {
171 if (iter->second != nullptr) {
172 delete iter->second;
173 }
174 mRecords.erase(iter);
175 }
176 }
177
isValidSceneId(const std::string & sceneId)178 bool AnimatorMonitor::isValidSceneId(const std::string& sceneId)
179 {
180 if (sceneId.empty()) {
181 return false;
182 }
183 return validSceneIds.count(sceneId);
184 }
185
FlushDataBase(AnimatorRecord * record,DataBase & data)186 void AnimatorMonitor::FlushDataBase(AnimatorRecord* record, DataBase& data)
187 {
188 if (record == nullptr) {
189 return;
190 }
191 data.sceneId = record->sceneId;
192 data.inputTime = record->inputTime;
193 data.beginVsyncTime = record->beginVsyncTime;
194 if (data.beginVsyncTime < data.inputTime) {
195 data.inputTime = data.beginVsyncTime;
196 }
197 data.endVsyncTime = record->endVsyncTime;
198 if (data.beginVsyncTime > data.endVsyncTime) {
199 data.endVsyncTime = data.beginVsyncTime;
200 }
201 data.maxFrameTime = record->maxFrameTime;
202 data.maxFrameTimeSinceStart = record->maxFrameTimeSinceStart;
203 data.maxHitchTime = record->maxHitchTime;
204 data.maxHitchTimeSinceStart = record->maxHitchTimeSinceStart;
205 data.maxSuccessiveFrames = record->maxSuccessiveFrames;
206 data.totalMissed = record->totalMissed;
207 data.totalFrames = record->totalFrames;
208 data.needReportRs = record->needReportRs;
209 data.isDisplayAnimator = record->isDisplayAnimator;
210 data.sourceType = record->sourceType;
211 data.actionType = record->actionType;
212 data.baseInfo = SceneMonitor::GetInstance().GetBaseInfo();
213 data.baseInfo.note = record->note;
214 }
215
ReportAnimateStart(const std::string & sceneId,AnimatorRecord * record)216 void AnimatorMonitor::ReportAnimateStart(const std::string& sceneId, AnimatorRecord* record)
217 {
218 if (record == nullptr) {
219 return;
220 }
221 DataBase data;
222 FlushDataBase(record, data);
223 PerfReporter::GetInstance().ReportAnimatorEvent(EVENT_RESPONSE, data);
224 }
225
ReportAnimateEnd(const std::string & sceneId,AnimatorRecord * record)226 void AnimatorMonitor::ReportAnimateEnd(const std::string& sceneId, AnimatorRecord* record)
227 {
228 if (record == nullptr) {
229 return;
230 }
231 DataBase data;
232 FlushDataBase(record, data);
233 PerfReporter::GetInstance().ReportAnimatorEvent(EVENT_JANK_FRAME, data);
234 PerfReporter::GetInstance().ReportAnimatorEvent(EVENT_COMPLETE, data);
235 }
236
237 }
238 }