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 <set>
17
18 #include "jank_frame_monitor.h"
19 #include "perf_reporter.h"
20 #include "perf_trace.h"
21 #include "perf_utils.h"
22 #include "scene_monitor.h"
23 #include "hiview_logger.h"
24
25 namespace OHOS {
26 namespace HiviewDFX {
27 DEFINE_LOG_LABEL(0xD002D66, "Hiview-PerfMonitor");
28
GetInstance()29 JankFrameMonitor& JankFrameMonitor::GetInstance()
30 {
31 static JankFrameMonitor instance;
32 return instance;
33 }
34
JankFrameMonitor()35 JankFrameMonitor::JankFrameMonitor()
36 {
37 InitJankFrameRecord();
38 RegisterFrameCallback(this);
39 }
40
~JankFrameMonitor()41 JankFrameMonitor::~JankFrameMonitor()
42 {
43 UnregisterFrameCallback(this);
44 }
45
RegisterFrameCallback(IFrameCallback * cb)46 void JankFrameMonitor::RegisterFrameCallback(IFrameCallback* cb)
47 {
48 std::lock_guard<std::mutex> Lock(mMutex);
49 if (std::find(frameCallbacks.begin(), frameCallbacks.end(), cb) == frameCallbacks.end()) {
50 frameCallbacks.push_back(cb);
51 }
52 }
53
UnregisterFrameCallback(IFrameCallback * cb)54 void JankFrameMonitor::UnregisterFrameCallback(IFrameCallback* cb)
55 {
56 std::lock_guard<std::mutex> Lock(mMutex);
57 auto it = std::find(frameCallbacks.begin(), frameCallbacks.end(), cb);
58 if (it != frameCallbacks.end()) {
59 frameCallbacks.erase(it);
60 }
61 }
62
OnFrameEnd(int64_t vsyncTime,int64_t duration,double jank,const std::string & windowName)63 void JankFrameMonitor::OnFrameEnd(int64_t vsyncTime, int64_t duration, double jank, const std::string& windowName)
64 {
65 AnimatorMonitor::GetInstance().OnVsyncEvent(vsyncTime, duration, jank, windowName);
66 for (auto* cb: frameCallbacks) {
67 cb->OnVsyncEvent(vsyncTime, duration, jank, windowName);
68 }
69 }
70
OnVsyncEvent(int64_t vsyncTime,int64_t duration,double jank,const std::string & windowName)71 void JankFrameMonitor::OnVsyncEvent(int64_t vsyncTime, int64_t duration, double jank, const std::string& windowName)
72 {
73 SceneMonitor::GetInstance().OnSceneChanged(SceneType::NON_EXPERIENCE_WINDOW, true, windowName);
74 if (AnimatorMonitor::GetInstance().IsSubHealthScene()) {
75 SceneMonitor::GetInstance().FlushSubHealthInfo();
76 }
77 ProcessJank(vsyncTime, jank, windowName);
78 JankFrameStatsRecord(jank);
79 SceneMonitor::GetInstance().SingleFrameSceneStop(windowName);
80 }
81
ProcessJank(int64_t vsyncTime,double jank,const std::string & windowName)82 void JankFrameMonitor::ProcessJank(int64_t vsyncTime, double jank, const std::string& windowName)
83 {
84 // single frame behavior report
85 if (jank >= static_cast<double>(DEFAULT_JANK_REPORT_THRESHOLD)) {
86 HIVIEW_LOGI("JankFrameMonitor::ProcessJank jank >= threshold");
87 JankInfo jankInfo;
88 jankInfo.skippedFrameTime = static_cast<int64_t>(jank * SINGLE_FRAME_TIME);
89 jankInfo.windowName = windowName;
90 jankInfo.baseInfo = SceneMonitor::GetInstance().GetBaseInfo();
91 jankInfo.sceneTag = SceneMonitor::GetInstance().GetNonexpFilterTag();
92 jankInfo.vsyncTime = vsyncTime;
93 if (!AnimatorMonitor::GetInstance().RecordsIsEmpty()) {
94 jankInfo.sceneId = SceneMonitor::GetInstance().GetCurrentSceneId();
95 } else {
96 jankInfo.sceneId = DEFAULT_SCENE_ID;
97 }
98 jankInfo.realSkippedFrameTime = jankInfo.sceneTag == 0 ? jankInfo.skippedFrameTime : 0;
99 PerfReporter::GetInstance().ReportSingleJankFrame(jankInfo);
100 }
101 }
102
JankFrameStatsRecord(double jank)103 void JankFrameMonitor::JankFrameStatsRecord(double jank)
104 {
105 std::lock_guard<std::mutex> Lock(mMutex);
106 if (SceneMonitor::GetInstance().GetIsStats() && jank > 1.0f && !jankFrameRecord.empty()) {
107 jankFrameRecord[GetJankLimit(jank)]++;
108 jankFrameTotalCount++;
109 }
110 }
111
InitJankFrameRecord()112 void JankFrameMonitor::InitJankFrameRecord()
113 {
114 jankFrameRecord = std::vector<uint16_t>(JANK_STATS_SIZE, 0);
115 }
116
ClearJankFrameRecord()117 void JankFrameMonitor::ClearJankFrameRecord()
118 {
119 std::lock_guard<std::mutex> Lock(mMutex);
120 std::fill(jankFrameRecord.begin(), jankFrameRecord.end(), 0);
121 jankFrameTotalCount = 0;
122 jankFrameRecordBeginTime = 0;
123 }
124
SetJankFrameRecordBeginTime(int64_t val)125 void JankFrameMonitor::SetJankFrameRecordBeginTime(int64_t val)
126 {
127 std::lock_guard<std::mutex> Lock(mMutex);
128 jankFrameRecordBeginTime = val;
129 return;
130 }
131
GetJankFrameRecordBeginTime()132 int64_t JankFrameMonitor::GetJankFrameRecordBeginTime()
133 {
134 std::lock_guard<std::mutex> Lock(mMutex);
135 return jankFrameRecordBeginTime;
136 }
137
GetJankFrameTotalCount()138 int32_t JankFrameMonitor::GetJankFrameTotalCount()
139 {
140 std::lock_guard<std::mutex> Lock(mMutex);
141 return jankFrameTotalCount;
142 }
143
GetJankFrameRecord()144 const std::vector<uint16_t>& JankFrameMonitor::GetJankFrameRecord()
145 {
146 std::lock_guard<std::mutex> Lock(mMutex);
147 return jankFrameRecord;
148 }
149
GetJankLimit(double jank)150 uint32_t JankFrameMonitor::GetJankLimit(double jank)
151 {
152 if (jank < 6.0f) {
153 return JANK_FRAME_6_LIMIT;
154 }
155 if (jank < 15.0f) {
156 return JANK_FRAME_15_LIMIT;
157 }
158 if (jank < 20.0f) {
159 return JANK_FRAME_20_LIMIT;
160 }
161 if (jank < 36.0f) {
162 return JANK_FRAME_36_LIMIT;
163 }
164 if (jank < 48.0f) {
165 return JANK_FRAME_48_LIMIT;
166 }
167 if (jank < 60.0f) {
168 return JANK_FRAME_60_LIMIT;
169 }
170 if (jank < 120.0f) {
171 return JANK_FRAME_120_LIMIT;
172 }
173 return JANK_FRAME_180_LIMIT;
174 }
175 }
176 }